class Group(Plugin): implements(ITelldusLiveObserver) def __init__(self): self.devices = [] self.deviceManager = DeviceManager(self.context) for d in self.deviceManager.retrieveDevices('group'): p = d.params() device = GroupDevice() self.devices.append(device) device.setNodeId(d.id()) device.setParams(p) self.deviceManager.addDevice(device) self.deviceManager.finishedLoading('group') self.live = TelldusLive(self.context) def addDevice(self, name, devices): if type(devices) != list: return device = GroupDevice() device.setName(name) device.setParams({ 'devices': devices }) self.devices.append(device) self.deviceManager.addDevice(device) @TelldusLive.handler('group') def __handleCommand(self, msg): data = msg.argument(0).toNative() action = data['action'] if action == 'addGroup': self.addDevice(data['name'], data['devices']) elif action == 'editGroup': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: device.setParams({ 'devices': data['devices'], }) device.paramUpdated('') break elif action == 'groupInfo': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: params = device.params() params['deviceId'] = deviceId self.live.pushToWeb('group', 'groupInfo', params) return elif action == 'remove': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: self.deviceManager.removeDevice(deviceId) self.devices.remove(device) return
class RF433(Plugin): implements(ITelldusLiveObserver) fwVersions = {'18F25K50': 1} def __init__(self): self.version = 0 self.hwVersion = None self.devices = [] self.sensors = [] self.rawEnabled = False self.rawEnabledAt = 0 self.dev = Adapter(self, Board.rf433Port()) deviceNode = DeviceNode(self.dev) self.deviceManager = DeviceManager(self.context) self.registerSensorCleanup() for d in self.deviceManager.retrieveDevices('433'): p = d.params() if 'type' not in p: continue if p['type'] == 'sensor': device = SensorNode() self.sensors.append(device) elif p['type'] == 'device': device = DeviceNode(self.dev) self.devices.append(device) else: continue device.setNodeId(d.id()) device.setParams(p) if p['type'] == 'sensor': device._packageCount = 7 # already loaded, keep it that way! device._sensorValues = d._sensorValues device.batteryLevel = d.batteryLevel self.deviceManager.addDevice(device) self.deviceManager.finishedLoading('433') self.dev.queue( RF433Msg('V', success=self.__version, failure=self.__noVersion)) self.dev.queue( RF433Msg('H', success=self.__hwVersion, failure=self.__noHWVersion)) self.live = TelldusLive(self.context) def addDevice(self, protocol, model, name, params): device = DeviceNode(self.dev) device.setName(name) device.setParams({ 'protocol': protocol, 'model': model, 'protocolParams': params }) self.devices.append(device) self.deviceManager.addDevice(device) def cleanupSensors(self): numberOfSensorsBefore = len(self.sensors) for i, sensor in enumerate(self.sensors): if not sensor.isValid(): self.deviceManager.removeDevice(sensor.id()) del self.sensors[i] self.deviceManager.sensorsUpdated() @TelldusLive.handler('rf433') def __handleCommand(self, msg): data = msg.argument(0).toNative() action = data['action'] if action == 'addDevice': self.addDevice(data['protocol'], data['model'], data['name'], data['parameters']) elif action == 'deviceInfo': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: params = device.params() params['deviceId'] = deviceId self.live.pushToWeb('rf433', 'deviceInfo', params) return elif action == 'editDevice': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: device.setParams({ 'protocol': data['protocol'], 'model': data['model'], 'protocolParams': data['parameters'] }) device.paramUpdated('') break elif action == 'remove': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: self.deviceManager.removeDevice(deviceId) self.devices.remove(device) return elif action == 'rawEnabled': if data['value']: self.rawEnabled = True self.rawEnabledAt = time.time() else: self.rawEnabled = False else: logging.warning("Unknown rf433 command %s", action) @signal('rf433RawData') def decode(self, msg): """ Signal send on any raw data received from 433 receiver. Please note that the TellStick must contain a receiver for this signal to be sent. Not all models contains a receiver. """ if 'class' in msg and msg['class'] == 'sensor': self.decodeSensor(msg) return msg = Protocol.decodeData(msg) for m in msg: self.decodeCommandData(m) if self.rawEnabled: if self.rawEnabledAt < (time.time() - 600): # timeout, only allow scan for 10 minutes at a time self.rawEnabled = False continue self.live.pushToWeb('client', 'rawData', m) def decodeCommandData(self, msg): protocol = msg['protocol'] model = msg['model'] method = msg['method'] methods = Protocol.methodsForProtocol(protocol, model) if not method & methods: return for device in self.devices: params = device.params() if params['protocol'] != protocol: continue if not method & device.methods(): continue deviceParams = params['protocolParams'] thisDevice = True for parameter in Protocol.parametersForProtocol(protocol, model): if parameter not in msg: thisDevice = False break if parameter not in deviceParams: thisDevice = False break if msg[parameter] != deviceParams[parameter]: thisDevice = False break if thisDevice: device.setState(method, None) def decodeData(self, cmd, params): if cmd == 'W': self.decode(params) elif cmd == 'V': # New version received, probably after firmware upload self.__version(params) else: logging.debug("Unknown data: %s", str(cmd)) def decodeSensor(self, msg): protocol = Protocol.protocolInstance(msg['protocol']) if not protocol: logging.error("No known protocol for %s", msg['protocol']) return data = protocol.decodeData(msg) if not data: return p = data['protocol'] m = data['model'] sensorId = data['id'] sensorData = data['values'] sensor = None for s in self.sensors: if s.compare(p, m, sensorId): sensor = s break if sensor is None: sensor = SensorNode() sensor.setParams({'protocol': p, 'model': m, 'sensorId': sensorId}) sensor.setManager(self.deviceManager) self.sensors.append(sensor) if 'battery' in data: sensor.batteryLevel = data['battery'] sensor.updateValues(sensorData) """ Register scheduled job to clean up sensors that have not been updated for a while""" def registerSensorCleanup(self): Application().registerScheduledTask(self.cleanupSensors, hours=12) # every 12th hour t = Timer(10, self.cleanupSensors) # run a first time after 10 minutes t.daemon = True t.name = 'Sensor cleanup' t.start() def __noVersion(self): logging.warning( "Could not get firmware version for RF433, force upgrade") def __noHWVersion(self): logging.warning("Could not get hw version for RF433") def __hwVersion(self, version): logging.debug("Got HW version %s", version) self.hwVersion = version if version not in RF433.fwVersions: return fwVersion = RF433.fwVersions[self.hwVersion] if fwVersion != self.version: logging.info("Version %i is to old, update firmware", self.version) # TODO: implement def __version(self, version): self.version = version logging.info("RF433 version: %i", self.version)
class SceneManager(Plugin): implements(ITelldusLiveObserver) def __init__(self): self.scenes = {} self.deviceManager = DeviceManager(self.context) for sceneId in self.config('scenes'): device = SceneDevice(sceneId) self.scenes[sceneId] = device self.deviceManager.addDevice(device) self.deviceManager.finishedLoading('scene') def addDevice(self, name, devices): if type(devices) != dict: return sceneId = str(uuid.uuid4()) device = SceneDevice(sceneId) device.setName(name) device.setParams({'devices': devices}) self.scenes[sceneId] = device self.deviceManager.addDevice(device) scenes = self.config('scenes') scenes.append(sceneId) self.setConfig('scenes', scenes) @TelldusLive.handler('scene') def __handleCommand(self, msg): data = msg.argument(0).toNative() action = data['action'] if action == 'addScene': self.addDevice(data['name'], data['devices']) elif action == 'editScene': deviceId = data['device'] for sceneId in self.scenes: device = self.scenes[sceneId] if device.id() == deviceId: device.setParams({ 'devices': data['devices'], }) device.paramUpdated('') break elif action == 'sceneInfo': deviceId = data['device'] for sceneId in self.scenes: device = self.scenes[sceneId] if device.id() == deviceId: params = device.params() params['deviceId'] = deviceId live = TelldusLive(self.context) live.pushToWeb('scene', 'sceneInfo', params) return elif action == 'remove': deviceId = data['device'] for sceneId in self.scenes: device = self.scenes[sceneId] if device.id() == deviceId: self.deviceManager.removeDevice(deviceId) del self.scenes[sceneId] return
class Hue(Plugin): implements(IWebRequestHandler) implements(IWebReactHandler) implements(ISSDPNotifier) STATE_NO_BRIDGE, STATE_UNAUTHORIZED, STATE_AUTHORIZED = range(3) def __init__(self): self.deviceManager = DeviceManager(self.context) self.username = None self.ssdp = None config = self.config('bridge') self.activated = config.get('activated', False) self.username = config.get('username', '') self.bridge = config.get('bridge', '') self.state = Hue.STATE_NO_BRIDGE self.lights = {} self.ssdp = SSDP(self.context) if self.activated: Application().queue(self.selectBridge, config.get('bridge')) Application().registerScheduledTask(self.update, minutes=1) @mainthread def authorize(self): if self.username is None or self.username == '': data = self.doCall('POST', '/api', '{"devicetype": "Telldus#TellStick"}') resp = data[0] if resp.get('error', {}).get('type', None) == 101: # Unauthorized, the user needs to press the button. Try again in 5 seconds thread = threading.Timer(5.0, self.authorize) thread.name = 'Philips Hue authorization poll timer' thread.daemon = True thread.start() return if 'success' in resp: self.username = resp['success']['username'] self.activated = True self.saveConfig() self.setState(Hue.STATE_AUTHORIZED) else: return # Check if username is ok data = self.doCall('GET', '/api/%s/lights' % self.username) self.setState(Hue.STATE_AUTHORIZED) self.parseLights(data) self.deviceManager.finishedLoading('hue') def doCall(self, requestType, endpoint, body='', bridge=None): if bridge is None: bridge = self.bridge conn = httplib.HTTPConnection(bridge) try: conn.request(requestType, endpoint, body) except Exception: return [{'error': 'Could not connect'}] response = conn.getresponse() try: rawData = response.read() data = json.loads(rawData) except Exception: logging.warning("Could not parse JSON") logging.warning("%s", rawData) return [{'error': 'Could not parse JSON'}] return data def getReactComponents(self): # pylint: disable=R0201 return { 'hue': { 'title': 'Philips Hue', 'script': 'hue/hue.js', } } def matchRequest(self, plugin, path): # pylint: disable=R0201 if plugin != 'hue': return False if path in ['reset', 'state']: return True return False def handleRequest(self, plugin, path, __params, **__kwargs): if plugin != 'hue': return None if path == 'state': if self.state == Hue.STATE_NO_BRIDGE: # If ssdp fails to detect, use the hue remote service self.searchNupnp() return WebResponseJson({'state': self.state}) if path == 'reset': self.setState(Hue.STATE_NO_BRIDGE) return WebResponseJson({'success': True}) def parseLights(self, lights): if isinstance(lights, list) and len(lights) and 'error' in lights[0]: return False oldDevices = self.lights.keys() for i in lights: lightData = lights[i] if 'uniqueid' not in lightData: continue lightId = lightData['uniqueid'] if lightId in oldDevices: # Find any removed lights oldDevices.remove(lightId) name = lightData.get('name', '') if lightId in self.lights: light = self.lights[lightId] if light.name() != name: light.setName(name) else: light = Light(lightId, i, self) self.lights[lightId] = light if 'type' in lightData: light.setType(lightData['type']) self.deviceManager.addDevice(light) light.setName(name) if 'state' in lightData: state = lightData['state'] ourState, ourStateValue = light.state() if state['on'] is False: hueState = Device.TURNOFF hueStateValue = ourStateValue elif state['bri'] == 254: hueState = Device.TURNON hueStateValue = ourStateValue else: hueState = Device.DIM hueStateValue = state['bri'] if ourState != hueState or ourStateValue != hueStateValue: light.setState(hueState, hueStateValue) for lightId in oldDevices: light = self.lights[lightId] self.deviceManager.removeDevice(light.id()) del self.lights[lightId] def saveConfig(self): self.setConfig( 'bridge', { 'bridge': self.bridge, 'username': self.username, 'activated': self.activated, }) def searchNupnp(self): conn = httplib.HTTPSConnection('www.meethue.com') conn.request('GET', '/api/nupnp') response = conn.getresponse() try: rawData = response.read() data = json.loads(rawData) except Exception: logging.warning("Could not parse JSON") logging.warning("%s", rawData) return for bridge in data: if 'internalipaddress' not in bridge: continue self.selectBridge(bridge['internalipaddress']) return def setState(self, newState): if newState == Hue.STATE_NO_BRIDGE: self.bridge = None self.username = None self.activated = False self.saveConfig() elif newState == Hue.STATE_UNAUTHORIZED: Application().queue(self.authorize) elif newState == Hue.STATE_AUTHORIZED: pass self.state = newState # Notify websocket Server(self.context).webSocketSend('hue', 'status', {'state': self.state}) def ssdpDeviceFound(self, device): if device.type != 'basic:1': return url = urlparse.urlparse(device.location) if self.state == Hue.STATE_NO_BRIDGE: self.selectBridge(url.netloc) elif self.state == Hue.STATE_AUTHORIZED: if url.netloc == self.bridge: return # Ip to bridge may have has changed data = self.doCall('GET', '/api/%s/lights' % self.username, bridge=url.netloc) try: if 'error' in data[0]: return except Exception as __error: pass # Save new address self.bridge = url.netloc self.saveConfig() self.parseLights(data) def selectBridge(self, urlbase): if urlbase == '' or urlbase is None: self.setState(Hue.STATE_NO_BRIDGE) return self.bridge = urlbase self.saveConfig() self.setState(Hue.STATE_UNAUTHORIZED) def tearDown(self): self.deviceManager.removeDevicesByType('hue') def update(self): if self.state != Hue.STATE_AUTHORIZED: # Skip return data = self.doCall('GET', '/api/%s/lights' % self.username) self.parseLights(data)
class Group(Plugin): implements(ITelldusLiveObserver) def __init__(self): self.devices = [] self.deviceManager = DeviceManager(self.context) # pylint: disable=too-many-function-args for oldDevice in self.deviceManager.retrieveDevices('group'): params = oldDevice.params() device = GroupDevice() self.devices.append(device) device.setNodeId(oldDevice.id()) device.setParams(params) self.deviceManager.addDevice(device) self.deviceManager.finishedLoading('group') self.live = TelldusLive(self.context) # pylint: disable=too-many-function-args def addDevice(self, uuid, name, devices): if not isinstance(devices, list): return device = GroupDevice() if uuid: device.setUuid(uuid) device.setName(name) device.setParams({'devices': devices}) self.devices.append(device) self.deviceManager.addDevice(device) @TelldusLive.handler('group') def __handleCommand(self, msg): data = msg.argument(0).toNative() action = data['action'] if action == 'addGroup': # Sent from web-v2 application self.addDevice(None, data['name'], data['devices']) elif action == 'addDevice': # Sent from Telldus API self.addDevice( data.get('id', None), data['name'], data.get('parameters', {}).get('devices', []) ) elif action == 'editGroup': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: device.setParams({ 'devices': data['devices'], }) device.paramUpdated('devices') break elif action == 'groupInfo': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: params = device.params() params['deviceId'] = deviceId self.live.pushToWeb('group', 'groupInfo', params) return elif action == 'remove': deviceId = data['device'] for device in self.devices: if device.id() == deviceId: self.deviceManager.removeDevice(deviceId) self.devices.remove(device) return