class SqueezeBox(Plugin):
    def __init__(self):
        self.deviceManager = DeviceManager(self.context)
        self.loaded = False
        if self.config('hostname') != '':
            self.setHostname(self.config('hostname'))

    def configWasUpdated(self, key, value):
        if key == 'hostname':
            self.setHostname(value)

    def setHostname(self, hostname):
        if self.loaded:
            logging.warning('Cannot change hostname, without a restart')
            return
        self.sc = Server(hostname=hostname)
        try:
            self.sc.connect()
        except:
            logging.error("Cannot connect to squeezebox server")
            return
        for player in self.sc.players:
            self.deviceManager.addDevice(Player(player))
        self.deviceManager.finishedLoading('squeezebox')
        self.loaded = True
Пример #2
0
class Eliq(Plugin):
    def __init__(self):
        self.deviceManager = DeviceManager(self.context)
        self.sensor = None
        Application().registerScheduledTask(self.__requestNewValue,
                                            minutes=1,
                                            runAtOnce=True)

    def __requestNewValue(self):
        accessToken = self.config('accessToken')
        if accessToken == '':
            return
        try:
            eliq = eliqonline.API(accessToken)
            data_now = eliq.get_data_now()
        except HTTPError as e:
            # Something wrong with our request apparantly
            logging.error('Could not request Eliq value %s', e)
            return
        except Exception as e:
            # Something wrong with our request apparantly
            logging.error('Could not request Eliq value %s', e)
            return
        if self.sensor is None:
            self.sensor = EliqSensor(data_now.channelid)
            self.sensor.setSensorValue(Sensor.WATT, data_now.power,
                                       Sensor.SCALE_POWER_WATT)
            self.deviceManager.addDevice(self.sensor)
            self.deviceManager.finishedLoading('eliq')
        else:
            self.sensor.setSensorValue(Sensor.WATT, data_now.power,
                                       Sensor.SCALE_POWER_WATT)
Пример #3
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
Пример #4
0
 def __init__(self):
     self.sensor = YRSensor()
     deviceManager = DeviceManager(self.context)
     deviceManager.addDevice(self.sensor)
     deviceManager.finishedLoading('yr')
     Application().registerScheduledTask(self.__requestWeather,
                                         hours=1,
                                         runAtOnce=True)
Пример #5
0
		def parseValues(overview):
			# Running in the main thread
			deviceManager = DeviceManager(self.context)

			self.armState = overview.get('armState', {}).get('statusType', '')
			# Main box
			if self.alarmDevice.updateStatus(overview['armState']):
				# Send signal
				self.verisureArmStateChanged(overview['armState']['date'], overview['armState']['statusType'], overview['armState']['name'], overview['armState']['changedVia'])

			# Door/Window sensors
			for door in overview.get('doorWindow', {}).get('doorWindowDevice', []):
				deviceLabel = door['deviceLabel']
				if deviceLabel not in self.devices:
					device = DoorWindowDevice(door)
					self.devices[deviceLabel] = device
					deviceManager.addDevice(device)
				else:
					device = self.devices[deviceLabel]
				device.updateStatus(door)

			# Climate values
			for climate in overview.get('climateValues', []):
				deviceLabel = climate['deviceLabel']
				if deviceLabel not in self.devices:
					device = ClimateDevice(climate)
					self.devices[deviceLabel] = device
					deviceManager.addDevice(device)
				else:
					device = self.devices[deviceLabel]
				device.updateValues(climate)

			# Smart plugs
			for plug in overview.get('smartPlugs', []):
				deviceLabel = plug['deviceLabel']
				if deviceLabel not in self.devices:
					device = SmartPlugDevice(plug, self)
					self.devices[deviceLabel] = device
					deviceManager.addDevice(device)
				else:
					device = self.devices[deviceLabel]
				device.updateValues(plug)

			# Door locks
			for lock in overview.get('doorLockStatusList', []):
				deviceLabel = lock['deviceLabel']
				if deviceLabel not in self.devices:
					device = DoorLockDevice(lock)
					self.devices[deviceLabel] = device
					deviceManager.addDevice(device)
				else:
					device = self.devices[deviceLabel]
				device.updateStatus(lock)

			if self.loaded == False:
				deviceManager.finishedLoading('verisure')
				self.loaded = True
Пример #6
0
 def discover(self):
     deviceManager = DeviceManager(self.context)
     for light in self.lifxClient.get_devices():
         try:
             device = LifxDevice(light)
         except Exception:
             continue
         deviceManager.addDevice(device)
     deviceManager.finishedLoading('lifx')
Пример #7
0
 def __init__(self):
     self.lastCheckedDate = None
     self.device = HolidayDevice()
     deviceManager = DeviceManager(self.context)
     deviceManager.addDevice(self.device)
     deviceManager.finishedLoading('holiday')
     Application().registerScheduledTask(self.checkDay,
                                         minutes=1,
                                         runAtOnce=False)
Пример #8
0
 def __scanDevices(self):
     l = soco.discover()
     if l is None:
         # No found, this could be an error. Don't remove all old. Try to check them manually
         self.__loadCached()
         return
     deviceManager = DeviceManager(self.context)
     for s in l:
         deviceManager.addDevice(SonosDevice(s))
     deviceManager.finishedLoading('sonos')
Пример #9
0
class Dummy(Plugin):
    '''This is the plugins main entry point and is a singleton
	Manage and load the plugins here
	'''
    def __init__(self):
        # The devicemanager is a globally manager handling all device types
        self.deviceManager = DeviceManager(self.context)

        # Load all devices this plugin handles here. Individual settings for the devices
        # are handled by the devicemanager
        self.deviceManager.addDevice(DummyDevice())

        # When all devices has been loaded we need to call finishedLoading() to tell
        # the manager we are finished. This clears old devices and caches
        self.deviceManager.finishedLoading('dummy')
Пример #10
0
class Lifx(Plugin):
    def __init__(self):
        self.deviceManager = DeviceManager(self.context)
        self.lifxClient = lifx.Client()
        Timer(2.0, self.discover).start()

    @mainthread
    def discover(self):
        for light in self.lifxClient.get_devices():
            try:
                d = LifxDevice(light)
            except Exception:
                continue
            self.deviceManager.addDevice(d)
        self.deviceManager.finishedLoading('lifx')
Пример #11
0
class Broadlink(Plugin):
    def __init__(self):
        self.deviceManager = DeviceManager(self.context)
        self.devices = None
        thread = Thread(target=self.detectBroadlink,
                        name="Detect Broadlink Devices")
        thread.start()

    def detectBroadlink(self):
        self.devices = broadlink.discover(timeout=5)
        for device in self.devices:
            self.deviceManager.addDevice(BroadDevice(device))
        self.deviceManager.finishedLoading('broadlink')
        Application().registerScheduledTask(self.updateValues,
                                            seconds=300,
                                            runAtOnce=True)

    def tearDown(self):
        self.deviceManager.removeDevicesByType('broadlink')

    def updateValues(self):
        for device in self.deviceManager.retrieveDevices("broadlink"):
            device.updateValue()
class Temperature(Plugin):
    '''This is the plugins main entry point and is a singleton
	Manage and load the plugins here
	'''
    def __init__(self):
        # The devicemanager is a globally manager handling all device types
        self.deviceManager = DeviceManager(self.context)

        # Load all devices this plugin handles here. Individual settings for the devices
        # are handled by the devicemanager
        self.sensor = TemperatureSensor()
        self.deviceManager.addDevice(self.sensor)

        # When all devices has been loaded we need to call finishedLoading() to tell
        # the manager we are finished. This clears old devices and caches
        self.deviceManager.finishedLoading('temperature')

        Application().registerScheduledTask(self.updateValues,
                                            minutes=1,
                                            runAtOnce=True)

    def updateValues(self):
        self.sensor.updateValue()
Пример #13
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
Пример #14
0
 def loadDevices(self):
     deviceManager = DeviceManager(self.context)
     for dev in TPLinkSmartHomeProtocol.discover():
         plug = SmartPlug(dev['ip'])
         deviceManager.addDevice(TPLinkDevice(plug))
     deviceManager.finishedLoading('tplink')
Пример #15
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)
Пример #16
0
class Netatmo(Plugin):
    implements(IWebRequestHandler)
    implements(IWebReactHandler)

    supportedTypes = {
        'Temperature': (Sensor.TEMPERATURE, Sensor.SCALE_TEMPERATURE_CELCIUS),
        'Humidity': (Sensor.HUMIDITY, Sensor.SCALE_HUMIDITY_PERCENT),
        #'CO2': (Sensor.UNKNOWN, Sensor.SCALE_UNKNOWN),
        #'Noise':,
        'Pressure':
        (Sensor.BAROMETRIC_PRESSURE, Sensor.SCALE_BAROMETRIC_PRESSURE_KPA),
        'Rain': (Sensor.RAINRATE, Sensor.SCALE_RAINRATE_MMH),
        'sum_rain_24': (Sensor.RAINTOTAL, Sensor.SCALE_RAINTOTAL_MM),
        'WindAngle': (Sensor.WINDDIRECTION, Sensor.SCALE_WIND_DIRECTION),
        'WindStrength': (Sensor.WINDAVERAGE, Sensor.SCALE_WIND_VELOCITY_MS),
        'GustStrength': (Sensor.WINDGUST, Sensor.SCALE_WIND_VELOCITY_MS),
    }
    products = {
        #		'NAMain': {}  # Base station
        'NAModule1': {
            'batteryMax': 6000,
            'batteryMin': 3600
        },  # Outdoor module
        'NAModule4': {
            'batteryMax': 6000,
            'batteryMin': 4200
        },  # Additional indoor module
        'NAModule3': {
            'batteryMax': 6000,
            'batteryMin': 3600
        },  # Rain gauge
        'NAModule2': {
            'batteryMax': 6000,
            'batteryMin': 3950
        },  # Wind gauge
        #		'NAPlug': {},  # Thermostat relay/plug
        #		'NATherm1': {},  # Thermostat module
    }

    def __init__(self):
        self.deviceManager = DeviceManager(self.context)
        self.sensors = {}
        self.loaded = False
        self.clientId = ''
        self.clientSecret = ''
        config = self.config('oauth')
        self.accessToken = config.get('accessToken', '')
        self.refreshToken = config.get('refreshToken', '')
        if self.accessToken is not '':
            self.configuration['oauth'].activated = True
        self.tokenTTL = config.get('tokenTTL', 0)
        Application().registerScheduledTask(self.__requestNewValues,
                                            minutes=10,
                                            runAtOnce=True)

    def getReactComponents(self):
        return {
            'netatmo': {
                'title': 'Netatmo',
                'script': 'netatmo/netatmo.js',
            }
        }

    def matchRequest(self, plugin, path):
        if plugin != 'netatmo':
            return False
        if path in ['activate', 'code', 'logout']:
            return True
        return False

    def handleRequest(self, plugin, path, params, request, **kwargs):
        # Web requests
        if path in ['activate', 'code']:
            service = rauth.OAuth2Service(
                client_id=self.clientId,
                client_secret=self.clientSecret,
                access_token_url='https://api.netatmo.net/oauth2/token',
                authorize_url='https://api.netatmo.net/oauth2/authorize')
            if path == 'activate':
                params = {
                    'redirect_uri': '%s/netatmo/code' % request.base(),
                    'response_type': 'code'
                }
                url = service.get_authorize_url(**params)
                return WebResponseJson({'url': url})
            if path == 'code':
                data = {
                    'code': params['code'],
                    'grant_type': 'authorization_code',
                    'redirect_uri': '%s/netatmo/code' % request.base()
                }
                session = service.get_auth_session(
                    data=data, decoder=self.__decodeAccessToken)
                return WebResponseRedirect('%s/plugins?settings=netatmo' %
                                           request.base())
        if path == 'logout':
            self.accessToken = ''
            self.refreshToken = ''
            self.tokenTTL = 0
            self.setConfig(
                'oauth', {
                    'accessToken': self.accessToken,
                    'refreshToken': self.refreshToken,
                    'tokenTTL': self.tokenTTL,
                })
            self.configuration['oauth'].activated = False
            return WebResponseJson({'success': True})
        return None

    def __addUpdateDevice(self, data):
        if data['_id'] not in self.sensors:
            sensor = NetatmoModule(data['_id'], data['module_name'],
                                   data['type'])
            self.deviceManager.addDevice(sensor)
            self.sensors[data['_id']] = sensor
        else:
            sensor = self.sensors[data['_id']]
        for dataType in Netatmo.supportedTypes:
            if dataType not in data['dashboard_data']:
                continue
            valueType, scale = Netatmo.supportedTypes[dataType]
            value = data['dashboard_data'][dataType]
            if dataType == 'WindStrength' or dataType == 'GustStrength':
                value = round(value / 3.6,
                              2)  # Data is reported in km/h, we want m/s
            elif dataType == 'Pressure':
                value = round(value /
                              10.0)  # Data is reported in mbar, we want kPa
            sensor.setSensorValue(valueType, value, scale)
        if 'battery_vp' in data and data['type'] in Netatmo.products:
            product = Netatmo.products[data['type']]
            battery = 1.0 * max(min(data['battery_vp'], product['batteryMax']),
                                product['batteryMin'])
            sensor.batteryLevel = int(
                (battery - product['batteryMin']) /
                (product['batteryMax'] - product['batteryMin']) * 100)

    @mainthread
    def __parseValues(self, data):
        if 'body' not in data:
            return
        body = data['body']
        if 'devices' not in body:
            return
        devices = body['devices']
        for device in devices:
            self.__addUpdateDevice(device)
            for module in device['modules']:
                self.__addUpdateDevice(module)
        if self.loaded == False:
            self.loaded = True
            self.deviceManager.finishedLoading('netatmo')

    def __requestNewValues(self):
        if self.accessToken == '':
            return

        def backgroundTask():
            service = rauth.OAuth2Service(
                client_id=self.clientId,
                client_secret=self.clientSecret,
                access_token_url='https://api.netatmo.net/oauth2/token')
            if time.time() > self.tokenTTL:
                session = self.__requestSession(service)
            else:
                session = rauth.OAuth2Session(self.clientId,
                                              self.clientSecret,
                                              access_token=self.accessToken,
                                              service=service)
            response = session.get(
                'https://api.netatmo.com/api/getstationsdata')
            data = response.json()
            if 'error' in data and data['error']['code'] in [2, 3]:
                # Token is expired. Request new
                session = self.__requestSession(service)
                response = session.get(
                    'https://api.netatmo.com/api/getstationsdata')
                data = response.json()
            self.__parseValues(data)

        Thread(target=backgroundTask).start()

    def __requestSession(self, service):
        data = {
            'grant_type': 'refresh_token',
            'refresh_token': self.refreshToken
        }
        session = service.get_auth_session(data=data,
                                           decoder=self.__decodeAccessToken)
        return session

    def __decodeAccessToken(self, data):
        response = json.loads(data)
        self.accessToken = response['access_token']
        self.refreshToken = response['refresh_token']
        self.tokenTTL = int(time.time()) + response['expires_in']
        self.setConfig(
            'oauth', {
                'accessToken': self.accessToken,
                'refreshToken': self.refreshToken,
                'tokenTTL': self.tokenTTL,
            })
        self.configuration['oauth'].activated = True
        return response
Пример #17
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
Пример #18
0
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)