Dedicated hardware poller + read-only consumers #4

Open
adamksmith wants to merge 13 commits from feat/dedicated-poller into main
Showing only changes of commit 44a7824425 - Show all commits

View File

@@ -80,7 +80,10 @@ class MqttPublisher:
self.discovery_prefix = os.environ.get("MQTT_DISCOVERY_PREFIX", "homeassistant") self.discovery_prefix = os.environ.get("MQTT_DISCOVERY_PREFIX", "homeassistant")
self.base_topic = os.environ.get("MQTT_BASE_TOPIC", "jbod-monitor") self.base_topic = os.environ.get("MQTT_BASE_TOPIC", "jbod-monitor")
self.interval = int(os.environ.get("MQTT_PUBLISH_INTERVAL", "60")) self.interval = int(os.environ.get("MQTT_PUBLISH_INTERVAL", "60"))
self.node = _slug(get_node_id()) self.node_raw = get_node_id()
self.node = _slug(self.node_raw)
# Parent "hub" device that the per-enclosure devices nest under.
self.hub_id = f"{self.node}_jbod_monitor"
self.availability_topic = f"{self.base_topic}/{self.node}/status" self.availability_topic = f"{self.base_topic}/{self.node}/status"
# unique_ids for which we've already published discovery this connection. # unique_ids for which we've already published discovery this connection.
@@ -127,6 +130,16 @@ class MqttPublisher:
logger.warning("MQTT disconnected: %s", reason_code) logger.warning("MQTT disconnected: %s", reason_code)
# discovery / state ------------------------------------------------------ # discovery / state ------------------------------------------------------
def _hub_device_block(self) -> dict:
"""The parent device the enclosures nest under (named, so HA doesn't
show an 'Unnamed Device')."""
return {
"identifiers": [self.hub_id],
"name": f"JBOD Monitor ({self.node_raw})",
"manufacturer": "jbod-monitor",
"model": "SES/SMART poller",
}
def _device_block(self, enc: dict) -> dict: def _device_block(self, enc: dict) -> dict:
enc_id = enc["id"] enc_id = enc["id"]
vendor = enc.get("vendor", "").strip() vendor = enc.get("vendor", "").strip()
@@ -137,9 +150,29 @@ class MqttPublisher:
"name": f"JBOD {name} ({enc_id})", "name": f"JBOD {name} ({enc_id})",
"manufacturer": vendor or None, "manufacturer": vendor or None,
"model": model or None, "model": model or None,
"via_device": f"{self.node}_jbod_monitor", "via_device": self.hub_id,
} }
def _publish_hub(self) -> None:
"""Announce the hub device via a connectivity binary_sensor, so the
parent device is named and shows monitor online/offline status."""
uid = f"{self.hub_id}_status"
if uid in self._discovered:
return
payload = {
"name": "Status",
"unique_id": uid,
"device_class": "connectivity",
"state_topic": self.availability_topic,
"payload_on": "online",
"payload_off": "offline",
"entity_category": "diagnostic",
"device": self._hub_device_block(),
}
topic = f"{self.discovery_prefix}/binary_sensor/{self.hub_id}/status/config"
self._client.publish(topic, json.dumps(payload), qos=1, retain=True)
self._discovered.add(uid)
def _publish_discovery(self, enc: dict) -> None: def _publish_discovery(self, enc: dict) -> None:
enc_id = enc["id"] enc_id = enc["id"]
enc_slug = _slug(enc_id) enc_slug = _slug(enc_id)
@@ -204,6 +237,7 @@ class MqttPublisher:
self._client.publish(state_topic, json.dumps(payload), qos=0, retain=True) self._client.publish(state_topic, json.dumps(payload), qos=0, retain=True)
def publish_snapshot(self, snapshot: dict) -> None: def publish_snapshot(self, snapshot: dict) -> None:
self._publish_hub() # name the parent device before nesting enclosures
for enc in snapshot.get("enclosures", []): for enc in snapshot.get("enclosures", []):
self._publish_discovery(enc) self._publish_discovery(enc)
self._publish_state(enc) self._publish_state(enc)