mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
Deprecate Homee valve sensor (#139578)
* remove valve sensor * deprecate valve sensor * fix * Add deprecation issue test * Add test for deleting disabled deprecated entities * parametrize issue test * eliminate one if iteration * review change 1 * review change 2 * add info where to find valve * Update homeassistant/components/homee/sensor.py --------- Co-authored-by: Robert Resch <robert@resch.dev> Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
bd28452807
commit
75b8cb19cf
@ -6,7 +6,10 @@ from dataclasses import dataclass
|
||||
from pyHomee.const import AttributeType, NodeState
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.automation import automations_with_entity
|
||||
from homeassistant.components.script import scripts_with_entity
|
||||
from homeassistant.components.sensor import (
|
||||
DOMAIN as SENSOR_DOMAIN,
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
@ -14,10 +17,17 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.issue_registry import (
|
||||
IssueSeverity,
|
||||
async_create_issue,
|
||||
async_delete_issue,
|
||||
)
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
HOMEE_UNIT_TO_HA_UNIT,
|
||||
OPEN_CLOSE_MAP,
|
||||
OPEN_CLOSE_MAP_REVERSED,
|
||||
@ -274,14 +284,55 @@ NODE_SENSOR_DESCRIPTIONS: tuple[HomeeNodeSensorEntityDescription, ...] = (
|
||||
)
|
||||
|
||||
|
||||
def entity_used_in(hass: HomeAssistant, entity_id: str) -> list[str]:
|
||||
"""Get list of related automations and scripts."""
|
||||
used_in = automations_with_entity(hass, entity_id)
|
||||
used_in += scripts_with_entity(hass, entity_id)
|
||||
return used_in
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the homee platform for the sensor components."""
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
devices: list[HomeeSensor | HomeeNodeSensor] = []
|
||||
|
||||
def add_deprecated_entity(
|
||||
attribute: HomeeAttribute, description: HomeeSensorEntityDescription
|
||||
) -> None:
|
||||
"""Add deprecated entities."""
|
||||
entity_uid = f"{config_entry.runtime_data.settings.uid}-{attribute.node_id}-{attribute.id}"
|
||||
if entity_id := ent_reg.async_get_entity_id(SENSOR_DOMAIN, DOMAIN, entity_uid):
|
||||
entity_entry = ent_reg.async_get(entity_id)
|
||||
if entity_entry and entity_entry.disabled:
|
||||
ent_reg.async_remove(entity_id)
|
||||
async_delete_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
f"deprecated_entity_{entity_uid}",
|
||||
)
|
||||
elif entity_entry:
|
||||
devices.append(HomeeSensor(attribute, config_entry, description))
|
||||
if entity_used_in(hass, entity_id):
|
||||
async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
f"deprecated_entity_{entity_uid}",
|
||||
breaks_in_ha_version="2025.12.0",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_entity",
|
||||
translation_placeholders={
|
||||
"name": str(
|
||||
entity_entry.name or entity_entry.original_name
|
||||
),
|
||||
"entity": entity_id,
|
||||
},
|
||||
)
|
||||
|
||||
for node in config_entry.runtime_data.nodes:
|
||||
# Node properties that are sensors.
|
||||
devices.extend(
|
||||
@ -290,11 +341,15 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
# Node attributes that are sensors.
|
||||
devices.extend(
|
||||
HomeeSensor(attribute, config_entry, SENSOR_DESCRIPTIONS[attribute.type])
|
||||
for attribute in node.attributes
|
||||
if attribute.type in SENSOR_DESCRIPTIONS and not attribute.editable
|
||||
)
|
||||
for attribute in node.attributes:
|
||||
if attribute.type == AttributeType.CURRENT_VALVE_POSITION:
|
||||
add_deprecated_entity(attribute, SENSOR_DESCRIPTIONS[attribute.type])
|
||||
elif attribute.type in SENSOR_DESCRIPTIONS and not attribute.editable:
|
||||
devices.append(
|
||||
HomeeSensor(
|
||||
attribute, config_entry, SENSOR_DESCRIPTIONS[attribute.type]
|
||||
)
|
||||
)
|
||||
|
||||
if devices:
|
||||
async_add_devices(devices)
|
||||
|
@ -357,5 +357,11 @@
|
||||
"connection_closed": {
|
||||
"message": "Could not connect to homee while setting attribute."
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_entity": {
|
||||
"title": "The Homee {name} entity is deprecated",
|
||||
"description": "The Homee entity `{entity}` is deprecated and will be removed in release 2025.12.\nThe valve is available directly in the respective climate entity.\nPlease update your automations and scripts, disable `{entity}` and reload the integration/restart Home Assistant to fix this issue."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1591,57 +1591,6 @@
|
||||
'state': '6.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor_snapshot[sensor.test_multisensor_valve_position-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.test_multisensor_valve_position',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Valve position',
|
||||
'platform': 'homee',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'valve_position',
|
||||
'unique_id': '00055511EECC-1-9',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor_snapshot[sensor.test_multisensor_valve_position-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test MultiSensor Valve position',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.test_multisensor_valve_position',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '70.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor_snapshot[sensor.test_multisensor_voltage_1-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
@ -6,16 +6,19 @@ import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.homee.const import (
|
||||
DOMAIN,
|
||||
OPEN_CLOSE_MAP,
|
||||
OPEN_CLOSE_MAP_REVERSED,
|
||||
WINDOW_MAP,
|
||||
WINDOW_MAP_REVERSED,
|
||||
)
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
||||
|
||||
from . import async_update_attribute_value, build_mock_node, setup_integration
|
||||
from .conftest import HOMEE_ID
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
@ -25,15 +28,22 @@ def enable_all_entities(entity_registry_enabled_by_default: None) -> None:
|
||||
"""Make sure all entities are enabled."""
|
||||
|
||||
|
||||
async def setup_sensor(
|
||||
hass: HomeAssistant, mock_homee: MagicMock, mock_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Setups the integration for sensor tests."""
|
||||
mock_homee.nodes = [build_mock_node("sensors.json")]
|
||||
mock_homee.get_node_by_id.return_value = mock_homee.nodes[0]
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
|
||||
async def test_up_down_values(
|
||||
hass: HomeAssistant,
|
||||
mock_homee: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test values for up/down sensor."""
|
||||
mock_homee.nodes = [build_mock_node("sensors.json")]
|
||||
mock_homee.get_node_by_id.return_value = mock_homee.nodes[0]
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
await setup_sensor(hass, mock_homee, mock_config_entry)
|
||||
|
||||
assert hass.states.get("sensor.test_multisensor_state").state == OPEN_CLOSE_MAP[0]
|
||||
|
||||
@ -60,9 +70,7 @@ async def test_window_position(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test values for window handle position."""
|
||||
mock_homee.nodes = [build_mock_node("sensors.json")]
|
||||
mock_homee.get_node_by_id.return_value = mock_homee.nodes[0]
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
await setup_sensor(hass, mock_homee, mock_config_entry)
|
||||
|
||||
assert (
|
||||
hass.states.get("sensor.test_multisensor_window_position").state
|
||||
@ -87,6 +95,79 @@ async def test_window_position(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("disabler", "expected_entity", "expected_issue"),
|
||||
[
|
||||
(None, False, False),
|
||||
(er.RegistryEntryDisabler.USER, True, True),
|
||||
],
|
||||
)
|
||||
async def test_sensor_deprecation(
|
||||
hass: HomeAssistant,
|
||||
mock_homee: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
disabler: er.RegistryEntryDisabler,
|
||||
expected_entity: bool,
|
||||
expected_issue: bool,
|
||||
) -> None:
|
||||
"""Test sensor deprecation issue."""
|
||||
entity_uid = f"{HOMEE_ID}-1-9"
|
||||
entity_id = "test_multisensor_valve_position"
|
||||
entity_registry.async_get_or_create(
|
||||
SENSOR_DOMAIN,
|
||||
DOMAIN,
|
||||
entity_uid,
|
||||
suggested_object_id=entity_id,
|
||||
disabled_by=disabler,
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.homee.sensor.entity_used_in", return_value=True
|
||||
):
|
||||
await setup_sensor(hass, mock_homee, mock_config_entry)
|
||||
|
||||
assert (entity_registry.async_get(f"sensor.{entity_id}") is None) is expected_entity
|
||||
assert (
|
||||
issue_registry.async_get_issue(
|
||||
domain=DOMAIN,
|
||||
issue_id=f"deprecated_entity_{entity_uid}",
|
||||
)
|
||||
is None
|
||||
) is expected_issue
|
||||
|
||||
|
||||
async def test_sensor_deprecation_unused_entity(
|
||||
hass: HomeAssistant,
|
||||
mock_homee: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test sensor deprecation issue."""
|
||||
entity_uid = f"{HOMEE_ID}-1-9"
|
||||
entity_id = "test_multisensor_valve_position"
|
||||
entity_registry.async_get_or_create(
|
||||
SENSOR_DOMAIN,
|
||||
DOMAIN,
|
||||
entity_uid,
|
||||
suggested_object_id=entity_id,
|
||||
disabled_by=None,
|
||||
)
|
||||
|
||||
await setup_sensor(hass, mock_homee, mock_config_entry)
|
||||
|
||||
assert entity_registry.async_get(f"sensor.{entity_id}") is not None
|
||||
assert (
|
||||
issue_registry.async_get_issue(
|
||||
domain=DOMAIN,
|
||||
issue_id=f"deprecated_entity_{entity_uid}",
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
||||
|
||||
async def test_sensor_snapshot(
|
||||
hass: HomeAssistant,
|
||||
mock_homee: MagicMock,
|
||||
|
Loading…
x
Reference in New Issue
Block a user