core/homeassistant/components/tellduslive.py

226 lines
6.9 KiB
Python
Raw Normal View History

"""
2016-03-07 17:49:31 +00:00
Support for Telldus Live.
2016-02-02 23:35:53 +00:00
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/tellduslive/
"""
from datetime import datetime, timedelta
import logging
2016-09-11 07:22:49 +00:00
from homeassistant.const import (
ATTR_BATTERY_LEVEL, DEVICE_DEFAULT_NAME, EVENT_HOMEASSISTANT_START)
2016-09-11 07:22:49 +00:00
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import track_point_in_utc_time
from homeassistant.util.dt import utcnow
import voluptuous as vol
2016-09-11 07:22:49 +00:00
DOMAIN = 'tellduslive'
2016-02-03 21:31:28 +00:00
REQUIREMENTS = ['tellduslive==0.3.4']
2016-02-03 21:31:28 +00:00
_LOGGER = logging.getLogger(__name__)
2016-09-11 07:22:49 +00:00
CONF_PUBLIC_KEY = 'public_key'
CONF_PRIVATE_KEY = 'private_key'
CONF_TOKEN = 'token'
CONF_TOKEN_SECRET = 'token_secret'
CONF_UPDATE_INTERVAL = 'update_interval'
MIN_UPDATE_INTERVAL = timedelta(seconds=5)
DEFAULT_UPDATE_INTERVAL = timedelta(minutes=1)
2016-09-11 07:22:49 +00:00
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_PUBLIC_KEY): cv.string,
vol.Required(CONF_PRIVATE_KEY): cv.string,
vol.Required(CONF_TOKEN): cv.string,
vol.Required(CONF_TOKEN_SECRET): cv.string,
vol.Optional(CONF_UPDATE_INTERVAL, default=DEFAULT_UPDATE_INTERVAL): (
vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL)))
2016-09-11 07:22:49 +00:00
}),
}, extra=vol.ALLOW_EXTRA)
ATTR_LAST_UPDATED = 'time_last_updated'
2016-09-11 07:22:49 +00:00
def setup(hass, config):
"""Set up the Telldus Live component."""
client = TelldusLiveClient(hass, config)
2016-09-11 07:22:49 +00:00
if not client.validate_session():
2016-09-11 07:22:49 +00:00
_LOGGER.error(
"Authentication Error: Please make sure you have configured your "
"keys that can be aquired from https://api.telldus.com/keys/index")
2016-09-11 07:22:49 +00:00
return False
hass.data[DOMAIN] = client
hass.bus.listen(EVENT_HOMEASSISTANT_START, client.update)
2016-09-11 07:22:49 +00:00
return True
2016-02-03 21:31:28 +00:00
class TelldusLiveClient(object):
2016-03-08 16:55:57 +00:00
"""Get the latest data and update the states."""
def __init__(self, hass, config):
2016-03-08 16:55:57 +00:00
"""Initialize the Tellus data object."""
from tellduslive import Client
public_key = config[DOMAIN].get(CONF_PUBLIC_KEY)
private_key = config[DOMAIN].get(CONF_PRIVATE_KEY)
token = config[DOMAIN].get(CONF_TOKEN)
token_secret = config[DOMAIN].get(CONF_TOKEN_SECRET)
self.entities = []
2016-02-03 21:31:28 +00:00
self._hass = hass
self._config = config
self._interval = config[DOMAIN].get(CONF_UPDATE_INTERVAL)
_LOGGER.debug('Update interval %s', self._interval)
self._client = Client(public_key,
private_key,
token,
token_secret)
2016-02-03 21:31:28 +00:00
def validate_session(self):
"""Make a request to see if the session is valid."""
response = self._client.request_user()
2016-02-16 16:36:09 +00:00
return response and 'email' in response
2016-02-03 21:31:28 +00:00
def update(self, *args):
"""Periodically poll the servers for current state."""
_LOGGER.debug("Updating")
2016-02-16 16:36:09 +00:00
try:
self._sync()
finally:
track_point_in_utc_time(
self._hass, self.update, utcnow() + self._interval)
def _sync(self):
"""Update local list of devices."""
if not self._client.update():
_LOGGER.warning("Failed request")
def identify_device(device):
"""Find out what type of HA component to create."""
from tellduslive import (DIM, UP, TURNON)
if device.methods & DIM:
return 'light'
elif device.methods & UP:
return 'cover'
elif device.methods & TURNON:
return 'switch'
else:
_LOGGER.warning(
"Unidentified device type (methods: %d)", device.methods)
return 'switch'
def discover(device_id, component):
"""Discover the component."""
discovery.load_platform(
self._hass, component, DOMAIN, [device_id], self._config)
known_ids = set([entity.device_id for entity in self.entities])
for device in self._client.devices:
if device.device_id in known_ids:
continue
if device.is_sensor:
2017-01-31 19:08:11 +00:00
for item in device.items:
discover((device.device_id, item.name, item.scale),
'sensor')
else:
discover(device.device_id,
identify_device(device))
for entity in self.entities:
entity.changed()
def device(self, device_id):
"""Return device representation."""
2017-01-31 19:08:11 +00:00
return self._client.device(device_id)
def is_available(self, device_id):
"""Return device availability."""
return device_id in self._client.device_ids
class TelldusLiveEntity(Entity):
"""Base class for all Telldus Live entities."""
def __init__(self, hass, device_id):
"""Initialize the entity."""
self._id = device_id
self._client = hass.data[DOMAIN]
self._client.entities.append(self)
self._name = self.device.name
_LOGGER.debug("Created device %s", self)
def changed(self):
"""Return the property of the device might have changed."""
if self.device.name:
self._name = self.device.name
self.schedule_update_ha_state()
@property
def device_id(self):
"""Return the id of the device."""
return self._id
@property
def device(self):
"""Return the representaion of the device."""
return self._client.device(self.device_id)
@property
def _state(self):
"""Return the state of the device."""
return self.device.state
@property
def should_poll(self):
"""Return the polling state."""
return False
@property
def assumed_state(self):
"""Return true if unable to access real state of entity."""
return True
@property
def name(self):
"""Return name of device."""
return self._name or DEVICE_DEFAULT_NAME
@property
def available(self):
"""Return true if device is not offline."""
return self._client.is_available(self.device_id)
@property
def device_state_attributes(self):
"""Return the state attributes."""
attrs = {}
if self._battery_level:
attrs[ATTR_BATTERY_LEVEL] = self._battery_level
if self._last_updated:
attrs[ATTR_LAST_UPDATED] = self._last_updated
return attrs
@property
def _battery_level(self):
"""Return the battery level of a device."""
return round(self.device.battery * 100 / 255) \
if self.device.battery else None
@property
def _last_updated(self):
"""Return the last update of a device."""
2017-01-31 19:08:11 +00:00
return str(datetime.fromtimestamp(self.device.lastUpdated)) \
if self.device.lastUpdated else None