mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Fix Shelly Gen1 entity description restore (#108052)
* Fix Shelly Gen1 entity description restore * Update tests/components/shelly/test_sensor.py Co-authored-by: J. Nick Koston <nick@koston.org> --------- Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
3bc20a072a
commit
28e18ce7bf
@ -15,7 +15,6 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import STATE_ON, EntityCategory
|
from homeassistant.const import STATE_ON, EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.entity_registry import RegistryEntry
|
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
|
|
||||||
from .const import CONF_SLEEP_PERIOD
|
from .const import CONF_SLEEP_PERIOD
|
||||||
@ -210,16 +209,6 @@ RPC_SENSORS: Final = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _build_block_description(entry: RegistryEntry) -> BlockBinarySensorDescription:
|
|
||||||
"""Build description when restoring block attribute entities."""
|
|
||||||
return BlockBinarySensorDescription(
|
|
||||||
key="",
|
|
||||||
name="",
|
|
||||||
icon=entry.original_icon,
|
|
||||||
device_class=entry.original_device_class,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
@ -248,7 +237,6 @@ async def async_setup_entry(
|
|||||||
async_add_entities,
|
async_add_entities,
|
||||||
SENSORS,
|
SENSORS,
|
||||||
BlockSleepingBinarySensor,
|
BlockSleepingBinarySensor,
|
||||||
_build_block_description,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
async_setup_entry_attribute_entities(
|
async_setup_entry_attribute_entities(
|
||||||
@ -257,7 +245,6 @@ async def async_setup_entry(
|
|||||||
async_add_entities,
|
async_add_entities,
|
||||||
SENSORS,
|
SENSORS,
|
||||||
BlockBinarySensor,
|
BlockBinarySensor,
|
||||||
_build_block_description,
|
|
||||||
)
|
)
|
||||||
async_setup_entry_rest(
|
async_setup_entry_rest(
|
||||||
hass,
|
hass,
|
||||||
|
@ -39,7 +39,6 @@ def async_setup_entry_attribute_entities(
|
|||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
sensors: Mapping[tuple[str, str], BlockEntityDescription],
|
sensors: Mapping[tuple[str, str], BlockEntityDescription],
|
||||||
sensor_class: Callable,
|
sensor_class: Callable,
|
||||||
description_class: Callable[[RegistryEntry], BlockEntityDescription],
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up entities for attributes."""
|
"""Set up entities for attributes."""
|
||||||
coordinator = get_entry_data(hass)[config_entry.entry_id].block
|
coordinator = get_entry_data(hass)[config_entry.entry_id].block
|
||||||
@ -56,7 +55,6 @@ def async_setup_entry_attribute_entities(
|
|||||||
coordinator,
|
coordinator,
|
||||||
sensors,
|
sensors,
|
||||||
sensor_class,
|
sensor_class,
|
||||||
description_class,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -113,7 +111,6 @@ def async_restore_block_attribute_entities(
|
|||||||
coordinator: ShellyBlockCoordinator,
|
coordinator: ShellyBlockCoordinator,
|
||||||
sensors: Mapping[tuple[str, str], BlockEntityDescription],
|
sensors: Mapping[tuple[str, str], BlockEntityDescription],
|
||||||
sensor_class: Callable,
|
sensor_class: Callable,
|
||||||
description_class: Callable[[RegistryEntry], BlockEntityDescription],
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Restore block attributes entities."""
|
"""Restore block attributes entities."""
|
||||||
entities = []
|
entities = []
|
||||||
@ -128,11 +125,12 @@ def async_restore_block_attribute_entities(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
attribute = entry.unique_id.split("-")[-1]
|
attribute = entry.unique_id.split("-")[-1]
|
||||||
description = description_class(entry)
|
block_type = entry.unique_id.split("-")[-2].split("_")[0]
|
||||||
|
|
||||||
entities.append(
|
if description := sensors.get((block_type, attribute)):
|
||||||
sensor_class(coordinator, None, attribute, description, entry, sensors)
|
entities.append(
|
||||||
)
|
sensor_class(coordinator, None, attribute, description, entry)
|
||||||
|
)
|
||||||
|
|
||||||
if not entities:
|
if not entities:
|
||||||
return
|
return
|
||||||
@ -444,7 +442,7 @@ class ShellyBlockAttributeEntity(ShellyBlockEntity, Entity):
|
|||||||
"""Available."""
|
"""Available."""
|
||||||
available = super().available
|
available = super().available
|
||||||
|
|
||||||
if not available or not self.entity_description.available:
|
if not available or not self.entity_description.available or self.block is None:
|
||||||
return available
|
return available
|
||||||
|
|
||||||
return self.entity_description.available(self.block)
|
return self.entity_description.available(self.block)
|
||||||
@ -559,10 +557,8 @@ class ShellySleepingBlockAttributeEntity(ShellyBlockAttributeEntity):
|
|||||||
attribute: str,
|
attribute: str,
|
||||||
description: BlockEntityDescription,
|
description: BlockEntityDescription,
|
||||||
entry: RegistryEntry | None = None,
|
entry: RegistryEntry | None = None,
|
||||||
sensors: Mapping[tuple[str, str], BlockEntityDescription] | None = None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the sleeping sensor."""
|
"""Initialize the sleeping sensor."""
|
||||||
self.sensors = sensors
|
|
||||||
self.last_state: State | None = None
|
self.last_state: State | None = None
|
||||||
self.coordinator = coordinator
|
self.coordinator = coordinator
|
||||||
self.attribute = attribute
|
self.attribute = attribute
|
||||||
@ -587,11 +583,7 @@ class ShellySleepingBlockAttributeEntity(ShellyBlockAttributeEntity):
|
|||||||
@callback
|
@callback
|
||||||
def _update_callback(self) -> None:
|
def _update_callback(self) -> None:
|
||||||
"""Handle device update."""
|
"""Handle device update."""
|
||||||
if (
|
if self.block is not None or not self.coordinator.device.initialized:
|
||||||
self.block is not None
|
|
||||||
or not self.coordinator.device.initialized
|
|
||||||
or self.sensors is None
|
|
||||||
):
|
|
||||||
super()._update_callback()
|
super()._update_callback()
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -607,13 +599,7 @@ class ShellySleepingBlockAttributeEntity(ShellyBlockAttributeEntity):
|
|||||||
if sensor_id != entity_sensor:
|
if sensor_id != entity_sensor:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
description = self.sensors.get((block.type, sensor_id))
|
|
||||||
if description is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
self.block = block
|
self.block = block
|
||||||
self.entity_description = description
|
|
||||||
|
|
||||||
LOGGER.debug("Entity %s attached to block", self.name)
|
LOGGER.debug("Entity %s attached to block", self.name)
|
||||||
super()._update_callback()
|
super()._update_callback()
|
||||||
return
|
return
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
"""Number for Shelly."""
|
"""Number for Shelly."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Mapping
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Final, cast
|
from typing import Any, Final, cast
|
||||||
|
|
||||||
@ -56,22 +55,6 @@ NUMBERS: Final = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _build_block_description(entry: RegistryEntry) -> BlockNumberDescription:
|
|
||||||
"""Build description when restoring block attribute entities."""
|
|
||||||
assert entry.capabilities
|
|
||||||
return BlockNumberDescription(
|
|
||||||
key="",
|
|
||||||
name="",
|
|
||||||
icon=entry.original_icon,
|
|
||||||
native_unit_of_measurement=entry.unit_of_measurement,
|
|
||||||
device_class=entry.original_device_class,
|
|
||||||
native_min_value=cast(float, entry.capabilities.get("min")),
|
|
||||||
native_max_value=cast(float, entry.capabilities.get("max")),
|
|
||||||
native_step=cast(float, entry.capabilities.get("step")),
|
|
||||||
mode=cast(NumberMode, entry.capabilities.get("mode")),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
@ -85,7 +68,6 @@ async def async_setup_entry(
|
|||||||
async_add_entities,
|
async_add_entities,
|
||||||
NUMBERS,
|
NUMBERS,
|
||||||
BlockSleepingNumber,
|
BlockSleepingNumber,
|
||||||
_build_block_description,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -101,11 +83,10 @@ class BlockSleepingNumber(ShellySleepingBlockAttributeEntity, RestoreNumber):
|
|||||||
attribute: str,
|
attribute: str,
|
||||||
description: BlockNumberDescription,
|
description: BlockNumberDescription,
|
||||||
entry: RegistryEntry | None = None,
|
entry: RegistryEntry | None = None,
|
||||||
sensors: Mapping[tuple[str, str], BlockNumberDescription] | None = None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the sleeping sensor."""
|
"""Initialize the sleeping sensor."""
|
||||||
self.restored_data: NumberExtraStoredData | None = None
|
self.restored_data: NumberExtraStoredData | None = None
|
||||||
super().__init__(coordinator, block, attribute, description, entry, sensors)
|
super().__init__(coordinator, block, attribute, description, entry)
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Handle entity which will be added."""
|
"""Handle entity which will be added."""
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
"""Sensor for Shelly."""
|
"""Sensor for Shelly."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Mapping
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Final, cast
|
from typing import Final, cast
|
||||||
|
|
||||||
@ -36,7 +35,6 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.entity_registry import RegistryEntry
|
from homeassistant.helpers.entity_registry import RegistryEntry
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
from homeassistant.util.enum import try_parse_enum
|
|
||||||
|
|
||||||
from .const import CONF_SLEEP_PERIOD, SHAIR_MAX_WORK_HOURS
|
from .const import CONF_SLEEP_PERIOD, SHAIR_MAX_WORK_HOURS
|
||||||
from .coordinator import ShellyBlockCoordinator, ShellyRpcCoordinator
|
from .coordinator import ShellyBlockCoordinator, ShellyRpcCoordinator
|
||||||
@ -963,17 +961,6 @@ RPC_SENSORS: Final = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _build_block_description(entry: RegistryEntry) -> BlockSensorDescription:
|
|
||||||
"""Build description when restoring block attribute entities."""
|
|
||||||
return BlockSensorDescription(
|
|
||||||
key="",
|
|
||||||
name="",
|
|
||||||
icon=entry.original_icon,
|
|
||||||
native_unit_of_measurement=entry.unit_of_measurement,
|
|
||||||
device_class=try_parse_enum(SensorDeviceClass, entry.original_device_class),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
@ -1002,7 +989,6 @@ async def async_setup_entry(
|
|||||||
async_add_entities,
|
async_add_entities,
|
||||||
SENSORS,
|
SENSORS,
|
||||||
BlockSleepingSensor,
|
BlockSleepingSensor,
|
||||||
_build_block_description,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
async_setup_entry_attribute_entities(
|
async_setup_entry_attribute_entities(
|
||||||
@ -1011,7 +997,6 @@ async def async_setup_entry(
|
|||||||
async_add_entities,
|
async_add_entities,
|
||||||
SENSORS,
|
SENSORS,
|
||||||
BlockSensor,
|
BlockSensor,
|
||||||
_build_block_description,
|
|
||||||
)
|
)
|
||||||
async_setup_entry_rest(
|
async_setup_entry_rest(
|
||||||
hass, config_entry, async_add_entities, REST_SENSORS, RestSensor
|
hass, config_entry, async_add_entities, REST_SENSORS, RestSensor
|
||||||
@ -1075,10 +1060,9 @@ class BlockSleepingSensor(ShellySleepingBlockAttributeEntity, RestoreSensor):
|
|||||||
attribute: str,
|
attribute: str,
|
||||||
description: BlockSensorDescription,
|
description: BlockSensorDescription,
|
||||||
entry: RegistryEntry | None = None,
|
entry: RegistryEntry | None = None,
|
||||||
sensors: Mapping[tuple[str, str], BlockSensorDescription] | None = None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the sleeping sensor."""
|
"""Initialize the sleeping sensor."""
|
||||||
super().__init__(coordinator, block, attribute, description, entry, sensors)
|
super().__init__(coordinator, block, attribute, description, entry)
|
||||||
self.restored_data: SensorExtraStoredData | None = None
|
self.restored_data: SensorExtraStoredData | None = None
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
|
@ -6,9 +6,15 @@ from homeassistant.components.homeassistant import (
|
|||||||
DOMAIN as HA_DOMAIN,
|
DOMAIN as HA_DOMAIN,
|
||||||
SERVICE_UPDATE_ENTITY,
|
SERVICE_UPDATE_ENTITY,
|
||||||
)
|
)
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
from homeassistant.components.sensor import (
|
||||||
|
ATTR_STATE_CLASS,
|
||||||
|
DOMAIN as SENSOR_DOMAIN,
|
||||||
|
SensorDeviceClass,
|
||||||
|
SensorStateClass,
|
||||||
|
)
|
||||||
from homeassistant.components.shelly.const import DOMAIN
|
from homeassistant.components.shelly.const import DOMAIN
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
ATTR_DEVICE_CLASS,
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
ATTR_UNIT_OF_MEASUREMENT,
|
ATTR_UNIT_OF_MEASUREMENT,
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
@ -153,7 +159,11 @@ async def test_block_restored_sleeping_sensor(
|
|||||||
await hass.config_entries.async_setup(entry.entry_id)
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "20.4"
|
state = hass.states.get(entity_id)
|
||||||
|
assert state
|
||||||
|
assert state.state == "20.4"
|
||||||
|
assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT
|
||||||
|
assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.TEMPERATURE
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
@ -237,7 +247,9 @@ async def test_block_not_matched_restored_sleeping_sensor(
|
|||||||
assert hass.states.get(entity_id).state == "20.4"
|
assert hass.states.get(entity_id).state == "20.4"
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "type", "other_type")
|
monkeypatch.setattr(
|
||||||
|
mock_block_device.blocks[SENSOR_BLOCK_ID], "description", "other_desc"
|
||||||
|
)
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_update()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user