Prevented MQTT command/state feedback loops while keeping HA-friendly behavior:
accepts retained /state topics during a short startup bootstrap window to restore last-known settings,
then stops processing /state messages and unsubscribes from .../+/state after bootstrap.
Ensures runtime control is driven only by /set topics, while /state remains publish-only for HA UI synchronization.
Adds explicit logging around bootstrap completion to make startup behavior clear.
Added MQTT topics for the new alarm duration control:
lva/<device_id>/alarm_duration/set
lva/<device_id>/alarm_duration/state
Published a new Home Assistant number discovery config:
number.<device_id>_alarm_duration (0–3600 seconds, step 5, unit s).
On /alarm_duration/set:
validates and parses the payload as a non-negative integer,
publishes a set_alarm_duration event on the EventBus,
echoes the value back to /alarm_duration/state.
On connect, publishes the current alarm_duration_seconds from preferences to the state topic for retained startup behavior.
__init__ was completely rewritten to be decoupled. It now listens for mic_muted/mic_unmuted events to manage its own state instead of reading from ServerState.
Goal: We'll apply the exact same pattern to the MqttController. The paho-mqtt library runs its _on_message callback in a separate thread. We'll stop it from modifying state directly and instead schedule a new function to run on the main asyncio loop.
Here is the complete file. The key changes are:
The _on_message function is now tiny. It just gets the topic/payload and uses self.state.loop.call_soon_threadsafe to schedule a new function.
A new function _handle_message_on_loop contains all the logic that used to be in _on_message. This new function will run safely on the main asyncio loop, eliminating the race condition.
Introduces the MqttController, a new class that manages all communication with the MQTT broker.
On startup, it connects to the broker and publishes discovery configurations for all entities, automatically creating them in Home Assistant.
Subscribes to command topics to receive instructions from the HA interface.
Subscribes to state topics to read retained messages on startup, ensuring all user settings are persistent.
Acts as a bridge, translating incoming MQTT messages into internal EventBus events for other components to act upon.