Skip to content

Commit bbd798f

Browse files
committed
#292: Publish HA discovery on HA reconnection
1 parent 0963431 commit bbd798f

File tree

7 files changed

+40
-8
lines changed

7 files changed

+40
-8
lines changed

configuration/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def __init__(self):
3737
self.ha_discovery_enabled: bool = True
3838
self.ha_discovery_prefix: str = 'homeassistant'
3939
self.ha_show_unavailable: bool = True
40+
self.ha_lwt_topic: str = 'homeassistant/status'
4041
self.charge_dynamic_polling_min_percentage: float = 1.0
4142
self.publish_raw_api_data: bool = False
4243

handlers/vehicle.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ def __init__(
4747
True
4848
)
4949
self.vehicle_state = vehicle_state
50-
self.ha_discovery = HomeAssistantDiscovery(vehicle_state, vin_info, config)
50+
if self.configuration.ha_discovery_enabled:
51+
self.__ha_discovery = HomeAssistantDiscovery(vehicle_state, vin_info, config)
52+
else:
53+
self.__ha_discovery = None
5154

5255
self.__setup_abrp(config, vin_info)
5356
self.__setup_osmand(config, vin_info)
@@ -114,8 +117,7 @@ async def handle_vehicle(self) -> None:
114117
exc_info=e
115118
)
116119
finally:
117-
if self.configuration.ha_discovery_enabled:
118-
self.ha_discovery.publish_ha_discovery_messages()
120+
self.publish_ha_discovery_messages(force=False)
119121
else:
120122
# car not active, wait a second
121123
await asyncio.sleep(1.0)
@@ -464,6 +466,10 @@ def __get_command_topics(self, topic: str) -> tuple[str, str]:
464466
result_topic = global_topic_removed.removesuffix(SET_SUFFIX).removesuffix('/') + '/' + RESULT_SUFFIX
465467
return set_topic, result_topic
466468

469+
def publish_ha_discovery_messages(self, *, force: bool = False):
470+
if self.__ha_discovery is not None:
471+
self.__ha_discovery.publish_ha_discovery_messages(force=force)
472+
467473

468474
class VehicleHandlerLocator(ABC):
469475

integrations/home_assistant/discovery.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ def __init__(self, vehicle_state: VehicleState, vin_info: VinInfo, configuration
9696
)
9797
self.published = False
9898

99-
def publish_ha_discovery_messages(self):
100-
if self.published:
101-
LOG.debug("Skipping Home Assistant discovery messages as it was already published")
102-
return
103-
99+
def publish_ha_discovery_messages(self, *, force: bool = False):
104100
if not self.__vehicle_state.is_complete():
105101
LOG.debug("Skipping Home Assistant discovery messages as vehicle state is not yet complete")
106102
return
107103

104+
if self.published and not force:
105+
LOG.debug("Skipping Home Assistant discovery messages as it was already published")
106+
return
107+
108108
self.__publish_ha_discovery_messages_real()
109109
self.published = True
110110

mqtt_gateway.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,16 @@ def get_vehicle_handler(self, vin: str) -> Optional[VehicleHandler]:
159159
def vehicle_handlers(self) -> dict[str, VehicleHandler]:
160160
return self.__vehicle_handlers
161161

162+
@override
163+
async def on_mqtt_global_command_received(self, *, topic: str, payload: str):
164+
match topic:
165+
case self.configuration.ha_lwt_topic:
166+
if payload == 'online':
167+
for (_, h) in self.vehicle_handlers.items():
168+
h.publish_ha_discovery_messages(force=True)
169+
case _:
170+
LOG.error(f'Received unknown global command {topic}: {payload}')
171+
162172
@override
163173
async def on_mqtt_command_received(self, *, vin: str, topic: str, payload: str) -> None:
164174
vehicle_handler = self.get_vehicle_handler(vin)

publisher/core.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88

99
INVALID_MQTT_CHARS = re.compile(r'[+#*$>]')
1010

11+
1112
class MqttCommandListener(ABC):
13+
async def on_mqtt_global_command_received(self, *, topic: str, payload: str):
14+
raise NotImplementedError("Should have implemented this")
15+
1216
async def on_mqtt_command_received(self, *, vin: str, topic: str, payload: str) -> None:
1317
raise NotImplementedError("Should have implemented this")
1418

publisher/mqtt_publisher.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ def __on_connect(self, _client, _flags, rc, _properties) -> None:
8383
LOG.debug(f'Subscribing to MQTT topic {charging_station.connected_topic}')
8484
self.vin_by_charger_connected_topic[charging_station.connected_topic] = charging_station.vin
8585
self.client.subscribe(charging_station.connected_topic)
86+
if self.configuration.ha_discovery_enabled:
87+
self.client.subscribe(
88+
self.configuration.ha_lwt_topic
89+
)
8690
self.keepalive()
8791
else:
8892
if rc == gmqtt.constants.CONNACK_REFUSED_BAD_USERNAME_PASSWORD:
@@ -120,6 +124,9 @@ async def __on_message_real(self, *, topic: str, payload: str) -> None:
120124
LOG.debug(f'Vehicle with vin {vin} is connected to its charging station')
121125
else:
122126
LOG.debug(f'Vehicle with vin {vin} is disconnected from its charging station')
127+
elif topic == self.configuration.ha_lwt_topic:
128+
if self.command_listener is not None:
129+
await self.command_listener.on_mqtt_global_command_received(topic=topic, payload=payload)
123130
else:
124131
vin = self.get_vin_from_topic(topic)
125132
if self.command_listener is not None:

tests/test_mqtt_publisher.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515

1616
class TestMqttPublisher(unittest.IsolatedAsyncioTestCase, MqttCommandListener):
17+
@override
18+
async def on_mqtt_global_command_received(self, *, topic: str, payload: str):
19+
pass
20+
1721
@override
1822
async def on_mqtt_command_received(self, *, vin: str, topic: str, payload: str) -> None:
1923
self.received_vin = vin

0 commit comments

Comments
 (0)