2019-02-13 20:21:14 +00:00
|
|
|
"""Support for Eight Sleep sensors."""
|
2021-10-26 04:33:44 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
from collections.abc import Mapping
|
2017-05-02 15:38:27 +00:00
|
|
|
import logging
|
2021-10-26 04:33:44 +00:00
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
from pyeight.eight import EightSleep
|
|
|
|
from pyeight.user import EightUser
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2021-03-22 11:52:29 +00:00
|
|
|
from homeassistant.components.sensor import SensorEntity
|
2021-07-12 20:45:29 +00:00
|
|
|
from homeassistant.const import (
|
|
|
|
DEVICE_CLASS_TEMPERATURE,
|
|
|
|
PERCENTAGE,
|
|
|
|
TEMP_CELSIUS,
|
|
|
|
TEMP_FAHRENHEIT,
|
|
|
|
)
|
2021-10-26 04:33:44 +00:00
|
|
|
from homeassistant.core import HomeAssistant, callback
|
|
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
2020-02-28 19:46:48 +00:00
|
|
|
|
2019-03-21 05:56:46 +00:00
|
|
|
from . import (
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_SENSORS,
|
2021-10-25 20:18:33 +00:00
|
|
|
DATA_API,
|
2019-07-31 19:25:30 +00:00
|
|
|
DATA_EIGHT,
|
2021-10-25 20:18:33 +00:00
|
|
|
DATA_HEAT,
|
|
|
|
DATA_USER,
|
2019-07-31 19:25:30 +00:00
|
|
|
NAME_MAP,
|
2021-10-25 20:18:33 +00:00
|
|
|
EightSleepEntity,
|
2021-10-26 04:33:44 +00:00
|
|
|
EightSleepHeatDataCoordinator,
|
|
|
|
EightSleepUserDataCoordinator,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
ATTR_ROOM_TEMP = "Room Temperature"
|
|
|
|
ATTR_AVG_ROOM_TEMP = "Average Room Temperature"
|
|
|
|
ATTR_BED_TEMP = "Bed Temperature"
|
|
|
|
ATTR_AVG_BED_TEMP = "Average Bed Temperature"
|
|
|
|
ATTR_RESP_RATE = "Respiratory Rate"
|
|
|
|
ATTR_AVG_RESP_RATE = "Average Respiratory Rate"
|
|
|
|
ATTR_HEART_RATE = "Heart Rate"
|
|
|
|
ATTR_AVG_HEART_RATE = "Average Heart Rate"
|
|
|
|
ATTR_SLEEP_DUR = "Time Slept"
|
2020-09-05 19:09:14 +00:00
|
|
|
ATTR_LIGHT_PERC = f"Light Sleep {PERCENTAGE}"
|
|
|
|
ATTR_DEEP_PERC = f"Deep Sleep {PERCENTAGE}"
|
|
|
|
ATTR_REM_PERC = f"REM Sleep {PERCENTAGE}"
|
2019-07-31 19:25:30 +00:00
|
|
|
ATTR_TNT = "Tosses & Turns"
|
|
|
|
ATTR_SLEEP_STAGE = "Sleep Stage"
|
|
|
|
ATTR_TARGET_HEAT = "Target Heating Level"
|
|
|
|
ATTR_ACTIVE_HEAT = "Heating Active"
|
|
|
|
ATTR_DURATION_HEAT = "Heating Time Remaining"
|
|
|
|
ATTR_PROCESSING = "Processing"
|
|
|
|
ATTR_SESSION_START = "Session Start"
|
2020-02-17 09:15:21 +00:00
|
|
|
ATTR_FIT_DATE = "Fitness Date"
|
|
|
|
ATTR_FIT_DURATION_SCORE = "Fitness Duration Score"
|
|
|
|
ATTR_FIT_ASLEEP_SCORE = "Fitness Asleep Score"
|
|
|
|
ATTR_FIT_OUT_SCORE = "Fitness Out-of-Bed Score"
|
|
|
|
ATTR_FIT_WAKEUP_SCORE = "Fitness Wakeup Score"
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2021-10-26 04:33:44 +00:00
|
|
|
async def async_setup_platform(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config: ConfigType,
|
|
|
|
async_add_entities: AddEntitiesCallback,
|
|
|
|
discovery_info: DiscoveryInfoType = None,
|
|
|
|
) -> None:
|
2017-05-02 20:47:20 +00:00
|
|
|
"""Set up the eight sleep sensors."""
|
2017-05-02 15:38:27 +00:00
|
|
|
if discovery_info is None:
|
|
|
|
return
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
name = "Eight"
|
2017-05-02 15:38:27 +00:00
|
|
|
sensors = discovery_info[CONF_SENSORS]
|
2021-10-25 20:18:33 +00:00
|
|
|
eight = hass.data[DATA_EIGHT][DATA_API]
|
2021-10-26 04:33:44 +00:00
|
|
|
heat_coordinator: EightSleepHeatDataCoordinator = hass.data[DATA_EIGHT][DATA_HEAT]
|
|
|
|
user_coordinator: EightSleepUserDataCoordinator = hass.data[DATA_EIGHT][DATA_USER]
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
if hass.config.units.is_metric:
|
2019-07-31 19:25:30 +00:00
|
|
|
units = "si"
|
2017-05-02 15:38:27 +00:00
|
|
|
else:
|
2019-07-31 19:25:30 +00:00
|
|
|
units = "us"
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2021-10-26 04:33:44 +00:00
|
|
|
all_sensors: list[EightSleepEntity] = []
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
for sensor in sensors:
|
2019-07-31 19:25:30 +00:00
|
|
|
if "bed_state" in sensor:
|
2021-10-25 20:18:33 +00:00
|
|
|
all_sensors.append(EightHeatSensor(name, heat_coordinator, eight, sensor))
|
2019-07-31 19:25:30 +00:00
|
|
|
elif "room_temp" in sensor:
|
2021-10-25 20:18:33 +00:00
|
|
|
all_sensors.append(
|
|
|
|
EightRoomSensor(name, user_coordinator, eight, sensor, units)
|
|
|
|
)
|
2017-05-02 15:38:27 +00:00
|
|
|
else:
|
2021-10-25 20:18:33 +00:00
|
|
|
all_sensors.append(
|
|
|
|
EightUserSensor(name, user_coordinator, eight, sensor, units)
|
|
|
|
)
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2018-08-24 14:37:30 +00:00
|
|
|
async_add_entities(all_sensors, True)
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
|
2021-10-25 20:18:33 +00:00
|
|
|
class EightHeatSensor(EightSleepEntity, SensorEntity):
|
2018-01-27 19:58:27 +00:00
|
|
|
"""Representation of an eight sleep heat-based sensor."""
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2021-10-26 04:33:44 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
name: str,
|
|
|
|
coordinator: EightSleepHeatDataCoordinator,
|
|
|
|
eight: EightSleep,
|
|
|
|
sensor: str,
|
|
|
|
) -> None:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Initialize the sensor."""
|
2021-10-25 20:18:33 +00:00
|
|
|
super().__init__(coordinator, eight)
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
self._sensor = sensor
|
|
|
|
self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
|
2019-09-03 15:10:56 +00:00
|
|
|
self._name = f"{name} {self._mapped_name}"
|
2017-05-02 15:38:27 +00:00
|
|
|
self._state = None
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
self._side = self._sensor.split("_")[0]
|
2017-05-02 15:38:27 +00:00
|
|
|
self._userid = self._eight.fetch_userid(self._side)
|
2021-10-26 04:33:44 +00:00
|
|
|
self._usrobj: EightUser = self._eight.users[self._userid]
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
_LOGGER.debug(
|
|
|
|
"Heat Sensor: %s, Side: %s, User: %s",
|
|
|
|
self._sensor,
|
|
|
|
self._side,
|
|
|
|
self._userid,
|
|
|
|
)
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def name(self) -> str:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the name of the sensor, if any."""
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def native_value(self) -> str | None:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the state of the sensor."""
|
|
|
|
return self._state
|
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def native_unit_of_measurement(self) -> str:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the unit the value is expressed in."""
|
2020-09-05 19:09:14 +00:00
|
|
|
return PERCENTAGE
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2021-10-25 20:18:33 +00:00
|
|
|
@callback
|
2021-10-26 04:33:44 +00:00
|
|
|
def _handle_coordinator_update(self) -> None:
|
2021-10-25 20:18:33 +00:00
|
|
|
"""Handle updated data from the coordinator."""
|
2017-05-02 20:47:20 +00:00
|
|
|
_LOGGER.debug("Updating Heat sensor: %s", self._sensor)
|
2017-05-02 15:38:27 +00:00
|
|
|
self._state = self._usrobj.heating_level
|
2021-10-25 20:18:33 +00:00
|
|
|
super()._handle_coordinator_update()
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def extra_state_attributes(self) -> Mapping[str, Any]:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return device state attributes."""
|
2020-10-06 14:55:16 +00:00
|
|
|
return {
|
|
|
|
ATTR_TARGET_HEAT: self._usrobj.target_heating_level,
|
|
|
|
ATTR_ACTIVE_HEAT: self._usrobj.now_heating,
|
|
|
|
ATTR_DURATION_HEAT: self._usrobj.heating_remaining,
|
|
|
|
}
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
|
2021-10-25 20:18:33 +00:00
|
|
|
class EightUserSensor(EightSleepEntity, SensorEntity):
|
2018-01-27 19:58:27 +00:00
|
|
|
"""Representation of an eight sleep user-based sensor."""
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2021-10-26 04:33:44 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
name: str,
|
|
|
|
coordinator: EightSleepUserDataCoordinator,
|
|
|
|
eight: EightSleep,
|
|
|
|
sensor: str,
|
|
|
|
units: str,
|
|
|
|
) -> None:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Initialize the sensor."""
|
2021-10-25 20:18:33 +00:00
|
|
|
super().__init__(coordinator, eight)
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
self._sensor = sensor
|
2019-07-31 19:25:30 +00:00
|
|
|
self._sensor_root = self._sensor.split("_", 1)[1]
|
2017-05-02 15:38:27 +00:00
|
|
|
self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
|
2019-09-03 15:10:56 +00:00
|
|
|
self._name = f"{name} {self._mapped_name}"
|
2017-05-02 15:38:27 +00:00
|
|
|
self._state = None
|
|
|
|
self._attr = None
|
|
|
|
self._units = units
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
self._side = self._sensor.split("_", 1)[0]
|
2017-05-02 15:38:27 +00:00
|
|
|
self._userid = self._eight.fetch_userid(self._side)
|
2021-10-26 04:33:44 +00:00
|
|
|
self._usrobj: EightUser = self._eight.users[self._userid]
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
_LOGGER.debug(
|
|
|
|
"User Sensor: %s, Side: %s, User: %s",
|
|
|
|
self._sensor,
|
|
|
|
self._side,
|
|
|
|
self._userid,
|
|
|
|
)
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def name(self) -> str:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the name of the sensor, if any."""
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def native_value(self) -> str | None:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the state of the sensor."""
|
|
|
|
return self._state
|
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def native_unit_of_measurement(self) -> str | None:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the unit the value is expressed in."""
|
2020-02-17 09:15:21 +00:00
|
|
|
if (
|
|
|
|
"current_sleep" in self._sensor
|
|
|
|
or "last_sleep" in self._sensor
|
|
|
|
or "current_sleep_fitness" in self._sensor
|
|
|
|
):
|
2019-07-31 19:25:30 +00:00
|
|
|
return "Score"
|
|
|
|
if "bed_temp" in self._sensor:
|
|
|
|
if self._units == "si":
|
2020-04-10 17:17:46 +00:00
|
|
|
return TEMP_CELSIUS
|
2020-04-10 19:10:10 +00:00
|
|
|
return TEMP_FAHRENHEIT
|
2017-07-06 06:30:01 +00:00
|
|
|
return None
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def device_class(self) -> str | None:
|
2021-07-12 20:45:29 +00:00
|
|
|
"""Return the class of this device, from component DEVICE_CLASSES."""
|
2019-07-31 19:25:30 +00:00
|
|
|
if "bed_temp" in self._sensor:
|
2021-07-12 20:45:29 +00:00
|
|
|
return DEVICE_CLASS_TEMPERATURE
|
|
|
|
return None
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2021-10-25 20:18:33 +00:00
|
|
|
@callback
|
2021-10-26 04:33:44 +00:00
|
|
|
def _handle_coordinator_update(self) -> None:
|
2021-10-25 20:18:33 +00:00
|
|
|
"""Handle updated data from the coordinator."""
|
2017-05-02 20:47:20 +00:00
|
|
|
_LOGGER.debug("Updating User sensor: %s", self._sensor)
|
2019-07-31 19:25:30 +00:00
|
|
|
if "current" in self._sensor:
|
2020-02-17 09:15:21 +00:00
|
|
|
if "fitness" in self._sensor:
|
|
|
|
self._state = self._usrobj.current_sleep_fitness_score
|
|
|
|
self._attr = self._usrobj.current_fitness_values
|
|
|
|
else:
|
|
|
|
self._state = self._usrobj.current_sleep_score
|
|
|
|
self._attr = self._usrobj.current_values
|
2019-07-31 19:25:30 +00:00
|
|
|
elif "last" in self._sensor:
|
2017-05-02 15:38:27 +00:00
|
|
|
self._state = self._usrobj.last_sleep_score
|
|
|
|
self._attr = self._usrobj.last_values
|
2019-07-31 19:25:30 +00:00
|
|
|
elif "bed_temp" in self._sensor:
|
|
|
|
temp = self._usrobj.current_values["bed_temp"]
|
2018-06-15 19:24:09 +00:00
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
if self._units == "si":
|
2018-06-15 19:24:09 +00:00
|
|
|
self._state = round(temp, 2)
|
|
|
|
else:
|
2019-07-31 19:25:30 +00:00
|
|
|
self._state = round((temp * 1.8) + 32, 2)
|
2018-06-15 19:24:09 +00:00
|
|
|
except TypeError:
|
|
|
|
self._state = None
|
2019-07-31 19:25:30 +00:00
|
|
|
elif "sleep_stage" in self._sensor:
|
|
|
|
self._state = self._usrobj.current_values["stage"]
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2021-10-25 20:18:33 +00:00
|
|
|
super()._handle_coordinator_update()
|
|
|
|
|
2017-05-02 15:38:27 +00:00
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return device state attributes."""
|
|
|
|
if self._attr is None:
|
|
|
|
# Skip attributes if sensor type doesn't support
|
|
|
|
return None
|
|
|
|
|
2020-02-17 09:15:21 +00:00
|
|
|
if "fitness" in self._sensor_root:
|
|
|
|
state_attr = {
|
|
|
|
ATTR_FIT_DATE: self._attr["date"],
|
|
|
|
ATTR_FIT_DURATION_SCORE: self._attr["duration"],
|
|
|
|
ATTR_FIT_ASLEEP_SCORE: self._attr["asleep"],
|
|
|
|
ATTR_FIT_OUT_SCORE: self._attr["out"],
|
|
|
|
ATTR_FIT_WAKEUP_SCORE: self._attr["wakeup"],
|
|
|
|
}
|
|
|
|
return state_attr
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
state_attr = {ATTR_SESSION_START: self._attr["date"]}
|
|
|
|
state_attr[ATTR_TNT] = self._attr["tnt"]
|
|
|
|
state_attr[ATTR_PROCESSING] = self._attr["processing"]
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
sleep_time = (
|
|
|
|
sum(self._attr["breakdown"].values()) - self._attr["breakdown"]["awake"]
|
|
|
|
)
|
2017-05-02 15:38:27 +00:00
|
|
|
state_attr[ATTR_SLEEP_DUR] = sleep_time
|
2017-08-03 13:58:40 +00:00
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
state_attr[ATTR_LIGHT_PERC] = round(
|
|
|
|
(self._attr["breakdown"]["light"] / sleep_time) * 100, 2
|
|
|
|
)
|
2017-08-03 13:58:40 +00:00
|
|
|
except ZeroDivisionError:
|
|
|
|
state_attr[ATTR_LIGHT_PERC] = 0
|
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
state_attr[ATTR_DEEP_PERC] = round(
|
|
|
|
(self._attr["breakdown"]["deep"] / sleep_time) * 100, 2
|
|
|
|
)
|
2017-08-03 13:58:40 +00:00
|
|
|
except ZeroDivisionError:
|
|
|
|
state_attr[ATTR_DEEP_PERC] = 0
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2018-06-15 19:24:09 +00:00
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
state_attr[ATTR_REM_PERC] = round(
|
|
|
|
(self._attr["breakdown"]["rem"] / sleep_time) * 100, 2
|
|
|
|
)
|
2018-06-15 19:24:09 +00:00
|
|
|
except ZeroDivisionError:
|
|
|
|
state_attr[ATTR_REM_PERC] = 0
|
|
|
|
|
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
if self._units == "si":
|
|
|
|
room_temp = round(self._attr["room_temp"], 2)
|
2018-06-15 19:24:09 +00:00
|
|
|
else:
|
2019-07-31 19:25:30 +00:00
|
|
|
room_temp = round((self._attr["room_temp"] * 1.8) + 32, 2)
|
2018-06-15 19:24:09 +00:00
|
|
|
except TypeError:
|
|
|
|
room_temp = None
|
|
|
|
|
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
if self._units == "si":
|
|
|
|
bed_temp = round(self._attr["bed_temp"], 2)
|
2018-06-15 19:24:09 +00:00
|
|
|
else:
|
2019-07-31 19:25:30 +00:00
|
|
|
bed_temp = round((self._attr["bed_temp"] * 1.8) + 32, 2)
|
2018-06-15 19:24:09 +00:00
|
|
|
except TypeError:
|
|
|
|
bed_temp = None
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
if "current" in self._sensor_root:
|
2020-03-03 02:01:39 +00:00
|
|
|
try:
|
|
|
|
state_attr[ATTR_RESP_RATE] = round(self._attr["resp_rate"], 2)
|
|
|
|
except TypeError:
|
|
|
|
state_attr[ATTR_RESP_RATE] = None
|
|
|
|
try:
|
|
|
|
state_attr[ATTR_HEART_RATE] = round(self._attr["heart_rate"], 2)
|
|
|
|
except TypeError:
|
|
|
|
state_attr[ATTR_HEART_RATE] = None
|
2019-07-31 19:25:30 +00:00
|
|
|
state_attr[ATTR_SLEEP_STAGE] = self._attr["stage"]
|
2017-05-02 15:38:27 +00:00
|
|
|
state_attr[ATTR_ROOM_TEMP] = room_temp
|
|
|
|
state_attr[ATTR_BED_TEMP] = bed_temp
|
2019-07-31 19:25:30 +00:00
|
|
|
elif "last" in self._sensor_root:
|
2020-03-03 02:01:39 +00:00
|
|
|
try:
|
|
|
|
state_attr[ATTR_AVG_RESP_RATE] = round(self._attr["resp_rate"], 2)
|
|
|
|
except TypeError:
|
|
|
|
state_attr[ATTR_AVG_RESP_RATE] = None
|
|
|
|
try:
|
|
|
|
state_attr[ATTR_AVG_HEART_RATE] = round(self._attr["heart_rate"], 2)
|
|
|
|
except TypeError:
|
|
|
|
state_attr[ATTR_AVG_HEART_RATE] = None
|
2017-05-02 15:38:27 +00:00
|
|
|
state_attr[ATTR_AVG_ROOM_TEMP] = room_temp
|
|
|
|
state_attr[ATTR_AVG_BED_TEMP] = bed_temp
|
|
|
|
|
|
|
|
return state_attr
|
|
|
|
|
|
|
|
|
2021-10-25 20:18:33 +00:00
|
|
|
class EightRoomSensor(EightSleepEntity, SensorEntity):
|
2018-01-27 19:58:27 +00:00
|
|
|
"""Representation of an eight sleep room sensor."""
|
2017-05-02 15:38:27 +00:00
|
|
|
|
2021-10-26 04:33:44 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
name: str,
|
|
|
|
coordinator: EightSleepUserDataCoordinator,
|
|
|
|
eight: EightSleep,
|
|
|
|
sensor: str,
|
|
|
|
units: str,
|
|
|
|
) -> None:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Initialize the sensor."""
|
2021-10-25 20:18:33 +00:00
|
|
|
super().__init__(coordinator, eight)
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
self._sensor = sensor
|
|
|
|
self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
|
2019-09-03 15:10:56 +00:00
|
|
|
self._name = f"{name} {self._mapped_name}"
|
2017-05-02 15:38:27 +00:00
|
|
|
self._state = None
|
|
|
|
self._attr = None
|
|
|
|
self._units = units
|
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def name(self) -> str:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the name of the sensor, if any."""
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def native_value(self) -> str | None:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the state of the sensor."""
|
|
|
|
return self._state
|
|
|
|
|
2021-10-25 20:18:33 +00:00
|
|
|
@callback
|
2021-10-26 04:33:44 +00:00
|
|
|
def _handle_coordinator_update(self) -> None:
|
2021-10-25 20:18:33 +00:00
|
|
|
"""Handle updated data from the coordinator."""
|
2017-05-02 20:47:20 +00:00
|
|
|
_LOGGER.debug("Updating Room sensor: %s", self._sensor)
|
2017-05-02 15:38:27 +00:00
|
|
|
temp = self._eight.room_temperature()
|
2018-06-15 19:24:09 +00:00
|
|
|
try:
|
2019-07-31 19:25:30 +00:00
|
|
|
if self._units == "si":
|
2018-06-15 19:24:09 +00:00
|
|
|
self._state = round(temp, 2)
|
|
|
|
else:
|
2019-07-31 19:25:30 +00:00
|
|
|
self._state = round((temp * 1.8) + 32, 2)
|
2018-06-15 19:24:09 +00:00
|
|
|
except TypeError:
|
|
|
|
self._state = None
|
2021-10-25 20:18:33 +00:00
|
|
|
super()._handle_coordinator_update()
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def native_unit_of_measurement(self) -> str:
|
2017-05-02 15:38:27 +00:00
|
|
|
"""Return the unit the value is expressed in."""
|
2019-07-31 19:25:30 +00:00
|
|
|
if self._units == "si":
|
2020-04-10 17:17:46 +00:00
|
|
|
return TEMP_CELSIUS
|
2020-04-10 19:10:10 +00:00
|
|
|
return TEMP_FAHRENHEIT
|
2017-05-02 15:38:27 +00:00
|
|
|
|
|
|
|
@property
|
2021-10-26 04:33:44 +00:00
|
|
|
def device_class(self) -> str:
|
2021-07-12 20:45:29 +00:00
|
|
|
"""Return the class of this device, from component DEVICE_CLASSES."""
|
|
|
|
return DEVICE_CLASS_TEMPERATURE
|