Eight Sleep add REM type, Update async syntax, Catch API quirks (#14937)

This commit is contained in:
John Mihalic 2018-06-15 15:24:09 -04:00 committed by Paulus Schoutsen
parent 8a777f6e78
commit 9efa31ef9f
4 changed files with 60 additions and 54 deletions

View File

@ -5,7 +5,6 @@ For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.eight_sleep/ https://home-assistant.io/components/binary_sensor.eight_sleep/
""" """
import logging import logging
import asyncio
from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.eight_sleep import ( from homeassistant.components.eight_sleep import (
@ -16,8 +15,8 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['eight_sleep'] DEPENDENCIES = ['eight_sleep']
@asyncio.coroutine async def async_setup_platform(hass, config, async_add_devices,
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): discovery_info=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
@ -63,7 +62,6 @@ class EightHeatSensor(EightSleepHeatEntity, BinarySensorDevice):
"""Return true if the binary sensor is on.""" """Return true if the binary sensor is on."""
return self._state return self._state
@asyncio.coroutine async def async_update(self):
def async_update(self):
"""Retrieve latest state.""" """Retrieve latest state."""
self._state = self._usrobj.bed_presence self._state = self._usrobj.bed_presence

View File

@ -4,7 +4,6 @@ Support for Eight smart mattress covers and mattresses.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/eight_sleep/ https://home-assistant.io/components/eight_sleep/
""" """
import asyncio
import logging import logging
from datetime import timedelta from datetime import timedelta
@ -22,7 +21,7 @@ from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
REQUIREMENTS = ['pyeight==0.0.8'] REQUIREMENTS = ['pyeight==0.0.9']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -86,8 +85,7 @@ CONFIG_SCHEMA = vol.Schema({
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
@asyncio.coroutine async def async_setup(hass, config):
def async_setup(hass, config):
"""Set up the Eight Sleep component.""" """Set up the Eight Sleep component."""
from pyeight.eight import EightSleep from pyeight.eight import EightSleep
@ -107,31 +105,29 @@ def async_setup(hass, config):
hass.data[DATA_EIGHT] = eight hass.data[DATA_EIGHT] = eight
# Authenticate, build sensors # Authenticate, build sensors
success = yield from eight.start() success = await eight.start()
if not success: if not success:
# Authentication failed, cannot continue # Authentication failed, cannot continue
return False return False
@asyncio.coroutine async def async_update_heat_data(now):
def async_update_heat_data(now):
"""Update heat data from eight in HEAT_SCAN_INTERVAL.""" """Update heat data from eight in HEAT_SCAN_INTERVAL."""
yield from eight.update_device_data() await eight.update_device_data()
async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT) async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT)
async_track_point_in_utc_time( async_track_point_in_utc_time(
hass, async_update_heat_data, utcnow() + HEAT_SCAN_INTERVAL) hass, async_update_heat_data, utcnow() + HEAT_SCAN_INTERVAL)
@asyncio.coroutine async def async_update_user_data(now):
def async_update_user_data(now):
"""Update user data from eight in USER_SCAN_INTERVAL.""" """Update user data from eight in USER_SCAN_INTERVAL."""
yield from eight.update_user_data() await eight.update_user_data()
async_dispatcher_send(hass, SIGNAL_UPDATE_USER) async_dispatcher_send(hass, SIGNAL_UPDATE_USER)
async_track_point_in_utc_time( async_track_point_in_utc_time(
hass, async_update_user_data, utcnow() + USER_SCAN_INTERVAL) hass, async_update_user_data, utcnow() + USER_SCAN_INTERVAL)
yield from async_update_heat_data(None) await async_update_heat_data(None)
yield from async_update_user_data(None) await async_update_user_data(None)
# Load sub components # Load sub components
sensors = [] sensors = []
@ -157,8 +153,7 @@ def async_setup(hass, config):
CONF_BINARY_SENSORS: binary_sensors, CONF_BINARY_SENSORS: binary_sensors,
}, config)) }, config))
@asyncio.coroutine async def async_service_handler(service):
def async_service_handler(service):
"""Handle eight sleep service calls.""" """Handle eight sleep service calls."""
params = service.data.copy() params = service.data.copy()
@ -170,7 +165,7 @@ def async_setup(hass, config):
side = sens.split('_')[1] side = sens.split('_')[1]
userid = eight.fetch_userid(side) userid = eight.fetch_userid(side)
usrobj = eight.users[userid] usrobj = eight.users[userid]
yield from usrobj.set_heating_level(target, duration) await usrobj.set_heating_level(target, duration)
async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT) async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT)
@ -179,10 +174,9 @@ def async_setup(hass, config):
DOMAIN, SERVICE_HEAT_SET, async_service_handler, DOMAIN, SERVICE_HEAT_SET, async_service_handler,
schema=SERVICE_EIGHT_SCHEMA) schema=SERVICE_EIGHT_SCHEMA)
@asyncio.coroutine async def stop_eight(event):
def stop_eight(event):
"""Handle stopping eight api session.""" """Handle stopping eight api session."""
yield from eight.stop() await eight.stop()
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_eight) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_eight)
@ -196,8 +190,7 @@ class EightSleepUserEntity(Entity):
"""Initialize the data object.""" """Initialize the data object."""
self._eight = eight self._eight = eight
@asyncio.coroutine async def async_added_to_hass(self):
def async_added_to_hass(self):
"""Register update dispatcher.""" """Register update dispatcher."""
@callback @callback
def async_eight_user_update(): def async_eight_user_update():
@ -220,8 +213,7 @@ class EightSleepHeatEntity(Entity):
"""Initialize the data object.""" """Initialize the data object."""
self._eight = eight self._eight = eight
@asyncio.coroutine async def async_added_to_hass(self):
def async_added_to_hass(self):
"""Register update dispatcher.""" """Register update dispatcher."""
@callback @callback
def async_eight_heat_update(): def async_eight_heat_update():

View File

@ -5,7 +5,6 @@ For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.eight_sleep/ https://home-assistant.io/components/sensor.eight_sleep/
""" """
import logging import logging
import asyncio
from homeassistant.components.eight_sleep import ( from homeassistant.components.eight_sleep import (
DATA_EIGHT, EightSleepHeatEntity, EightSleepUserEntity, DATA_EIGHT, EightSleepHeatEntity, EightSleepUserEntity,
@ -24,20 +23,20 @@ ATTR_AVG_HEART_RATE = 'Average Heart Rate'
ATTR_SLEEP_DUR = 'Time Slept' ATTR_SLEEP_DUR = 'Time Slept'
ATTR_LIGHT_PERC = 'Light Sleep %' ATTR_LIGHT_PERC = 'Light Sleep %'
ATTR_DEEP_PERC = 'Deep Sleep %' ATTR_DEEP_PERC = 'Deep Sleep %'
ATTR_REM_PERC = 'REM Sleep %'
ATTR_TNT = 'Tosses & Turns' ATTR_TNT = 'Tosses & Turns'
ATTR_SLEEP_STAGE = 'Sleep Stage' ATTR_SLEEP_STAGE = 'Sleep Stage'
ATTR_TARGET_HEAT = 'Target Heating Level' ATTR_TARGET_HEAT = 'Target Heating Level'
ATTR_ACTIVE_HEAT = 'Heating Active' ATTR_ACTIVE_HEAT = 'Heating Active'
ATTR_DURATION_HEAT = 'Heating Time Remaining' ATTR_DURATION_HEAT = 'Heating Time Remaining'
ATTR_LAST_SEEN = 'Last In Bed'
ATTR_PROCESSING = 'Processing' ATTR_PROCESSING = 'Processing'
ATTR_SESSION_START = 'Session Start' ATTR_SESSION_START = 'Session Start'
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@asyncio.coroutine async def async_setup_platform(hass, config, async_add_devices,
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): discovery_info=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
@ -98,8 +97,7 @@ class EightHeatSensor(EightSleepHeatEntity):
"""Return the unit the value is expressed in.""" """Return the unit the value is expressed in."""
return '%' return '%'
@asyncio.coroutine async def async_update(self):
def async_update(self):
"""Retrieve latest state.""" """Retrieve latest state."""
_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
@ -110,7 +108,6 @@ class EightHeatSensor(EightSleepHeatEntity):
state_attr = {ATTR_TARGET_HEAT: self._usrobj.target_heating_level} state_attr = {ATTR_TARGET_HEAT: self._usrobj.target_heating_level}
state_attr[ATTR_ACTIVE_HEAT] = self._usrobj.now_heating state_attr[ATTR_ACTIVE_HEAT] = self._usrobj.now_heating
state_attr[ATTR_DURATION_HEAT] = self._usrobj.heating_remaining state_attr[ATTR_DURATION_HEAT] = self._usrobj.heating_remaining
state_attr[ATTR_LAST_SEEN] = self._usrobj.last_seen
return state_attr return state_attr
@ -164,8 +161,7 @@ class EightUserSensor(EightSleepUserEntity):
if 'bed_temp' in self._sensor: if 'bed_temp' in self._sensor:
return 'mdi:thermometer' return 'mdi:thermometer'
@asyncio.coroutine async def async_update(self):
def async_update(self):
"""Retrieve latest state.""" """Retrieve latest state."""
_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:
@ -176,10 +172,13 @@ class EightUserSensor(EightSleepUserEntity):
self._attr = self._usrobj.last_values self._attr = self._usrobj.last_values
elif 'bed_temp' in self._sensor: elif 'bed_temp' in self._sensor:
temp = self._usrobj.current_values['bed_temp'] temp = self._usrobj.current_values['bed_temp']
try:
if self._units == 'si': if self._units == 'si':
self._state = round(temp, 2) self._state = round(temp, 2)
else: else:
self._state = round((temp*1.8)+32, 2) self._state = round((temp*1.8)+32, 2)
except TypeError:
self._state = None
elif 'sleep_stage' in self._sensor: elif 'sleep_stage' in self._sensor:
self._state = self._usrobj.current_values['stage'] self._state = self._usrobj.current_values['stage']
@ -208,12 +207,27 @@ class EightUserSensor(EightSleepUserEntity):
except ZeroDivisionError: except ZeroDivisionError:
state_attr[ATTR_DEEP_PERC] = 0 state_attr[ATTR_DEEP_PERC] = 0
try:
state_attr[ATTR_REM_PERC] = round((
self._attr['breakdown']['rem'] / sleep_time) * 100, 2)
except ZeroDivisionError:
state_attr[ATTR_REM_PERC] = 0
try:
if self._units == 'si': if self._units == 'si':
room_temp = round(self._attr['room_temp'], 2) room_temp = round(self._attr['room_temp'], 2)
bed_temp = round(self._attr['bed_temp'], 2)
else: else:
room_temp = round((self._attr['room_temp']*1.8)+32, 2) room_temp = round((self._attr['room_temp']*1.8)+32, 2)
except TypeError:
room_temp = None
try:
if self._units == 'si':
bed_temp = round(self._attr['bed_temp'], 2)
else:
bed_temp = round((self._attr['bed_temp']*1.8)+32, 2) bed_temp = round((self._attr['bed_temp']*1.8)+32, 2)
except TypeError:
bed_temp = None
if 'current' in self._sensor_root: if 'current' in self._sensor_root:
state_attr[ATTR_RESP_RATE] = round(self._attr['resp_rate'], 2) state_attr[ATTR_RESP_RATE] = round(self._attr['resp_rate'], 2)
@ -255,15 +269,17 @@ class EightRoomSensor(EightSleepUserEntity):
"""Return the state of the sensor.""" """Return the state of the sensor."""
return self._state return self._state
@asyncio.coroutine async def async_update(self):
def async_update(self):
"""Retrieve latest state.""" """Retrieve latest state."""
_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()
try:
if self._units == 'si': if self._units == 'si':
self._state = round(temp, 2) self._state = round(temp, 2)
else: else:
self._state = round((temp*1.8)+32, 2) self._state = round((temp*1.8)+32, 2)
except TypeError:
self._state = None
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):

View File

@ -811,7 +811,7 @@ pyeconet==0.0.5
pyedimax==0.1 pyedimax==0.1
# homeassistant.components.eight_sleep # homeassistant.components.eight_sleep
pyeight==0.0.8 pyeight==0.0.9
# homeassistant.components.media_player.emby # homeassistant.components.media_player.emby
pyemby==1.5 pyemby==1.5