Beispiel #1
0
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
Beispiel #2
0
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)
Beispiel #3
0
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)
Beispiel #5
0
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