mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add Eight sleep component (#7275)
* Eight Sleep Implementation * Update coverage * Update hass requirements * Remove unnecessary debug statements * Bump version to fix date error * Address comments * Update requirements
This commit is contained in:
parent
350a6fd5fa
commit
752a4b958e
@ -158,6 +158,9 @@ omit =
|
||||
homeassistant/components/zha/const.py
|
||||
homeassistant/components/*/zha.py
|
||||
|
||||
homeassistant/components/eight_sleep.py
|
||||
homeassistant/components/*/eight_sleep.py
|
||||
|
||||
homeassistant/components/alarm_control_panel/alarmdotcom.py
|
||||
homeassistant/components/alarm_control_panel/concord232.py
|
||||
homeassistant/components/alarm_control_panel/nx584.py
|
||||
|
69
homeassistant/components/binary_sensor/eight_sleep.py
Normal file
69
homeassistant/components/binary_sensor/eight_sleep.py
Normal file
@ -0,0 +1,69 @@
|
||||
"""
|
||||
Support for Eight Sleep binary sensors.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/binary_sensor.eight_sleep/
|
||||
"""
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
from homeassistant.components.eight_sleep import (
|
||||
DATA_EIGHT, EightSleepHeatEntity, CONF_BINARY_SENSORS, NAME_MAP)
|
||||
|
||||
DEPENDENCIES = ['eight_sleep']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Setup the eight sleep binary sensor."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
|
||||
name = 'Eight'
|
||||
sensors = discovery_info[CONF_BINARY_SENSORS]
|
||||
eight = hass.data[DATA_EIGHT]
|
||||
|
||||
all_sensors = []
|
||||
|
||||
for sensor in sensors:
|
||||
all_sensors.append(EightHeatSensor(name, eight, sensor))
|
||||
|
||||
async_add_devices(all_sensors, True)
|
||||
|
||||
|
||||
class EightHeatSensor(EightSleepHeatEntity, BinarySensorDevice):
|
||||
"""Representation of a eight sleep heat-based sensor."""
|
||||
|
||||
def __init__(self, name, eight, sensor):
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(eight)
|
||||
|
||||
self._sensor = sensor
|
||||
self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
|
||||
self._name = '{} {}'.format(name, self._mapped_name)
|
||||
self._state = None
|
||||
|
||||
self._side = self._sensor.split('_')[0]
|
||||
self._userid = self._eight.fetch_userid(self._side)
|
||||
self._usrobj = self._eight.users[self._userid]
|
||||
|
||||
_LOGGER.debug('Presence Sensor: %s, Side: %s, User: %s',
|
||||
self._sensor, self._side, self._userid)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor, if any."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if the binary sensor is on."""
|
||||
return self._state
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
"""Retrieve latest state."""
|
||||
self._state = self._usrobj.bed_presence
|
241
homeassistant/components/eight_sleep.py
Normal file
241
homeassistant/components/eight_sleep.py
Normal file
@ -0,0 +1,241 @@
|
||||
"""
|
||||
Support for Eight smart mattress covers and mattresses.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/eight_sleep/
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from datetime import timedelta
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.const import (
|
||||
CONF_USERNAME, CONF_PASSWORD, CONF_SENSORS, CONF_BINARY_SENSORS,
|
||||
ATTR_ENTITY_ID, EVENT_HOMEASSISTANT_STOP)
|
||||
from homeassistant.helpers import discovery
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_send, async_dispatcher_connect)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
REQUIREMENTS = ['pyeight==0.0.4']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_PARTNER = 'partner'
|
||||
|
||||
DATA_EIGHT = 'eight_sleep'
|
||||
DEFAULT_PARTNER = False
|
||||
DOMAIN = 'eight_sleep'
|
||||
|
||||
HEAT_ENTITY = 'heat'
|
||||
USER_ENTITY = 'user'
|
||||
|
||||
HEAT_SCAN_INTERVAL = timedelta(seconds=60)
|
||||
USER_SCAN_INTERVAL = timedelta(seconds=300)
|
||||
|
||||
SIGNAL_UPDATE_HEAT = 'eight_heat_update'
|
||||
SIGNAL_UPDATE_USER = 'eight_user_update'
|
||||
|
||||
NAME_MAP = {
|
||||
'left_current_sleep': 'Left Sleep Session',
|
||||
'left_last_sleep': 'Left Previous Sleep Session',
|
||||
'left_bed_state': 'Left Bed State',
|
||||
'left_presence': 'Left Bed Presence',
|
||||
'left_bed_temp': 'Left Bed Temperature',
|
||||
'left_sleep_stage': 'Left Sleep Stage',
|
||||
'right_current_sleep': 'Right Sleep Session',
|
||||
'right_last_sleep': 'Right Previous Sleep Session',
|
||||
'right_bed_state': 'Right Bed State',
|
||||
'right_presence': 'Right Bed Presence',
|
||||
'right_bed_temp': 'Right Bed Temperature',
|
||||
'right_sleep_stage': 'Right Sleep Stage',
|
||||
'room_temp': 'Room Temperature',
|
||||
}
|
||||
|
||||
SENSORS = ['current_sleep',
|
||||
'last_sleep',
|
||||
'bed_state',
|
||||
'bed_temp',
|
||||
'sleep_stage']
|
||||
|
||||
SERVICE_HEAT_SET = 'heat_set'
|
||||
|
||||
ATTR_TARGET_HEAT = 'target'
|
||||
ATTR_HEAT_DURATION = 'duration'
|
||||
|
||||
VALID_TARGET_HEAT = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=100))
|
||||
VALID_DURATION = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=28800))
|
||||
|
||||
SERVICE_EIGHT_SCHEMA = vol.Schema({
|
||||
ATTR_ENTITY_ID: cv.entity_ids,
|
||||
ATTR_TARGET_HEAT: VALID_TARGET_HEAT,
|
||||
ATTR_HEAT_DURATION: VALID_DURATION,
|
||||
})
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_PARTNER, default=DEFAULT_PARTNER): cv.boolean,
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
"""Set up the Eight Sleep component."""
|
||||
from pyeight.eight import EightSleep
|
||||
|
||||
conf = config.get(DOMAIN)
|
||||
user = conf.get(CONF_USERNAME)
|
||||
password = conf.get(CONF_PASSWORD)
|
||||
partner = conf.get(CONF_PARTNER)
|
||||
|
||||
if hass.config.time_zone is None:
|
||||
_LOGGER.error('Timezone is not set in Home Assistant.')
|
||||
return False
|
||||
|
||||
timezone = hass.config.time_zone
|
||||
|
||||
eight = EightSleep(user, password, timezone, partner, None, hass.loop)
|
||||
|
||||
hass.data[DATA_EIGHT] = eight
|
||||
|
||||
# Authenticate, build sensors
|
||||
success = yield from eight.start()
|
||||
if not success:
|
||||
# Authentication failed, cannot continue
|
||||
return False
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update_heat_data(now):
|
||||
"""Update heat data from eight in HEAT_SCAN_INTERVAL."""
|
||||
yield from eight.update_device_data()
|
||||
async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT)
|
||||
|
||||
async_track_point_in_utc_time(
|
||||
hass, async_update_heat_data, utcnow() + HEAT_SCAN_INTERVAL)
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update_user_data(now):
|
||||
"""Update user data from eight in USER_SCAN_INTERVAL."""
|
||||
yield from eight.update_user_data()
|
||||
async_dispatcher_send(hass, SIGNAL_UPDATE_USER)
|
||||
|
||||
async_track_point_in_utc_time(
|
||||
hass, async_update_user_data, utcnow() + USER_SCAN_INTERVAL)
|
||||
|
||||
yield from async_update_heat_data(None)
|
||||
yield from async_update_user_data(None)
|
||||
|
||||
# Load sub components
|
||||
sensors = []
|
||||
binary_sensors = []
|
||||
if eight.users:
|
||||
for user in eight.users:
|
||||
obj = eight.users[user]
|
||||
for sensor in SENSORS:
|
||||
sensors.append('{}_{}'.format(obj.side, sensor))
|
||||
binary_sensors.append('{}_presence'.format(obj.side))
|
||||
sensors.append('room_temp')
|
||||
|
||||
hass.async_add_job(discovery.async_load_platform(
|
||||
hass, 'sensor', DOMAIN, {
|
||||
CONF_SENSORS: sensors,
|
||||
}, config))
|
||||
|
||||
hass.async_add_job(discovery.async_load_platform(
|
||||
hass, 'binary_sensor', DOMAIN, {
|
||||
CONF_BINARY_SENSORS: binary_sensors,
|
||||
}, config))
|
||||
|
||||
descriptions = yield from hass.loop.run_in_executor(
|
||||
None, load_yaml_config_file,
|
||||
os.path.join(os.path.dirname(__file__), 'services.yaml'))
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_service_handler(service):
|
||||
"""Handle eight sleep service calls."""
|
||||
params = service.data.copy()
|
||||
|
||||
sensor = params.pop(ATTR_ENTITY_ID, None)
|
||||
target = params.pop(ATTR_TARGET_HEAT, None)
|
||||
duration = params.pop(ATTR_HEAT_DURATION, 0)
|
||||
|
||||
for sens in sensor:
|
||||
side = sens.split('_')[1]
|
||||
userid = eight.fetch_userid(side)
|
||||
usrobj = eight.users[userid]
|
||||
yield from usrobj.set_heating_level(target, duration)
|
||||
|
||||
async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT)
|
||||
|
||||
# Register services
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_HEAT_SET, async_service_handler,
|
||||
descriptions[DOMAIN].get(SERVICE_HEAT_SET),
|
||||
schema=SERVICE_EIGHT_SCHEMA)
|
||||
|
||||
@asyncio.coroutine
|
||||
def stop_eight(event):
|
||||
"""Handle stopping eight api session."""
|
||||
yield from eight.stop()
|
||||
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_eight)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class EightSleepUserEntity(Entity):
|
||||
"""The Eight Sleep device entity."""
|
||||
|
||||
def __init__(self, eight):
|
||||
"""Initialize the data oject."""
|
||||
self._eight = eight
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Register update dispatcher."""
|
||||
@callback
|
||||
def async_eight_user_update():
|
||||
"""Update callback."""
|
||||
self.hass.async_add_job(self.async_update_ha_state(True))
|
||||
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_UPDATE_USER, async_eight_user_update)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return True if entity has to be polled for state."""
|
||||
return False
|
||||
|
||||
|
||||
class EightSleepHeatEntity(Entity):
|
||||
"""The Eight Sleep device entity."""
|
||||
|
||||
def __init__(self, eight):
|
||||
"""Initialize the data oject."""
|
||||
self._eight = eight
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Register update dispatcher."""
|
||||
@callback
|
||||
def async_eight_heat_update():
|
||||
"""Update callback."""
|
||||
self.hass.async_add_job(self.async_update_ha_state(True))
|
||||
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_UPDATE_HEAT, async_eight_heat_update)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Return True if entity has to be polled for state."""
|
||||
return False
|
273
homeassistant/components/sensor/eight_sleep.py
Normal file
273
homeassistant/components/sensor/eight_sleep.py
Normal file
@ -0,0 +1,273 @@
|
||||
"""
|
||||
Support for Eight Sleep sensors.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/sensor.eight_sleep/
|
||||
"""
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
from homeassistant.components.eight_sleep import (
|
||||
DATA_EIGHT, EightSleepHeatEntity, EightSleepUserEntity,
|
||||
CONF_SENSORS, NAME_MAP)
|
||||
|
||||
DEPENDENCIES = ['eight_sleep']
|
||||
|
||||
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'
|
||||
ATTR_LIGHT_PERC = 'Light Sleep %'
|
||||
ATTR_DEEP_PERC = 'Deep Sleep %'
|
||||
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_LAST_SEEN = 'Last In Bed'
|
||||
ATTR_PROCESSING = 'Processing'
|
||||
ATTR_SESSION_START = 'Session Start'
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Setup the eight sleep sensors."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
|
||||
name = 'Eight'
|
||||
sensors = discovery_info[CONF_SENSORS]
|
||||
eight = hass.data[DATA_EIGHT]
|
||||
|
||||
if hass.config.units.is_metric:
|
||||
units = 'si'
|
||||
else:
|
||||
units = 'us'
|
||||
|
||||
all_sensors = []
|
||||
|
||||
for sensor in sensors:
|
||||
if 'bed_state' in sensor:
|
||||
all_sensors.append(EightHeatSensor(name, eight, sensor))
|
||||
elif 'room_temp' in sensor:
|
||||
all_sensors.append(EightRoomSensor(name, eight, sensor, units))
|
||||
else:
|
||||
all_sensors.append(EightUserSensor(name, eight, sensor, units))
|
||||
|
||||
async_add_devices(all_sensors, True)
|
||||
|
||||
|
||||
class EightHeatSensor(EightSleepHeatEntity):
|
||||
"""Representation of a eight sleep heat-based sensor."""
|
||||
|
||||
def __init__(self, name, eight, sensor):
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(eight)
|
||||
|
||||
self._sensor = sensor
|
||||
self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
|
||||
self._name = '{} {}'.format(name, self._mapped_name)
|
||||
self._state = None
|
||||
|
||||
self._side = self._sensor.split('_')[0]
|
||||
self._userid = self._eight.fetch_userid(self._side)
|
||||
self._usrobj = self._eight.users[self._userid]
|
||||
|
||||
_LOGGER.debug('Heat Sensor: %s, Side: %s, User: %s',
|
||||
self._sensor, self._side, self._userid)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor, if any."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit the value is expressed in."""
|
||||
return '%'
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
"""Retrieve latest state."""
|
||||
_LOGGER.debug('Updating Heat sensor: %s', self._sensor)
|
||||
self._state = self._usrobj.heating_level
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return device state attributes."""
|
||||
state_attr = {ATTR_TARGET_HEAT: self._usrobj.target_heating_level}
|
||||
state_attr[ATTR_ACTIVE_HEAT] = self._usrobj.now_heating
|
||||
state_attr[ATTR_DURATION_HEAT] = self._usrobj.heating_remaining
|
||||
state_attr[ATTR_LAST_SEEN] = self._usrobj.last_seen
|
||||
|
||||
return state_attr
|
||||
|
||||
|
||||
class EightUserSensor(EightSleepUserEntity):
|
||||
"""Representation of a eight sleep user-based sensor."""
|
||||
|
||||
def __init__(self, name, eight, sensor, units):
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(eight)
|
||||
|
||||
self._sensor = sensor
|
||||
self._sensor_root = self._sensor.split('_', 1)[1]
|
||||
self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
|
||||
self._name = '{} {}'.format(name, self._mapped_name)
|
||||
self._state = None
|
||||
self._attr = None
|
||||
self._units = units
|
||||
|
||||
self._side = self._sensor.split('_', 1)[0]
|
||||
self._userid = self._eight.fetch_userid(self._side)
|
||||
self._usrobj = self._eight.users[self._userid]
|
||||
|
||||
_LOGGER.debug('User Sensor: %s, Side: %s, User: %s',
|
||||
self._sensor, self._side, self._userid)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor, if any."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit the value is expressed in."""
|
||||
if 'current_sleep' in self._sensor or 'last_sleep' in self._sensor:
|
||||
return 'Score'
|
||||
elif 'bed_temp' in self._sensor:
|
||||
if self._units == 'si':
|
||||
return '°C'
|
||||
else:
|
||||
return '°F'
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Icon to use in the frontend, if any."""
|
||||
if 'bed_temp' in self._sensor:
|
||||
return 'mdi:thermometer'
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
"""Retrieve latest state."""
|
||||
_LOGGER.debug('Updating User sensor: %s', self._sensor)
|
||||
if 'current' in self._sensor:
|
||||
self._state = self._usrobj.current_sleep_score
|
||||
self._attr = self._usrobj.current_values
|
||||
elif 'last' in self._sensor:
|
||||
self._state = self._usrobj.last_sleep_score
|
||||
self._attr = self._usrobj.last_values
|
||||
elif 'bed_temp' in self._sensor:
|
||||
temp = self._usrobj.current_values['bed_temp']
|
||||
if self._units == 'si':
|
||||
self._state = round(temp, 2)
|
||||
else:
|
||||
self._state = round((temp*1.8)+32, 2)
|
||||
elif 'sleep_stage' in self._sensor:
|
||||
self._state = self._usrobj.current_values['stage']
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return device state attributes."""
|
||||
if self._attr is None:
|
||||
# Skip attributes if sensor type doesn't support
|
||||
return None
|
||||
|
||||
state_attr = {ATTR_SESSION_START: self._attr['date']}
|
||||
state_attr[ATTR_TNT] = self._attr['tnt']
|
||||
state_attr[ATTR_PROCESSING] = self._attr['processing']
|
||||
|
||||
sleep_time = sum(self._attr['breakdown'].values()) - \
|
||||
self._attr['breakdown']['awake']
|
||||
state_attr[ATTR_SLEEP_DUR] = sleep_time
|
||||
state_attr[ATTR_LIGHT_PERC] = round((
|
||||
self._attr['breakdown']['light'] / sleep_time) * 100, 2)
|
||||
state_attr[ATTR_DEEP_PERC] = round((
|
||||
self._attr['breakdown']['deep'] / sleep_time) * 100, 2)
|
||||
|
||||
if self._units == 'si':
|
||||
room_temp = round(self._attr['room_temp'], 2)
|
||||
bed_temp = round(self._attr['bed_temp'], 2)
|
||||
else:
|
||||
room_temp = round((self._attr['room_temp']*1.8)+32, 2)
|
||||
bed_temp = round((self._attr['bed_temp']*1.8)+32, 2)
|
||||
|
||||
if 'current' in self._sensor_root:
|
||||
state_attr[ATTR_RESP_RATE] = round(self._attr['resp_rate'], 2)
|
||||
state_attr[ATTR_HEART_RATE] = round(self._attr['heart_rate'], 2)
|
||||
state_attr[ATTR_SLEEP_STAGE] = self._attr['stage']
|
||||
state_attr[ATTR_ROOM_TEMP] = room_temp
|
||||
state_attr[ATTR_BED_TEMP] = bed_temp
|
||||
elif 'last' in self._sensor_root:
|
||||
state_attr[ATTR_AVG_RESP_RATE] = round(self._attr['resp_rate'], 2)
|
||||
state_attr[ATTR_AVG_HEART_RATE] = round(
|
||||
self._attr['heart_rate'], 2)
|
||||
state_attr[ATTR_AVG_ROOM_TEMP] = room_temp
|
||||
state_attr[ATTR_AVG_BED_TEMP] = bed_temp
|
||||
|
||||
return state_attr
|
||||
|
||||
|
||||
class EightRoomSensor(EightSleepUserEntity):
|
||||
"""Representation of a eight sleep room sensor."""
|
||||
|
||||
def __init__(self, name, eight, sensor, units):
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(eight)
|
||||
|
||||
self._sensor = sensor
|
||||
self._mapped_name = NAME_MAP.get(self._sensor, self._sensor)
|
||||
self._name = '{} {}'.format(name, self._mapped_name)
|
||||
self._state = None
|
||||
self._attr = None
|
||||
self._units = units
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor, if any."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self._state
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
"""Retrieve latest state."""
|
||||
_LOGGER.debug('Updating Room sensor: %s', self._sensor)
|
||||
temp = self._eight.room_temperature()
|
||||
if self._units == 'si':
|
||||
self._state = round(temp, 2)
|
||||
else:
|
||||
self._state = round((temp*1.8)+32, 2)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit the value is expressed in."""
|
||||
if self._units == 'si':
|
||||
return '°C'
|
||||
else:
|
||||
return '°F'
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Icon to use in the frontend, if any."""
|
||||
return 'mdi:thermometer'
|
@ -388,3 +388,17 @@ hassio:
|
||||
addon:
|
||||
description: Name of addon.
|
||||
example: 'smb_config'
|
||||
|
||||
eight_sleep:
|
||||
heat_set:
|
||||
description: Set heating level for eight sleep.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Entity id of the bed state to adjust.
|
||||
example: 'sensor.eight_left_bed_state'
|
||||
target:
|
||||
description: Target heating level from 0-100.
|
||||
example: 35
|
||||
duration:
|
||||
description: Duration to heat at the target level in seconds.
|
||||
example: 3600
|
||||
|
@ -530,6 +530,9 @@ pydroid-ipcam==0.8
|
||||
# homeassistant.components.sensor.ebox
|
||||
pyebox==0.1.0
|
||||
|
||||
# homeassistant.components.eight_sleep
|
||||
pyeight==0.0.4
|
||||
|
||||
# homeassistant.components.notify.html5
|
||||
pyelliptic==1.5.7
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user