Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

PowerView Connect

An async Python client for Hunter Douglas / Luxaflex PowerView Gen 3 gateways, over their local HTTP API and shade event stream.

It is built on what a real Gen 3 gateway was measured to do (see the protocol notes):

  • A move sends only the rails it names. The gateway leaves a rail that is not sent where it is, so a command to the top rail of a top-down/bottom-up shade can never undo a command to the bottom rail sent a moment before.
  • The event stream says when a shade starts and stops moving, whatever moved it: this client, the PowerView app, a scene, a voice assistant. Nothing needs polling while nothing moves.
  • A moving shade reports its live position, so a shade can be followed by polling it, and only it, while it moves. ShadeTracker decides when a move has ended.

aiohttp is its only dependency. It is unofficial: PowerView is a trademark of Hunter Douglas, which has nothing to do with this library.

Installation

pip install powerview-connect

Usage

import asyncio
import aiohttp
from powerview_connect import EventKind, PowerViewClient, Rail

async def main():
    async with aiohttp.ClientSession() as session:
        client = PowerViewClient(session, "<gateway-ip>")

        home = await client.get_home()                 # gateways, shades, scenes
        for shade in home.shades.values():
            print(shade.id, shade.name, shade.capability, dict(shade.positions))

        await client.set_positions([154], secondary=0.5)   # the top rail only
        await client.set_positions([154], primary=0.2)     # the bottom rail only

        async with client.shade_events(idle_timeout=360) as events:
            async for event in events:
                if event.kind == EventKind.MOTION_STOPPED:
                    print(event.shade_id, "stopped at", dict(event.current))

asyncio.run(main())

Use the address of the primary gateway: it lists the whole home, auxiliary gateways and their shades included. home.gateway_at(host) says which gateway an address is.

What a shade reports

A Shade carries its name, room, capabilities (named by capability), type, power_type (1 is hard-wired), firmware, positions, and signal_strength: how well the gateway hears it, in dBm, closer to 0 being stronger. battery names the battery status (BatteryStatus); a hard-wired shade reports one too, so it means something only where hard_wired is false.

Positions

Every rail runs from 0.0, fully closed, to 1.0, fully open:

Rail Is 0.0 1.0
Rail.PRIMARY the bottom rail of a top-down/bottom-up shade, the only rail of most others down up
Rail.SECONDARY the top rail of a top-down/bottom-up shade up down
Rail.TILT the vanes of a shade that tilts closed open

A top-down/bottom-up shade's own firmware stops a rail where it meets the other one, so a move that would cross them is safe to send.

Commands

Method Sends
set_positions(ids, primary=, secondary=, tilt=, velocity=) only the rails given, to every shade in ids, in one request
stop(ids) stop where they are
activate_scene(scene_id) a scene stored on the gateway

A command the gateway reports an error for raises CommandError. A client made with read_only=True refuses every command with ReadOnlyError before anything is sent.

Events

shade_events(idle_timeout) opens the event stream; iterating it yields a ShadeEvent for each event, with kind, shade_id, current and, for a motion start, target and eta:

EventKind When
MOTION_STARTED a move starts, from any source; the motor follows some seconds later
MOTION_STOPPED a move ends, with the final positions
BATTERY_ALERT right before every move, by hard-wired shades too
SHADE_ONLINE, SHADE_OFFLINE a shade is reachable again, or no longer

The stream ends when the gateway closes it, and raises CannotConnectError when it breaks or sends nothing for idle_timeout seconds; the gateway sends nothing while nothing moves, so reopen it. eta is the gateway's estimate of the move's time, which real moves took about twice as long as.

Following a move

ShadeTracker follows one shade. It does no I/O and reads no clock: give it the events, the positions polled while the shade moves, and the commands sent, each with the time.

tracker = ShadeTracker(shade.positions)
tracker.motion_started(event, now=time.monotonic())        # or tracker.command(now, {Rail.PRIMARY: 0.2})
while tracker.poll((await client.get_shade(shade.id)).positions, now=time.monotonic()):
    print(tracker.current[Rail.PRIMARY], tracker.direction(Rail.PRIMARY))
    await asyncio.sleep(1)

A move ends with whichever comes first: motion-stopped, the target reached and still for 1.5 s, no change for 6 s after the shade moved, no move at all 25 s after the command, or a timeout.

Testing your code

powerview_connect.testing.SimulatedGateway is a gateway on 127.0.0.1 that answers as a real one was measured to, for your own tests:

from powerview_connect import Capabilities, PowerViewClient, Rail
from powerview_connect.testing import SimulatedGateway

async with SimulatedGateway() as gateway:
    gateway.add_room(1, "Living Room")
    gateway.add_shade(10, "Window", room_id=1, capabilities=Capabilities.TOP_DOWN_BOTTOM_UP)
    client = PowerViewClient(session, gateway.host)
    await client.set_positions([10], primary=0.5)    # motion-started on every stream
    gateway.move(10, {Rail.PRIMARY: 0.2})            # part of the way, as a poll sees it
    gateway.finish(10)                               # at the target; motion-stopped
    print(gateway.requests[-1].body)                 # {'positions': {'primary': 0.5}}

It also drops streams (drop_streams), goes offline and comes back (close, start), reports a shade offline (set_online) and reports errors for commands (command_errors).

Metadata

Release files for powerview-connect 0.1.0rc2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for powerview-connect 0.1.0rc2
File Size Uploaded
powerview_connect-0.1.0rc2.tar.gz 46.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for powerview-connect 0.1.0rc2
File Interpreter ABI Platform
powerview_connect-0.1.0rc2-py3-none-any.whl Python 3 none any Details

Total release size: 65.3 kB

Release files / powerview_connect-0.1.0rc2.tar.gz

Download URL powerview_connect-0.1.0rc2.tar.gz
Size 46.2 kB
Tags Source
SHA-256 checksum
How to use checksums
c0b2592f725011255b57be0276f141059eef4a01ffa6db2fcd7f790d67a8d5c7
BLAKE2b-256 checksum
How to use checksums
3e71b73d58ba3bfb1a115abd98b9df81f1ab44d95823297917ba69d83abadfb0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / powerview_connect-0.1.0rc2-py3-none-any.whl

Download URL powerview_connect-0.1.0rc2-py3-none-any.whl
Size 19.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c26f06953f1bb16b9818693abbed4da8e134d8841c620e60b626a71e6118fd4e
BLAKE2b-256 checksum
How to use checksums
15566a817e9811ed2c0290771a247075df5832b9ef08a2e831c2fe58c5ee4cda
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page