Skip to main content

Autogenerates Python classes for communicating with Zigbee2MQTT

Project description

pyziggy

Source@Github — Documentation — PyPI


Control Zigbee2MQTT with Python scripts and no boilerplate. Based on a configuration file the pyziggy run command will

  • connect to an MQTT server
  • download the device information posted by Zigbee2MQTT
  • generate Python classes for each parameter under each device
    • in a way where each parameter will have setters, getters or query functions based on the reported access flags
  • relay MQTT communication between the broker and these generated classes
  • load a user specified script, which can import said autogenerated classes, and use mypy to check the correctness of it
  • maintain MQTT communication until the user decides to terminate it.

This way instead of composing and parsing MQTT messages, user scripts can mutate Python objects to interact with the Zigbee network. Using an IDE you should have full code completion to take the guesswork out of interacting with your smart devices.

# Your IDE should offer valid choices after each press of .
devices.color_bulb.brightness.set_normalized(0.5)

The optional Flask integration makes it easy for scripts to expose an HTTP interface that interacts with the device objects.

Getting started

First you need a working Zigbee2MQTT installation. You should be able to reach the MQTT broker from the machine that's meant to run pyziggy. Please refer to the Zigbee2MQTT documentation for details about this.

If you have a Python 3.12+ environment, you can install pyziggy with:

pip install pyziggy

Create an empty directory for your automation scripts. Navigate to it and issue

pyziggy run automation.py

and follow the instructions.

A minimal automation project

Side note: I like to set up a virtual environment in the .venv subdirectory of my project directory. I do this with the pyziggy-setup script.


The rest of the documentation will assume, that you set up an automation project by issuing the following commands.

mkdir my_automation
cd my_automation
pyziggy run automation.py

Pyziggy will create a default config.toml file in the directory, instruct you to edit it and exit. After specifying your MQTT connection details, you need to issue the command again:

pyziggy run automation.py

This would result in the following directory contents.

my_automation/
├─ pyziggy_autogenerate/
│  └─ available_devices.py
├─ automation.py
└─ config.toml

After the first execution of pyziggy run automation.py you were instructed to edit the config.toml file so that it contains accurate information about connecting to the MQTT broker.

The contents of the initially autogenerated (but editable) automation.py file would be as follows

from pyziggy_autogenerate.available_devices import AvailableDevices

devices = AvailableDevices()

Although it won't do much, this is a fully formed automation module file that's ready to go.

Next steps

The way to get the most out of pyziggy is to use an IDE with code completion features. PyCharm is my favourite, which is free for non-professional use. If your automation directory contains a virtual environment in .venv, all you need to do is open it in PyCharm, and it should be correctly configured.

Open your automation.py file and start editing it. Typing devices. should show you suggestions for all the devices that Zigbee2MQTT knows about. Going further and typing e.g. devices.color_bulb. will show suggestions for all the parameters of color_bulb that can be queried, set or both. Not every parameter is settable, in which case it will not have setter functions.

All public members of devices are your actual devices that Zigbee2MQTT knows about and pyziggy could successfully parse. And all public members of each device are parameters, such as brightness or color_temp in case of a smart light bulb.

Most home automation tasks can be implemented by

  • calling setters and getters on the parameters in {mod}pyziggy.parameters
  • attaching change listeners to...
    • your parameters: {class}pyziggy.parameters.ParameterBase
    • the global on_connect event on the devices variable: {attr}pyziggy.devices_client.DevicesClient.on_connect
  • creating {class}pyziggy.message_loop.MessageLoopTimer objects that can interact with the parameters in a thread-safe way

A full example

A complete automation project running in our home is available at https://github.com/bebump/pyziggy-example.

For simpler examples with more explanation, see the chapter.

Startup sequence

Understanding the inner workings of pyziggy can be helpful for debugging or supporting advanced use-cases, but for getting started it isn’t necessary. For the curious, there are even more explanations spread out over the API reference.

At this point, after issuing the pyziggy run automation.py command in the my_automation directory, pyziggy will

  1. Check that the config.toml file is correct and connection to the MQTT broker is possible.
  2. Connect to the MQTT broker and wait for a message on the bridge/devices topic.
    1. If it receives the message, it regenerates the pyziggy_autogenerate/available_devices.py file based on its contents. The file should now only contain devices and parameters of devices that the MQTT broker presently knows about.
    2. If the message isn't received for 5 seconds, the program times out and exits with code 1. This allows service management daemons to detect the error condition, and retry later or take some other action.
  3. Checks the correctness of automation.py by running mypy. For example, if automation.py is trying to access a device or a parameter of the device that doesn't exist, or is misspelled, that will generate an error at this point and the program will exit with code 1.
  4. Imports the automation.py module. Checks that it has exactly one public member object that is an instance of the DevicesClient class. AvailableDevices inherits from DevicesClient so the devices object will pass this check. If this check fails, the program exits with code 1.
  5. Checks whether the automation.py module defines a member object that is an instance of the flask.Flask class. This is optional and failing this check has no consequence.
    1. If a Flask object was found, a web server is started listening on the port specified by flask_port in config.toml. Requests sent to this port are routed to the Flask object.
  6. The program initiates a connection to the MQTT broker and enters an infinite message loop. On sucessful connection the listeners of the DevicesClient.on_connect {class}pyziggy.broadcasters.Broadcaster are called.
  7. Upon receiving the SIGINT signal, the program stops the infinite loop and cleanly exits with code 0. You can use CTRL+C to send SIGINT if running pyziggy in the terminal.

Running as a service

Pyziggy was designed with running as a service in mind. I only know how to do this on MacOS, but this information can probably be adapted to other platforms as well.

MacOS

You need to add the following .plist file to $HOME/Library/LaunchAgents.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>net.bebump.pyziggy/string>

    <key>ProgramArguments</key>
    <array>
        <string>/Users/ExampleUser/my_automation/.venv/bin/python</string>
        <string>-m</string>
        <string>pyziggy</string>
        <string>run</string>
        <string>/Users/ExampleUser/my_automation/automation.py</string>
    </array>

    <key>WorkingDirectory</key>
    <string>/Users/ExampleUser/my_automation</string>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <true/>

    <key>StandardOutPath</key>
    <string>/tmp/net.bebump.pyziggy/stdout.log</string>

    <key>StandardErrorPath</key>
    <string>/tmp/net.bebump.pyziggy/stderr.log</string>
</dict>
</plist>

You can start the service by issuing

launchctl load ~/Library/LaunchAgents/net.bebump.pyziggy.plist

and stop and uninstall it by

launchctl unload net.bebump.pyziggy.plist && rm ~/Library/LaunchAgents/net.bebump.pyziggy.plist

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyziggy-0.9.1.tar.gz (83.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyziggy-0.9.1-py3-none-any.whl (82.0 kB view details)

Uploaded Python 3

File details

Details for the file pyziggy-0.9.1.tar.gz.

File metadata

  • Download URL: pyziggy-0.9.1.tar.gz
  • Upload date:
  • Size: 83.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.11

File hashes

Hashes for pyziggy-0.9.1.tar.gz
Algorithm Hash digest
SHA256 1465638ff9b61f1da4555f78f60967e4d484f83f90fb521cd542a34e4b51c446
MD5 1a06355412b8ad4fd78733b482b0ebb2
BLAKE2b-256 1187385f954490b50686275a12bcf470eeeeb27ebf06f1f5300ff53905d75a16

See more details on using hashes here.

File details

Details for the file pyziggy-0.9.1-py3-none-any.whl.

File metadata

  • Download URL: pyziggy-0.9.1-py3-none-any.whl
  • Upload date:
  • Size: 82.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.11

File hashes

Hashes for pyziggy-0.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a812ea630d213f4dcdde01307496a249fb4ee87e4735697f57524cfef04d8283
MD5 65ee002b5aca5186ad18dc68f74de0d3
BLAKE2b-256 8af9dfbeaa5116364de87e9ddfce8d143c5376e514372344cbff21fb2301171c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page