Python SDK for Homie MQTT Convention (eBus)
Project description
ebus-sdk
Python SDK for the Electrification Bus (eBus) integration framework, which adopts and supports the Homie Convention.
Installation
pip install ebus-sdk
Quick Start
Device Role
Create a Homie device that publishes sensor data:
from ebus_sdk import Device, Node, PropertyDatatype, Unit
# Create device
device = Device('my-device-id', name='My Sensor', mqtt_cfg={
'host': 'mqtt.example.com',
'port': 1883
})
# Add a node with properties
node = device.add_node_from_dict({
'id': 'sensors',
'name': 'Sensors',
'type': 'sensor'
})
# Add a temperature property
temp = node.add_property_from_dict({
'id': 'temperature',
'name': 'Temperature',
'datatype': PropertyDatatype.FLOAT,
'unit': Unit.DEGREE_CELSIUS
})
# Start and publish
device.start_mqtt_client()
temp.set_value(23.5)
Device Trees (parent / child)
Build a tree of devices that share a single MQTT connection. The root device owns the connection (and the Last Will), every child borrows it via the parent= constructor arg, and $description root / parent / children fields are kept in sync automatically. The tree can be any depth.
panel = Device('panel-1', type='energy.ebus.device.electrical-panel', mqtt_cfg={...})
panel.start_mqtt_client()
# Add 32 circuit children inside one state transition — the broker sees
# exactly one INIT→READY cycle on the panel, not 32.
with panel.state_transition():
for cid in commissioned_circuits:
Device(id=cid, type='energy.ebus.device.circuit', parent=panel)
# Three-level tree: panel → BESS child → MID grandchild
bess = Device(id='bess-1', type='...battery-storage', parent=panel)
Device(id='mid-1', type='...metering', parent=bess)
# Remove a child at runtime (runs the Homie remove-child protocol)
panel.children()[0].delete()
Children may have children of their own. A single Last Will registered on the root marks the entire tree lost if the publisher process dies — controllers compute effective state per the Homie 5 precedence table (see HOMIE_EFFECTIVE_STATE_TABLE).
Controller Role
Discover and monitor Homie devices:
from ebus_sdk import Controller, DiscoveredDevice
def on_device_discovered(device: DiscoveredDevice):
print(f'Found: {device.device_id}')
def on_property_changed(device_id, node_id, prop_id, new_val, old_val):
print(f'{device_id}/{node_id}/{prop_id} = {new_val}')
controller = Controller(mqtt_cfg={'host': 'mqtt.example.com', 'port': 1883})
controller.set_on_device_discovered_callback(on_device_discovered)
controller.set_on_property_changed_callback(on_property_changed)
controller.start_discovery()
Controllers can also navigate device hierarchies and compute effective state:
# Walk the tree
roots = controller.get_root_devices()
for root in roots:
for descendant in controller.get_descendants(root.device_id):
# When the root is lost/disconnected/sleeping/init, every descendant
# is effectively the same regardless of its own reported $state.
print(f'{descendant.device_id}: {controller.get_effective_state(descendant.device_id)}')
Three controller discovery modes select what the controller listens for:
# Wildcard (default) — every device on the broker
Controller(mqtt_cfg=cfg)
# Single-device — subscribe to exactly one device, no children, no wildcards
Controller(mqtt_cfg=cfg, device_id='panel-1')
# Tree-rooted — subscribe to a root and auto-subscribe to its descendants
# as they're announced; subscription changes are gated on the parent's
# $state init→ready edge per the Homie 5 spec.
Controller(mqtt_cfg=cfg, root_device_id='panel-1')
Tree-rooted mode is the right pick for consumers that want exactly one
device's tree on a multi-publisher broker — wildcard would re-introduce
multi-panel scope creep at the application layer, and single-device would
see the root and none of its children. As the publisher mutates the tree
(Device(parent=...) to add, child.delete() to remove), descendants are
subscribed or dropped on the parent's next init→ready transition.
Module Structure
src/ebus_sdk/
├── __init__.py # Package exports
├── homie.py # Homie convention implementation (Device, Node, Property, Controller, ...)
└── property.py # Application-level property abstractions
MQTT transport lives in the separate ebus-mqtt-client package; this SDK depends on it.
homie.py
Core Homie convention implementation:
- Device - Represents a Homie device; pass
parent=to build a child in a tree - Node - Groups related properties within a device
- Property - Individual data points (sensors, controls)
- Controller - Discovers and monitors Homie devices on a broker; navigates trees and computes effective state
- DiscoveredDevice - Represents a device found by the controller; exposes
root_id,parent_id,children_ids,is_root - DeviceState - Enum:
init,ready,disconnected,sleeping,lost - HOMIE_EFFECTIVE_STATE_TABLE - Homie 5 state-precedence table used by
Controller.get_effective_state() - PropertyDatatype - Enum:
STRING,INTEGER,FLOAT,BOOLEAN,ENUM,COLOR,DATETIME,DURATION,JSON - Unit - Common units:
DEGREE_CELSIUS,PERCENT,WATT,KILOWATT_HOUR, etc.
property.py
Application-level property abstractions for bridging application state to Homie:
- Property - Thread-safe observable property with change callbacks
- GroupedPropertyDict - Two-level dictionary organizing properties by group
- PropertyDict - Simple property dictionary
- ChangeEvent - Enum for property change event types
Examples
See examples/README.md for example scripts demonstrating device and controller usage.
Requirements
- Python 3.10+
- paho-mqtt >= 1.6.1
Releases
See CHANGELOG.md. 0.2.0 introduces parent/child device trees and contains breaking changes to the Device constructor — see the changelog entry before upgrading from 0.1.x.
Contributing
See CONTRIBUTING.md for how to file Discussions, Issues, and pull requests. Pure MQTT-transport changes (TLS, auth, paho upgrades) belong in ebus-mqtt-client, not here. Normative behavior tracks the Electrification Bus specification.
License
MIT License — Copyright (c) 2026 Clark Communications Corporation
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ebus_sdk-0.3.1.tar.gz.
File metadata
- Download URL: ebus_sdk-0.3.1.tar.gz
- Upload date:
- Size: 54.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
142cc17429dd0e3fe151c6c7c516c6fd59854f0a9d229eaf11c311382ddd8851
|
|
| MD5 |
47b9c9909cf6df499d8c9c5dfb0d2200
|
|
| BLAKE2b-256 |
0c3b9011c36d4e74e1c596b3fe1bb2110e3c90fe4d9142b7476cbdd88a6f2d9c
|
Provenance
The following attestation bundles were made for ebus_sdk-0.3.1.tar.gz:
Publisher:
publish.yml on electrification-bus/python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ebus_sdk-0.3.1.tar.gz -
Subject digest:
142cc17429dd0e3fe151c6c7c516c6fd59854f0a9d229eaf11c311382ddd8851 - Sigstore transparency entry: 1820685449
- Sigstore integration time:
-
Permalink:
electrification-bus/python-sdk@cfe4d3c602c118b961ec4fbfd33ca3e88cba65ac -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/electrification-bus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cfe4d3c602c118b961ec4fbfd33ca3e88cba65ac -
Trigger Event:
push
-
Statement type:
File details
Details for the file ebus_sdk-0.3.1-py3-none-any.whl.
File metadata
- Download URL: ebus_sdk-0.3.1-py3-none-any.whl
- Upload date:
- Size: 33.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7770bc9fbb60c87c58b97a2c27708bac736740ed51d494b0dfddb3cfc2ce67bf
|
|
| MD5 |
babd1a32ecedec9497d206c92b5e6cbd
|
|
| BLAKE2b-256 |
903145e021ff6a470366b8eca0ad4b7d15650d37753a865b8d0179f69a5ff73f
|
Provenance
The following attestation bundles were made for ebus_sdk-0.3.1-py3-none-any.whl:
Publisher:
publish.yml on electrification-bus/python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ebus_sdk-0.3.1-py3-none-any.whl -
Subject digest:
7770bc9fbb60c87c58b97a2c27708bac736740ed51d494b0dfddb3cfc2ce67bf - Sigstore transparency entry: 1820685484
- Sigstore integration time:
-
Permalink:
electrification-bus/python-sdk@cfe4d3c602c118b961ec4fbfd33ca3e88cba65ac -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/electrification-bus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cfe4d3c602c118b961ec4fbfd33ca3e88cba65ac -
Trigger Event:
push
-
Statement type: