diff --git a/homeassistant/components/shelly/binary_sensor.py b/homeassistant/components/shelly/binary_sensor.py index 67e71a712a3..8912b27c057 100644 --- a/homeassistant/components/shelly/binary_sensor.py +++ b/homeassistant/components/shelly/binary_sensor.py @@ -5,6 +5,7 @@ from __future__ import annotations from dataclasses import dataclass from typing import Final, cast +from aioshelly.block_device import Block from aioshelly.const import RPC_GENERATIONS from homeassistant.components.binary_sensor import ( @@ -16,10 +17,11 @@ from homeassistant.components.binary_sensor import ( from homeassistant.const import STATE_ON, EntityCategory from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.helpers.entity_registry import RegistryEntry from homeassistant.helpers.restore_state import RestoreEntity from .const import CONF_SLEEP_PERIOD, MODEL_FRANKEVER_WATER_VALVE, ROLE_GENERIC -from .coordinator import ShellyConfigEntry, ShellyRpcCoordinator +from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator from .entity import ( BlockEntityDescription, RestEntityDescription, @@ -37,6 +39,10 @@ from .utils import ( async_remove_orphaned_entities, get_blu_trv_device_info, get_device_entry_gen, + get_entity_translation_attributes, + get_rpc_channel_name, + get_rpc_custom_name, + get_rpc_key, is_block_momentary_input, is_rpc_momentary_input, is_view_for_platform, @@ -67,6 +73,44 @@ class RpcBinarySensor(ShellyRpcAttributeEntity, BinarySensorEntity): entity_description: RpcBinarySensorDescription + def __init__( + self, + coordinator: ShellyRpcCoordinator, + key: str, + attribute: str, + description: RpcBinarySensorDescription, + ) -> None: + """Initialize sensor.""" + super().__init__(coordinator, key, attribute, description) + + if hasattr(self, "_attr_name") and description.role != ROLE_GENERIC: + if not description.role and description.key == "input": + _, component, component_id = get_rpc_key(key) + if not get_rpc_custom_name(coordinator.device, key) and ( + component.lower() == "input" and component_id.isnumeric() + ): + self._attr_translation_placeholders = {"input_number": component_id} + self._attr_translation_key = "input_with_number" + else: + return + + delattr(self, "_attr_name") + + if not description.role and description.key != "input": + translation_placeholders, translation_key = ( + get_entity_translation_attributes( + get_rpc_channel_name(coordinator.device, key), + description.translation_key, + description.device_class, + self._default_to_device_class_name(), + ) + ) + + if translation_placeholders: + self._attr_translation_placeholders = translation_placeholders + if translation_key: + self._attr_translation_key = translation_key + @property def is_on(self) -> bool: """Return true if RPC sensor state is on.""" @@ -107,85 +151,84 @@ class RpcBluTrvBinarySensor(RpcBinarySensor): SENSORS: dict[tuple[str, str], BlockBinarySensorDescription] = { ("device", "overtemp"): BlockBinarySensorDescription( key="device|overtemp", - name="Overheating", + translation_key="overheating", device_class=BinarySensorDeviceClass.PROBLEM, entity_category=EntityCategory.DIAGNOSTIC, ), ("device", "overpower"): BlockBinarySensorDescription( key="device|overpower", - name="Overpowering", + translation_key="overpowering", device_class=BinarySensorDeviceClass.PROBLEM, entity_category=EntityCategory.DIAGNOSTIC, ), ("light", "overpower"): BlockBinarySensorDescription( key="light|overpower", - name="Overpowering", + translation_key="overpowering", device_class=BinarySensorDeviceClass.PROBLEM, entity_category=EntityCategory.DIAGNOSTIC, ), ("relay", "overpower"): BlockBinarySensorDescription( key="relay|overpower", - name="Overpowering", + translation_key="overpowering", device_class=BinarySensorDeviceClass.PROBLEM, entity_category=EntityCategory.DIAGNOSTIC, ), ("sensor", "dwIsOpened"): BlockBinarySensorDescription( key="sensor|dwIsOpened", - name="Door", + translation_key="door", device_class=BinarySensorDeviceClass.OPENING, available=lambda block: cast(int, block.dwIsOpened) != -1, ), ("sensor", "flood"): BlockBinarySensorDescription( - key="sensor|flood", name="Flood", device_class=BinarySensorDeviceClass.MOISTURE + key="sensor|flood", + translation_key="flood", + device_class=BinarySensorDeviceClass.MOISTURE, ), ("sensor", "gas"): BlockBinarySensorDescription( key="sensor|gas", - name="Gas", device_class=BinarySensorDeviceClass.GAS, - translation_key="gas", value=lambda value: value in ["mild", "heavy"], ), ("sensor", "smoke"): BlockBinarySensorDescription( - key="sensor|smoke", name="Smoke", device_class=BinarySensorDeviceClass.SMOKE + key="sensor|smoke", device_class=BinarySensorDeviceClass.SMOKE ), ("sensor", "vibration"): BlockBinarySensorDescription( key="sensor|vibration", - name="Vibration", device_class=BinarySensorDeviceClass.VIBRATION, ), ("input", "input"): BlockBinarySensorDescription( key="input|input", - name="Input", + translation_key="input", device_class=BinarySensorDeviceClass.POWER, removal_condition=is_block_momentary_input, ), ("relay", "input"): BlockBinarySensorDescription( key="relay|input", - name="Input", + translation_key="input", device_class=BinarySensorDeviceClass.POWER, removal_condition=is_block_momentary_input, ), ("device", "input"): BlockBinarySensorDescription( key="device|input", - name="Input", + translation_key="input", device_class=BinarySensorDeviceClass.POWER, removal_condition=is_block_momentary_input, ), ("sensor", "extInput"): BlockBinarySensorDescription( key="sensor|extInput", - name="External input", + translation_key="external_input", device_class=BinarySensorDeviceClass.POWER, entity_registry_enabled_default=False, ), ("sensor", "motion"): BlockBinarySensorDescription( - key="sensor|motion", name="Motion", device_class=BinarySensorDeviceClass.MOTION + key="sensor|motion", device_class=BinarySensorDeviceClass.MOTION ), } REST_SENSORS: Final = { "cloud": RestBinarySensorDescription( key="cloud", - name="Cloud", + translation_key="cloud", value=lambda status, _: status["cloud"]["connected"], device_class=BinarySensorDeviceClass.CONNECTIVITY, entity_registry_enabled_default=False, @@ -197,13 +240,14 @@ RPC_SENSORS: Final = { "input": RpcBinarySensorDescription( key="input", sub_key="state", + translation_key="input", device_class=BinarySensorDeviceClass.POWER, removal_condition=is_rpc_momentary_input, ), "cloud": RpcBinarySensorDescription( key="cloud", sub_key="connected", - name="Cloud", + translation_key="cloud", device_class=BinarySensorDeviceClass.CONNECTIVITY, entity_registry_enabled_default=False, entity_category=EntityCategory.DIAGNOSTIC, @@ -211,7 +255,7 @@ RPC_SENSORS: Final = { "external_power": RpcBinarySensorDescription( key="devicepower", sub_key="external", - name="External power", + translation_key="external_power", value=lambda status, _: status["present"], device_class=BinarySensorDeviceClass.POWER, entity_category=EntityCategory.DIAGNOSTIC, @@ -219,7 +263,7 @@ RPC_SENSORS: Final = { "overtemp": RpcBinarySensorDescription( key="switch", sub_key="errors", - name="Overheating", + translation_key="overheating", device_class=BinarySensorDeviceClass.PROBLEM, value=lambda status, _: False if status is None else "overtemp" in status, entity_category=EntityCategory.DIAGNOSTIC, @@ -228,7 +272,7 @@ RPC_SENSORS: Final = { "overpower": RpcBinarySensorDescription( key="switch", sub_key="errors", - name="Overpowering", + translation_key="overpowering", device_class=BinarySensorDeviceClass.PROBLEM, value=lambda status, _: False if status is None else "overpower" in status, entity_category=EntityCategory.DIAGNOSTIC, @@ -237,7 +281,7 @@ RPC_SENSORS: Final = { "overvoltage": RpcBinarySensorDescription( key="switch", sub_key="errors", - name="Overvoltage", + translation_key="overvoltage", device_class=BinarySensorDeviceClass.PROBLEM, value=lambda status, _: False if status is None else "overvoltage" in status, entity_category=EntityCategory.DIAGNOSTIC, @@ -246,7 +290,7 @@ RPC_SENSORS: Final = { "overcurrent": RpcBinarySensorDescription( key="switch", sub_key="errors", - name="Overcurrent", + translation_key="overcurrent", device_class=BinarySensorDeviceClass.PROBLEM, value=lambda status, _: False if status is None else "overcurrent" in status, entity_category=EntityCategory.DIAGNOSTIC, @@ -255,13 +299,12 @@ RPC_SENSORS: Final = { "smoke": RpcBinarySensorDescription( key="smoke", sub_key="alarm", - name="Smoke", device_class=BinarySensorDeviceClass.SMOKE, ), "restart": RpcBinarySensorDescription( key="sys", sub_key="restart_required", - name="Restart required", + translation_key="restart_required", device_class=BinarySensorDeviceClass.PROBLEM, entity_registry_enabled_default=False, entity_category=EntityCategory.DIAGNOSTIC, @@ -269,7 +312,7 @@ RPC_SENSORS: Final = { "boolean_generic": RpcBinarySensorDescription( key="boolean", sub_key="value", - removal_condition=lambda config, _status, key: not is_view_for_platform( + removal_condition=lambda config, _, key: not is_view_for_platform( config, key, BINARY_SENSOR_PLATFORM ), role=ROLE_GENERIC, @@ -285,7 +328,7 @@ RPC_SENSORS: Final = { "calibration": RpcBinarySensorDescription( key="blutrv", sub_key="errors", - name="Calibration", + translation_key="calibration", device_class=BinarySensorDeviceClass.PROBLEM, value=lambda status, _: False if status is None else "not_calibrated" in status, entity_category=EntityCategory.DIAGNOSTIC, @@ -294,13 +337,13 @@ RPC_SENSORS: Final = { "flood": RpcBinarySensorDescription( key="flood", sub_key="alarm", - name="Flood", + translation_key="flood", device_class=BinarySensorDeviceClass.MOISTURE, ), "mute": RpcBinarySensorDescription( key="flood", sub_key="mute", - name="Mute", + translation_key="mute", entity_category=EntityCategory.DIAGNOSTIC, ), "flood_cable_unplugged": RpcBinarySensorDescription( @@ -309,7 +352,7 @@ RPC_SENSORS: Final = { value=lambda status, _: False if status is None else "cable_unplugged" in status, - name="Cable unplugged", + translation_key="cable_unplugged", device_class=BinarySensorDeviceClass.PROBLEM, entity_category=EntityCategory.DIAGNOSTIC, supported=lambda status: status.get("alarm") is not None, @@ -318,14 +361,12 @@ RPC_SENSORS: Final = { key="presence", sub_key="num_objects", value=lambda status, _: bool(status), - name="Occupancy", device_class=BinarySensorDeviceClass.OCCUPANCY, entity_class=RpcPresenceBinarySensor, ), "presencezone_state": RpcBinarySensorDescription( key="presencezone", sub_key="value", - name="Occupancy", device_class=BinarySensorDeviceClass.OCCUPANCY, entity_class=RpcPresenceBinarySensor, ), @@ -413,6 +454,19 @@ class BlockBinarySensor(ShellyBlockAttributeEntity, BinarySensorEntity): entity_description: BlockBinarySensorDescription + def __init__( + self, + coordinator: ShellyBlockCoordinator, + block: Block, + attribute: str, + description: BlockBinarySensorDescription, + ) -> None: + """Initialize sensor.""" + super().__init__(coordinator, block, attribute, description) + + if hasattr(self, "_attr_name"): + delattr(self, "_attr_name") + @property def is_on(self) -> bool: """Return true if sensor state is on.""" @@ -424,6 +478,18 @@ class RestBinarySensor(ShellyRestAttributeEntity, BinarySensorEntity): entity_description: RestBinarySensorDescription + def __init__( + self, + coordinator: ShellyBlockCoordinator, + attribute: str, + description: RestBinarySensorDescription, + ) -> None: + """Initialize sensor.""" + super().__init__(coordinator, attribute, description) + + if hasattr(self, "_attr_name"): + delattr(self, "_attr_name") + @property def is_on(self) -> bool: """Return true if REST sensor state is on.""" @@ -437,6 +503,20 @@ class BlockSleepingBinarySensor( entity_description: BlockBinarySensorDescription + def __init__( + self, + coordinator: ShellyBlockCoordinator, + block: Block | None, + attribute: str, + description: BlockBinarySensorDescription, + entry: RegistryEntry | None = None, + ) -> None: + """Initialize the sleeping sensor.""" + super().__init__(coordinator, block, attribute, description, entry) + + if hasattr(self, "_attr_name"): + delattr(self, "_attr_name") + async def async_added_to_hass(self) -> None: """Handle entity which will be added.""" await super().async_added_to_hass() @@ -461,6 +541,35 @@ class RpcSleepingBinarySensor( entity_description: RpcBinarySensorDescription + def __init__( + self, + coordinator: ShellyRpcCoordinator, + key: str, + attribute: str, + description: RpcBinarySensorDescription, + entry: RegistryEntry | None = None, + ) -> None: + """Initialize the sleeping sensor.""" + super().__init__(coordinator, key, attribute, description, entry) + + if coordinator.device.initialized: + if hasattr(self, "_attr_name"): + delattr(self, "_attr_name") + + translation_placeholders, translation_key = ( + get_entity_translation_attributes( + get_rpc_channel_name(coordinator.device, key), + description.translation_key, + description.device_class, + self._default_to_device_class_name(), + ) + ) + + if translation_placeholders: + self._attr_translation_placeholders = translation_placeholders + if translation_key: + self._attr_translation_key = translation_key + async def async_added_to_hass(self) -> None: """Handle entity which will be added.""" await super().async_added_to_hass() diff --git a/homeassistant/components/shelly/strings.json b/homeassistant/components/shelly/strings.json index 86af0df88fd..0e85fc25998 100644 --- a/homeassistant/components/shelly/strings.json +++ b/homeassistant/components/shelly/strings.json @@ -129,6 +129,80 @@ } }, "entity": { + "binary_sensor": { + "cable_unplugged": { + "name": "Cable unplugged" + }, + "cable_unplugged_with_channel_name": { + "name": "{channel_name} cable unplugged" + }, + "calibration": { + "name": "Calibration" + }, + "cloud": { + "name": "Cloud" + }, + "door": { + "name": "Door" + }, + "external_input": { + "name": "External input" + }, + "external_power": { + "name": "External power" + }, + "flood": { + "name": "Flood" + }, + "flood_with_channel_name": { + "name": "{channel_name} flood" + }, + "input": { + "name": "Input" + }, + "input_with_number": { + "name": "Input {input_number}" + }, + "mute": { + "name": "Mute" + }, + "mute_with_channel_name": { + "name": "{channel_name} mute" + }, + "occupancy_with_channel_name": { + "name": "{channel_name} occupancy" + }, + "overcurrent": { + "name": "Overcurrent" + }, + "overcurrent_with_channel_name": { + "name": "{channel_name} overcurrent" + }, + "overheating": { + "name": "Overheating" + }, + "overheating_with_channel_name": { + "name": "{channel_name} overheating" + }, + "overpowering": { + "name": "Overpowering" + }, + "overpowering_with_channel_name": { + "name": "{channel_name} overpowering" + }, + "overvoltage": { + "name": "Overvoltage" + }, + "overvoltage_with_channel_name": { + "name": "{channel_name} overvoltage" + }, + "restart_required": { + "name": "Restart required" + }, + "smoke_with_channel_name": { + "name": "{channel_name} smoke" + } + }, "button": { "calibrate": { "name": "Calibrate" diff --git a/homeassistant/components/shelly/utils.py b/homeassistant/components/shelly/utils.py index 4595c623fbc..e2483d18059 100644 --- a/homeassistant/components/shelly/utils.py +++ b/homeassistant/components/shelly/utils.py @@ -391,7 +391,13 @@ def get_shelly_model_name( return cast(str, MODEL_NAMES.get(model)) -def get_rpc_component_name(device: RpcDevice, key: str) -> str | None: +def get_rpc_key(value: str) -> tuple[bool, str, str]: + """Get split device key.""" + parts = value.split(":") + return len(parts) > 1, parts[0], parts[-1] + + +def get_rpc_custom_name(device: RpcDevice, key: str) -> str | None: """Get component name from device config.""" if ( key in device.config @@ -403,6 +409,11 @@ def get_rpc_component_name(device: RpcDevice, key: str) -> str | None: return None +def get_rpc_component_name(device: RpcDevice, key: str) -> str | None: + """Get component name from device config.""" + return get_rpc_custom_name(device, key) + + def get_rpc_channel_name(device: RpcDevice, key: str) -> str | None: """Get name based on device and channel name.""" if BLU_TRV_IDENTIFIER in key: @@ -414,11 +425,11 @@ def get_rpc_channel_name(device: RpcDevice, key: str) -> str | None: component = key.split(":")[0] component_id = key.split(":")[-1] - if component_name := get_rpc_component_name(device, key): + if custom_name := get_rpc_custom_name(device, key): if component in (*VIRTUAL_COMPONENTS, "input", "presencezone", "script"): - return component_name + return custom_name - return component_name if instances == 1 else None + return custom_name if instances == 1 else None if component in (*VIRTUAL_COMPONENTS, "input"): return f"{component.title()} {component_id}" diff --git a/tests/components/shelly/conftest.py b/tests/components/shelly/conftest.py index e68ebf84bc7..d41824c771b 100644 --- a/tests/components/shelly/conftest.py +++ b/tests/components/shelly/conftest.py @@ -247,6 +247,7 @@ MOCK_CONFIG = { "wifi": {"sta": {"enable": True}, "sta1": {"enable": False}}, "ws": {"enable": False, "server": None}, "voltmeter:100": {"xvoltage": {"unit": "ppm"}}, + "smoke:0": {"id": 0, "name": "test channel name"}, "script:1": {"id": 1, "name": "test_script.js", "enable": True}, "script:2": {"id": 2, "name": "test_script_2.js", "enable": False}, "script:3": {"id": 3, "name": BLE_SCRIPT_NAME, "enable": False}, @@ -439,6 +440,7 @@ MOCK_STATUS_RPC = { "current_C": 12.3, "output": True, }, + "smoke:0": {"id": 0, "alarm": False, "mute": False}, "script:1": { "id": 1, "running": True, diff --git a/tests/components/shelly/snapshots/test_binary_sensor.ambr b/tests/components/shelly/snapshots/test_binary_sensor.ambr index 5388dcfedc6..9caad9e3516 100644 --- a/tests/components/shelly/snapshots/test_binary_sensor.ambr +++ b/tests/components/shelly/snapshots/test_binary_sensor.ambr @@ -29,7 +29,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'calibration', 'unique_id': '123456789ABC-blutrv:200-calibration', 'unit_of_measurement': None, }) @@ -78,7 +78,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cable_unplugged_with_channel_name', 'unique_id': '123456789ABC-flood:0-flood_cable_unplugged', 'unit_of_measurement': None, }) @@ -127,7 +127,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'flood_with_channel_name', 'unique_id': '123456789ABC-flood:0-flood', 'unit_of_measurement': None, }) @@ -176,7 +176,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'mute_with_channel_name', 'unique_id': '123456789ABC-flood:0-mute', 'unit_of_measurement': None, }) diff --git a/tests/components/shelly/snapshots/test_devices.ambr b/tests/components/shelly/snapshots/test_devices.ambr index d24a3d0cd1c..68e31835073 100644 --- a/tests/components/shelly/snapshots/test_devices.ambr +++ b/tests/components/shelly/snapshots/test_devices.ambr @@ -29,7 +29,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cloud', 'unique_id': '123456789ABC-cloud-cloud', 'unit_of_measurement': None, }) @@ -78,7 +78,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'restart_required', 'unique_id': '123456789ABC-sys-restart', 'unit_of_measurement': None, }) @@ -1023,7 +1023,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cloud', 'unique_id': '123456789ABC-cloud-cloud', 'unit_of_measurement': None, }) @@ -1072,7 +1072,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'restart_required', 'unique_id': '123456789ABC-sys-restart', 'unit_of_measurement': None, }) @@ -1580,7 +1580,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overcurrent', 'unique_id': '123456789ABC-switch:1-overcurrent', 'unit_of_measurement': None, }) @@ -1629,7 +1629,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overheating', 'unique_id': '123456789ABC-switch:1-overtemp', 'unit_of_measurement': None, }) @@ -1678,7 +1678,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overpowering', 'unique_id': '123456789ABC-switch:1-overpower', 'unit_of_measurement': None, }) @@ -1727,7 +1727,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overvoltage', 'unique_id': '123456789ABC-switch:1-overvoltage', 'unit_of_measurement': None, }) @@ -1776,7 +1776,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overcurrent', 'unique_id': '123456789ABC-switch:3-overcurrent', 'unit_of_measurement': None, }) @@ -1825,7 +1825,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overheating', 'unique_id': '123456789ABC-switch:3-overtemp', 'unit_of_measurement': None, }) @@ -1874,7 +1874,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overpowering', 'unique_id': '123456789ABC-switch:3-overpower', 'unit_of_measurement': None, }) @@ -1923,7 +1923,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overvoltage', 'unique_id': '123456789ABC-switch:3-overvoltage', 'unit_of_measurement': None, }) @@ -1972,7 +1972,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cloud', 'unique_id': '123456789ABC-cloud-cloud', 'unit_of_measurement': None, }) @@ -2021,7 +2021,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'restart_required', 'unique_id': '123456789ABC-sys-restart', 'unit_of_measurement': None, }) @@ -2070,7 +2070,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overcurrent', 'unique_id': '123456789ABC-switch:0-overcurrent', 'unit_of_measurement': None, }) @@ -2119,7 +2119,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overheating', 'unique_id': '123456789ABC-switch:0-overtemp', 'unit_of_measurement': None, }) @@ -2168,7 +2168,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overpowering', 'unique_id': '123456789ABC-switch:0-overpower', 'unit_of_measurement': None, }) @@ -2217,7 +2217,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overvoltage', 'unique_id': '123456789ABC-switch:0-overvoltage', 'unit_of_measurement': None, }) @@ -2266,7 +2266,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overcurrent', 'unique_id': '123456789ABC-switch:2-overcurrent', 'unit_of_measurement': None, }) @@ -2315,7 +2315,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overheating', 'unique_id': '123456789ABC-switch:2-overtemp', 'unit_of_measurement': None, }) @@ -2364,7 +2364,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overpowering', 'unique_id': '123456789ABC-switch:2-overpower', 'unit_of_measurement': None, }) @@ -2413,7 +2413,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overvoltage', 'unique_id': '123456789ABC-switch:2-overvoltage', 'unit_of_measurement': None, }) @@ -4540,7 +4540,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cloud', 'unique_id': '123456789ABC-cloud-cloud', 'unit_of_measurement': None, }) @@ -4589,7 +4589,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'occupancy_with_channel_name', 'unique_id': '123456789ABC-presencezone:201-presencezone_state', 'unit_of_measurement': None, }) @@ -4638,7 +4638,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'occupancy_with_channel_name', 'unique_id': '123456789ABC-presencezone:202-presencezone_state', 'unit_of_measurement': None, }) @@ -4687,7 +4687,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'restart_required', 'unique_id': '123456789ABC-sys-restart', 'unit_of_measurement': None, }) @@ -4736,7 +4736,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'occupancy_with_channel_name', 'unique_id': '123456789ABC-presencezone:200-presencezone_state', 'unit_of_measurement': None, }) @@ -5274,7 +5274,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cloud', 'unique_id': '123456789ABC-cloud-cloud', 'unit_of_measurement': None, }) @@ -5323,7 +5323,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'external_power', 'unique_id': '123456789ABC-devicepower:0-external_power', 'unit_of_measurement': None, }) @@ -5372,7 +5372,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'input_with_number', 'unique_id': '123456789ABC-input:2-input', 'unit_of_measurement': None, }) @@ -5421,7 +5421,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'restart_required', 'unique_id': '123456789ABC-sys-restart', 'unit_of_measurement': None, }) @@ -6289,7 +6289,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cloud', 'unique_id': '123456789ABC-cloud-cloud', 'unit_of_measurement': None, }) @@ -6338,7 +6338,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'input_with_number', 'unique_id': '123456789ABC-input:0-input', 'unit_of_measurement': None, }) @@ -6387,7 +6387,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'input_with_number', 'unique_id': '123456789ABC-input:1-input', 'unit_of_measurement': None, }) @@ -6436,7 +6436,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overcurrent', 'unique_id': '123456789ABC-cover:0-overcurrent', 'unit_of_measurement': None, }) @@ -6485,7 +6485,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overheating', 'unique_id': '123456789ABC-cover:0-overtemp', 'unit_of_measurement': None, }) @@ -6534,7 +6534,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overpowering', 'unique_id': '123456789ABC-cover:0-overpower', 'unit_of_measurement': None, }) @@ -6583,7 +6583,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overvoltage', 'unique_id': '123456789ABC-cover:0-overvoltage', 'unit_of_measurement': None, }) @@ -6632,7 +6632,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'restart_required', 'unique_id': '123456789ABC-sys-restart', 'unit_of_measurement': None, }) @@ -7343,7 +7343,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cloud', 'unique_id': '123456789ABC-cloud-cloud', 'unit_of_measurement': None, }) @@ -7392,7 +7392,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'input_with_number', 'unique_id': '123456789ABC-input:0-input', 'unit_of_measurement': None, }) @@ -7441,7 +7441,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'input_with_number', 'unique_id': '123456789ABC-input:1-input', 'unit_of_measurement': None, }) @@ -7490,7 +7490,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'restart_required', 'unique_id': '123456789ABC-sys-restart', 'unit_of_measurement': None, }) @@ -7539,7 +7539,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overcurrent', 'unique_id': '123456789ABC-switch:0-overcurrent', 'unit_of_measurement': None, }) @@ -7588,7 +7588,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overheating', 'unique_id': '123456789ABC-switch:0-overtemp', 'unit_of_measurement': None, }) @@ -7637,7 +7637,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overpowering', 'unique_id': '123456789ABC-switch:0-overpower', 'unit_of_measurement': None, }) @@ -7686,7 +7686,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overvoltage', 'unique_id': '123456789ABC-switch:0-overvoltage', 'unit_of_measurement': None, }) @@ -7735,7 +7735,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overcurrent', 'unique_id': '123456789ABC-switch:1-overcurrent', 'unit_of_measurement': None, }) @@ -7784,7 +7784,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overheating', 'unique_id': '123456789ABC-switch:1-overtemp', 'unit_of_measurement': None, }) @@ -7833,7 +7833,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overpowering', 'unique_id': '123456789ABC-switch:1-overpower', 'unit_of_measurement': None, }) @@ -7882,7 +7882,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'overvoltage', 'unique_id': '123456789ABC-switch:1-overvoltage', 'unit_of_measurement': None, }) @@ -9214,7 +9214,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'cloud', 'unique_id': '123456789ABC-cloud-cloud', 'unit_of_measurement': None, }) @@ -9263,7 +9263,7 @@ 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'restart_required', 'unique_id': '123456789ABC-sys-restart', 'unit_of_measurement': None, }) diff --git a/tests/components/shelly/test_binary_sensor.py b/tests/components/shelly/test_binary_sensor.py index 7e60141f5ea..9fe4b673ab2 100644 --- a/tests/components/shelly/test_binary_sensor.py +++ b/tests/components/shelly/test_binary_sensor.py @@ -3,7 +3,7 @@ from copy import deepcopy from unittest.mock import Mock -from aioshelly.const import MODEL_BLU_GATEWAY_G3, MODEL_MOTION +from aioshelly.const import MODEL_BLU_GATEWAY_G3, MODEL_MOTION, MODEL_PLUS_SMOKE from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion @@ -333,6 +333,35 @@ async def test_rpc_sleeping_binary_sensor( assert entry.unique_id == "123456789ABC-devicepower:0-external_power" +async def test_rpc_sleeping_binary_sensor_with_channel_name( + hass: HomeAssistant, + mock_rpc_device: Mock, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Test RPC online sleeping binary sensor with channel name.""" + entity_id = f"{BINARY_SENSOR_DOMAIN}.test_name_test_channel_name_smoke" + monkeypatch.setattr(mock_rpc_device, "connected", False) + monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000) + await init_integration(hass, 2, sleep_period=1000, model=MODEL_PLUS_SMOKE) + + # Sensor should be created when device is online + assert hass.states.get(entity_id) is None + + # Make device online + mock_rpc_device.mock_online() + await hass.async_block_till_done(wait_background_tasks=True) + + assert (state := hass.states.get(entity_id)) + assert state.attributes["friendly_name"] == "Test name test channel name smoke" + assert state.state == STATE_OFF + + mutate_rpc_device_status(monkeypatch, mock_rpc_device, "smoke:0", "alarm", True) + mock_rpc_device.mock_update() + + assert (state := hass.states.get(entity_id)) + assert state.state == STATE_ON + + async def test_rpc_restored_sleeping_binary_sensor( hass: HomeAssistant, mock_rpc_device: Mock, diff --git a/tests/components/shelly/test_button.py b/tests/components/shelly/test_button.py index bfc240d639d..6290e95c653 100644 --- a/tests/components/shelly/test_button.py +++ b/tests/components/shelly/test_button.py @@ -487,36 +487,18 @@ async def test_migrate_unique_id_virtual_components_roles( async def test_rpc_smoke_mute_alarm_button( hass: HomeAssistant, mock_rpc_device: Mock, - device_registry: DeviceRegistry, monkeypatch: pytest.MonkeyPatch, ) -> None: """Test RPC smoke mute alarm button.""" entity_id = f"{BUTTON_DOMAIN}.test_name_mute_alarm" - status = { - "sys": {"wakeup_period": 1000}, - "smoke:0": { - "id": 0, - "alarm": False, - "mute": False, - }, - } - monkeypatch.setattr(mock_rpc_device, "status", status) - config = {"smoke:0": {"id": 0, "name": None}} - monkeypatch.setattr(mock_rpc_device, "config", config) + monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000) + monkeypatch.setattr(mock_rpc_device, "config", {"smoke:0": {"id": 0, "name": None}}) monkeypatch.setattr(mock_rpc_device, "connected", False) - entry = await init_integration(hass, 2, sleep_period=1000, model=MODEL_PLUS_SMOKE) + await init_integration(hass, 2, sleep_period=1000, model=MODEL_PLUS_SMOKE) # Sensor should be created when device is online assert hass.states.get(entity_id) is None - register_entity( - hass, - BUTTON_DOMAIN, - "test_name_mute_alarm", - "smoke:0-smoke_mute", - entry, - ) - # Make device online mock_rpc_device.mock_online() await hass.async_block_till_done(wait_background_tasks=True)