forked from home-assistant/core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tellstick.py
208 lines (159 loc) · 6.78 KB
/
tellstick.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
"""
Tellstick Component.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/Tellstick/
"""
import logging
import threading
import voluptuous as vol
from homeassistant.helpers import discovery
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.helpers.entity import Entity
DOMAIN = 'tellstick'
REQUIREMENTS = ['tellcore-py==1.1.2']
_LOGGER = logging.getLogger(__name__)
ATTR_SIGNAL_REPETITIONS = 'signal_repetitions'
DEFAULT_SIGNAL_REPETITIONS = 1
ATTR_DISCOVER_DEVICES = 'devices'
ATTR_DISCOVER_CONFIG = 'config'
# Use a global tellstick domain lock to handle Tellcore errors then calling
# to concurrently
TELLSTICK_LOCK = threading.Lock()
# Keep a reference the the callback registry. Used from entities that register
# callback listeners
TELLCORE_REGISTRY = None
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Optional(ATTR_SIGNAL_REPETITIONS,
default=DEFAULT_SIGNAL_REPETITIONS): vol.Coerce(int),
}),
}, extra=vol.ALLOW_EXTRA)
def _discover(hass, config, found_devices, component_name):
"""Setup and send the discovery event."""
if not len(found_devices):
return
_LOGGER.info(
"Discovered %d new %s devices", len(found_devices), component_name)
signal_repetitions = config[DOMAIN].get(ATTR_SIGNAL_REPETITIONS)
discovery.load_platform(hass, component_name, DOMAIN, {
ATTR_DISCOVER_DEVICES: found_devices,
ATTR_DISCOVER_CONFIG: signal_repetitions}, config)
def setup(hass, config):
"""Setup the Tellstick component."""
# pylint: disable=global-statement, import-error
global TELLCORE_REGISTRY
import tellcore.telldus as telldus
import tellcore.constants as tellcore_constants
from tellcore.library import DirectCallbackDispatcher
core = telldus.TelldusCore(callback_dispatcher=DirectCallbackDispatcher())
TELLCORE_REGISTRY = TellstickRegistry(hass, core)
devices = core.devices()
# Register devices
TELLCORE_REGISTRY.register_devices(devices)
# Discover the switches
_discover(hass, config, [switch.id for switch in
devices if not switch.methods(
tellcore_constants.TELLSTICK_DIM)],
'switch')
# Discover the lights
_discover(hass, config, [light.id for light in
devices if light.methods(
tellcore_constants.TELLSTICK_DIM)],
'light')
return True
class TellstickRegistry(object):
"""Handle everything around Tellstick callbacks.
Keeps a map device ids to home-assistant entities.
Also responsible for registering / cleanup of callbacks.
All device specific logic should be elsewhere (Entities).
"""
def __init__(self, hass, tellcore_lib):
"""Initialize the Tellstick mappings and callbacks."""
self._core_lib = tellcore_lib
# used when map callback device id to ha entities.
self._id_to_entity_map = {}
self._id_to_device_map = {}
self._setup_device_callback(hass, tellcore_lib)
def _device_callback(self, tellstick_id, method, data, cid):
"""Handle the actual callback from Tellcore."""
entity = self._id_to_entity_map.get(tellstick_id, None)
if entity is not None:
entity.set_tellstick_state(method, data)
entity.update_ha_state()
def _setup_device_callback(self, hass, tellcore_lib):
"""Register the callback handler."""
callback_id = tellcore_lib.register_device_event(self._device_callback)
def clean_up_callback(event):
"""Unregister the callback bindings."""
if callback_id is not None:
tellcore_lib.unregister_callback(callback_id)
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, clean_up_callback)
def register_entity(self, tellcore_id, entity):
"""Register a new entity to receive callback updates."""
self._id_to_entity_map[tellcore_id] = entity
def register_devices(self, devices):
"""Register a list of devices."""
self._id_to_device_map.update(
{device.id: device for device in devices})
def get_device(self, tellcore_id):
"""Return a device by tellcore_id."""
return self._id_to_device_map.get(tellcore_id, None)
class TellstickDevice(Entity):
"""Representation of a Tellstick device.
Contains the common logic for all Tellstick devices.
"""
def __init__(self, tellstick_device, signal_repetitions):
"""Initalize the Tellstick device."""
self.signal_repetitions = signal_repetitions
self._state = None
self.tellstick_device = tellstick_device
# Add to id to entity mapping
TELLCORE_REGISTRY.register_entity(tellstick_device.id, self)
# Query tellcore for the current state
self.update()
@property
def should_poll(self):
"""Tell Home Assistant not to poll this entity."""
return False
@property
def assumed_state(self):
"""Tellstick devices are always assumed state."""
return True
@property
def name(self):
"""Return the name of the switch if any."""
return self.tellstick_device.name
def set_tellstick_state(self, last_command_sent, last_data_sent):
"""Set the private switch state."""
raise NotImplementedError(
"set_tellstick_state needs to be implemented.")
def _send_tellstick_command(self, command, data):
"""Do the actual call to the tellstick device."""
raise NotImplementedError(
"_call_tellstick needs to be implemented.")
def call_tellstick(self, command, data=None):
"""Send a command to the device."""
from tellcore.library import TelldusError
with TELLSTICK_LOCK:
try:
for _ in range(self.signal_repetitions):
self._send_tellstick_command(command, data)
# Update the internal state
self.set_tellstick_state(command, data)
self.update_ha_state()
except TelldusError:
_LOGGER.error(TelldusError)
def update(self):
"""Poll the current state of the device."""
import tellcore.constants as tellcore_constants
from tellcore.library import TelldusError
try:
last_command = self.tellstick_device.last_sent_command(
tellcore_constants.TELLSTICK_TURNON |
tellcore_constants.TELLSTICK_TURNOFF |
tellcore_constants.TELLSTICK_DIM
)
last_value = self.tellstick_device.last_sent_value()
self.set_tellstick_state(last_command, last_value)
except TelldusError:
_LOGGER.error(TelldusError)