Rework and restructure MQTT
This commit is contained in:
parent
6c0f1c3d13
commit
67a25eeef9
1 changed files with 54 additions and 27 deletions
|
@ -116,28 +116,37 @@ PayloadType: TypeAlias = str | bytes | bytearray | int | float | None
|
|||
|
||||
|
||||
class MqttConsumer(BaseConsumer):
|
||||
client: mqtt.Client
|
||||
initialized: List[str]
|
||||
|
||||
_client: mqtt.Client | None = None
|
||||
|
||||
def __init__(self, settings: Dict[str, Any]) -> None:
|
||||
self.initialized = []
|
||||
|
||||
super().__init__(settings)
|
||||
self.client = mqtt.Client(client_id=settings["client"]["id"], userdata=self)
|
||||
self.client.on_connect = self.on_connect
|
||||
self.client.on_message = self.on_message
|
||||
self.client.on_disconnect = self.on_disconnect
|
||||
self.client.on_connect_fail = self.on_connect_fail
|
||||
|
||||
@property
|
||||
def client(self) -> mqtt.Client:
|
||||
if self._client is not None:
|
||||
return self._client
|
||||
|
||||
self._client = mqtt.Client(
|
||||
client_id=self.settings["client"]["id"], userdata=self
|
||||
)
|
||||
self._client.on_connect = self.on_connect
|
||||
self._client.on_message = self.on_message
|
||||
self._client.on_disconnect = self.on_disconnect
|
||||
self._client.on_connect_fail = self.on_connect_fail
|
||||
# Will must be set before connecting!!
|
||||
self.client.will_set(
|
||||
self._client.will_set(
|
||||
f"{self.topic_prefix}/available", payload="offline", retain=True
|
||||
)
|
||||
while True:
|
||||
try:
|
||||
self.client.connect(
|
||||
settings["client"]["host"],
|
||||
settings["client"]["port"],
|
||||
settings["client"]["keepalive"],
|
||||
self._client.connect(
|
||||
self.settings["client"]["host"],
|
||||
self.settings["client"]["port"],
|
||||
self.settings["client"]["keepalive"],
|
||||
)
|
||||
break
|
||||
except OSError as err:
|
||||
|
@ -151,6 +160,7 @@ class MqttConsumer(BaseConsumer):
|
|||
raise
|
||||
print(err)
|
||||
sleep(0.1)
|
||||
return self._client
|
||||
|
||||
def config(self, settings: Dict[str, Any]):
|
||||
super().config(settings)
|
||||
|
@ -167,9 +177,19 @@ class MqttConsumer(BaseConsumer):
|
|||
|
||||
settings.setdefault("discovery_prefix", "homeassistant")
|
||||
|
||||
_controller_id: str | None = None
|
||||
|
||||
@property
|
||||
def controller_id(self) -> str:
|
||||
assert self.controller is not None
|
||||
# Controller serial is fetched from device, cache it.
|
||||
if self._controller_id is None:
|
||||
self._controller_id = self.controller.serial
|
||||
return f"{self.controller.manufacturer_id}_{self._controller_id}"
|
||||
|
||||
@property
|
||||
def topic_prefix(self):
|
||||
return f"{self.settings['prefix']}/{self.settings['device_id']}"
|
||||
return f"{self.settings['prefix']}/{self.controller_id}"
|
||||
|
||||
def get_ha_config(
|
||||
self,
|
||||
|
@ -181,21 +201,25 @@ class MqttConsumer(BaseConsumer):
|
|||
state_class: Optional[str] = None,
|
||||
):
|
||||
assert state_class in [None, "measurement", "total", "total_increasing"]
|
||||
assert self.controller is not None
|
||||
|
||||
res = {
|
||||
"~": f"{self.topic_prefix}",
|
||||
"unique_id": f"{self.settings['device_id']}_{id}",
|
||||
"unique_id": f"{self.controller_id}_{id}",
|
||||
"object_id": f"{self.controller_id}_{id}",
|
||||
"availability_topic": "~/available",
|
||||
"state_topic": f"~/{id}",
|
||||
"name": name,
|
||||
"device": {
|
||||
"identifiers": [
|
||||
self.settings["device_id"],
|
||||
self.controller_id,
|
||||
],
|
||||
# TODO: Get charger serial and use for identifier instead
|
||||
# See: https://www.home-assistant.io/integrations/sensor.mqtt/#device
|
||||
# "via_device": self.settings["device_id"],
|
||||
"manufacturer": self.controller.manufacturer,
|
||||
"model": self.controller.model,
|
||||
"hw_version": self.controller.version,
|
||||
"via_device": self.settings["device_id"],
|
||||
"suggested_area": "Solar panel",
|
||||
"name": self.controller.name,
|
||||
},
|
||||
"force_update": True,
|
||||
"expire_after": expiry,
|
||||
|
@ -253,22 +277,25 @@ class MqttConsumer(BaseConsumer):
|
|||
def write(self, data: Dict[str, PayloadType]):
|
||||
self.client.publish(f"{self.topic_prefix}/raw", payload=json.dumps(data))
|
||||
|
||||
for k, v in data.items():
|
||||
if k in MAP_VALUES:
|
||||
if k not in self.initialized:
|
||||
km = MAP_VALUES[DataName(k)]
|
||||
pretty_name = k.replace("_", " ").capitalize()
|
||||
for dataname, data_value in data.items():
|
||||
if dataname in MAP_VALUES:
|
||||
if dataname not in self.initialized:
|
||||
km = MAP_VALUES[DataName(dataname)]
|
||||
pretty_name = dataname.replace("_", " ").capitalize()
|
||||
disc_prefix = self.settings["discovery_prefix"]
|
||||
device_id = self.settings["device_id"]
|
||||
|
||||
self.client.publish(
|
||||
f"{disc_prefix}/sensor/{device_id}_{k}/config",
|
||||
payload=json.dumps(self.get_ha_config(k, pretty_name, **km)),
|
||||
f"{disc_prefix}/sensor/{self.controller_id}/{dataname}/config",
|
||||
payload=json.dumps(
|
||||
self.get_ha_config(dataname, pretty_name, **km)
|
||||
),
|
||||
retain=True,
|
||||
)
|
||||
self.initialized.append(k)
|
||||
self.initialized.append(dataname)
|
||||
|
||||
self.client.publish(f"{self.topic_prefix}/{k}", v, retain=True)
|
||||
self.client.publish(
|
||||
f"{self.topic_prefix}/{dataname}", data_value, retain=True
|
||||
)
|
||||
|
||||
def exit(self):
|
||||
self.client.publish(
|
||||
|
|
Loading…
Reference in a new issue