hass-core/homeassistant/components/home_connect/sensor.py
Leah Oswald 02fb60b33e
Fix home connect remaining progress time (#109525)
* fix remaining progress time for home connect component

The home connect API is sending some default values (on dishwashers) for
the remaining progress time after the program finished. This is a problem
because this value is stored and on every API event, for example opening
the door of a dishwasher, the value for remaining progress time is
updated with this wrong value. So I see a wrong value the whole time the
dishwasher is not running and therefore has no remaining progress time.
This coming fixes this problem and adds a check if the appliance is in
running, pause or finished state, because there we have valid data. In
the other states the new code just returns none like on other edge
cases. Now there is no value if there is no program running.

* fix some formating according to the ruff rules

* fix some formating according to the ruff rules again

* fix alphabetic order of imports

* add check if keys exist in dict before accessing them

check if BSH_OPERATION_STATE and ATTR_VALUE key values exist before
accessing them later in the elif statement

* fix formating because forgotten local ruff run
2024-02-04 23:56:12 +01:00

102 lines
3.8 KiB
Python

"""Provides a sensor for Home Connect."""
from datetime import datetime, timedelta
import logging
from typing import cast
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ENTITIES
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.util.dt as dt_util
from .const import (
ATTR_VALUE,
BSH_OPERATION_STATE,
BSH_OPERATION_STATE_FINISHED,
BSH_OPERATION_STATE_PAUSE,
BSH_OPERATION_STATE_RUN,
DOMAIN,
)
from .entity import HomeConnectEntity
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Home Connect sensor."""
def get_entities():
"""Get a list of entities."""
entities = []
hc_api = hass.data[DOMAIN][config_entry.entry_id]
for device_dict in hc_api.devices:
entity_dicts = device_dict.get(CONF_ENTITIES, {}).get("sensor", [])
entities += [HomeConnectSensor(**d) for d in entity_dicts]
return entities
async_add_entities(await hass.async_add_executor_job(get_entities), True)
class HomeConnectSensor(HomeConnectEntity, SensorEntity):
"""Sensor class for Home Connect."""
def __init__(self, device, desc, key, unit, icon, device_class, sign=1):
"""Initialize the entity."""
super().__init__(device, desc)
self._key = key
self._sign = sign
self._attr_native_unit_of_measurement = unit
self._attr_icon = icon
self._attr_device_class = device_class
@property
def available(self) -> bool:
"""Return true if the sensor is available."""
return self._attr_native_value is not None
async def async_update(self) -> None:
"""Update the sensor's status."""
status = self.device.appliance.status
if self._key not in status:
self._attr_native_value = None
elif self.device_class == SensorDeviceClass.TIMESTAMP:
if ATTR_VALUE not in status[self._key]:
self._attr_native_value = None
elif (
self._attr_native_value is not None
and self._sign == 1
and isinstance(self._attr_native_value, datetime)
and self._attr_native_value < dt_util.utcnow()
):
# if the date is supposed to be in the future but we're
# already past it, set state to None.
self._attr_native_value = None
elif (
BSH_OPERATION_STATE in status
and ATTR_VALUE in status[BSH_OPERATION_STATE]
and status[BSH_OPERATION_STATE][ATTR_VALUE]
in [
BSH_OPERATION_STATE_RUN,
BSH_OPERATION_STATE_PAUSE,
BSH_OPERATION_STATE_FINISHED,
]
):
seconds = self._sign * float(status[self._key][ATTR_VALUE])
self._attr_native_value = dt_util.utcnow() + timedelta(seconds=seconds)
else:
self._attr_native_value = None
else:
self._attr_native_value = status[self._key].get(ATTR_VALUE)
if self._key == BSH_OPERATION_STATE:
# Value comes back as an enum, we only really care about the
# last part, so split it off
# https://developer.home-connect.com/docs/status/operation_state
self._attr_native_value = cast(str, self._attr_native_value).split(".")[
-1
]
_LOGGER.debug("Updated, new state: %s", self._attr_native_value)