mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Remove mysensors notify (#90402)
This commit is contained in:
parent
b6a0ac6f0a
commit
e6c94d7854
@ -2,7 +2,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from functools import partial
|
||||
import logging
|
||||
|
||||
from mysensors import BaseAsyncGateway
|
||||
@ -12,24 +11,19 @@ from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.device_registry import DeviceEntry
|
||||
from homeassistant.helpers.discovery import async_load_platform
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import (
|
||||
ATTR_DEVICES,
|
||||
DOMAIN,
|
||||
MYSENSORS_DISCOVERY,
|
||||
MYSENSORS_GATEWAYS,
|
||||
MYSENSORS_ON_UNLOAD,
|
||||
PLATFORMS_WITH_ENTRY_SUPPORT,
|
||||
PLATFORMS,
|
||||
DevId,
|
||||
DiscoveryInfo,
|
||||
SensorType,
|
||||
)
|
||||
from .device import MySensorsDevice, get_mysensors_devices
|
||||
from .gateway import finish_setup, gw_stop, setup_gateway
|
||||
from .helpers import on_unload
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -39,14 +33,6 @@ DATA_HASS_CONFIG = "hass_config"
|
||||
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the MySensors component."""
|
||||
# This is needed to set up the notify platform via discovery.
|
||||
hass.data[DOMAIN] = {DATA_HASS_CONFIG: config}
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up an instance of the MySensors integration.
|
||||
|
||||
@ -58,33 +44,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
_LOGGER.error("Gateway setup failed for %s", entry.data)
|
||||
return False
|
||||
|
||||
if MYSENSORS_GATEWAYS not in hass.data[DOMAIN]:
|
||||
hass.data[DOMAIN][MYSENSORS_GATEWAYS] = {}
|
||||
hass.data[DOMAIN][MYSENSORS_GATEWAYS][entry.entry_id] = gateway
|
||||
mysensors_data = hass.data.setdefault(DOMAIN, {})
|
||||
if MYSENSORS_GATEWAYS not in mysensors_data:
|
||||
mysensors_data[MYSENSORS_GATEWAYS] = {}
|
||||
mysensors_data[MYSENSORS_GATEWAYS][entry.entry_id] = gateway
|
||||
|
||||
# Connect notify discovery as that integration doesn't support entry forwarding.
|
||||
|
||||
load_discovery_platform = partial(
|
||||
async_load_platform,
|
||||
hass,
|
||||
Platform.NOTIFY,
|
||||
DOMAIN,
|
||||
hass_config=hass.data[DOMAIN][DATA_HASS_CONFIG],
|
||||
)
|
||||
|
||||
on_unload(
|
||||
hass,
|
||||
entry.entry_id,
|
||||
async_dispatcher_connect(
|
||||
hass,
|
||||
MYSENSORS_DISCOVERY.format(entry.entry_id, Platform.NOTIFY),
|
||||
load_discovery_platform,
|
||||
),
|
||||
)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(
|
||||
entry, PLATFORMS_WITH_ENTRY_SUPPORT
|
||||
)
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
await finish_setup(hass, entry, gateway)
|
||||
|
||||
return True
|
||||
@ -95,9 +60,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
gateway: BaseAsyncGateway = hass.data[DOMAIN][MYSENSORS_GATEWAYS][entry.entry_id]
|
||||
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(
|
||||
entry, PLATFORMS_WITH_ENTRY_SUPPORT
|
||||
)
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
if not unload_ok:
|
||||
return False
|
||||
|
||||
|
@ -40,7 +40,6 @@ class DiscoveryInfo(TypedDict):
|
||||
"""Represent the discovery info type for mysensors platforms."""
|
||||
|
||||
devices: list[DevId]
|
||||
name: str # CONF_NAME is used in the notify base integration.
|
||||
gateway_id: GatewayId
|
||||
|
||||
|
||||
@ -92,8 +91,6 @@ LIGHT_TYPES: dict[SensorType, set[ValueType]] = {
|
||||
"S_RGBW_LIGHT": {"V_RGBW"},
|
||||
}
|
||||
|
||||
NOTIFY_TYPES: dict[SensorType, set[ValueType]] = {"S_INFO": {"V_TEXT"}}
|
||||
|
||||
REMOTE_TYPES: dict[SensorType, set[ValueType]] = {"S_IR": {"V_IR_SEND"}}
|
||||
|
||||
SENSOR_TYPES: dict[SensorType, set[ValueType]] = {
|
||||
@ -148,7 +145,6 @@ PLATFORM_TYPES: dict[Platform, dict[SensorType, set[ValueType]]] = {
|
||||
Platform.COVER: COVER_TYPES,
|
||||
Platform.DEVICE_TRACKER: DEVICE_TRACKER_TYPES,
|
||||
Platform.LIGHT: LIGHT_TYPES,
|
||||
Platform.NOTIFY: NOTIFY_TYPES,
|
||||
Platform.REMOTE: REMOTE_TYPES,
|
||||
Platform.SENSOR: SENSOR_TYPES,
|
||||
Platform.SWITCH: SWITCH_TYPES,
|
||||
@ -167,6 +163,4 @@ for platform, platform_types in PLATFORM_TYPES.items():
|
||||
for s_type_name in platform_types:
|
||||
TYPE_TO_PLATFORMS[s_type_name].append(platform)
|
||||
|
||||
PLATFORMS_WITH_ENTRY_SUPPORT = set(PLATFORM_TYPES.keys()) - {
|
||||
Platform.NOTIFY,
|
||||
}
|
||||
PLATFORMS = tuple(PLATFORM_TYPES)
|
||||
|
@ -1,100 +0,0 @@
|
||||
"""MySensors notification service."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, cast
|
||||
|
||||
from homeassistant.components.notify import ATTR_TARGET, BaseNotificationService
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .. import mysensors
|
||||
from .const import DOMAIN, DevId, DiscoveryInfo
|
||||
|
||||
|
||||
async def async_get_service(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> BaseNotificationService | None:
|
||||
"""Get the MySensors notification service."""
|
||||
if not discovery_info:
|
||||
return None
|
||||
|
||||
new_devices = mysensors.setup_mysensors_platform(
|
||||
hass,
|
||||
Platform.NOTIFY,
|
||||
cast(DiscoveryInfo, discovery_info),
|
||||
MySensorsNotificationDevice,
|
||||
)
|
||||
if not new_devices:
|
||||
return None
|
||||
return MySensorsNotificationService(hass)
|
||||
|
||||
|
||||
class MySensorsNotificationDevice(mysensors.device.MySensorsDevice):
|
||||
"""Represent a MySensors Notification device."""
|
||||
|
||||
@callback
|
||||
def _async_update_callback(self) -> None:
|
||||
"""Update the device."""
|
||||
self._async_update()
|
||||
|
||||
def send_msg(self, msg: str) -> None:
|
||||
"""Send a message."""
|
||||
for sub_msg in [msg[i : i + 25] for i in range(0, len(msg), 25)]:
|
||||
# Max mysensors payload is 25 bytes.
|
||||
self.gateway.set_child_value(
|
||||
self.node_id, self.child_id, self.value_type, sub_msg
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Return the representation."""
|
||||
return f"<MySensorsNotificationDevice {self.name}>"
|
||||
|
||||
|
||||
class MySensorsNotificationService(BaseNotificationService):
|
||||
"""Implement a MySensors notification service."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant) -> None:
|
||||
"""Initialize the service."""
|
||||
self.devices: dict[
|
||||
DevId, MySensorsNotificationDevice
|
||||
] = mysensors.get_mysensors_devices(
|
||||
hass, Platform.NOTIFY
|
||||
) # type: ignore[assignment]
|
||||
self.hass = hass
|
||||
|
||||
async def async_send_message(self, message: str = "", **kwargs: Any) -> None:
|
||||
"""Send a message to a user."""
|
||||
target_devices = kwargs.get(ATTR_TARGET)
|
||||
devices = [
|
||||
device
|
||||
for device in self.devices.values()
|
||||
if target_devices is None or device.name in target_devices
|
||||
]
|
||||
|
||||
placeholders = {
|
||||
"alternate_service": "text.set_value",
|
||||
"deprecated_service": f"notify.{self._service_name}",
|
||||
"alternate_target": str(
|
||||
[f"text.{slugify(device.name)}" for device in devices]
|
||||
),
|
||||
}
|
||||
|
||||
async_create_issue(
|
||||
self.hass,
|
||||
DOMAIN,
|
||||
"deprecated_notify_service",
|
||||
breaks_in_ha_version="2023.4.0",
|
||||
is_fixable=True,
|
||||
is_persistent=True,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_service",
|
||||
translation_placeholders=placeholders,
|
||||
)
|
||||
|
||||
for device in devices:
|
||||
device.send_msg(message)
|
@ -61,8 +61,6 @@ async def test_config_mqtt(hass: HomeAssistant, mqtt: None) -> None:
|
||||
flow_id = step["flow_id"]
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.mysensors.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
"homeassistant.components.mysensors.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
@ -89,7 +87,6 @@ async def test_config_mqtt(hass: HomeAssistant, mqtt: None) -> None:
|
||||
CONF_VERSION: "2.4",
|
||||
CONF_GATEWAY_TYPE: "MQTT",
|
||||
}
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@ -121,8 +118,6 @@ async def test_config_serial(hass: HomeAssistant) -> None:
|
||||
), patch(
|
||||
"homeassistant.components.mysensors.config_flow.try_connect", return_value=True
|
||||
), patch(
|
||||
"homeassistant.components.mysensors.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
"homeassistant.components.mysensors.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
@ -146,7 +141,6 @@ async def test_config_serial(hass: HomeAssistant) -> None:
|
||||
CONF_VERSION: "2.4",
|
||||
CONF_GATEWAY_TYPE: "Serial",
|
||||
}
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@ -158,8 +152,6 @@ async def test_config_tcp(hass: HomeAssistant) -> None:
|
||||
with patch(
|
||||
"homeassistant.components.mysensors.config_flow.try_connect", return_value=True
|
||||
), patch(
|
||||
"homeassistant.components.mysensors.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
"homeassistant.components.mysensors.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
@ -183,7 +175,6 @@ async def test_config_tcp(hass: HomeAssistant) -> None:
|
||||
CONF_VERSION: "2.4",
|
||||
CONF_GATEWAY_TYPE: "TCP",
|
||||
}
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@ -195,8 +186,6 @@ async def test_fail_to_connect(hass: HomeAssistant) -> None:
|
||||
with patch(
|
||||
"homeassistant.components.mysensors.config_flow.try_connect", return_value=False
|
||||
), patch(
|
||||
"homeassistant.components.mysensors.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
"homeassistant.components.mysensors.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
@ -215,7 +204,6 @@ async def test_fail_to_connect(hass: HomeAssistant) -> None:
|
||||
errors = result["errors"]
|
||||
assert errors
|
||||
assert errors.get("base") == "cannot_connect"
|
||||
assert len(mock_setup.mock_calls) == 0
|
||||
assert len(mock_setup_entry.mock_calls) == 0
|
||||
|
||||
|
||||
@ -358,8 +346,6 @@ async def test_config_invalid(
|
||||
"homeassistant.components.mysensors.gateway.socket.getaddrinfo",
|
||||
side_effect=OSError,
|
||||
), patch(
|
||||
"homeassistant.components.mysensors.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
"homeassistant.components.mysensors.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
@ -375,7 +361,6 @@ async def test_config_invalid(
|
||||
assert errors
|
||||
assert err_field in errors
|
||||
assert errors[err_field] == err_string
|
||||
assert len(mock_setup.mock_calls) == 0
|
||||
assert len(mock_setup_entry.mock_calls) == 0
|
||||
|
||||
|
||||
|
@ -1,95 +0,0 @@
|
||||
"""Provide tests for mysensors notify platform."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from unittest.mock import MagicMock, call
|
||||
|
||||
from mysensors.sensor import Sensor
|
||||
|
||||
from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_text_type(
|
||||
hass: HomeAssistant,
|
||||
text_node: Sensor,
|
||||
transport_write: MagicMock,
|
||||
integration: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test a text type child."""
|
||||
# Test without target.
|
||||
await hass.services.async_call(
|
||||
NOTIFY_DOMAIN, "mysensors", {"message": "Hello World"}, blocking=True
|
||||
)
|
||||
|
||||
assert transport_write.call_count == 1
|
||||
assert transport_write.call_args == call("1;1;1;0;47;Hello World\n")
|
||||
|
||||
# Test with target.
|
||||
await hass.services.async_call(
|
||||
NOTIFY_DOMAIN,
|
||||
"mysensors",
|
||||
{"message": "Hello", "target": "Text Node 1 1"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert transport_write.call_count == 2
|
||||
assert transport_write.call_args == call("1;1;1;0;47;Hello\n")
|
||||
|
||||
transport_write.reset_mock()
|
||||
|
||||
# Test a message longer than 25 characters.
|
||||
await hass.services.async_call(
|
||||
NOTIFY_DOMAIN,
|
||||
"mysensors",
|
||||
{
|
||||
"message": "This is a long message that will be split",
|
||||
"target": "Text Node 1 1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert transport_write.call_count == 2
|
||||
assert transport_write.call_args_list == [
|
||||
call("1;1;1;0;47;This is a long message th\n"),
|
||||
call("1;1;1;0;47;at will be split\n"),
|
||||
]
|
||||
|
||||
|
||||
async def test_text_type_discovery(
|
||||
hass: HomeAssistant,
|
||||
text_node: Sensor,
|
||||
transport_write: MagicMock,
|
||||
receive_message: Callable[[str], None],
|
||||
) -> None:
|
||||
"""Test text type discovery."""
|
||||
receive_message("1;2;0;0;36;\n")
|
||||
receive_message("1;2;1;0;47;test\n")
|
||||
receive_message("1;2;1;0;47;test2\n") # Test that more than one set message works.
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Test targeting the discovered child.
|
||||
await hass.services.async_call(
|
||||
NOTIFY_DOMAIN,
|
||||
"mysensors",
|
||||
{"message": "Hello", "target": "Text Node 1 2"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert transport_write.call_count == 1
|
||||
assert transport_write.call_args == call("1;2;1;0;47;Hello\n")
|
||||
|
||||
transport_write.reset_mock()
|
||||
|
||||
# Test targeting all notify children.
|
||||
await hass.services.async_call(
|
||||
NOTIFY_DOMAIN, "mysensors", {"message": "Hello World"}, blocking=True
|
||||
)
|
||||
|
||||
assert transport_write.call_count == 2
|
||||
assert transport_write.call_args_list == [
|
||||
call("1;1;1;0;47;Hello World\n"),
|
||||
call("1;2;1;0;47;Hello World\n"),
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user