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 that occasionally lights every shade at once).

License

MIT

Metadata

Release files for pyowershades 0.4.1

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.1
File Size Uploaded
pyowershades-0.4.1.tar.gz 28.9 kB Details

Built distribution (wheel)

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

Total release size: 47.2 kB

Release files / pyowershades-0.4.1.tar.gz

Download URL pyowershades-0.4.1.tar.gz
Size 28.9 kB
Tags Source
SHA-256 checksum
How to use checksums
c67845f63f1e707bc013abcaa2c640f562545df93eb73532280da48f60ca1bd1
BLAKE2b-256 checksum
How to use checksums
7f94f03b3fc1c3d6bae759f913b97dd701021a1bfd68c96972aa315818f4b4f7
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 13, 2026.

Transparency log

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

Download URL pyowershades-0.4.1-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ccc49ed0c8face2137ba11dce4baf3497bbc1251341eac73cdbde0a458928745
BLAKE2b-256 checksum
How to use checksums
2c069c94b7d1eba8d970fc5891c9a0a643072625298cddbd849adef09236ff55
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 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.1 This release

2 release files

0.4.0

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