Skip to main content

Pyowershades

Pyowershades is an asyncio Python library for communicating with PowerShades motorized shade controllers over UDP. It handles connection management, packet building and parsing, device discovery, and asynchronous status push callbacks. While orginally developed for use in Home Assistant it can work for any asyncio application.

Requirements

  • Python 3.12+

Installation

pip install pyowershades

Usage

Discover devices on the network

import asyncio
from pyowershades import async_discover_devices

async def main():
    devices = await async_discover_devices(["192.168.1.255"])
    for device in devices:
        print(device)  # {"ip": "192.168.1.50", "serial": 12345, "model": 1}

asyncio.run(main())

Connect to a shade and control it

import asyncio
from pyowershades import PowerShadesConnection, OP_SET_POSITION, build_set_position_payload

async def main():
    conn = PowerShadesConnection("192.168.1.50")
    await conn.async_connect()

    # Move to 50%
    await conn.async_request(OP_SET_POSITION, build_set_position_payload(50))

    conn.close()

asyncio.run(main())

Receive live status pushes

from pyowershades import PowerShadesConnection, StatusReply, parse_status_reply

def on_status(status: StatusReply) -> None:
    print(f"Position: {status.position}%  Battery: {status.battery_mv} mV")

conn = PowerShadesConnection("192.168.1.50")
conn.set_status_callback(on_status)
await conn.async_connect()

The shade sends status pushes to whichever UDP socket last sent it a command (the "UDP subscriber"). As long as your connection stays active and periodically polls the device, it will receive live position updates.

API reference

Discovery

async_discover_devices(local_addresses: list[str], timeout: float = ...) -> list[DiscoveredDevice]
async_get_device_info(ip: str, timeout: float = ...) -> PowerShadesDeviceInfo

Connection

class PowerShadesConnection:
    def __init__(self, ip: str) -> None
    async def async_connect(self) -> None
    async def async_request(self, op: int, payload: bytes = b"", ...) -> bytes
    def set_status_callback(self, callback: Callable[[StatusReply], None]) -> None
    def close(self) -> None

Raises PowerShadesTimeoutError if the device does not respond.

Packet building

Function Description
build_packet(op, payload) Build a raw UDP packet for any opcode
build_set_position_payload(percent) Payload for moving to a position (0–100)
build_set_limit_payload(limit_type) Payload for setting upper/lower limits
build_set_name_payload(name) Payload for renaming a PoE shade

Parsing

Function Description
parse_status_reply(data) Parse a status packet into a StatusReply
parse_serial_reply(data) Parse a serial/model reply
parse_shade_name_reply(data) Parse a shade name reply
parse_device_name_reply(data) Parse a device name reply
parse_error_list(raw) Decode Get Debug Info's error_list (comma-separated PoEErrorCode values) into list[int]
battery_percentage(battery_mv) Convert mV to a battery percentage (0–100)

Constants

Opcodes (OP_GET_STATUS, OP_SET_POSITION, OP_JOG_UP, OP_JOG_DOWN, OP_JOG_STOP, OP_STEP_UP, OP_STEP_DOWN, OP_SET_LIMIT, OP_CLEAR_LIMITS, OP_INDICATE, OP_GET_SERIAL, OP_GET_SHADE_NAME, OP_GET_DEVICE_NAME), limit types (LIMIT_UPPER, LIMIT_LOWER), POE_ERROR_CODES (int → name mapping for parse_error_list's output), and timing constants (REQUEST_TIMEOUT, REQUEST_RETRIES, DISCOVERY_TIMEOUT).

See docs/PROTOCOL.md for a full reference of every UDP command the protocol supports, including ones this library doesn't implement yet.

Notes

  • PowerShades devices send status pushes only to the last controller that sent them a command. If another controller (e.g. the PowerShades app or Control4) sends a command, your connection will stop receiving pushes until it sends one again.
  • State inference (opening, closing, open, closed) is not done by this library (beacuse the shade does not send it), only raw position values are reported.
  • Push packets are sent every ~10 seconds by the shade while its moving.
  • Tested with PoE PowerShades controllers. RF hub support is unknown.
  • No authentitcation is needed to control the shade, this means anyone on your local network using this can control your shade(s).
  • See docs/KNOWN_BEHAVIORS.md for real-world behaviors observed on live installations that don't have a confirmed root cause yet (e.g. green LED activity rotating across shades).

License

MIT

Metadata

Release files for pyowershades 0.4.0

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

Source distribution (sdist)

Source distribution for pyowershades 0.4.0
File Size Uploaded
pyowershades-0.4.0.tar.gz 28.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyowershades 0.4.0
File Interpreter ABI Platform
pyowershades-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 46.0 kB

Release files / pyowershades-0.4.0.tar.gz

Download URL pyowershades-0.4.0.tar.gz
Size 28.0 kB
Tags Source
SHA-256 checksum
How to use checksums
3ceed42b6c9af55360a92b173a2f841b00c46300f79a97fcc1afdff6897fafa1
BLAKE2b-256 checksum
How to use checksums
29984ec8964d0e9456a37ca5bfb09266db20c8d5d24202721dfdad3c8fbc2b43
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 Sep 17, 2026.

Transparency log

Release files / pyowershades-0.4.0-py3-none-any.whl

Download URL pyowershades-0.4.0-py3-none-any.whl
Size 18.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
293175142f86738f001b7046f530b296051e1cfe83909f4e8c010fc9eaacce74
BLAKE2b-256 checksum
How to use checksums
0c631389d30066a03f05f73bb224e8e86483cb8cd47e771d1b1f7988966c10bb
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 Sep 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

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