mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Avoid importing MQTT into core for ServiceInfo dataclass (#74418)
* Avoid importing MQTT into core for discovery dataclass Likely fixes #73863 * relo * adjust * rename * rename * rename * adjust missed imports * drop compat * fix conflict correctly * Update homeassistant/helpers/config_entry_flow.py * fix black from trying to fix the conflict in github
This commit is contained in:
parent
1725948d4a
commit
666f715e76
@ -3,8 +3,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
|
||||||
import datetime as dt
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
@ -23,7 +21,6 @@ from homeassistant.const import (
|
|||||||
SERVICE_RELOAD,
|
SERVICE_RELOAD,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HassJob, HomeAssistant, ServiceCall, callback
|
from homeassistant.core import HassJob, HomeAssistant, ServiceCall, callback
|
||||||
from homeassistant.data_entry_flow import BaseServiceInfo
|
|
||||||
from homeassistant.exceptions import TemplateError, Unauthorized
|
from homeassistant.exceptions import TemplateError, Unauthorized
|
||||||
from homeassistant.helpers import config_validation as cv, event, template
|
from homeassistant.helpers import config_validation as cv, event, template
|
||||||
from homeassistant.helpers.device_registry import DeviceEntry
|
from homeassistant.helpers.device_registry import DeviceEntry
|
||||||
@ -145,18 +142,6 @@ MQTT_PUBLISH_SCHEMA = vol.All(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MqttServiceInfo(BaseServiceInfo):
|
|
||||||
"""Prepared info from mqtt entries."""
|
|
||||||
|
|
||||||
topic: str
|
|
||||||
payload: ReceivePayloadType
|
|
||||||
qos: int
|
|
||||||
retain: bool
|
|
||||||
subscribed_topic: str
|
|
||||||
timestamp: dt.datetime
|
|
||||||
|
|
||||||
|
|
||||||
async def _async_setup_discovery(
|
async def _async_setup_discovery(
|
||||||
hass: HomeAssistant, conf: ConfigType, config_entry
|
hass: HomeAssistant, conf: ConfigType, config_entry
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -17,6 +17,7 @@ from homeassistant.helpers.dispatcher import (
|
|||||||
async_dispatcher_send,
|
async_dispatcher_send,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.json import json_loads
|
from homeassistant.helpers.json import json_loads
|
||||||
|
from homeassistant.helpers.service_info.mqtt import MqttServiceInfo
|
||||||
from homeassistant.loader import async_get_mqtt
|
from homeassistant.loader import async_get_mqtt
|
||||||
|
|
||||||
from .. import mqtt
|
from .. import mqtt
|
||||||
@ -267,7 +268,7 @@ async def async_start( # noqa: C901
|
|||||||
if key not in hass.data[INTEGRATION_UNSUBSCRIBE]:
|
if key not in hass.data[INTEGRATION_UNSUBSCRIBE]:
|
||||||
return
|
return
|
||||||
|
|
||||||
data = mqtt.MqttServiceInfo(
|
data = MqttServiceInfo(
|
||||||
topic=msg.topic,
|
topic=msg.topic,
|
||||||
payload=msg.payload,
|
payload=msg.payload,
|
||||||
qos=msg.qos,
|
qos=msg.qos,
|
||||||
|
@ -12,12 +12,12 @@ from homeassistant.const import ATTR_ENTITY_ID, ATTR_NAME
|
|||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers import template
|
from homeassistant.helpers import template
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.helpers.service_info.mqtt import ReceivePayloadType
|
||||||
from homeassistant.helpers.typing import TemplateVarsType
|
from homeassistant.helpers.typing import TemplateVarsType
|
||||||
|
|
||||||
_SENTINEL = object()
|
_SENTINEL = object()
|
||||||
|
|
||||||
PublishPayloadType = Union[str, bytes, int, float, None]
|
PublishPayloadType = Union[str, bytes, int, float, None]
|
||||||
ReceivePayloadType = Union[str, bytes]
|
|
||||||
|
|
||||||
|
|
||||||
@attr.s(slots=True, frozen=True)
|
@attr.s(slots=True, frozen=True)
|
||||||
|
@ -6,8 +6,9 @@ from typing import Any
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.mqtt import MqttServiceInfo, valid_subscribe_topic
|
from homeassistant.components.mqtt import valid_subscribe_topic
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
from homeassistant.helpers.service_info.mqtt import MqttServiceInfo
|
||||||
|
|
||||||
from .const import CONF_DISCOVERY_PREFIX, DEFAULT_PREFIX, DOMAIN
|
from .const import CONF_DISCOVERY_PREFIX, DEFAULT_PREFIX, DOMAIN
|
||||||
|
|
||||||
|
@ -31,10 +31,10 @@ if TYPE_CHECKING:
|
|||||||
from .components.bluetooth import BluetoothServiceInfo
|
from .components.bluetooth import BluetoothServiceInfo
|
||||||
from .components.dhcp import DhcpServiceInfo
|
from .components.dhcp import DhcpServiceInfo
|
||||||
from .components.hassio import HassioServiceInfo
|
from .components.hassio import HassioServiceInfo
|
||||||
from .components.mqtt import MqttServiceInfo
|
|
||||||
from .components.ssdp import SsdpServiceInfo
|
from .components.ssdp import SsdpServiceInfo
|
||||||
from .components.usb import UsbServiceInfo
|
from .components.usb import UsbServiceInfo
|
||||||
from .components.zeroconf import ZeroconfServiceInfo
|
from .components.zeroconf import ZeroconfServiceInfo
|
||||||
|
from .helpers.service_info.mqtt import MqttServiceInfo
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import logging
|
|||||||
from typing import TYPE_CHECKING, Any, Generic, TypeVar, Union, cast
|
from typing import TYPE_CHECKING, Any, Generic, TypeVar, Union, cast
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import bluetooth, dhcp, onboarding, ssdp, zeroconf
|
from homeassistant.components import onboarding
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
|
||||||
@ -15,8 +15,12 @@ from .typing import UNDEFINED, DiscoveryInfoType, UndefinedType
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from homeassistant.components import mqtt
|
from homeassistant.components.bluetooth import BluetoothServiceInfo
|
||||||
|
from homeassistant.components.dhcp import DhcpServiceInfo
|
||||||
|
from homeassistant.components.ssdp import SsdpServiceInfo
|
||||||
|
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
||||||
|
|
||||||
|
from .service_info.mqtt import MqttServiceInfo
|
||||||
|
|
||||||
_R = TypeVar("_R", bound="Awaitable[bool] | bool")
|
_R = TypeVar("_R", bound="Awaitable[bool] | bool")
|
||||||
DiscoveryFunctionType = Callable[[HomeAssistant], _R]
|
DiscoveryFunctionType = Callable[[HomeAssistant], _R]
|
||||||
@ -93,7 +97,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow, Generic[_R]):
|
|||||||
return await self.async_step_confirm()
|
return await self.async_step_confirm()
|
||||||
|
|
||||||
async def async_step_bluetooth(
|
async def async_step_bluetooth(
|
||||||
self, discovery_info: bluetooth.BluetoothServiceInfo
|
self, discovery_info: BluetoothServiceInfo
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Handle a flow initialized by bluetooth discovery."""
|
"""Handle a flow initialized by bluetooth discovery."""
|
||||||
if self._async_in_progress() or self._async_current_entries():
|
if self._async_in_progress() or self._async_current_entries():
|
||||||
@ -103,7 +107,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow, Generic[_R]):
|
|||||||
|
|
||||||
return await self.async_step_confirm()
|
return await self.async_step_confirm()
|
||||||
|
|
||||||
async def async_step_dhcp(self, discovery_info: dhcp.DhcpServiceInfo) -> FlowResult:
|
async def async_step_dhcp(self, discovery_info: DhcpServiceInfo) -> FlowResult:
|
||||||
"""Handle a flow initialized by dhcp discovery."""
|
"""Handle a flow initialized by dhcp discovery."""
|
||||||
if self._async_in_progress() or self._async_current_entries():
|
if self._async_in_progress() or self._async_current_entries():
|
||||||
return self.async_abort(reason="single_instance_allowed")
|
return self.async_abort(reason="single_instance_allowed")
|
||||||
@ -113,7 +117,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow, Generic[_R]):
|
|||||||
return await self.async_step_confirm()
|
return await self.async_step_confirm()
|
||||||
|
|
||||||
async def async_step_homekit(
|
async def async_step_homekit(
|
||||||
self, discovery_info: zeroconf.ZeroconfServiceInfo
|
self, discovery_info: ZeroconfServiceInfo
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Handle a flow initialized by Homekit discovery."""
|
"""Handle a flow initialized by Homekit discovery."""
|
||||||
if self._async_in_progress() or self._async_current_entries():
|
if self._async_in_progress() or self._async_current_entries():
|
||||||
@ -123,7 +127,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow, Generic[_R]):
|
|||||||
|
|
||||||
return await self.async_step_confirm()
|
return await self.async_step_confirm()
|
||||||
|
|
||||||
async def async_step_mqtt(self, discovery_info: mqtt.MqttServiceInfo) -> FlowResult:
|
async def async_step_mqtt(self, discovery_info: MqttServiceInfo) -> FlowResult:
|
||||||
"""Handle a flow initialized by mqtt discovery."""
|
"""Handle a flow initialized by mqtt discovery."""
|
||||||
if self._async_in_progress() or self._async_current_entries():
|
if self._async_in_progress() or self._async_current_entries():
|
||||||
return self.async_abort(reason="single_instance_allowed")
|
return self.async_abort(reason="single_instance_allowed")
|
||||||
@ -133,7 +137,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow, Generic[_R]):
|
|||||||
return await self.async_step_confirm()
|
return await self.async_step_confirm()
|
||||||
|
|
||||||
async def async_step_zeroconf(
|
async def async_step_zeroconf(
|
||||||
self, discovery_info: zeroconf.ZeroconfServiceInfo
|
self, discovery_info: ZeroconfServiceInfo
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Handle a flow initialized by Zeroconf discovery."""
|
"""Handle a flow initialized by Zeroconf discovery."""
|
||||||
if self._async_in_progress() or self._async_current_entries():
|
if self._async_in_progress() or self._async_current_entries():
|
||||||
@ -143,7 +147,7 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow, Generic[_R]):
|
|||||||
|
|
||||||
return await self.async_step_confirm()
|
return await self.async_step_confirm()
|
||||||
|
|
||||||
async def async_step_ssdp(self, discovery_info: ssdp.SsdpServiceInfo) -> FlowResult:
|
async def async_step_ssdp(self, discovery_info: SsdpServiceInfo) -> FlowResult:
|
||||||
"""Handle a flow initialized by Ssdp discovery."""
|
"""Handle a flow initialized by Ssdp discovery."""
|
||||||
if self._async_in_progress() or self._async_current_entries():
|
if self._async_in_progress() or self._async_current_entries():
|
||||||
return self.async_abort(reason="single_instance_allowed")
|
return self.async_abort(reason="single_instance_allowed")
|
||||||
|
20
homeassistant/helpers/service_info/mqtt.py
Normal file
20
homeassistant/helpers/service_info/mqtt.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"""MQTT Discovery data."""
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import datetime as dt
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from homeassistant.data_entry_flow import BaseServiceInfo
|
||||||
|
|
||||||
|
ReceivePayloadType = Union[str, bytes]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MqttServiceInfo(BaseServiceInfo):
|
||||||
|
"""Prepared info from mqtt entries."""
|
||||||
|
|
||||||
|
topic: str
|
||||||
|
payload: ReceivePayloadType
|
||||||
|
qos: int
|
||||||
|
retain: bool
|
||||||
|
subscribed_topic: str
|
||||||
|
timestamp: dt.datetime
|
@ -1,6 +1,6 @@
|
|||||||
"""Test config flow."""
|
"""Test config flow."""
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import mqtt
|
from homeassistant.helpers.service_info.mqtt import MqttServiceInfo
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ async def test_mqtt_abort_if_existing_entry(hass, mqtt_mock):
|
|||||||
|
|
||||||
async def test_mqtt_abort_invalid_topic(hass, mqtt_mock):
|
async def test_mqtt_abort_invalid_topic(hass, mqtt_mock):
|
||||||
"""Check MQTT flow aborts if discovery topic is invalid."""
|
"""Check MQTT flow aborts if discovery topic is invalid."""
|
||||||
discovery_info = mqtt.MqttServiceInfo(
|
discovery_info = MqttServiceInfo(
|
||||||
topic="tasmota/discovery/DC4F220848A2/bla",
|
topic="tasmota/discovery/DC4F220848A2/bla",
|
||||||
payload=(
|
payload=(
|
||||||
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
||||||
@ -42,7 +42,7 @@ async def test_mqtt_abort_invalid_topic(hass, mqtt_mock):
|
|||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "invalid_discovery_info"
|
assert result["reason"] == "invalid_discovery_info"
|
||||||
|
|
||||||
discovery_info = mqtt.MqttServiceInfo(
|
discovery_info = MqttServiceInfo(
|
||||||
topic="tasmota/discovery/DC4F220848A2/config",
|
topic="tasmota/discovery/DC4F220848A2/config",
|
||||||
payload="",
|
payload="",
|
||||||
qos=0,
|
qos=0,
|
||||||
@ -56,7 +56,7 @@ async def test_mqtt_abort_invalid_topic(hass, mqtt_mock):
|
|||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "invalid_discovery_info"
|
assert result["reason"] == "invalid_discovery_info"
|
||||||
|
|
||||||
discovery_info = mqtt.MqttServiceInfo(
|
discovery_info = MqttServiceInfo(
|
||||||
topic="tasmota/discovery/DC4F220848A2/config",
|
topic="tasmota/discovery/DC4F220848A2/config",
|
||||||
payload=(
|
payload=(
|
||||||
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
||||||
@ -81,7 +81,7 @@ async def test_mqtt_abort_invalid_topic(hass, mqtt_mock):
|
|||||||
|
|
||||||
async def test_mqtt_setup(hass, mqtt_mock) -> None:
|
async def test_mqtt_setup(hass, mqtt_mock) -> None:
|
||||||
"""Test we can finish a config flow through MQTT with custom prefix."""
|
"""Test we can finish a config flow through MQTT with custom prefix."""
|
||||||
discovery_info = mqtt.MqttServiceInfo(
|
discovery_info = MqttServiceInfo(
|
||||||
topic="tasmota/discovery/DC4F220848A2/config",
|
topic="tasmota/discovery/DC4F220848A2/config",
|
||||||
payload=(
|
payload=(
|
||||||
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user