Move MqttServiceInfo to init.py (#60905)
Co-authored-by: epenet <epenet@users.noreply.github.com> Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
74d1c340d7
commit
b65b25c1bb
8 changed files with 66 additions and 72 deletions
|
@ -2,6 +2,8 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import datetime as dt
|
||||||
from functools import lru_cache, partial, wraps
|
from functools import lru_cache, partial, wraps
|
||||||
import inspect
|
import inspect
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
@ -38,9 +40,11 @@ from homeassistant.core import (
|
||||||
ServiceCall,
|
ServiceCall,
|
||||||
callback,
|
callback,
|
||||||
)
|
)
|
||||||
|
from homeassistant.data_entry_flow import BaseServiceInfo
|
||||||
from homeassistant.exceptions import HomeAssistantError, TemplateError, Unauthorized
|
from homeassistant.exceptions import HomeAssistantError, 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.dispatcher import async_dispatcher_connect, dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
|
||||||
|
from homeassistant.helpers.frame import report
|
||||||
from homeassistant.helpers.typing import ConfigType, ServiceDataType
|
from homeassistant.helpers.typing import ConfigType, ServiceDataType
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
@ -246,6 +250,36 @@ MQTT_PUBLISH_SCHEMA = vol.All(
|
||||||
SubscribePayloadType = Union[str, bytes] # Only bytes if encoding is None
|
SubscribePayloadType = Union[str, bytes] # Only bytes if encoding is None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MqttServiceInfo(BaseServiceInfo):
|
||||||
|
"""Prepared info from mqtt entries."""
|
||||||
|
|
||||||
|
topic: str
|
||||||
|
payload: ReceivePayloadType
|
||||||
|
qos: int
|
||||||
|
retain: bool
|
||||||
|
subscribed_topic: str
|
||||||
|
timestamp: dt.datetime
|
||||||
|
|
||||||
|
# Used to prevent log flooding. To be removed in 2022.6
|
||||||
|
_warning_logged: bool = False
|
||||||
|
|
||||||
|
def __getitem__(self, name: str) -> Any:
|
||||||
|
"""
|
||||||
|
Allow property access by name for compatibility reason.
|
||||||
|
|
||||||
|
Deprecated, and will be removed in version 2022.6.
|
||||||
|
"""
|
||||||
|
if not self._warning_logged:
|
||||||
|
report(
|
||||||
|
f"accessed discovery_info['{name}'] instead of discovery_info.{name}; this will fail in version 2022.6",
|
||||||
|
exclude_integrations={"mqtt"},
|
||||||
|
error_if_core=False,
|
||||||
|
)
|
||||||
|
self._warning_logged = True
|
||||||
|
return getattr(self, name)
|
||||||
|
|
||||||
|
|
||||||
def _build_publish_data(topic: Any, qos: int, retain: bool) -> ServiceDataType:
|
def _build_publish_data(topic: Any, qos: int, retain: bool) -> ServiceDataType:
|
||||||
"""Build the arguments for the publish service without the payload."""
|
"""Build the arguments for the publish service without the payload."""
|
||||||
data = {ATTR_TOPIC: topic}
|
data = {ATTR_TOPIC: topic}
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
"""Support for MQTT discovery."""
|
"""Support for MQTT discovery."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from dataclasses import dataclass
|
|
||||||
import datetime as dt
|
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from homeassistant.const import CONF_DEVICE, CONF_PLATFORM
|
from homeassistant.const import CONF_DEVICE, CONF_PLATFORM
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import RESULT_TYPE_ABORT, BaseServiceInfo
|
from homeassistant.data_entry_flow import RESULT_TYPE_ABORT
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.dispatcher import (
|
from homeassistant.helpers.dispatcher import (
|
||||||
async_dispatcher_connect,
|
async_dispatcher_connect,
|
||||||
async_dispatcher_send,
|
async_dispatcher_send,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.frame import report
|
|
||||||
from homeassistant.loader import async_get_mqtt
|
from homeassistant.loader import async_get_mqtt
|
||||||
|
|
||||||
from .. import mqtt
|
from .. import mqtt
|
||||||
|
@ -31,7 +27,6 @@ from .const import (
|
||||||
CONF_TOPIC,
|
CONF_TOPIC,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from .models import ReceivePayloadType
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -91,36 +86,6 @@ class MQTTConfig(dict):
|
||||||
"""Dummy class to allow adding attributes."""
|
"""Dummy class to allow adding attributes."""
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MqttServiceInfo(BaseServiceInfo):
|
|
||||||
"""Prepared info from mqtt entries."""
|
|
||||||
|
|
||||||
topic: str
|
|
||||||
payload: ReceivePayloadType
|
|
||||||
qos: int
|
|
||||||
retain: bool
|
|
||||||
subscribed_topic: str
|
|
||||||
timestamp: dt.datetime
|
|
||||||
|
|
||||||
# Used to prevent log flooding. To be removed in 2022.6
|
|
||||||
_warning_logged: bool = False
|
|
||||||
|
|
||||||
def __getitem__(self, name: str) -> Any:
|
|
||||||
"""
|
|
||||||
Allow property access by name for compatibility reason.
|
|
||||||
|
|
||||||
Deprecated, and will be removed in version 2022.6.
|
|
||||||
"""
|
|
||||||
if not self._warning_logged:
|
|
||||||
report(
|
|
||||||
f"accessed discovery_info['{name}'] instead of discovery_info.{name}; this will fail in version 2022.6",
|
|
||||||
exclude_integrations={"mqtt"},
|
|
||||||
error_if_core=False,
|
|
||||||
)
|
|
||||||
self._warning_logged = True
|
|
||||||
return getattr(self, name)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_start( # noqa: C901
|
async def async_start( # noqa: C901
|
||||||
hass: HomeAssistant, discovery_topic, config_entry=None
|
hass: HomeAssistant, discovery_topic, config_entry=None
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -323,7 +288,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 = MqttServiceInfo(
|
data = mqtt.MqttServiceInfo(
|
||||||
topic=msg.topic,
|
topic=msg.topic,
|
||||||
payload=msg.payload,
|
payload=msg.payload,
|
||||||
qos=msg.qos,
|
qos=msg.qos,
|
||||||
|
|
|
@ -6,7 +6,7 @@ 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 discovery as mqtt, valid_subscribe_topic
|
from homeassistant.components.mqtt import MqttServiceInfo, valid_subscribe_topic
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
|
||||||
from .const import CONF_DISCOVERY_PREFIX, DEFAULT_PREFIX, DOMAIN
|
from .const import CONF_DISCOVERY_PREFIX, DEFAULT_PREFIX, DOMAIN
|
||||||
|
@ -21,7 +21,7 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""Initialize flow."""
|
"""Initialize flow."""
|
||||||
self._prefix = DEFAULT_PREFIX
|
self._prefix = DEFAULT_PREFIX
|
||||||
|
|
||||||
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")
|
||||||
|
|
|
@ -35,7 +35,7 @@ import homeassistant.util.uuid as uuid_util
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from homeassistant.components.dhcp import DhcpServiceInfo
|
from homeassistant.components.dhcp import DhcpServiceInfo
|
||||||
from homeassistant.components.hassio import HassioServiceInfo
|
from homeassistant.components.hassio import HassioServiceInfo
|
||||||
from homeassistant.components.mqtt.discovery import MqttServiceInfo
|
from homeassistant.components.mqtt import MqttServiceInfo
|
||||||
from homeassistant.components.ssdp import SsdpServiceInfo
|
from homeassistant.components.ssdp import SsdpServiceInfo
|
||||||
from homeassistant.components.usb import UsbServiceInfo
|
from homeassistant.components.usb import UsbServiceInfo
|
||||||
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
||||||
|
|
|
@ -5,8 +5,7 @@ import logging
|
||||||
from typing import Any, Awaitable, Callable, Union
|
from typing import Any, Awaitable, Callable, Union
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import dhcp, ssdp, zeroconf
|
from homeassistant.components import dhcp, mqtt, ssdp, zeroconf
|
||||||
from homeassistant.components.mqtt import discovery as mqtt
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers.typing import UNDEFINED, DiscoveryInfoType, UndefinedType
|
from homeassistant.helpers.typing import UNDEFINED, DiscoveryInfoType, UndefinedType
|
||||||
|
|
|
@ -11,11 +11,7 @@ from homeassistant.components.mqtt.abbreviations import (
|
||||||
ABBREVIATIONS,
|
ABBREVIATIONS,
|
||||||
DEVICE_ABBREVIATIONS,
|
DEVICE_ABBREVIATIONS,
|
||||||
)
|
)
|
||||||
from homeassistant.components.mqtt.discovery import (
|
from homeassistant.components.mqtt.discovery import ALREADY_DISCOVERED, async_start
|
||||||
ALREADY_DISCOVERED,
|
|
||||||
MqttServiceInfo,
|
|
||||||
async_start,
|
|
||||||
)
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
EVENT_STATE_CHANGED,
|
EVENT_STATE_CHANGED,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
|
@ -909,27 +905,3 @@ async def test_mqtt_discovery_unsubscribe_once(hass, mqtt_client_mock, mqtt_mock
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
mqtt_client_mock.unsubscribe.assert_called_once_with("comp/discovery/#")
|
mqtt_client_mock.unsubscribe.assert_called_once_with("comp/discovery/#")
|
||||||
|
|
||||||
|
|
||||||
async def test_service_info_compatibility(hass, caplog):
|
|
||||||
"""Test compatibility with old-style dict.
|
|
||||||
|
|
||||||
To be removed in 2022.6
|
|
||||||
"""
|
|
||||||
discovery_info = MqttServiceInfo(
|
|
||||||
topic="tasmota/discovery/DC4F220848A2/config",
|
|
||||||
payload="",
|
|
||||||
qos=0,
|
|
||||||
retain=False,
|
|
||||||
subscribed_topic="tasmota/discovery/#",
|
|
||||||
timestamp=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Ensure first call get logged
|
|
||||||
assert discovery_info["topic"] == "tasmota/discovery/DC4F220848A2/config"
|
|
||||||
assert "Detected code that accessed discovery_info['topic']" in caplog.text
|
|
||||||
|
|
||||||
# Ensure second call doesn't get logged
|
|
||||||
caplog.clear()
|
|
||||||
assert discovery_info["topic"] == "tasmota/discovery/DC4F220848A2/config"
|
|
||||||
assert "Detected code that accessed discovery_info['topic']" not in caplog.text
|
|
||||||
|
|
|
@ -1812,3 +1812,27 @@ async def test_publish_json_from_template(hass, mqtt_mock):
|
||||||
|
|
||||||
assert mqtt_mock.async_publish.called
|
assert mqtt_mock.async_publish.called
|
||||||
assert mqtt_mock.async_publish.call_args[0][1] == test_str
|
assert mqtt_mock.async_publish.call_args[0][1] == test_str
|
||||||
|
|
||||||
|
|
||||||
|
async def test_service_info_compatibility(hass, caplog):
|
||||||
|
"""Test compatibility with old-style dict.
|
||||||
|
|
||||||
|
To be removed in 2022.6
|
||||||
|
"""
|
||||||
|
discovery_info = mqtt.MqttServiceInfo(
|
||||||
|
topic="tasmota/discovery/DC4F220848A2/config",
|
||||||
|
payload="",
|
||||||
|
qos=0,
|
||||||
|
retain=False,
|
||||||
|
subscribed_topic="tasmota/discovery/#",
|
||||||
|
timestamp=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure first call get logged
|
||||||
|
assert discovery_info["topic"] == "tasmota/discovery/DC4F220848A2/config"
|
||||||
|
assert "Detected code that accessed discovery_info['topic']" in caplog.text
|
||||||
|
|
||||||
|
# Ensure second call doesn't get logged
|
||||||
|
caplog.clear()
|
||||||
|
assert discovery_info["topic"] == "tasmota/discovery/DC4F220848A2/config"
|
||||||
|
assert "Detected code that accessed discovery_info['topic']" not in caplog.text
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Test config flow."""
|
"""Test config flow."""
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.mqtt import discovery as mqtt
|
from homeassistant.components import mqtt
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue