Skip to content

Commit

Permalink
Only reflect unavailable state in DSMR when disconnected (home-assist…
Browse files Browse the repository at this point in the history
…ant#84862)

* Only reflect unavailable state in DSMR when disonnected

* Addressreview comment
  • Loading branch information
frenck authored and balloob committed Jan 2, 2023
1 parent 7ab27cd commit c5f7d7a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
34 changes: 26 additions & 8 deletions homeassistant/components/dsmr/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ async def async_setup_entry(
)

@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."""
# Make all device entities aware of new telegram
for entity in entities:
Expand Down Expand Up @@ -445,6 +445,11 @@ async def connect_and_reconnect() -> None:

while hass.state == CoreState.not_running or hass.is_running:
# Start DSMR asyncio.Protocol reader

# Reflect connected state in devices state by setting an
# empty telegram resulting in `unknown` states
update_entities_telegram({})

try:
transport, protocol = await hass.loop.create_task(reader_factory())

Expand Down Expand Up @@ -472,8 +477,8 @@ def close_transport(_event: EventType) -> None:
protocol = None

# Reflect disconnect state in devices state by setting an
# empty telegram resulting in `unknown` states
update_entities_telegram({})
# None telegram resulting in `unavailable` states
update_entities_telegram(None)

# throttle reconnect attempts
await asyncio.sleep(
Expand All @@ -487,11 +492,19 @@ def close_transport(_event: EventType) -> None:
transport = 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
await asyncio.sleep(
entry.data.get(CONF_RECONNECT_INTERVAL, DEFAULT_RECONNECT_INTERVAL)
)
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 (
hass.state == CoreState.not_running or hass.is_running
):
Expand Down Expand Up @@ -534,7 +547,7 @@ def __init__(
"""Initialize entity."""
self.entity_description = entity_description
self._entry = entry
self.telegram: dict[str, DSMRObject] = {}
self.telegram: dict[str, DSMRObject] | None = {}

device_serial = entry.data[CONF_SERIAL_ID]
device_name = DEVICE_NAME_ELECTRICITY
Expand All @@ -551,16 +564,21 @@ def __init__(
self._attr_unique_id = f"{device_serial}_{entity_description.key}"

@callback
def update_data(self, telegram: dict[str, DSMRObject]) -> None:
def update_data(self, telegram: dict[str, DSMRObject] | None) -> None:
"""Update data."""
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()

def get_dsmr_object_attr(self, attribute: str) -> str | None:
"""Read attribute from last received telegram for this DSMR object."""
# 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

# Get the attribute value if the object has it
Expand All @@ -571,7 +589,7 @@ def get_dsmr_object_attr(self, attribute: str) -> str | None:
@property
def available(self) -> bool:
"""Entity is only available if there is a telegram."""
return bool(self.telegram)
return self.telegram is not None

@property
def native_value(self) -> StateType:
Expand Down
5 changes: 5 additions & 0 deletions tests/components/dsmr/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
ATTR_UNIT_OF_MEASUREMENT,
ENERGY_KILO_WATT_HOUR,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
VOLUME_CUBIC_METERS,
UnitOfPower,
)
Expand Down Expand Up @@ -783,6 +784,10 @@ async def wait_closed():

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
closed.set()
# wait for lock set to resolve
Expand Down

0 comments on commit c5f7d7a

Please sign in to comment.