From 29645d5820a1240155493d4651ae5895e1928e07 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Tue, 28 Mar 2023 13:39:32 +0200 Subject: [PATCH] Remove mysensors ir switch (#90403) --- .../components/mysensors/__init__.py | 12 +- homeassistant/components/mysensors/const.py | 1 - homeassistant/components/mysensors/device.py | 4 +- homeassistant/components/mysensors/light.py | 4 +- .../components/mysensors/services.yaml | 18 -- .../components/mysensors/strings.json | 24 --- homeassistant/components/mysensors/switch.py | 158 +----------------- tests/components/mysensors/test_switch.py | 79 --------- 8 files changed, 18 insertions(+), 282 deletions(-) delete mode 100644 homeassistant/components/mysensors/services.yaml diff --git a/homeassistant/components/mysensors/__init__.py b/homeassistant/components/mysensors/__init__.py index 129b1430625..5b8154e17aa 100644 --- a/homeassistant/components/mysensors/__init__.py +++ b/homeassistant/components/mysensors/__init__.py @@ -1,7 +1,7 @@ """Connect to a MySensors gateway via pymysensors API.""" from __future__ import annotations -from collections.abc import Callable +from collections.abc import Callable, Mapping import logging from mysensors import BaseAsyncGateway @@ -22,7 +22,7 @@ from .const import ( DiscoveryInfo, SensorType, ) -from .device import MySensorsDevice, get_mysensors_devices +from .device import MySensorsEntity, get_mysensors_devices from .gateway import finish_setup, gw_stop, setup_gateway _LOGGER = logging.getLogger(__name__) @@ -99,12 +99,12 @@ def setup_mysensors_platform( hass: HomeAssistant, domain: Platform, # hass platform name discovery_info: DiscoveryInfo, - device_class: type[MySensorsDevice] | dict[SensorType, type[MySensorsDevice]], + device_class: type[MySensorsEntity] | Mapping[SensorType, type[MySensorsEntity]], device_args: ( None | tuple ) = None, # extra arguments that will be given to the entity constructor async_add_entities: Callable | None = None, -) -> list[MySensorsDevice] | None: +) -> list[MySensorsEntity] | None: """Set up a MySensors platform. Sets up a bunch of instances of a single platform that is supported by this @@ -118,10 +118,10 @@ def setup_mysensors_platform( """ if device_args is None: device_args = () - new_devices: list[MySensorsDevice] = [] + new_devices: list[MySensorsEntity] = [] new_dev_ids: list[DevId] = discovery_info[ATTR_DEVICES] for dev_id in new_dev_ids: - devices: dict[DevId, MySensorsDevice] = get_mysensors_devices(hass, domain) + devices: dict[DevId, MySensorsEntity] = get_mysensors_devices(hass, domain) if dev_id in devices: _LOGGER.debug( "Skipping setup of %s for platform %s as it already exists", diff --git a/homeassistant/components/mysensors/const.py b/homeassistant/components/mysensors/const.py index bcdc6f80ab2..7f9326091fe 100644 --- a/homeassistant/components/mysensors/const.py +++ b/homeassistant/components/mysensors/const.py @@ -132,7 +132,6 @@ SWITCH_TYPES: dict[SensorType, set[ValueType]] = { "S_SOUND": {"V_ARMED"}, "S_VIBRATION": {"V_ARMED"}, "S_MOISTURE": {"V_ARMED"}, - "S_IR": {"V_IR_SEND"}, "S_LOCK": {"V_LOCK_STATUS"}, "S_WATER_QUALITY": {"V_STATUS"}, } diff --git a/homeassistant/components/mysensors/device.py b/homeassistant/components/mysensors/device.py index de4cbff9b9d..d7405dba187 100644 --- a/homeassistant/components/mysensors/device.py +++ b/homeassistant/components/mysensors/device.py @@ -202,11 +202,11 @@ class MySensorsDevice(ABC): def get_mysensors_devices( hass: HomeAssistant, domain: Platform -) -> dict[DevId, MySensorsDevice]: +) -> dict[DevId, MySensorsEntity]: """Return MySensors devices for a hass platform name.""" if MYSENSORS_PLATFORM_DEVICES.format(domain) not in hass.data[DOMAIN]: hass.data[DOMAIN][MYSENSORS_PLATFORM_DEVICES.format(domain)] = {} - devices: dict[DevId, MySensorsDevice] = hass.data[DOMAIN][ + devices: dict[DevId, MySensorsEntity] = hass.data[DOMAIN][ MYSENSORS_PLATFORM_DEVICES.format(domain) ] return devices diff --git a/homeassistant/components/mysensors/light.py b/homeassistant/components/mysensors/light.py index e83002ed870..68f8bb566f1 100644 --- a/homeassistant/components/mysensors/light.py +++ b/homeassistant/components/mysensors/light.py @@ -19,7 +19,7 @@ from homeassistant.util.color import rgb_hex_to_rgb_list from .. import mysensors from .const import MYSENSORS_DISCOVERY, DiscoveryInfo, SensorType -from .device import MySensorsDevice +from .device import MySensorsEntity from .helpers import on_unload @@ -29,7 +29,7 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up this platform for a specific ConfigEntry(==Gateway).""" - device_class_map: dict[SensorType, type[MySensorsDevice]] = { + device_class_map: dict[SensorType, type[MySensorsEntity]] = { "S_DIMMER": MySensorsLightDimmer, "S_RGB_LIGHT": MySensorsLightRGB, "S_RGBW_LIGHT": MySensorsLightRGBW, diff --git a/homeassistant/components/mysensors/services.yaml b/homeassistant/components/mysensors/services.yaml deleted file mode 100644 index 7293a676a76..00000000000 --- a/homeassistant/components/mysensors/services.yaml +++ /dev/null @@ -1,18 +0,0 @@ -send_ir_code: - name: Send IR code - description: Set an IR code as a state attribute for a MySensors IR device switch and turn the switch on. - fields: - entity_id: - name: Entity - description: Name of entity that should have the IR code set and be turned on. Platform dependent. - selector: - entity: - integration: mysensors - domain: switch - V_IR_SEND: - name: IR send - description: IR code to send. - required: true - example: "0xC284" - selector: - text: diff --git a/homeassistant/components/mysensors/strings.json b/homeassistant/components/mysensors/strings.json index c192db7549f..dc5dc76c7ae 100644 --- a/homeassistant/components/mysensors/strings.json +++ b/homeassistant/components/mysensors/strings.json @@ -83,29 +83,5 @@ "port_out_of_range": "Port number must be at least 1 and at most 65535", "unknown": "[%key:common::config_flow::error::unknown%]" } - }, - "issues": { - "deprecated_entity": { - "title": "The {deprecated_entity} entity will be removed", - "fix_flow": { - "step": { - "confirm": { - "title": "The {deprecated_entity} entity will be removed", - "description": "Update any automations or scripts that use this entity in service calls using the `{deprecated_service}` service to instead use the `{alternate_service}` service with a target entity ID of `{alternate_target}`." - } - } - } - }, - "deprecated_service": { - "title": "The {deprecated_service} service will be removed", - "fix_flow": { - "step": { - "confirm": { - "title": "The {deprecated_service} service will be removed", - "description": "Update any automations or scripts that use this service to instead use the `{alternate_service}` service with a target entity ID of `{alternate_target}`." - } - } - } - } } } diff --git a/homeassistant/components/mysensors/switch.py b/homeassistant/components/mysensors/switch.py index e5b0968785f..6067a98af08 100644 --- a/homeassistant/components/mysensors/switch.py +++ b/homeassistant/components/mysensors/switch.py @@ -3,34 +3,18 @@ from __future__ import annotations from typing import Any -import voluptuous as vol - from homeassistant.components.switch import SwitchEntity from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, Platform -from homeassistant.core import HomeAssistant, ServiceCall, callback, split_entity_id -import homeassistant.helpers.config_validation as cv +from homeassistant.const import STATE_OFF, STATE_ON, Platform +from homeassistant.core import HomeAssistant from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue -from .. import mysensors -from .const import ( - DOMAIN as MYSENSORS_DOMAIN, - MYSENSORS_DISCOVERY, - SERVICE_SEND_IR_CODE, - DiscoveryInfo, - SensorType, -) -from .device import MySensorsDevice +from . import setup_mysensors_platform +from .const import MYSENSORS_DISCOVERY, DiscoveryInfo, SensorType +from .device import MySensorsEntity from .helpers import on_unload -ATTR_IR_CODE = "V_IR_SEND" - -SEND_IR_CODE_SERVICE_SCHEMA = vol.Schema( - {vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, vol.Required(ATTR_IR_CODE): cv.string} -) - async def async_setup_entry( hass: HomeAssistant, @@ -38,13 +22,12 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up this platform for a specific ConfigEntry(==Gateway).""" - device_class_map: dict[SensorType, type[MySensorsDevice]] = { + device_class_map: dict[SensorType, type[MySensorsSwitch]] = { "S_DOOR": MySensorsSwitch, "S_MOTION": MySensorsSwitch, "S_SMOKE": MySensorsSwitch, "S_LIGHT": MySensorsSwitch, "S_LOCK": MySensorsSwitch, - "S_IR": MySensorsIRSwitch, "S_BINARY": MySensorsSwitch, "S_SPRINKLER": MySensorsSwitch, "S_WATER_LEAK": MySensorsSwitch, @@ -56,7 +39,7 @@ async def async_setup_entry( async def async_discover(discovery_info: DiscoveryInfo) -> None: """Discover and add a MySensors switch.""" - mysensors.setup_mysensors_platform( + setup_mysensors_platform( hass, Platform.SWITCH, discovery_info, @@ -64,37 +47,6 @@ async def async_setup_entry( async_add_entities=async_add_entities, ) - async def async_send_ir_code_service(service: ServiceCall) -> None: - """Set IR code as device state attribute.""" - entity_ids = service.data.get(ATTR_ENTITY_ID) - ir_code = service.data.get(ATTR_IR_CODE) - devices = mysensors.get_mysensors_devices(hass, Platform.SWITCH) - - if entity_ids: - _devices = [ - device - for device in devices.values() - if isinstance(device, MySensorsIRSwitch) - and device.entity_id in entity_ids - ] - else: - _devices = [ - device - for device in devices.values() - if isinstance(device, MySensorsIRSwitch) - ] - - kwargs = {ATTR_IR_CODE: ir_code} - for device in _devices: - await device.async_turn_on(**kwargs) - - hass.services.async_register( - MYSENSORS_DOMAIN, - SERVICE_SEND_IR_CODE, - async_send_ir_code_service, - schema=SEND_IR_CODE_SERVICE_SCHEMA, - ) - on_unload( hass, config_entry.entry_id, @@ -106,7 +58,7 @@ async def async_setup_entry( ) -class MySensorsSwitch(mysensors.device.MySensorsEntity, SwitchEntity): +class MySensorsSwitch(MySensorsEntity, SwitchEntity): """Representation of the value of a MySensors Switch child node.""" @property @@ -133,97 +85,3 @@ class MySensorsSwitch(mysensors.device.MySensorsEntity, SwitchEntity): # Optimistically assume that switch has changed state self._values[self.value_type] = STATE_OFF self.async_write_ha_state() - - -class MySensorsIRSwitch(MySensorsSwitch): - """IR switch child class to MySensorsSwitch.""" - - def __init__(self, *args: Any) -> None: - """Set up instance attributes.""" - super().__init__(*args) - self._ir_code: str | None = None - - @property - def is_on(self) -> bool: - """Return True if switch is on.""" - set_req = self.gateway.const.SetReq - return self._values.get(set_req.V_LIGHT) == STATE_ON - - async def async_turn_on(self, **kwargs: Any) -> None: - """Turn the IR switch on.""" - set_req = self.gateway.const.SetReq - placeholders = { - "deprecated_entity": self.entity_id, - "alternate_target": f"remote.{split_entity_id(self.entity_id)[1]}", - } - - if ATTR_IR_CODE in kwargs: - self._ir_code = kwargs[ATTR_IR_CODE] - placeholders[ - "deprecated_service" - ] = f"{MYSENSORS_DOMAIN}.{SERVICE_SEND_IR_CODE}" - placeholders["alternate_service"] = "remote.send_command" - else: - placeholders["deprecated_service"] = "switch.turn_on" - placeholders["alternate_service"] = "remote.turn_on" - - async_create_issue( - self.hass, - MYSENSORS_DOMAIN, - ( - "deprecated_ir_switch_entity_" - f"{self.entity_id}_{placeholders['deprecated_service']}" - ), - breaks_in_ha_version="2023.4.0", - is_fixable=True, - is_persistent=True, - severity=IssueSeverity.WARNING, - translation_key="deprecated_entity", - translation_placeholders=placeholders, - ) - self.gateway.set_child_value( - self.node_id, self.child_id, self.value_type, self._ir_code - ) - self.gateway.set_child_value( - self.node_id, self.child_id, set_req.V_LIGHT, 1, ack=1 - ) - if self.assumed_state: - # Optimistically assume that switch has changed state - self._values[self.value_type] = self._ir_code - self._values[set_req.V_LIGHT] = STATE_ON - self.async_write_ha_state() - # Turn off switch after switch was turned on - await self.async_turn_off() - - async def async_turn_off(self, **kwargs: Any) -> None: - """Turn the IR switch off.""" - async_create_issue( - self.hass, - MYSENSORS_DOMAIN, - f"deprecated_ir_switch_entity_{self.entity_id}_switch.turn_off", - breaks_in_ha_version="2023.4.0", - is_fixable=True, - is_persistent=True, - severity=IssueSeverity.WARNING, - translation_key="deprecated_entity", - translation_placeholders={ - "deprecated_entity": self.entity_id, - "deprecated_service": "switch.turn_off", - "alternate_service": "remote.turn_off", - "alternate_target": f"remote.{split_entity_id(self.entity_id)[1]}", - }, - ) - set_req = self.gateway.const.SetReq - self.gateway.set_child_value( - self.node_id, self.child_id, set_req.V_LIGHT, 0, ack=1 - ) - if self.assumed_state: - # Optimistically assume that switch has changed state - self._values[set_req.V_LIGHT] = STATE_OFF - self.async_write_ha_state() - - @callback - def _async_update(self) -> None: - """Update the controller with the latest value from a sensor.""" - super()._async_update() - self._ir_code = self._values.get(self.value_type) diff --git a/tests/components/mysensors/test_switch.py b/tests/components/mysensors/test_switch.py index b77d540d543..59cea514d77 100644 --- a/tests/components/mysensors/test_switch.py +++ b/tests/components/mysensors/test_switch.py @@ -6,7 +6,6 @@ from unittest.mock import MagicMock, call from mysensors.sensor import Sensor -from homeassistant.components.mysensors.const import DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.core import HomeAssistant @@ -62,81 +61,3 @@ async def test_relay_node( assert state assert state.state == "off" - - -async def test_ir_transceiver( - hass: HomeAssistant, - ir_transceiver: Sensor, - receive_message: Callable[[str], None], - transport_write: MagicMock, -) -> None: - """Test an ir transceiver.""" - entity_id = "switch.ir_transceiver_1_1" - - state = hass.states.get(entity_id) - - assert state - assert state.state == "off" - - await hass.services.async_call( - SWITCH_DOMAIN, - "turn_on", - {"entity_id": entity_id}, - blocking=True, - ) - - assert transport_write.call_count == 2 - assert transport_write.call_args_list[0] == call("1;1;1;0;32;test_code\n") - assert transport_write.call_args_list[1] == call("1;1;1;1;2;1\n") - - receive_message("1;1;1;0;2;1\n") - await hass.async_block_till_done() - - state = hass.states.get(entity_id) - - assert state - assert state.state == "on" - assert state.attributes["V_IR_SEND"] == "test_code" - - transport_write.reset_mock() - - await hass.services.async_call( - SWITCH_DOMAIN, - "turn_off", - {"entity_id": entity_id}, - blocking=True, - ) - - assert transport_write.call_count == 1 - assert transport_write.call_args == call("1;1;1;1;2;0\n") - - receive_message("1;1;1;0;2;0\n") - await hass.async_block_till_done() - - state = hass.states.get(entity_id) - - assert state - assert state.state == "off" - - transport_write.reset_mock() - - await hass.services.async_call( - DOMAIN, - "send_ir_code", - {"entity_id": entity_id, "V_IR_SEND": "new_code"}, - blocking=True, - ) - - assert transport_write.call_count == 2 - assert transport_write.call_args_list[0] == call("1;1;1;0;32;new_code\n") - assert transport_write.call_args_list[1] == call("1;1;1;1;2;1\n") - - receive_message("1;1;1;0;32;new_code\n") - receive_message("1;1;1;0;2;1\n") - await hass.async_block_till_done() - - state = hass.states.get(entity_id) - - assert state - assert state.state == "on" - assert state.attributes["V_IR_SEND"] == "new_code"