Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ See [`examples/README.md`](examples/README.md) for example scripts demonstrating
## Requirements

- Python 3.10+
- [`ebus-mqtt-client`](https://github.com/electrification-bus/ebus-mqtt-client) >= 0.3.0 (the MQTT transport layer; it pins `paho-mqtt`, so the SDK does not depend on paho directly. 0.3.0 ships the `py.typed` marker, so a downstream type checker resolves the re-exported `MqttClient` to the concrete class rather than `Any`; 0.2.0 adds the `on_disconnect_callback` the SDK's disconnect hook adopts; and, since 0.1.8, it carries the asynchronous, down-broker-tolerant connect the resilient-connect behavior relies on)
- [`ebus-mqtt-client`](https://github.com/electrification-bus/ebus-mqtt-client) >= 0.4.0 (the MQTT transport layer; it pins `paho-mqtt`, so the SDK does not depend on paho directly. 0.4.0 provides `MqttClient.asyncio_driver()`, the loop-native alternative to paho's background thread; 0.3.0 ships the `py.typed` marker, so a downstream type checker resolves the re-exported `MqttClient` to the concrete class rather than `Any`; 0.2.0 adds the `on_disconnect_callback` the SDK's disconnect hook adopts; and, since 0.1.8, it carries the asynchronous, down-broker-tolerant connect the resilient-connect behavior relies on)

Optional extras:

Expand Down
18 changes: 9 additions & 9 deletions doc/ha-discovery-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,17 @@ Two mechanisms preserve the `entity_id`:

1. **Set `default_entity_id` at creation.** `HAComponent` carries a typed `default_entity_id` field (emitted as HA's `default_entity_id`); set it to the OLD integration's `entity_id` and Home Assistant uses that id when it first creates the entity. This is the clean path for a device that has not been discovered yet. Set it from an override hook (or the customizer table):

```python
OLD_IDS = {("meter", "active-power"): "sensor.panel_main_power"} # prior entity_ids
```python
OLD_IDS = {("meter", "active-power"): "sensor.panel_main_power"} # prior entity_ids

def preserve_ids(component, ctx):
old = OLD_IDS.get((ctx.node_id, ctx.prop_id))
if old:
component.default_entity_id = old
return component
def preserve_ids(component, ctx):
old = OLD_IDS.get((ctx.node_id, ctx.prop_id))
if old:
component.default_entity_id = old
return component

HaDiscoveryBridge(controller, default_override=preserve_ids)
```
HaDiscoveryBridge(controller, default_override=preserve_ids)
```

`default_entity_id` applies only when the entity is first created; it has no effect on an entity that already exists.

Expand Down
4 changes: 4 additions & 0 deletions doc/packaging-for-legacy-setuptools.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,20 @@ setup()
2. Extract the sdist: `tar xzf dist/<pkg>-X.Y.Z.tar.gz -C /tmp`.
3. Confirm `setup.py` (or `setup.cfg [metadata]`) is present in the extracted tree.
4. Build a wheel using an **old** setuptools to simulate the legacy environment:

```bash
python -m venv /tmp/legacy-env
/tmp/legacy-env/bin/pip install 'setuptools<61' wheel
cd /tmp/<pkg>-X.Y.Z
/tmp/legacy-env/bin/python -m build --wheel --no-isolation
```

5. Inspect the produced wheel:

```bash
unzip -l dist/<pkg>-X.Y.Z-py3-none-any.whl
```

6. Confirm the wheel name is `<pkg>-X.Y.Z-...` (NOT `UNKNOWN-0.0.0-...`) and contains your actual `.py` files (not just `dist-info/` metadata).

If you have a Yocto consumer, a more authoritative test is to build the package via the bitbake recipe (e.g., on dsw-build-01) and inspect the produced `.deb` with `dpkg-deb -c`.
Expand Down
4 changes: 3 additions & 1 deletion src/ebus_sdk/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ def set_homie_property_from_python_property(homie_property: HomieProperty, pytho

This is the on-change adapter that mirrors the observable model to Homie.
Register it as the ``GroupedPropertyDict`` on-change callback for a
``(group, property_id)`` pair so every value change republishes to MQTT::
``(group, property_id)`` pair so every value change reaches MQTT (subject to
the Homie layer's own publish-on-change gate, which drops a republish whose
wire payload is unchanged -- see ``homie.Property.set_value``)::

properties.add_property_on_change_callback(
group,
Expand Down
9 changes: 5 additions & 4 deletions src/ebus_sdk/homie.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,8 +848,9 @@ def publish_value(self, *, force: bool = False) -> bool:
# NOTE: this clears the topic (empty MQTT payload). It does NOT
# represent an actual empty-string *value*, which the Homie 5
# convention encodes as a 1-character 0x00 payload — see the module
# header "empty string values" note; that encoding is not yet
# implemented (SDK-ef1 / known limitation).
# header "empty string values" note. That encoding IS implemented,
# below, via encode_empty_string(); the two payloads are distinct and
# only the zero-length one retracts a retained topic.
logger.debug(
f"reason=propertyPublishValueIsNoneClearing,deviceID={device_id},nodeID={node_id},propertyID={self._id}"
)
Expand Down Expand Up @@ -903,8 +904,8 @@ def clear_value(self) -> bool:
previously-published property (see ``publish_value``).

This clears the topic; it does NOT publish an actual empty-string
*value* (which the Homie 5 convention encodes as a 1-character 0x00
payload — not yet implemented, see the module header note).
*value*, which the Homie 5 convention encodes as a 1-character 0x00
payload and ``publish_value()`` emits via ``encode_empty_string()``.

No-ops (returns True) if the property was never published, to avoid
creating a phantom retained-empty topic. Returns True on success, else
Expand Down