Only reflect unavailable state in DSMR when disconnected (#84862)
* Only reflect unavailable state in DSMR when disonnected * Addressreview comment
This commit is contained in:
parent
f8fa676ac8
commit
02f64ada2d
2 changed files with 31 additions and 8 deletions
|
@ -401,7 +401,7 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
@Throttle(min_time_between_updates)
|
@Throttle(min_time_between_updates)
|
||||||
def update_entities_telegram(telegram: dict[str, DSMRObject]) -> None:
|
def update_entities_telegram(telegram: dict[str, DSMRObject] | None) -> None:
|
||||||
"""Update entities with latest telegram and trigger state update."""
|
"""Update entities with latest telegram and trigger state update."""
|
||||||
# Make all device entities aware of new telegram
|
# Make all device entities aware of new telegram
|
||||||
for entity in entities:
|
for entity in entities:
|
||||||
|
@ -445,6 +445,11 @@ async def async_setup_entry(
|
||||||
|
|
||||||
while hass.state == CoreState.not_running or hass.is_running:
|
while hass.state == CoreState.not_running or hass.is_running:
|
||||||
# Start DSMR asyncio.Protocol reader
|
# Start DSMR asyncio.Protocol reader
|
||||||
|
|
||||||
|
# Reflect connected state in devices state by setting an
|
||||||
|
# empty telegram resulting in `unknown` states
|
||||||
|
update_entities_telegram({})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
transport, protocol = await hass.loop.create_task(reader_factory())
|
transport, protocol = await hass.loop.create_task(reader_factory())
|
||||||
|
|
||||||
|
@ -472,8 +477,8 @@ async def async_setup_entry(
|
||||||
protocol = None
|
protocol = None
|
||||||
|
|
||||||
# Reflect disconnect state in devices state by setting an
|
# Reflect disconnect state in devices state by setting an
|
||||||
# empty telegram resulting in `unknown` states
|
# None telegram resulting in `unavailable` states
|
||||||
update_entities_telegram({})
|
update_entities_telegram(None)
|
||||||
|
|
||||||
# throttle reconnect attempts
|
# throttle reconnect attempts
|
||||||
await asyncio.sleep(
|
await asyncio.sleep(
|
||||||
|
@ -487,11 +492,19 @@ async def async_setup_entry(
|
||||||
transport = None
|
transport = None
|
||||||
protocol = None
|
protocol = None
|
||||||
|
|
||||||
|
# Reflect disconnect state in devices state by setting an
|
||||||
|
# None telegram resulting in `unavailable` states
|
||||||
|
update_entities_telegram(None)
|
||||||
|
|
||||||
# throttle reconnect attempts
|
# throttle reconnect attempts
|
||||||
await asyncio.sleep(
|
await asyncio.sleep(
|
||||||
entry.data.get(CONF_RECONNECT_INTERVAL, DEFAULT_RECONNECT_INTERVAL)
|
entry.data.get(CONF_RECONNECT_INTERVAL, DEFAULT_RECONNECT_INTERVAL)
|
||||||
)
|
)
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
|
# Reflect disconnect state in devices state by setting an
|
||||||
|
# None telegram resulting in `unavailable` states
|
||||||
|
update_entities_telegram(None)
|
||||||
|
|
||||||
if stop_listener and (
|
if stop_listener and (
|
||||||
hass.state == CoreState.not_running or hass.is_running
|
hass.state == CoreState.not_running or hass.is_running
|
||||||
):
|
):
|
||||||
|
@ -534,7 +547,7 @@ class DSMREntity(SensorEntity):
|
||||||
"""Initialize entity."""
|
"""Initialize entity."""
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
self._entry = entry
|
self._entry = entry
|
||||||
self.telegram: dict[str, DSMRObject] = {}
|
self.telegram: dict[str, DSMRObject] | None = {}
|
||||||
|
|
||||||
device_serial = entry.data[CONF_SERIAL_ID]
|
device_serial = entry.data[CONF_SERIAL_ID]
|
||||||
device_name = DEVICE_NAME_ELECTRICITY
|
device_name = DEVICE_NAME_ELECTRICITY
|
||||||
|
@ -551,16 +564,21 @@ class DSMREntity(SensorEntity):
|
||||||
self._attr_unique_id = f"{device_serial}_{entity_description.key}"
|
self._attr_unique_id = f"{device_serial}_{entity_description.key}"
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_data(self, telegram: dict[str, DSMRObject]) -> None:
|
def update_data(self, telegram: dict[str, DSMRObject] | None) -> None:
|
||||||
"""Update data."""
|
"""Update data."""
|
||||||
self.telegram = telegram
|
self.telegram = telegram
|
||||||
if self.hass and self.entity_description.obis_reference in self.telegram:
|
if self.hass and (
|
||||||
|
telegram is None or self.entity_description.obis_reference in telegram
|
||||||
|
):
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
def get_dsmr_object_attr(self, attribute: str) -> str | None:
|
def get_dsmr_object_attr(self, attribute: str) -> str | None:
|
||||||
"""Read attribute from last received telegram for this DSMR object."""
|
"""Read attribute from last received telegram for this DSMR object."""
|
||||||
# Make sure telegram contains an object for this entities obis
|
# Make sure telegram contains an object for this entities obis
|
||||||
if self.entity_description.obis_reference not in self.telegram:
|
if (
|
||||||
|
self.telegram is None
|
||||||
|
or self.entity_description.obis_reference not in self.telegram
|
||||||
|
):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Get the attribute value if the object has it
|
# Get the attribute value if the object has it
|
||||||
|
@ -571,7 +589,7 @@ class DSMREntity(SensorEntity):
|
||||||
@property
|
@property
|
||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
"""Entity is only available if there is a telegram."""
|
"""Entity is only available if there is a telegram."""
|
||||||
return bool(self.telegram)
|
return self.telegram is not None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> StateType:
|
def native_value(self) -> StateType:
|
||||||
|
|
|
@ -24,6 +24,7 @@ from homeassistant.const import (
|
||||||
ATTR_UNIT_OF_MEASUREMENT,
|
ATTR_UNIT_OF_MEASUREMENT,
|
||||||
ENERGY_KILO_WATT_HOUR,
|
ENERGY_KILO_WATT_HOUR,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
|
STATE_UNKNOWN,
|
||||||
VOLUME_CUBIC_METERS,
|
VOLUME_CUBIC_METERS,
|
||||||
UnitOfPower,
|
UnitOfPower,
|
||||||
)
|
)
|
||||||
|
@ -783,6 +784,10 @@ async def test_reconnect(hass, dsmr_connection_fixture):
|
||||||
|
|
||||||
assert connection_factory.call_count == 1
|
assert connection_factory.call_count == 1
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.electricity_meter_power_consumption")
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
||||||
# indicate disconnect, release wait lock and allow reconnect to happen
|
# indicate disconnect, release wait lock and allow reconnect to happen
|
||||||
closed.set()
|
closed.set()
|
||||||
# wait for lock set to resolve
|
# wait for lock set to resolve
|
||||||
|
|
Loading…
Add table
Reference in a new issue