Make sure MQTT client is available when starting depending platforms (#91164)

* Make sure MQTT is available starting mqtt_json

* Wait for mqtt client

* Sync client connect

* Simplify

* Addiitional tests async_wait_for_mqtt_client

* Improve comment waiting for mqtt

* Improve docstr

* Do not wait unless the MQTT client is in setup

* Handle entry errors during setup

* More comments - do not clear event

* Add snips and mqtt_room

* Add manual_mqtt

* Update homeassistant/components/mqtt/__init__.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Use a fixture, improve tests

* Simplify

---------

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Jan Bouwhuis 2023-04-20 08:07:35 +02:00 committed by GitHub
parent adc472862b
commit 0bcda9fe9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 346 additions and 34 deletions

View file

@ -2,13 +2,16 @@
from __future__ import annotations
import asyncio
import os
from pathlib import Path
import tempfile
from typing import Any
import async_timeout
import voluptuous as vol
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv, template
from homeassistant.helpers.typing import ConfigType
@ -22,6 +25,7 @@ from .const import (
CONF_CLIENT_CERT,
CONF_CLIENT_KEY,
DATA_MQTT,
DATA_MQTT_AVAILABLE,
DEFAULT_ENCODING,
DEFAULT_QOS,
DEFAULT_RETAIN,
@ -29,6 +33,8 @@ from .const import (
)
from .models import MqttData
AVAILABILITY_TIMEOUT = 30.0
TEMP_DIR_NAME = f"home-assistant-{DOMAIN}"
_VALID_QOS_SCHEMA = vol.All(vol.Coerce(int), vol.In([0, 1, 2]))
@ -41,6 +47,37 @@ def mqtt_config_entry_enabled(hass: HomeAssistant) -> bool | None:
return not bool(hass.config_entries.async_entries(DOMAIN)[0].disabled_by)
async def async_wait_for_mqtt_client(hass: HomeAssistant) -> bool:
"""Wait for the MQTT client to become available.
Waits when mqtt set up is in progress,
It is not needed that the client is connected.
Returns True if the mqtt client is available.
Returns False when the client is not available.
"""
if not mqtt_config_entry_enabled(hass):
return False
entry = hass.config_entries.async_entries(DOMAIN)[0]
if entry.state == ConfigEntryState.LOADED:
return True
state_reached_future: asyncio.Future[bool]
if DATA_MQTT_AVAILABLE not in hass.data:
hass.data[DATA_MQTT_AVAILABLE] = state_reached_future = asyncio.Future()
else:
state_reached_future = hass.data[DATA_MQTT_AVAILABLE]
if state_reached_future.done():
return state_reached_future.result()
try:
async with async_timeout.timeout(AVAILABILITY_TIMEOUT):
# Await the client setup or an error state was received
return await state_reached_future
except asyncio.TimeoutError:
return False
def valid_topic(topic: Any) -> str:
"""Validate that this is a valid topic name/filter."""
validated_topic = cv.string(topic)