Add typehints to eight_sleep (#58442)

This commit is contained in:
Raman Gupta 2021-10-26 00:33:44 -04:00 committed by GitHub
parent 2517ba59b5
commit cee51ead91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 103 additions and 42 deletions

View File

@ -1,8 +1,11 @@
"""Support for Eight smart mattress covers and mattresses.""" """Support for Eight smart mattress covers and mattresses."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from pyeight.eight import EightSleep from pyeight.eight import EightSleep
from pyeight.user import EightUser
import voluptuous as vol import voluptuous as vol
from homeassistant.const import ( from homeassistant.const import (
@ -12,9 +15,11 @@ from homeassistant.const import (
CONF_SENSORS, CONF_SENSORS,
CONF_USERNAME, CONF_USERNAME,
) )
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import ( from homeassistant.helpers.update_coordinator import (
CoordinatorEntity, CoordinatorEntity,
DataUpdateCoordinator, 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.""" """Set up the Eight Sleep component."""
conf = config.get(DOMAIN) if DOMAIN not in config:
user = conf.get(CONF_USERNAME) return True
password = conf.get(CONF_PASSWORD)
conf = config[DOMAIN]
user = conf[CONF_USERNAME]
password = conf[CONF_PASSWORD]
if hass.config.time_zone is None: if hass.config.time_zone is None:
_LOGGER.error("Timezone is not set in Home Assistant") _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.""" """Handle eight sleep service calls."""
params = service.data.copy() params = service.data.copy()
@ -167,7 +175,7 @@ async def async_setup(hass, config):
for sens in sensor: for sens in sensor:
side = sens.split("_")[1] side = sens.split("_")[1]
userid = eight.fetch_userid(side) userid = eight.fetch_userid(side)
usrobj = eight.users[userid] usrobj: EightUser = eight.users[userid]
await usrobj.set_heating_level(target, duration) await usrobj.set_heating_level(target, duration)
await heat_coordinator.async_request_refresh() await heat_coordinator.async_request_refresh()
@ -183,7 +191,7 @@ async def async_setup(hass, config):
class EightSleepHeatDataCoordinator(DataUpdateCoordinator): class EightSleepHeatDataCoordinator(DataUpdateCoordinator):
"""Class to retrieve heat data from Eight Sleep.""" """Class to retrieve heat data from Eight Sleep."""
def __init__(self, hass, api): def __init__(self, hass: HomeAssistant, api: EightSleep) -> None:
"""Initialize coordinator.""" """Initialize coordinator."""
self.api = api self.api = api
super().__init__( super().__init__(
@ -198,7 +206,7 @@ class EightSleepHeatDataCoordinator(DataUpdateCoordinator):
class EightSleepUserDataCoordinator(DataUpdateCoordinator): class EightSleepUserDataCoordinator(DataUpdateCoordinator):
"""Class to retrieve user data from Eight Sleep.""" """Class to retrieve user data from Eight Sleep."""
def __init__(self, hass, api): def __init__(self, hass: HomeAssistant, api: EightSleep) -> None:
"""Initialize coordinator.""" """Initialize coordinator."""
self.api = api self.api = api
super().__init__( super().__init__(
@ -213,7 +221,7 @@ class EightSleepUserDataCoordinator(DataUpdateCoordinator):
class EightSleepEntity(CoordinatorEntity): class EightSleepEntity(CoordinatorEntity):
"""The Eight Sleep device entity.""" """The Eight Sleep device entity."""
def __init__(self, coordinator, eight): def __init__(self, coordinator: DataUpdateCoordinator, eight: EightSleep) -> None:
"""Initialize the data object.""" """Initialize the data object."""
super().__init__(coordinator) super().__init__(coordinator)
self._eight = eight self._eight = eight

View File

@ -1,11 +1,17 @@
"""Support for Eight Sleep binary sensors.""" """Support for Eight Sleep binary sensors."""
import logging import logging
from pyeight.eight import EightSleep
from pyeight.user import EightUser
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DEVICE_CLASS_OCCUPANCY, DEVICE_CLASS_OCCUPANCY,
BinarySensorEntity, 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 ( from . import (
CONF_BINARY_SENSORS, CONF_BINARY_SENSORS,
@ -19,7 +25,12 @@ from . import (
_LOGGER = logging.getLogger(__name__) _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.""" """Set up the eight sleep binary sensor."""
if discovery_info is None: if discovery_info is None:
return return
@ -40,7 +51,13 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
class EightHeatSensor(EightSleepEntity, BinarySensorEntity): class EightHeatSensor(EightSleepEntity, BinarySensorEntity):
"""Representation of a Eight Sleep heat-based sensor.""" """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.""" """Initialize the sensor."""
super().__init__(coordinator, eight) super().__init__(coordinator, eight)
@ -50,7 +67,7 @@ class EightHeatSensor(EightSleepEntity, BinarySensorEntity):
self._side = self._sensor.split("_")[0] self._side = self._sensor.split("_")[0]
self._userid = self._eight.fetch_userid(self._side) 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_name = f"{name} {self._mapped_name}"
self._attr_device_class = DEVICE_CLASS_OCCUPANCY self._attr_device_class = DEVICE_CLASS_OCCUPANCY
@ -63,12 +80,12 @@ class EightHeatSensor(EightSleepEntity, BinarySensorEntity):
) )
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return true if the binary sensor is on.""" """Return true if the binary sensor is on."""
return self._state return bool(self._state)
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator.""" """Handle updated data from the coordinator."""
self._state = self._usrobj.bed_presence self._state = self._usrobj.bed_presence
super()._handle_coordinator_update() super()._handle_coordinator_update()

View File

@ -1,5 +1,12 @@
"""Support for Eight Sleep sensors.""" """Support for Eight Sleep sensors."""
from __future__ import annotations
from collections.abc import Mapping
import logging import logging
from typing import Any
from pyeight.eight import EightSleep
from pyeight.user import EightUser
from homeassistant.components.sensor import SensorEntity from homeassistant.components.sensor import SensorEntity
from homeassistant.const import ( from homeassistant.const import (
@ -8,7 +15,9 @@ from homeassistant.const import (
TEMP_CELSIUS, TEMP_CELSIUS,
TEMP_FAHRENHEIT, 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 ( from . import (
CONF_SENSORS, CONF_SENSORS,
@ -18,6 +27,8 @@ from . import (
DATA_USER, DATA_USER,
NAME_MAP, NAME_MAP,
EightSleepEntity, EightSleepEntity,
EightSleepHeatDataCoordinator,
EightSleepUserDataCoordinator,
) )
ATTR_ROOM_TEMP = "Room Temperature" ATTR_ROOM_TEMP = "Room Temperature"
@ -48,7 +59,12 @@ ATTR_FIT_WAKEUP_SCORE = "Fitness Wakeup Score"
_LOGGER = logging.getLogger(__name__) _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.""" """Set up the eight sleep sensors."""
if discovery_info is None: if discovery_info is None:
return return
@ -56,15 +72,15 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
name = "Eight" name = "Eight"
sensors = discovery_info[CONF_SENSORS] sensors = discovery_info[CONF_SENSORS]
eight = hass.data[DATA_EIGHT][DATA_API] eight = hass.data[DATA_EIGHT][DATA_API]
heat_coordinator = hass.data[DATA_EIGHT][DATA_HEAT] heat_coordinator: EightSleepHeatDataCoordinator = hass.data[DATA_EIGHT][DATA_HEAT]
user_coordinator = hass.data[DATA_EIGHT][DATA_USER] user_coordinator: EightSleepUserDataCoordinator = hass.data[DATA_EIGHT][DATA_USER]
if hass.config.units.is_metric: if hass.config.units.is_metric:
units = "si" units = "si"
else: else:
units = "us" units = "us"
all_sensors = [] all_sensors: list[EightSleepEntity] = []
for sensor in sensors: for sensor in sensors:
if "bed_state" in sensor: 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): class EightHeatSensor(EightSleepEntity, SensorEntity):
"""Representation of an eight sleep heat-based sensor.""" """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.""" """Initialize the sensor."""
super().__init__(coordinator, eight) super().__init__(coordinator, eight)
@ -95,7 +117,7 @@ class EightHeatSensor(EightSleepEntity, SensorEntity):
self._side = self._sensor.split("_")[0] self._side = self._sensor.split("_")[0]
self._userid = self._eight.fetch_userid(self._side) 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( _LOGGER.debug(
"Heat Sensor: %s, Side: %s, User: %s", "Heat Sensor: %s, Side: %s, User: %s",
@ -105,29 +127,29 @@ class EightHeatSensor(EightSleepEntity, SensorEntity):
) )
@property @property
def name(self): def name(self) -> str:
"""Return the name of the sensor, if any.""" """Return the name of the sensor, if any."""
return self._name return self._name
@property @property
def native_value(self): def native_value(self) -> str | None:
"""Return the state of the sensor.""" """Return the state of the sensor."""
return self._state return self._state
@property @property
def native_unit_of_measurement(self): def native_unit_of_measurement(self) -> str:
"""Return the unit the value is expressed in.""" """Return the unit the value is expressed in."""
return PERCENTAGE return PERCENTAGE
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator.""" """Handle updated data from the coordinator."""
_LOGGER.debug("Updating Heat sensor: %s", self._sensor) _LOGGER.debug("Updating Heat sensor: %s", self._sensor)
self._state = self._usrobj.heating_level self._state = self._usrobj.heating_level
super()._handle_coordinator_update() super()._handle_coordinator_update()
@property @property
def extra_state_attributes(self): def extra_state_attributes(self) -> Mapping[str, Any]:
"""Return device state attributes.""" """Return device state attributes."""
return { return {
ATTR_TARGET_HEAT: self._usrobj.target_heating_level, ATTR_TARGET_HEAT: self._usrobj.target_heating_level,
@ -139,7 +161,14 @@ class EightHeatSensor(EightSleepEntity, SensorEntity):
class EightUserSensor(EightSleepEntity, SensorEntity): class EightUserSensor(EightSleepEntity, SensorEntity):
"""Representation of an eight sleep user-based sensor.""" """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.""" """Initialize the sensor."""
super().__init__(coordinator, eight) super().__init__(coordinator, eight)
@ -153,7 +182,7 @@ class EightUserSensor(EightSleepEntity, SensorEntity):
self._side = self._sensor.split("_", 1)[0] self._side = self._sensor.split("_", 1)[0]
self._userid = self._eight.fetch_userid(self._side) 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( _LOGGER.debug(
"User Sensor: %s, Side: %s, User: %s", "User Sensor: %s, Side: %s, User: %s",
@ -163,17 +192,17 @@ class EightUserSensor(EightSleepEntity, SensorEntity):
) )
@property @property
def name(self): def name(self) -> str:
"""Return the name of the sensor, if any.""" """Return the name of the sensor, if any."""
return self._name return self._name
@property @property
def native_value(self): def native_value(self) -> str | None:
"""Return the state of the sensor.""" """Return the state of the sensor."""
return self._state return self._state
@property @property
def native_unit_of_measurement(self): def native_unit_of_measurement(self) -> str | None:
"""Return the unit the value is expressed in.""" """Return the unit the value is expressed in."""
if ( if (
"current_sleep" in self._sensor "current_sleep" in self._sensor
@ -188,14 +217,14 @@ class EightUserSensor(EightSleepEntity, SensorEntity):
return None return None
@property @property
def device_class(self): def device_class(self) -> str | None:
"""Return the class of this device, from component DEVICE_CLASSES.""" """Return the class of this device, from component DEVICE_CLASSES."""
if "bed_temp" in self._sensor: if "bed_temp" in self._sensor:
return DEVICE_CLASS_TEMPERATURE return DEVICE_CLASS_TEMPERATURE
return None return None
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator.""" """Handle updated data from the coordinator."""
_LOGGER.debug("Updating User sensor: %s", self._sensor) _LOGGER.debug("Updating User sensor: %s", self._sensor)
if "current" in self._sensor: if "current" in self._sensor:
@ -223,7 +252,7 @@ class EightUserSensor(EightSleepEntity, SensorEntity):
super()._handle_coordinator_update() super()._handle_coordinator_update()
@property @property
def extra_state_attributes(self): def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return device state attributes.""" """Return device state attributes."""
if self._attr is None: if self._attr is None:
# Skip attributes if sensor type doesn't support # Skip attributes if sensor type doesn't support
@ -313,7 +342,14 @@ class EightUserSensor(EightSleepEntity, SensorEntity):
class EightRoomSensor(EightSleepEntity, SensorEntity): class EightRoomSensor(EightSleepEntity, SensorEntity):
"""Representation of an eight sleep room sensor.""" """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.""" """Initialize the sensor."""
super().__init__(coordinator, eight) super().__init__(coordinator, eight)
@ -325,17 +361,17 @@ class EightRoomSensor(EightSleepEntity, SensorEntity):
self._units = units self._units = units
@property @property
def name(self): def name(self) -> str:
"""Return the name of the sensor, if any.""" """Return the name of the sensor, if any."""
return self._name return self._name
@property @property
def native_value(self): def native_value(self) -> str | None:
"""Return the state of the sensor.""" """Return the state of the sensor."""
return self._state return self._state
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator.""" """Handle updated data from the coordinator."""
_LOGGER.debug("Updating Room sensor: %s", self._sensor) _LOGGER.debug("Updating Room sensor: %s", self._sensor)
temp = self._eight.room_temperature() temp = self._eight.room_temperature()
@ -349,13 +385,13 @@ class EightRoomSensor(EightSleepEntity, SensorEntity):
super()._handle_coordinator_update() super()._handle_coordinator_update()
@property @property
def native_unit_of_measurement(self): def native_unit_of_measurement(self) -> str:
"""Return the unit the value is expressed in.""" """Return the unit the value is expressed in."""
if self._units == "si": if self._units == "si":
return TEMP_CELSIUS return TEMP_CELSIUS
return TEMP_FAHRENHEIT return TEMP_FAHRENHEIT
@property @property
def device_class(self): def device_class(self) -> str:
"""Return the class of this device, from component DEVICE_CLASSES.""" """Return the class of this device, from component DEVICE_CLASSES."""
return DEVICE_CLASS_TEMPERATURE return DEVICE_CLASS_TEMPERATURE