diff --git a/homeassistant/components/eight_sleep/__init__.py b/homeassistant/components/eight_sleep/__init__.py index 07474c44c62..7413e5009de 100644 --- a/homeassistant/components/eight_sleep/__init__.py +++ b/homeassistant/components/eight_sleep/__init__.py @@ -1,8 +1,11 @@ """Support for Eight smart mattress covers and mattresses.""" +from __future__ import annotations + from datetime import timedelta import logging from pyeight.eight import EightSleep +from pyeight.user import EightUser import voluptuous as vol from homeassistant.const import ( @@ -12,9 +15,11 @@ from homeassistant.const import ( CONF_SENSORS, CONF_USERNAME, ) +from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.helpers import discovery from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, @@ -99,12 +104,15 @@ CONFIG_SCHEMA = vol.Schema( ) -async def async_setup(hass, config): +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the Eight Sleep component.""" - conf = config.get(DOMAIN) - user = conf.get(CONF_USERNAME) - password = conf.get(CONF_PASSWORD) + if DOMAIN not in config: + return True + + conf = config[DOMAIN] + user = conf[CONF_USERNAME] + password = conf[CONF_PASSWORD] if hass.config.time_zone is None: _LOGGER.error("Timezone is not set in Home Assistant") @@ -156,7 +164,7 @@ async def async_setup(hass, config): ) ) - async def async_service_handler(service): + async def async_service_handler(service: ServiceCall) -> None: """Handle eight sleep service calls.""" params = service.data.copy() @@ -167,7 +175,7 @@ async def async_setup(hass, config): for sens in sensor: side = sens.split("_")[1] userid = eight.fetch_userid(side) - usrobj = eight.users[userid] + usrobj: EightUser = eight.users[userid] await usrobj.set_heating_level(target, duration) await heat_coordinator.async_request_refresh() @@ -183,7 +191,7 @@ async def async_setup(hass, config): class EightSleepHeatDataCoordinator(DataUpdateCoordinator): """Class to retrieve heat data from Eight Sleep.""" - def __init__(self, hass, api): + def __init__(self, hass: HomeAssistant, api: EightSleep) -> None: """Initialize coordinator.""" self.api = api super().__init__( @@ -198,7 +206,7 @@ class EightSleepHeatDataCoordinator(DataUpdateCoordinator): class EightSleepUserDataCoordinator(DataUpdateCoordinator): """Class to retrieve user data from Eight Sleep.""" - def __init__(self, hass, api): + def __init__(self, hass: HomeAssistant, api: EightSleep) -> None: """Initialize coordinator.""" self.api = api super().__init__( @@ -213,7 +221,7 @@ class EightSleepUserDataCoordinator(DataUpdateCoordinator): class EightSleepEntity(CoordinatorEntity): """The Eight Sleep device entity.""" - def __init__(self, coordinator, eight): + def __init__(self, coordinator: DataUpdateCoordinator, eight: EightSleep) -> None: """Initialize the data object.""" super().__init__(coordinator) self._eight = eight diff --git a/homeassistant/components/eight_sleep/binary_sensor.py b/homeassistant/components/eight_sleep/binary_sensor.py index ca8a10b0f93..5b6e1f6a9c3 100644 --- a/homeassistant/components/eight_sleep/binary_sensor.py +++ b/homeassistant/components/eight_sleep/binary_sensor.py @@ -1,11 +1,17 @@ """Support for Eight Sleep binary sensors.""" import logging +from pyeight.eight import EightSleep +from pyeight.user import EightUser + from homeassistant.components.binary_sensor import ( DEVICE_CLASS_OCCUPANCY, BinarySensorEntity, ) -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from . import ( CONF_BINARY_SENSORS, @@ -19,7 +25,12 @@ from . import ( _LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): +async def async_setup_platform( + hass: HomeAssistant, + config: ConfigType, + async_add_entities: AddEntitiesCallback, + discovery_info: DiscoveryInfoType = None, +) -> None: """Set up the eight sleep binary sensor.""" if discovery_info is None: return @@ -40,7 +51,13 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= class EightHeatSensor(EightSleepEntity, BinarySensorEntity): """Representation of a Eight Sleep heat-based sensor.""" - def __init__(self, name, coordinator, eight, sensor): + def __init__( + self, + name: str, + coordinator: DataUpdateCoordinator, + eight: EightSleep, + sensor: str, + ) -> None: """Initialize the sensor.""" super().__init__(coordinator, eight) @@ -50,7 +67,7 @@ class EightHeatSensor(EightSleepEntity, BinarySensorEntity): self._side = self._sensor.split("_")[0] self._userid = self._eight.fetch_userid(self._side) - self._usrobj = self._eight.users[self._userid] + self._usrobj: EightUser = self._eight.users[self._userid] self._attr_name = f"{name} {self._mapped_name}" self._attr_device_class = DEVICE_CLASS_OCCUPANCY @@ -63,12 +80,12 @@ class EightHeatSensor(EightSleepEntity, BinarySensorEntity): ) @property - def is_on(self): + def is_on(self) -> bool: """Return true if the binary sensor is on.""" - return self._state + return bool(self._state) @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" self._state = self._usrobj.bed_presence super()._handle_coordinator_update() diff --git a/homeassistant/components/eight_sleep/sensor.py b/homeassistant/components/eight_sleep/sensor.py index 0e84eea64f6..c7c58c05e7d 100644 --- a/homeassistant/components/eight_sleep/sensor.py +++ b/homeassistant/components/eight_sleep/sensor.py @@ -1,5 +1,12 @@ """Support for Eight Sleep sensors.""" +from __future__ import annotations + +from collections.abc import Mapping import logging +from typing import Any + +from pyeight.eight import EightSleep +from pyeight.user import EightUser from homeassistant.components.sensor import SensorEntity from homeassistant.const import ( @@ -8,7 +15,9 @@ from homeassistant.const import ( TEMP_CELSIUS, TEMP_FAHRENHEIT, ) -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from . import ( CONF_SENSORS, @@ -18,6 +27,8 @@ from . import ( DATA_USER, NAME_MAP, EightSleepEntity, + EightSleepHeatDataCoordinator, + EightSleepUserDataCoordinator, ) ATTR_ROOM_TEMP = "Room Temperature" @@ -48,7 +59,12 @@ ATTR_FIT_WAKEUP_SCORE = "Fitness Wakeup Score" _LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): +async def async_setup_platform( + hass: HomeAssistant, + config: ConfigType, + async_add_entities: AddEntitiesCallback, + discovery_info: DiscoveryInfoType = None, +) -> None: """Set up the eight sleep sensors.""" if discovery_info is None: return @@ -56,15 +72,15 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= name = "Eight" sensors = discovery_info[CONF_SENSORS] eight = hass.data[DATA_EIGHT][DATA_API] - heat_coordinator = hass.data[DATA_EIGHT][DATA_HEAT] - user_coordinator = hass.data[DATA_EIGHT][DATA_USER] + heat_coordinator: EightSleepHeatDataCoordinator = hass.data[DATA_EIGHT][DATA_HEAT] + user_coordinator: EightSleepUserDataCoordinator = hass.data[DATA_EIGHT][DATA_USER] if hass.config.units.is_metric: units = "si" else: units = "us" - all_sensors = [] + all_sensors: list[EightSleepEntity] = [] for sensor in sensors: if "bed_state" in sensor: @@ -84,7 +100,13 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= class EightHeatSensor(EightSleepEntity, SensorEntity): """Representation of an eight sleep heat-based sensor.""" - def __init__(self, name, coordinator, eight, sensor): + def __init__( + self, + name: str, + coordinator: EightSleepHeatDataCoordinator, + eight: EightSleep, + sensor: str, + ) -> None: """Initialize the sensor.""" super().__init__(coordinator, eight) @@ -95,7 +117,7 @@ class EightHeatSensor(EightSleepEntity, SensorEntity): self._side = self._sensor.split("_")[0] self._userid = self._eight.fetch_userid(self._side) - self._usrobj = self._eight.users[self._userid] + self._usrobj: EightUser = self._eight.users[self._userid] _LOGGER.debug( "Heat Sensor: %s, Side: %s, User: %s", @@ -105,29 +127,29 @@ class EightHeatSensor(EightSleepEntity, SensorEntity): ) @property - def name(self): + def name(self) -> str: """Return the name of the sensor, if any.""" return self._name @property - def native_value(self): + def native_value(self) -> str | None: """Return the state of the sensor.""" return self._state @property - def native_unit_of_measurement(self): + def native_unit_of_measurement(self) -> str: """Return the unit the value is expressed in.""" return PERCENTAGE @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" _LOGGER.debug("Updating Heat sensor: %s", self._sensor) self._state = self._usrobj.heating_level super()._handle_coordinator_update() @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> Mapping[str, Any]: """Return device state attributes.""" return { ATTR_TARGET_HEAT: self._usrobj.target_heating_level, @@ -139,7 +161,14 @@ class EightHeatSensor(EightSleepEntity, SensorEntity): class EightUserSensor(EightSleepEntity, SensorEntity): """Representation of an eight sleep user-based sensor.""" - def __init__(self, name, coordinator, eight, sensor, units): + def __init__( + self, + name: str, + coordinator: EightSleepUserDataCoordinator, + eight: EightSleep, + sensor: str, + units: str, + ) -> None: """Initialize the sensor.""" super().__init__(coordinator, eight) @@ -153,7 +182,7 @@ class EightUserSensor(EightSleepEntity, SensorEntity): self._side = self._sensor.split("_", 1)[0] self._userid = self._eight.fetch_userid(self._side) - self._usrobj = self._eight.users[self._userid] + self._usrobj: EightUser = self._eight.users[self._userid] _LOGGER.debug( "User Sensor: %s, Side: %s, User: %s", @@ -163,17 +192,17 @@ class EightUserSensor(EightSleepEntity, SensorEntity): ) @property - def name(self): + def name(self) -> str: """Return the name of the sensor, if any.""" return self._name @property - def native_value(self): + def native_value(self) -> str | None: """Return the state of the sensor.""" return self._state @property - def native_unit_of_measurement(self): + def native_unit_of_measurement(self) -> str | None: """Return the unit the value is expressed in.""" if ( "current_sleep" in self._sensor @@ -188,14 +217,14 @@ class EightUserSensor(EightSleepEntity, SensorEntity): return None @property - def device_class(self): + def device_class(self) -> str | None: """Return the class of this device, from component DEVICE_CLASSES.""" if "bed_temp" in self._sensor: return DEVICE_CLASS_TEMPERATURE return None @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" _LOGGER.debug("Updating User sensor: %s", self._sensor) if "current" in self._sensor: @@ -223,7 +252,7 @@ class EightUserSensor(EightSleepEntity, SensorEntity): super()._handle_coordinator_update() @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> Mapping[str, Any] | None: """Return device state attributes.""" if self._attr is None: # Skip attributes if sensor type doesn't support @@ -313,7 +342,14 @@ class EightUserSensor(EightSleepEntity, SensorEntity): class EightRoomSensor(EightSleepEntity, SensorEntity): """Representation of an eight sleep room sensor.""" - def __init__(self, name, coordinator, eight, sensor, units): + def __init__( + self, + name: str, + coordinator: EightSleepUserDataCoordinator, + eight: EightSleep, + sensor: str, + units: str, + ) -> None: """Initialize the sensor.""" super().__init__(coordinator, eight) @@ -325,17 +361,17 @@ class EightRoomSensor(EightSleepEntity, SensorEntity): self._units = units @property - def name(self): + def name(self) -> str: """Return the name of the sensor, if any.""" return self._name @property - def native_value(self): + def native_value(self) -> str | None: """Return the state of the sensor.""" return self._state @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" _LOGGER.debug("Updating Room sensor: %s", self._sensor) temp = self._eight.room_temperature() @@ -349,13 +385,13 @@ class EightRoomSensor(EightSleepEntity, SensorEntity): super()._handle_coordinator_update() @property - def native_unit_of_measurement(self): + def native_unit_of_measurement(self) -> str: """Return the unit the value is expressed in.""" if self._units == "si": return TEMP_CELSIUS return TEMP_FAHRENHEIT @property - def device_class(self): + def device_class(self) -> str: """Return the class of this device, from component DEVICE_CLASSES.""" return DEVICE_CLASS_TEMPERATURE