2019-02-13 20:21:14 +00:00
|
|
|
"""Support for SleepIQ from SleepNumber."""
|
2016-09-13 22:11:50 +00:00
|
|
|
from datetime import timedelta
|
2019-12-06 08:13:44 +00:00
|
|
|
import logging
|
2016-09-13 22:11:50 +00:00
|
|
|
|
2019-12-06 08:13:44 +00:00
|
|
|
from sleepyq import Sleepyq
|
2016-09-13 22:11:50 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2022-01-10 09:45:11 +00:00
|
|
|
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
|
2022-01-02 15:29:52 +00:00
|
|
|
from homeassistant.core import HomeAssistant
|
2016-09-13 22:11:50 +00:00
|
|
|
from homeassistant.helpers import discovery
|
2019-12-06 08:13:44 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2016-09-13 22:11:50 +00:00
|
|
|
from homeassistant.helpers.entity import Entity
|
2022-01-02 15:29:52 +00:00
|
|
|
from homeassistant.helpers.typing import ConfigType
|
2016-09-13 22:11:50 +00:00
|
|
|
from homeassistant.util import Throttle
|
|
|
|
|
2020-04-05 22:46:50 +00:00
|
|
|
from .const import DOMAIN
|
2016-09-13 22:11:50 +00:00
|
|
|
|
|
|
|
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
|
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
CONFIG_SCHEMA = vol.Schema(
|
|
|
|
{
|
|
|
|
vol.Required(DOMAIN): vol.Schema(
|
|
|
|
{
|
|
|
|
vol.Required(CONF_USERNAME): cv.string,
|
|
|
|
vol.Required(CONF_PASSWORD): cv.string,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
extra=vol.ALLOW_EXTRA,
|
|
|
|
)
|
2016-09-13 22:11:50 +00:00
|
|
|
|
|
|
|
|
2022-01-02 15:29:52 +00:00
|
|
|
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Set up the SleepIQ component.
|
2016-09-13 22:11:50 +00:00
|
|
|
|
|
|
|
Will automatically load sensor components to support
|
|
|
|
devices discovered on the account.
|
|
|
|
"""
|
|
|
|
username = config[DOMAIN][CONF_USERNAME]
|
|
|
|
password = config[DOMAIN][CONF_PASSWORD]
|
|
|
|
client = Sleepyq(username, password)
|
|
|
|
try:
|
2020-04-05 22:46:50 +00:00
|
|
|
data = SleepIQData(client)
|
|
|
|
data.update()
|
2019-07-07 06:40:02 +00:00
|
|
|
except ValueError:
|
2016-09-13 22:11:50 +00:00
|
|
|
message = """
|
|
|
|
SleepIQ failed to login, double check your username and password"
|
|
|
|
"""
|
|
|
|
_LOGGER.error(message)
|
|
|
|
return False
|
|
|
|
|
2020-04-05 22:46:50 +00:00
|
|
|
hass.data[DOMAIN] = data
|
2022-01-10 09:45:11 +00:00
|
|
|
discovery.load_platform(hass, Platform.SENSOR, DOMAIN, {}, config)
|
|
|
|
discovery.load_platform(hass, Platform.BINARY_SENSOR, DOMAIN, {}, config)
|
2016-09-13 22:11:50 +00:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2018-07-20 08:45:20 +00:00
|
|
|
class SleepIQData:
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Get the latest data from SleepIQ."""
|
2016-09-13 22:11:50 +00:00
|
|
|
|
|
|
|
def __init__(self, client):
|
|
|
|
"""Initialize the data object."""
|
|
|
|
self._client = client
|
|
|
|
self.beds = {}
|
|
|
|
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
|
|
|
def update(self):
|
|
|
|
"""Get the latest data from SleepIQ."""
|
|
|
|
self._client.login()
|
|
|
|
beds = self._client.beds_with_sleeper_status()
|
|
|
|
|
|
|
|
self.beds = {bed.bed_id: bed for bed in beds}
|
|
|
|
|
|
|
|
|
|
|
|
class SleepIQSensor(Entity):
|
|
|
|
"""Implementation of a SleepIQ sensor."""
|
|
|
|
|
|
|
|
def __init__(self, sleepiq_data, bed_id, side):
|
|
|
|
"""Initialize the sensor."""
|
|
|
|
self._bed_id = bed_id
|
|
|
|
self._side = side
|
|
|
|
self.sleepiq_data = sleepiq_data
|
|
|
|
self.side = None
|
|
|
|
self.bed = None
|
|
|
|
|
|
|
|
# added by subclass
|
|
|
|
self._name = None
|
|
|
|
self.type = None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"""Return the name of the sensor."""
|
2019-07-31 19:25:30 +00:00
|
|
|
return "SleepNumber {} {} {}".format(
|
|
|
|
self.bed.name, self.side.sleeper.first_name, self._name
|
|
|
|
)
|
2016-09-13 22:11:50 +00:00
|
|
|
|
2022-02-14 22:01:15 +00:00
|
|
|
@property
|
|
|
|
def unique_id(self):
|
|
|
|
"""Return a unique ID for the bed."""
|
|
|
|
return f"{self._bed_id}-{self._side}-{self.type}"
|
|
|
|
|
2016-09-13 22:11:50 +00:00
|
|
|
def update(self):
|
|
|
|
"""Get the latest data from SleepIQ and updates the states."""
|
|
|
|
# Call the API for new sleepiq data. Each sensor will re-trigger this
|
2017-09-23 15:15:46 +00:00
|
|
|
# same exact call, but that's fine. We cache results for a short period
|
2016-09-13 22:11:50 +00:00
|
|
|
# of time to prevent hitting API limits.
|
|
|
|
self.sleepiq_data.update()
|
|
|
|
|
|
|
|
self.bed = self.sleepiq_data.beds[self._bed_id]
|
|
|
|
self.side = getattr(self.bed, self._side)
|