Cleaner discovery topics, ability to specify own node_id
This commit is contained in:
@@ -9,6 +9,7 @@ mqtt:
|
|||||||
monitor:
|
monitor:
|
||||||
interval: 15 # seconds between stat publishes
|
interval: 15 # seconds between stat publishes
|
||||||
device_name: "" # display name in HA; defaults to hostname
|
device_name: "" # display name in HA; defaults to hostname
|
||||||
|
node_id: "" # MQTT topic slug and unique_id prefix; defaults to hostname if empty
|
||||||
|
|
||||||
sensors:
|
sensors:
|
||||||
cpu: true
|
cpu: true
|
||||||
|
|||||||
+20
-8
@@ -62,6 +62,7 @@ def load_config(path: Path = CONFIG_PATH) -> dict:
|
|||||||
mn = cfg["monitor"]
|
mn = cfg["monitor"]
|
||||||
mn.setdefault("interval", 30)
|
mn.setdefault("interval", 30)
|
||||||
mn.setdefault("device_name", "")
|
mn.setdefault("device_name", "")
|
||||||
|
mn.setdefault("node_id", "")
|
||||||
|
|
||||||
s = cfg["sensors"]
|
s = cfg["sensors"]
|
||||||
s.setdefault("cpu", True)
|
s.setdefault("cpu", True)
|
||||||
@@ -711,14 +712,14 @@ class DiscoveryPublisher:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
client: mqtt.Client,
|
client: mqtt.Client,
|
||||||
hostname: str,
|
node_id: str,
|
||||||
device_name: str,
|
device_name: str,
|
||||||
state_topic: str,
|
state_topic: str,
|
||||||
availability_topic: str,
|
availability_topic: str,
|
||||||
discovery_prefix: str = "homeassistant",
|
discovery_prefix: str = "homeassistant",
|
||||||
):
|
):
|
||||||
self._client = client
|
self._client = client
|
||||||
self._hostname = hostname
|
self._node_id = node_id
|
||||||
self._device_name = device_name
|
self._device_name = device_name
|
||||||
self._state_topic = state_topic
|
self._state_topic = state_topic
|
||||||
self._availability_topic = availability_topic
|
self._availability_topic = availability_topic
|
||||||
@@ -726,7 +727,7 @@ def __init__(
|
|||||||
|
|
||||||
def _device_block(self) -> dict:
|
def _device_block(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"identifiers": [f"{self._hostname}_monitor"],
|
"identifiers": [f"{self._node_id}_monitor"],
|
||||||
"name": self._device_name,
|
"name": self._device_name,
|
||||||
"manufacturer": "monitor.py",
|
"manufacturer": "monitor.py",
|
||||||
"model": "Linux System Monitor",
|
"model": "Linux System Monitor",
|
||||||
@@ -740,7 +741,7 @@ def publish_all(self, sensor_defs: list[dict]) -> None:
|
|||||||
|
|
||||||
def _publish_one(self, defn: dict) -> None:
|
def _publish_one(self, defn: dict) -> None:
|
||||||
key = defn["key"]
|
key = defn["key"]
|
||||||
unique_id = f"{self._hostname}_{key}"
|
unique_id = f"{self._node_id}_{key}"
|
||||||
object_id = unique_id
|
object_id = unique_id
|
||||||
|
|
||||||
payload: dict[str, Any] = {
|
payload: dict[str, Any] = {
|
||||||
@@ -762,7 +763,7 @@ def _publish_one(self, defn: dict) -> None:
|
|||||||
payload["icon"] = defn["icon"]
|
payload["icon"] = defn["icon"]
|
||||||
|
|
||||||
discovery_topic = (
|
discovery_topic = (
|
||||||
f"{self._discovery_prefix}/sensor/{object_id}/config"
|
f"{self._discovery_prefix}/sensor/{self._node_id}/{object_id}/config"
|
||||||
)
|
)
|
||||||
self._client.publish(
|
self._client.publish(
|
||||||
discovery_topic,
|
discovery_topic,
|
||||||
@@ -836,22 +837,24 @@ def __init__(self, cfg: dict):
|
|||||||
self._cfg = cfg
|
self._cfg = cfg
|
||||||
self._hostname = socket.gethostname()
|
self._hostname = socket.gethostname()
|
||||||
self._device_name = cfg["monitor"].get("device_name") or self._hostname
|
self._device_name = cfg["monitor"].get("device_name") or self._hostname
|
||||||
|
raw_node_id = cfg["monitor"].get("node_id", "").strip()
|
||||||
|
self._node_id = self._make_node_id(raw_node_id or self._hostname)
|
||||||
self._interval = max(5, int(cfg["monitor"].get("interval", 30)))
|
self._interval = max(5, int(cfg["monitor"].get("interval", 30)))
|
||||||
|
|
||||||
prefix = cfg["mqtt"]["topic_prefix"]
|
prefix = cfg["mqtt"]["topic_prefix"]
|
||||||
self._state_topic, self._avail_topic = make_topics(prefix, self._hostname)
|
self._state_topic, self._avail_topic = make_topics(prefix, self._node_id)
|
||||||
|
|
||||||
self._collectors = self._build_collectors()
|
self._collectors = self._build_collectors()
|
||||||
self._sensor_defs = all_sensor_defs(self._collectors, self._hostname)
|
self._sensor_defs = all_sensor_defs(self._collectors, self._hostname)
|
||||||
|
|
||||||
self._client = build_client(cfg, self._hostname)
|
self._client = build_client(cfg, self._node_id)
|
||||||
self._client.on_connect = self._on_connect
|
self._client.on_connect = self._on_connect
|
||||||
self._client.on_disconnect = self._on_disconnect
|
self._client.on_disconnect = self._on_disconnect
|
||||||
self._client.on_message = self._on_message
|
self._client.on_message = self._on_message
|
||||||
|
|
||||||
self._discovery = DiscoveryPublisher(
|
self._discovery = DiscoveryPublisher(
|
||||||
self._client,
|
self._client,
|
||||||
self._hostname,
|
self._node_id,
|
||||||
self._device_name,
|
self._device_name,
|
||||||
self._state_topic,
|
self._state_topic,
|
||||||
self._avail_topic,
|
self._avail_topic,
|
||||||
@@ -862,6 +865,15 @@ def __init__(self, cfg: dict):
|
|||||||
# Warm up cpu_percent (first call always returns 0.0)
|
# Warm up cpu_percent (first call always returns 0.0)
|
||||||
psutil.cpu_percent(interval=None)
|
psutil.cpu_percent(interval=None)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _make_node_id(name: str) -> str:
|
||||||
|
"""Sanitize a string for use in MQTT topics and HA unique_ids."""
|
||||||
|
safe = "".join(c if c.isalnum() or c in "-_" else "-" for c in name.lower())
|
||||||
|
# Collapse consecutive hyphens and strip leading/trailing separators
|
||||||
|
while "--" in safe:
|
||||||
|
safe = safe.replace("--", "-")
|
||||||
|
return safe.strip("-_") or "monitor"
|
||||||
|
|
||||||
def _build_collectors(self) -> list:
|
def _build_collectors(self) -> list:
|
||||||
s = self._cfg["sensors"]
|
s = self._cfg["sensors"]
|
||||||
collectors = []
|
collectors = []
|
||||||
|
|||||||
Reference in New Issue
Block a user