core/homeassistant/components/tellduslive.py

214 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/
"""
import logging
2016-02-19 05:27:50 +00:00
from datetime import timedelta
2016-09-11 07:22:49 +00:00
import voluptuous as vol
from homeassistant.helpers import discovery
2016-02-19 05:27:50 +00:00
from homeassistant.util import Throttle
2016-09-11 07:22:49 +00:00
import homeassistant.helpers.config_validation as cv
2016-09-11 07:22:49 +00:00
DOMAIN = 'tellduslive'
2016-02-03 21:31:28 +00:00
REQUIREMENTS = ['tellive-py==0.5.2']
_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'
2016-02-03 21:31:28 +00:00
MIN_TIME_BETWEEN_SWITCH_UPDATES = timedelta(minutes=1)
MIN_TIME_BETWEEN_SENSOR_UPDATES = timedelta(minutes=5)
NETWORK = None
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,
}),
}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):
"""Setup the Telldus Live component."""
# fixme: aquire app key and provide authentication using username+password
global NETWORK
NETWORK = TelldusLiveData(hass, config)
if not NETWORK.validate_session():
_LOGGER.error(
"Authentication Error: "
"Please make sure you have configured your keys "
"that can be aquired from https://api.telldus.com/keys/index")
return False
NETWORK.discover()
return True
2016-02-03 21:31:28 +00:00
@Throttle(MIN_TIME_BETWEEN_SWITCH_UPDATES)
def request_switches():
2016-03-07 17:49:31 +00:00
"""Make request to online service."""
2016-02-03 21:31:28 +00:00
_LOGGER.debug("Updating switches from Telldus Live")
2016-09-11 07:22:49 +00:00
switches = NETWORK.request('devices/list')['device']
2016-03-07 17:49:31 +00:00
# Filter out any group of switches.
2016-02-03 21:31:28 +00:00
switches = {switch["id"]: switch for switch in switches
if switch["type"] == "device"}
return switches
@Throttle(MIN_TIME_BETWEEN_SENSOR_UPDATES)
def request_sensors():
2016-03-07 17:49:31 +00:00
"""Make request to online service."""
2016-02-03 21:31:28 +00:00
_LOGGER.debug("Updating sensors from Telldus Live")
2016-09-11 07:22:49 +00:00
units = NETWORK.request('sensors/list')['sensor']
2016-03-07 17:49:31 +00:00
# One unit can contain many sensors.
2016-09-11 07:22:49 +00:00
sensors = {unit['id']+sensor['name']: dict(unit, data=sensor)
2016-02-03 21:31:28 +00:00
for unit in units
2016-09-11 07:22:49 +00:00
for sensor in unit['data']}
2016-02-03 21:31:28 +00:00
return sensors
class TelldusLiveData(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."""
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)
from tellive.client import LiveClient
2016-02-03 21:31:28 +00:00
self._switches = {}
self._sensors = {}
self._hass = hass
self._config = config
2016-09-11 07:22:49 +00:00
self._client = LiveClient(
public_key=public_key, private_key=private_key, access_token=token,
access_secret=token_secret)
2016-02-03 21:31:28 +00:00
def validate_session(self):
2016-03-07 17:49:31 +00:00
"""Make a dummy request to see if the session is valid."""
2016-02-16 16:36:09 +00:00
response = self.request("user/profile")
return response and 'email' in response
2016-02-03 21:31:28 +00:00
def discover(self):
2016-03-07 17:49:31 +00:00
"""Update states, will trigger discover."""
2016-02-03 21:31:28 +00:00
self.update_sensors()
self.update_switches()
def _discover(self, found_devices, component_name):
2016-03-07 17:49:31 +00:00
"""Send discovery event if component not yet discovered."""
2016-02-03 21:31:28 +00:00
if not len(found_devices):
return
_LOGGER.info("discovered %d new %s devices",
len(found_devices), component_name)
discovery.load_platform(self._hass, component_name, DOMAIN,
found_devices, self._config)
2016-02-03 21:31:28 +00:00
def request(self, what, **params):
2016-03-08 16:55:57 +00:00
"""Send a request to the Tellstick Live API."""
from tellive.live import const
supported_methods = const.TELLSTICK_TURNON \
| const.TELLSTICK_TURNOFF \
2016-02-03 21:31:28 +00:00
| const.TELLSTICK_TOGGLE \
# Tellstick device methods not yet supported
# | const.TELLSTICK_BELL \
# | const.TELLSTICK_DIM \
# | const.TELLSTICK_LEARN \
# | const.TELLSTICK_EXECUTE \
# | const.TELLSTICK_UP \
# | const.TELLSTICK_DOWN \
# | const.TELLSTICK_STOP
default_params = {'supportedMethods': supported_methods,
2016-09-11 07:22:49 +00:00
'includeValues': 1,
'includeScale': 1,
'includeIgnored': 0}
params.update(default_params)
# room for improvement: the telllive library doesn't seem to
# re-use sessions, instead it opens a new session for each request
# this needs to be fixed
2016-02-03 21:31:28 +00:00
2016-02-16 16:36:09 +00:00
try:
response = self._client.request(what, params)
_LOGGER.debug("got response %s", response)
return response
except (ConnectionError, TimeoutError):
_LOGGER.error("failed to make request to Tellduslive servers")
return None
2016-03-07 17:49:31 +00:00
def update_devices(self, local_devices, remote_devices, component_name):
"""Update local device list and discover new devices."""
2016-02-03 21:31:28 +00:00
if remote_devices is None:
return local_devices
remote_ids = remote_devices.keys()
local_ids = local_devices.keys()
added_devices = list(remote_ids - local_ids)
self._discover(added_devices,
component_name)
removed_devices = list(local_ids - remote_ids)
remote_devices.update({id: dict(local_devices[id], offline=True)
for id in removed_devices})
return remote_devices
def update_sensors(self):
2016-03-07 17:49:31 +00:00
"""Update local list of sensors."""
2016-09-11 07:22:49 +00:00
self._sensors = self.update_devices(
self._sensors, request_sensors(), 'sensor')
2016-02-03 21:31:28 +00:00
def update_switches(self):
2016-03-07 17:49:31 +00:00
"""Update local list of switches."""
2016-09-11 07:22:49 +00:00
self._switches = self.update_devices(
self._switches, request_switches(), 'switch')
2016-02-03 21:31:28 +00:00
def _check_request(self, what, **params):
2016-03-07 17:49:31 +00:00
"""Make request, check result if successful."""
2016-02-03 21:31:28 +00:00
response = self.request(what, **params)
return response and response.get('status') == 'success'
def get_switch(self, switch_id):
2016-03-07 17:49:31 +00:00
"""Return the switch representation."""
2016-02-03 21:31:28 +00:00
return self._switches[switch_id]
2016-02-03 21:31:28 +00:00
def get_sensor(self, sensor_id):
2016-03-07 17:49:31 +00:00
"""Return the sensor representation."""
2016-02-03 21:31:28 +00:00
return self._sensors[sensor_id]
def turn_switch_on(self, switch_id):
2016-03-07 17:49:31 +00:00
"""Turn switch off."""
2016-09-11 07:22:49 +00:00
if self._check_request('device/turnOn', id=switch_id):
2016-02-03 21:31:28 +00:00
from tellive.live import const
2016-09-11 07:22:49 +00:00
self.get_switch(switch_id)['state'] = const.TELLSTICK_TURNON
def turn_switch_off(self, switch_id):
2016-03-07 17:49:31 +00:00
"""Turn switch on."""
2016-09-11 07:22:49 +00:00
if self._check_request('device/turnOff', id=switch_id):
2016-02-03 21:31:28 +00:00
from tellive.live import const
2016-09-11 07:22:49 +00:00
self.get_switch(switch_id)['state'] = const.TELLSTICK_TURNOFF