1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 12:59:34 +00:00

Add Shelly binary sensor translation (#154116)

Signed-off-by: David Rapan <david@rapan.cz>
This commit is contained in:
David Rapan
2025-11-17 21:39:14 +01:00
committed by GitHub
parent 5d87e0f429
commit 433712b407
8 changed files with 322 additions and 115 deletions

View File

@@ -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()

View File

@@ -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"

View File

@@ -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}"

View File

@@ -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,

View File

@@ -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,
})

View File

@@ -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,
})

View File

@@ -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,

View File

@@ -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)