mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
added rudimentary support for telldus live
This commit is contained in:
parent
384f1344fd
commit
d63e5a60ae
@ -15,6 +15,10 @@ omit =
|
|||||||
homeassistant/components/*/modbus.py
|
homeassistant/components/*/modbus.py
|
||||||
|
|
||||||
homeassistant/components/*/tellstick.py
|
homeassistant/components/*/tellstick.py
|
||||||
|
|
||||||
|
homeassistant/components/tellduslive.py
|
||||||
|
homeassistant/components/*/tellduslive.py
|
||||||
|
|
||||||
homeassistant/components/*/vera.py
|
homeassistant/components/*/vera.py
|
||||||
|
|
||||||
homeassistant/components/ecobee.py
|
homeassistant/components/ecobee.py
|
||||||
|
@ -9,7 +9,8 @@ https://home-assistant.io/components/sensor/
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.components import wink, zwave, isy994, verisure, ecobee
|
from homeassistant.components import (wink, zwave, isy994,
|
||||||
|
verisure, ecobee, tellduslive)
|
||||||
|
|
||||||
DOMAIN = 'sensor'
|
DOMAIN = 'sensor'
|
||||||
SCAN_INTERVAL = 30
|
SCAN_INTERVAL = 30
|
||||||
@ -22,7 +23,8 @@ DISCOVERY_PLATFORMS = {
|
|||||||
zwave.DISCOVER_SENSORS: 'zwave',
|
zwave.DISCOVER_SENSORS: 'zwave',
|
||||||
isy994.DISCOVER_SENSORS: 'isy994',
|
isy994.DISCOVER_SENSORS: 'isy994',
|
||||||
verisure.DISCOVER_SENSORS: 'verisure',
|
verisure.DISCOVER_SENSORS: 'verisure',
|
||||||
ecobee.DISCOVER_SENSORS: 'ecobee'
|
ecobee.DISCOVER_SENSORS: 'ecobee',
|
||||||
|
tellduslive.DISCOVER_SENSORS: 'tellduslive',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
100
homeassistant/components/sensor/tellduslive.py
Normal file
100
homeassistant/components/sensor/tellduslive.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.sensor.tellduslive
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Shows sensor values from Tellstick Net/Telstick Live.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/sensor.tellduslive/
|
||||||
|
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from homeassistant.const import TEMP_CELCIUS, ATTR_BATTERY_LEVEL
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.components import tellduslive
|
||||||
|
|
||||||
|
ATTR_LAST_UPDATED = "time_last_updated"
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
DEPENDENCIES = ['tellduslive']
|
||||||
|
|
||||||
|
SENSOR_TYPE_TEMP = "temp"
|
||||||
|
SENSOR_TYPE_HUMIDITY = "humidity"
|
||||||
|
|
||||||
|
SENSOR_TYPES = {
|
||||||
|
SENSOR_TYPE_TEMP: ['Temperature', TEMP_CELCIUS, "mdi:thermometer"],
|
||||||
|
SENSOR_TYPE_HUMIDITY: ['Humidity', '%', "mdi:water"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
""" Sets up Tellstick sensors. """
|
||||||
|
sensors = tellduslive.NETWORK.get_sensors()
|
||||||
|
devices = []
|
||||||
|
|
||||||
|
for component in sensors:
|
||||||
|
for sensor in component["data"]:
|
||||||
|
# one component can have more than one sensor
|
||||||
|
# (e.g. both humidity and temperature)
|
||||||
|
devices.append(TelldusLiveSensor(component["id"],
|
||||||
|
component["name"],
|
||||||
|
sensor["name"]))
|
||||||
|
add_devices(devices)
|
||||||
|
|
||||||
|
|
||||||
|
class TelldusLiveSensor(Entity):
|
||||||
|
""" Represents a Telldus Live sensor. """
|
||||||
|
|
||||||
|
def __init__(self, sensor_id, sensor_name, sensor_type):
|
||||||
|
self._sensor_id = sensor_id
|
||||||
|
self._sensor_type = sensor_type
|
||||||
|
self._state = None
|
||||||
|
self._name = sensor_name + ' ' + SENSOR_TYPES[sensor_type][0]
|
||||||
|
self._last_update = None
|
||||||
|
self._battery_level = None
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
""" Returns the name of the device. """
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
""" Returns the state of the device. """
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state_attributes(self):
|
||||||
|
attrs = dict()
|
||||||
|
if self._battery_level is not None:
|
||||||
|
attrs[ATTR_BATTERY_LEVEL] = self._battery_level
|
||||||
|
if self._last_update is not None:
|
||||||
|
attrs[ATTR_LAST_UPDATED] = self._last_update
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
return SENSOR_TYPES[self._sensor_type][1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
return SENSOR_TYPES[self._sensor_type][2]
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
values = tellduslive.NETWORK.get_sensor_value(self._sensor_id,
|
||||||
|
self._sensor_type)
|
||||||
|
self._state, self._battery_level, self._last_update = values
|
||||||
|
|
||||||
|
self._state = float(self._state)
|
||||||
|
if self._sensor_type == SENSOR_TYPE_TEMP:
|
||||||
|
self._state = round(self._state, 1)
|
||||||
|
elif self._sensor_type == SENSOR_TYPE_HUMIDITY:
|
||||||
|
self._state = int(round(self._state))
|
||||||
|
|
||||||
|
self._battery_level = round(self._battery_level * 100 / 255) # percent
|
||||||
|
self._battery_level = "%d %%" % self._battery_level
|
||||||
|
|
||||||
|
self._last_update = str(datetime.fromtimestamp(self._last_update))
|
@ -17,7 +17,7 @@ from homeassistant.helpers.entity import ToggleEntity
|
|||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
||||||
from homeassistant.components import (
|
from homeassistant.components import (
|
||||||
group, discovery, wink, isy994, verisure, zwave)
|
group, discovery, wink, isy994, verisure, zwave, tellduslive)
|
||||||
|
|
||||||
DOMAIN = 'switch'
|
DOMAIN = 'switch'
|
||||||
SCAN_INTERVAL = 30
|
SCAN_INTERVAL = 30
|
||||||
@ -40,6 +40,7 @@ DISCOVERY_PLATFORMS = {
|
|||||||
isy994.DISCOVER_SWITCHES: 'isy994',
|
isy994.DISCOVER_SWITCHES: 'isy994',
|
||||||
verisure.DISCOVER_SWITCHES: 'verisure',
|
verisure.DISCOVER_SWITCHES: 'verisure',
|
||||||
zwave.DISCOVER_SWITCHES: 'zwave',
|
zwave.DISCOVER_SWITCHES: 'zwave',
|
||||||
|
tellduslive.DISCOVER_SWITCHES: 'tellduslive',
|
||||||
}
|
}
|
||||||
|
|
||||||
PROP_TO_ATTR = {
|
PROP_TO_ATTR = {
|
||||||
|
70
homeassistant/components/switch/tellduslive.py
Normal file
70
homeassistant/components/switch/tellduslive.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.switch.tellduslive
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Support for Tellstick switches using Tellstick Net and
|
||||||
|
the Telldus Live online service.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/switch.tellduslive/
|
||||||
|
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.const import (STATE_ON, STATE_OFF, STATE_UNKNOWN)
|
||||||
|
from homeassistant.components import tellduslive
|
||||||
|
from homeassistant.helpers.entity import ToggleEntity
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
DEPENDENCIES = ['tellduslive']
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
""" Find and return Tellstick switches. """
|
||||||
|
switches = tellduslive.NETWORK.get_switches()
|
||||||
|
add_devices([TelldusLiveSwitch(switch["name"],
|
||||||
|
switch["id"])
|
||||||
|
for switch in switches if switch["type"] == "device"])
|
||||||
|
|
||||||
|
|
||||||
|
class TelldusLiveSwitch(ToggleEntity):
|
||||||
|
""" Represents a Tellstick switch. """
|
||||||
|
|
||||||
|
def __init__(self, name, switch_id):
|
||||||
|
self._name = name
|
||||||
|
self._id = switch_id
|
||||||
|
self._state = STATE_UNKNOWN
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
""" Tells Home Assistant to poll this entity. """
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
""" Returns the name of the switch if any. """
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
from tellcore.constants import (
|
||||||
|
TELLSTICK_TURNON, TELLSTICK_TURNOFF)
|
||||||
|
states = {TELLSTICK_TURNON: STATE_ON,
|
||||||
|
TELLSTICK_TURNOFF: STATE_OFF}
|
||||||
|
state = tellduslive.NETWORK.get_switch_state(self._id)
|
||||||
|
self._state = states[state]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
""" True if switch is on. """
|
||||||
|
self.update()
|
||||||
|
return self._state == STATE_ON
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
""" Turns the switch on. """
|
||||||
|
if tellduslive.NETWORK.turn_switch_on(self._id):
|
||||||
|
self._state = STATE_ON
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs):
|
||||||
|
""" Turns the switch off. """
|
||||||
|
if tellduslive.NETWORK.turn_switch_off(self._id):
|
||||||
|
self._state = STATE_OFF
|
210
homeassistant/components/tellduslive.py
Normal file
210
homeassistant/components/tellduslive.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
"""
|
||||||
|
homeassistant.components.tellduslive
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tellduslive Component
|
||||||
|
|
||||||
|
This component adds support for the Telldus Live service.
|
||||||
|
Telldus Live is the online service used with Tellstick Net devices.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/sensor.tellduslive/
|
||||||
|
|
||||||
|
Developer access to the Telldus Live service is neccessary
|
||||||
|
API keys can be aquired from https://api.telldus.com/keys/index
|
||||||
|
|
||||||
|
Tellstick Net devices can be auto discovered using the method described in:
|
||||||
|
https://developer.telldus.com/doxygen/html/TellStickNet.html
|
||||||
|
|
||||||
|
It might be possible to communicate with the Tellstick Net device
|
||||||
|
directly, bypassing the Tellstick Live service.
|
||||||
|
This however is poorly documented and yet not fully supported (?) according to
|
||||||
|
http://developer.telldus.se/ticket/114 and
|
||||||
|
https://developer.telldus.com/doxygen/html/TellStickNet.html
|
||||||
|
|
||||||
|
API requests to certain methods, as described in
|
||||||
|
https://api.telldus.com/explore/sensor/info
|
||||||
|
are limited to one request every 10 minutes
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.loader import get_component
|
||||||
|
from homeassistant import bootstrap
|
||||||
|
from homeassistant.util import Throttle
|
||||||
|
from homeassistant.helpers import validate_config
|
||||||
|
from homeassistant.const import (
|
||||||
|
EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED)
|
||||||
|
|
||||||
|
|
||||||
|
DOMAIN = "tellduslive"
|
||||||
|
DISCOVER_SWITCHES = "tellduslive.switches"
|
||||||
|
DISCOVER_SENSORS = "tellduslive.sensors"
|
||||||
|
|
||||||
|
CONF_PUBLIC_KEY = "public_key"
|
||||||
|
CONF_PRIVATE_KEY = "private_key"
|
||||||
|
CONF_TOKEN = "token"
|
||||||
|
CONF_TOKEN_SECRET = "token_secret"
|
||||||
|
|
||||||
|
REQUIREMENTS = ['tellive-py==0.5.2']
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
NETWORK = None
|
||||||
|
|
||||||
|
# Return cached results if last scan was less then this time ago
|
||||||
|
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=600)
|
||||||
|
|
||||||
|
|
||||||
|
class TelldusLiveData(object):
|
||||||
|
""" Gets the latest data and update the states. """
|
||||||
|
|
||||||
|
def __init__(self, hass, config):
|
||||||
|
|
||||||
|
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
|
||||||
|
from tellive.live import TelldusLive
|
||||||
|
|
||||||
|
self._sensors = []
|
||||||
|
self._switches = []
|
||||||
|
|
||||||
|
self._client = LiveClient(public_key=public_key,
|
||||||
|
private_key=private_key,
|
||||||
|
access_token=token,
|
||||||
|
access_secret=token_secret)
|
||||||
|
self._api = TelldusLive(self._client)
|
||||||
|
|
||||||
|
def update(self, hass, config):
|
||||||
|
""" Send discovery event if component not yet discovered """
|
||||||
|
self._update_sensors()
|
||||||
|
self._update_switches()
|
||||||
|
for component_name, found_devices, discovery_type in \
|
||||||
|
(('sensor', self._sensors, DISCOVER_SENSORS),
|
||||||
|
('switch', self._switches, DISCOVER_SWITCHES)):
|
||||||
|
if len(found_devices):
|
||||||
|
component = get_component(component_name)
|
||||||
|
bootstrap.setup_component(hass, component.DOMAIN, config)
|
||||||
|
hass.bus.fire(EVENT_PLATFORM_DISCOVERED,
|
||||||
|
{ATTR_SERVICE: discovery_type,
|
||||||
|
ATTR_DISCOVERED: {}})
|
||||||
|
|
||||||
|
def _request(self, what, **params):
|
||||||
|
""" Sends a request to the tellstick live API """
|
||||||
|
|
||||||
|
from tellcore.constants import (
|
||||||
|
TELLSTICK_TURNON, TELLSTICK_TURNOFF, TELLSTICK_TOGGLE)
|
||||||
|
|
||||||
|
supported_methods = TELLSTICK_TURNON \
|
||||||
|
| TELLSTICK_TURNOFF \
|
||||||
|
| TELLSTICK_TOGGLE
|
||||||
|
|
||||||
|
default_params = {'supportedMethods': supported_methods,
|
||||||
|
"includeValues": 1,
|
||||||
|
"includeScale": 1}
|
||||||
|
|
||||||
|
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
|
||||||
|
response = self._client.request(what, params)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def check_request(self, what, **params):
|
||||||
|
""" Make request, check result if successful """
|
||||||
|
return self._request(what, **params) == "success"
|
||||||
|
|
||||||
|
def validate_session(self):
|
||||||
|
""" Make a dummy request to see if the session is valid """
|
||||||
|
try:
|
||||||
|
response = self._request("user/profile")
|
||||||
|
return 'email' in response
|
||||||
|
except RuntimeError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
|
def _update_sensors(self):
|
||||||
|
""" Get the latest sensor data from Telldus Live """
|
||||||
|
_LOGGER.info("Updating sensors from Telldus Live")
|
||||||
|
self._sensors = self._request("sensors/list")["sensor"]
|
||||||
|
|
||||||
|
def _update_switches(self):
|
||||||
|
""" Get the configured switches from Telldus Live"""
|
||||||
|
_LOGGER.info("Updating switches from Telldus Live")
|
||||||
|
self._switches = self._request("devices/list")["device"]
|
||||||
|
# filter out any group of switches
|
||||||
|
self._switches = [switch for switch in self._switches
|
||||||
|
if switch["type"] == "device"]
|
||||||
|
|
||||||
|
def get_sensors(self):
|
||||||
|
""" Get the configured sensors """
|
||||||
|
self._update_sensors()
|
||||||
|
return self._sensors
|
||||||
|
|
||||||
|
def get_switches(self):
|
||||||
|
""" Get the configured switches """
|
||||||
|
self._update_switches()
|
||||||
|
return self._switches
|
||||||
|
|
||||||
|
def get_sensor_value(self, sensor_id, sensor_name):
|
||||||
|
""" Get the latest (possibly cached) sensor value """
|
||||||
|
self._update_sensors()
|
||||||
|
for component in self._sensors:
|
||||||
|
if component["id"] == sensor_id:
|
||||||
|
for sensor in component["data"]:
|
||||||
|
if sensor["name"] == sensor_name:
|
||||||
|
return (sensor["value"],
|
||||||
|
component["battery"],
|
||||||
|
component["lastUpdated"])
|
||||||
|
|
||||||
|
def get_switch_state(self, switch_id):
|
||||||
|
""" returns state of switch. """
|
||||||
|
_LOGGER.info("Updating switch state from Telldus Live")
|
||||||
|
return int(self._request("device/info", id=switch_id)["state"])
|
||||||
|
|
||||||
|
def turn_switch_on(self, switch_id):
|
||||||
|
""" turn switch off """
|
||||||
|
return self.check_request("device/turnOn", id=switch_id)
|
||||||
|
|
||||||
|
def turn_switch_off(self, switch_id):
|
||||||
|
""" turn switch on """
|
||||||
|
return self.check_request("device/turnOff", id=switch_id)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(hass, config):
|
||||||
|
""" Setup the tellduslive component """
|
||||||
|
|
||||||
|
# fixme: aquire app key and provide authentication
|
||||||
|
# using username + password
|
||||||
|
if not validate_config(config,
|
||||||
|
{DOMAIN: [CONF_PUBLIC_KEY,
|
||||||
|
CONF_PRIVATE_KEY,
|
||||||
|
CONF_TOKEN,
|
||||||
|
CONF_TOKEN_SECRET]},
|
||||||
|
_LOGGER):
|
||||||
|
_LOGGER.error(
|
||||||
|
"Configuration Error: "
|
||||||
|
"Please make sure you have configured your keys "
|
||||||
|
"that can be aquired from https://api.telldus.com/keys/index")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# fixme: validate key?
|
||||||
|
|
||||||
|
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.update(hass, config)
|
||||||
|
|
||||||
|
return True
|
@ -176,6 +176,9 @@ orvibo==1.1.0
|
|||||||
# homeassistant.components.switch.wemo
|
# homeassistant.components.switch.wemo
|
||||||
pywemo==0.3.3
|
pywemo==0.3.3
|
||||||
|
|
||||||
|
# homeassistant.components.tellduslive
|
||||||
|
tellive-py==0.5.2
|
||||||
|
|
||||||
# homeassistant.components.thermostat.heatmiser
|
# homeassistant.components.thermostat.heatmiser
|
||||||
heatmiserV3==0.9.1
|
heatmiserV3==0.9.1
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user