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.