Add L2 and L3 voltage and current sensors to EARN-E P1 Meter (#181833)

Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com>
This commit is contained in:
Michael Rademaker
2026-09-13 14:24:31 +02:00
committed by GitHub
co-authored by Simon Lamon
parent 6c0b4847f6
commit 0e181a824a
6 changed files with 401 additions and 31 deletions
@@ -44,6 +44,7 @@ class EarnEP1Coordinator(DataUpdateCoordinator[dict[str, Any]]):
self.mac = mac
self.model: str | None = None
self.sw_version: str | None = None
self.data_complete = False
self._listener = listener
def _handle_update(self, device: EarnEP1Device, _raw: dict[str, Any]) -> None:
@@ -62,6 +63,8 @@ class EarnEP1Coordinator(DataUpdateCoordinator[dict[str, Any]]):
model=self.model,
sw_version=self.sw_version,
)
# Listeners run synchronously from async_set_updated_data and read this.
self.data_complete = device.data_complete
self.async_set_updated_data(device.data)
def start(self) -> None:
+42 -4
View File
@@ -46,7 +46,26 @@ SENSOR_DESCRIPTIONS: tuple[SensorEntityDescription, ...] = (
),
SensorEntityDescription(
key="voltage_l1",
translation_key="voltage_l1",
translation_key="voltage_phase",
translation_placeholders={"phase": "1"},
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
),
SensorEntityDescription(
key="voltage_l2",
translation_key="voltage_phase",
translation_placeholders={"phase": "2"},
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
),
SensorEntityDescription(
key="voltage_l3",
translation_key="voltage_phase",
translation_placeholders={"phase": "3"},
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -54,7 +73,26 @@ SENSOR_DESCRIPTIONS: tuple[SensorEntityDescription, ...] = (
),
SensorEntityDescription(
key="current_l1",
translation_key="current_l1",
translation_key="current_phase",
translation_placeholders={"phase": "1"},
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=2,
),
SensorEntityDescription(
key="current_l2",
translation_key="current_phase",
translation_placeholders={"phase": "2"},
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=2,
),
SensorEntityDescription(
key="current_l3",
translation_key="current_phase",
translation_placeholders={"phase": "3"},
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
@@ -140,11 +178,11 @@ async def async_setup_entry(
for description in SENSOR_DESCRIPTIONS
if description.key in new_keys
)
if not pending_keys:
if not pending_keys or coordinator.data_complete:
_async_remove_listener()
_async_add_sensors()
if pending_keys:
if pending_keys and not coordinator.data_complete:
remove_listener = coordinator.async_add_listener(_async_add_sensors)
entry.async_on_unload(_async_remove_listener)
@@ -28,8 +28,8 @@
},
"entity": {
"sensor": {
"current_l1": {
"name": "Current L1"
"current_phase": {
"name": "Current phase {phase}"
},
"energy_exported_tariff1": {
"name": "Energy exported tariff 1"
@@ -52,8 +52,8 @@
"power_imported": {
"name": "Power imported"
},
"voltage_l1": {
"name": "Voltage L1"
"voltage_phase": {
"name": "Voltage phase {phase}"
},
"wifi_rssi": {
"name": "Wi-Fi RSSI"
+9 -1
View File
@@ -4,7 +4,7 @@ from collections.abc import Generator
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
from earn_e_p1 import EarnEP1Device
from earn_e_p1 import EarnEP1Device, PacketType
import pytest
from homeassistant.components.earn_e_p1.const import CONF_SERIAL, DOMAIN
@@ -25,7 +25,11 @@ MOCK_DEVICE_DATA: dict[str, Any] = {
"power_delivered": 2.5,
"power_returned": 0.0,
"voltage_l1": 230.1,
"voltage_l2": 229.8,
"voltage_l3": 231.5,
"current_l1": 10.87,
"current_l2": 8.2,
"current_l3": 4.35,
"energy_delivered_tariff1": 12345.678,
"energy_delivered_tariff2": 6789.012,
"energy_returned_tariff1": 100.0,
@@ -44,17 +48,21 @@ DHCP_DISCOVERY = DhcpServiceInfo(
def trigger_callback(
mock_listener: MagicMock,
device_data: dict[str, Any] | None = None,
seen_packet_types: set[PacketType] | None = None,
model: str | None = "P1 Meter",
sw_version: str | None = "1.0.0",
) -> None:
"""Trigger the registered listener callback with device data."""
if device_data is None:
device_data = MOCK_DEVICE_DATA
if seen_packet_types is None:
seen_packet_types = set(PacketType)
callback = mock_listener.register.call_args[0][1]
device = EarnEP1Device(host=MOCK_HOST, serial=MOCK_SERIAL)
device.model = model
device.sw_version = sw_version
device.data = device_data
device.seen_packet_types = seen_packet_types
callback(device, device_data)
@@ -1,5 +1,5 @@
# serializer version: 1
# name: test_sensor_platform[sensor.earn_e_p1_meter_current_l1-entry]
# name: test_sensor_platform[sensor.earn_e_p1_meter_current_phase_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -15,7 +15,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.earn_e_p1_meter_current_l1',
'entity_id': 'sensor.earn_e_p1_meter_current_phase_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -23,7 +23,7 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Current L1',
'object_id_base': 'Current phase 1',
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
@@ -31,32 +31,148 @@
}),
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
'original_icon': None,
'original_name': 'Current L1',
'original_name': 'Current phase 1',
'platform': 'earn_e_p1',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'current_l1',
'translation_key': 'current_phase',
'unique_id': 'E0012345678901234_current_l1',
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_current_l1-state]
# name: test_sensor_platform[sensor.earn_e_p1_meter_current_phase_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'current',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'EARN-E P1 Meter Current L1',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'EARN-E P1 Meter Current phase 1',
<SensorEntityCapabilityAttribute.STATE_CLASS: 'state_class'>: <SensorStateClass.MEASUREMENT: 'measurement'>,
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: <UnitOfElectricCurrent.AMPERE: 'A'>,
}),
'context': <ANY>,
'entity_id': 'sensor.earn_e_p1_meter_current_l1',
'entity_id': 'sensor.earn_e_p1_meter_current_phase_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '10.87',
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_current_phase_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
<SensorEntityCapabilityAttribute.STATE_CLASS: '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': None,
'entity_id': 'sensor.earn_e_p1_meter_current_phase_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Current phase 2',
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
'original_icon': None,
'original_name': 'Current phase 2',
'platform': 'earn_e_p1',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'current_phase',
'unique_id': 'E0012345678901234_current_l2',
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_current_phase_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'current',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'EARN-E P1 Meter Current phase 2',
<SensorEntityCapabilityAttribute.STATE_CLASS: 'state_class'>: <SensorStateClass.MEASUREMENT: 'measurement'>,
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: <UnitOfElectricCurrent.AMPERE: 'A'>,
}),
'context': <ANY>,
'entity_id': 'sensor.earn_e_p1_meter_current_phase_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '8.2',
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_current_phase_3-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
<SensorEntityCapabilityAttribute.STATE_CLASS: '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': None,
'entity_id': 'sensor.earn_e_p1_meter_current_phase_3',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Current phase 3',
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
'original_icon': None,
'original_name': 'Current phase 3',
'platform': 'earn_e_p1',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'current_phase',
'unique_id': 'E0012345678901234_current_l3',
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_current_phase_3-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'current',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'EARN-E P1 Meter Current phase 3',
<SensorEntityCapabilityAttribute.STATE_CLASS: 'state_class'>: <SensorStateClass.MEASUREMENT: 'measurement'>,
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: <UnitOfElectricCurrent.AMPERE: 'A'>,
}),
'context': <ANY>,
'entity_id': 'sensor.earn_e_p1_meter_current_phase_3',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '4.35',
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_energy_exported_tariff_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
@@ -463,7 +579,7 @@
'state': '2.5',
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_voltage_l1-entry]
# name: test_sensor_platform[sensor.earn_e_p1_meter_voltage_phase_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -479,7 +595,7 @@
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.earn_e_p1_meter_voltage_l1',
'entity_id': 'sensor.earn_e_p1_meter_voltage_phase_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -487,7 +603,7 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Voltage L1',
'object_id_base': 'Voltage phase 1',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
@@ -495,32 +611,148 @@
}),
'original_device_class': <SensorDeviceClass.VOLTAGE: 'voltage'>,
'original_icon': None,
'original_name': 'Voltage L1',
'original_name': 'Voltage phase 1',
'platform': 'earn_e_p1',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'voltage_l1',
'translation_key': 'voltage_phase',
'unique_id': 'E0012345678901234_voltage_l1',
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_voltage_l1-state]
# name: test_sensor_platform[sensor.earn_e_p1_meter_voltage_phase_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'voltage',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'EARN-E P1 Meter Voltage L1',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'EARN-E P1 Meter Voltage phase 1',
<SensorEntityCapabilityAttribute.STATE_CLASS: 'state_class'>: <SensorStateClass.MEASUREMENT: 'measurement'>,
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: <UnitOfElectricPotential.VOLT: 'V'>,
}),
'context': <ANY>,
'entity_id': 'sensor.earn_e_p1_meter_voltage_l1',
'entity_id': 'sensor.earn_e_p1_meter_voltage_phase_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '230.1',
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_voltage_phase_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
<SensorEntityCapabilityAttribute.STATE_CLASS: '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': None,
'entity_id': 'sensor.earn_e_p1_meter_voltage_phase_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Voltage phase 2',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.VOLTAGE: 'voltage'>,
'original_icon': None,
'original_name': 'Voltage phase 2',
'platform': 'earn_e_p1',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'voltage_phase',
'unique_id': 'E0012345678901234_voltage_l2',
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_voltage_phase_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'voltage',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'EARN-E P1 Meter Voltage phase 2',
<SensorEntityCapabilityAttribute.STATE_CLASS: 'state_class'>: <SensorStateClass.MEASUREMENT: 'measurement'>,
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: <UnitOfElectricPotential.VOLT: 'V'>,
}),
'context': <ANY>,
'entity_id': 'sensor.earn_e_p1_meter_voltage_phase_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '229.8',
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_voltage_phase_3-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
<SensorEntityCapabilityAttribute.STATE_CLASS: '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': None,
'entity_id': 'sensor.earn_e_p1_meter_voltage_phase_3',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Voltage phase 3',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.VOLTAGE: 'voltage'>,
'original_icon': None,
'original_name': 'Voltage phase 3',
'platform': 'earn_e_p1',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'voltage_phase',
'unique_id': 'E0012345678901234_voltage_l3',
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_voltage_phase_3-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'voltage',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'EARN-E P1 Meter Voltage phase 3',
<SensorEntityCapabilityAttribute.STATE_CLASS: 'state_class'>: <SensorStateClass.MEASUREMENT: 'measurement'>,
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: <UnitOfElectricPotential.VOLT: 'V'>,
}),
'context': <ANY>,
'entity_id': 'sensor.earn_e_p1_meter_voltage_phase_3',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '231.5',
})
# ---
# name: test_sensor_platform[sensor.earn_e_p1_meter_wi_fi_rssi-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
+95 -6
View File
@@ -2,23 +2,45 @@
from unittest.mock import MagicMock
from earn_e_p1 import PacketType
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .conftest import trigger_callback
from .conftest import MOCK_DEVICE_DATA, trigger_callback
from tests.common import MockConfigEntry, snapshot_platform
# A partial packet carries only the instantaneous values, without energy/gas.
PARTIAL_DEVICE_DATA = {
# The meter alternates between a realtime packet holding the instantaneous
# values and a heartbeat packet holding the meter totals. Each type only
# carries the keys the meter itself supports, so a single-phase meter never
# sends the L2/L3 keys and an electricity-only meter never sends gas.
REALTIME_3PHASE = {
"power_delivered": 0.35,
"power_returned": 0.0,
"voltage_l1": 232.0,
"voltage_l2": 231.4,
"voltage_l3": 230.8,
"current_l1": 2.0,
"current_l2": 1.5,
"current_l3": 1.1,
}
REALTIME_1PHASE = {
"power_delivered": 0.35,
"power_returned": 0.0,
"voltage_l1": 232.0,
"current_l1": 2.0,
}
HEARTBEAT_NO_GAS = {
"energy_delivered_tariff1": 12345.678,
"energy_delivered_tariff2": 6789.012,
"energy_returned_tariff1": 100.0,
"energy_returned_tariff2": 50.0,
"wifiRSSI": -65,
}
HEARTBEAT = {**HEARTBEAT_NO_GAS, "gas_delivered": 1234.567}
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@@ -75,12 +97,16 @@ async def test_sensors_added_when_key_appears_in_later_packet(
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
trigger_callback(mock_listener, device_data=PARTIAL_DEVICE_DATA)
trigger_callback(
mock_listener,
device_data=REALTIME_3PHASE,
seen_packet_types={PacketType.REALTIME},
)
await hass.async_block_till_done()
assert len(
er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)
) == len(PARTIAL_DEVICE_DATA)
) == len(REALTIME_3PHASE)
assert hass.states.get("sensor.earn_e_p1_meter_energy_imported_tariff_1") is None
assert hass.states.get("sensor.earn_e_p1_meter_gas_consumed") is None
@@ -90,7 +116,7 @@ async def test_sensors_added_when_key_appears_in_later_packet(
entries = er.async_entries_for_config_entry(
entity_registry, mock_config_entry.entry_id
)
assert len(entries) == 10
assert len(entries) == len(MOCK_DEVICE_DATA)
energy = hass.states.get("sensor.earn_e_p1_meter_energy_imported_tariff_1")
assert energy is not None
@@ -101,6 +127,69 @@ async def test_sensors_added_when_key_appears_in_later_packet(
assert gas.state == "1234.567"
@pytest.mark.parametrize(
("realtime", "heartbeat", "absent_entity_ids"),
[
pytest.param(
REALTIME_1PHASE,
HEARTBEAT,
[
"sensor.earn_e_p1_meter_voltage_phase_2",
"sensor.earn_e_p1_meter_voltage_phase_3",
"sensor.earn_e_p1_meter_current_phase_2",
"sensor.earn_e_p1_meter_current_phase_3",
],
id="single_phase_meter",
),
pytest.param(
REALTIME_3PHASE,
HEARTBEAT_NO_GAS,
["sensor.earn_e_p1_meter_gas_consumed"],
id="no_gas_meter",
),
],
)
async def test_unsupported_keys_never_create_entities(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_listener: MagicMock,
entity_registry: er.EntityRegistry,
realtime: dict[str, float],
heartbeat: dict[str, float],
absent_entity_ids: list[str],
) -> None:
"""Test keys a meter never sends do not become entities."""
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
trigger_callback(
mock_listener,
device_data=realtime,
seen_packet_types={PacketType.REALTIME},
)
await hass.async_block_till_done()
trigger_callback(mock_listener, device_data={**realtime, **heartbeat})
await hass.async_block_till_done()
for entity_id in absent_entity_ids:
assert hass.states.get(entity_id) is None
# Counted from the registry rather than the state machine, because the
# Wi-Fi RSSI sensor is disabled by default and so has no state.
assert len(
er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)
) == len(realtime) + len(heartbeat)
trigger_callback(mock_listener)
await hass.async_block_till_done()
# Both packet types have been seen, so the setup listener unsubscribed and
# a packet carrying the unsupported keys can no longer add them.
for entity_id in absent_entity_ids:
assert hass.states.get(entity_id) is None
async def test_unload_after_all_sensors_added(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,