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
	def __requestLocalKey(self, msg):
		args = msg.argument(0).toNative()
		live = TelldusLive(self.context)
		try:
			publicKey = serialization.load_pem_public_key(
				args.get('publicKey', ''),
				backend=default_backend(),
			)
			ttl = int(time.time()+2629743)  # One month
			accessToken = self.__generateToken({}, {
				'aud': args.get('app', 'Unknown'),
				'exp': ttl,
			})
			ciphertext = publicKey.encrypt(
				str(accessToken),
				padding.OAEP(
					mgf=padding.MGF1(algorithm=hashes.SHA256()),
					algorithm=hashes.SHA256(),
					label=None
				)
			)
		except Exception as error:
			live.pushToWeb('api', 'localkey', {
				'success': False,
				'error': str(error)
			})
			return
		live.pushToWeb('api', 'localkey', {
			'key': base64.b64encode(ciphertext),
			'ttl': ttl,
			'uuid': args.get('uuid', ''),
			'client': live.uuid,
		})
Beispiel #3
0
    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
Beispiel #4
0
    def __webMessage(self, msg):
        live = TelldusLive(self.context)  # pylint: disable=too-many-function-args
        data = msg.argument(0).toNative()
        print("Store", data)
        loader = Loader(self.context)
        if data['action'] == 'getState':
            live.pushToWeb(
                'plugins', 'state', {
                    'plugins':
                    [plugin.infoObject() for plugin in loader.plugins],
                    'suggested': list(loader.suggestedPlugins),
                })
            return

        if data['action'] == 'getStorePlugins':
            live.pushToWeb('plugins', 'storePlugins', self.storePlugins())
            return

        if data['action'] == 'install':
            live.pushToWeb('plugins', 'installStatus',
                           self.installStorePlugin(data.get('plugin')))
            return
Beispiel #5
0
class Scheduler(Plugin):
    implements(ITelldusLiveObserver, IDeviceChange)

    def __init__(self):
        self.running = False
        #self.runningJobsLock = threading.Lock() #TODO needed?
        self.jobsLock = threading.Lock()
        self.maintenanceJobsLock = threading.Lock()
        self.maintenanceJobs = []
        self.lastMaintenanceJobId = 0
        self.runningJobs = {}  #id:s as keys
        self.settings = Settings('telldus.scheduler')
        Application().registerShutdown(self.stop)
        Application().registerMaintenanceJobHandler(
            self.addMaintenanceJobGeneric)
        self.timezone = self.settings.get('tz', 'UTC')
        self.latitude = self.settings.get('latitude', '55.699592')
        self.longitude = self.settings.get('longitude', '13.187836')
        self.jobs = []
        self.fetchLocalJobs()
        self.live = TelldusLive(self.context)
        self.deviceManager = DeviceManager(self.context)
        if self.live.isRegistered():
            #probably not practically possible to end up here
            self.requestJobsFromServer()

        self.thread = threading.Thread(target=self.run)
        self.thread.start()

    def addMaintenanceJobGeneric(self, job):
        self.addMaintenanceJob(job['nextRunTime'], job['callback'],
                               job['recurrence'])

    def addMaintenanceJob(self, nextRunTime, timeoutCallback, recurrence=0):
        """ nextRunTime - GMT timestamp, timeoutCallback - the method to run,
		recurrence - when to repeat it, in seconds
		Returns: An id for the newly added job (for removal and whatnot)
		Note, if the next nextRunTime needs to be calculated, it's better to do that
		in the callback-method, and add a new job from there, instead of using "recurrence" """
        jobData = {
            'nextRunTime': nextRunTime,
            'callback': timeoutCallback,
            'recurrence': recurrence
        }
        with self.maintenanceJobsLock:
            self.lastMaintenanceJobId = self.lastMaintenanceJobId + 1
            jobData[
                'id'] = self.lastMaintenanceJobId  # add an ID, make it possible to remove it someday
            self.maintenanceJobs.append(jobData)
            self.maintenanceJobs.sort(
                key=lambda jobData: jobData['nextRunTime'])
            return self.lastMaintenanceJobId

    def calculateJobs(self, jobs):
        """Calculate nextRunTime for all jobs in the supplied list, order it and assign it to self.jobs"""
        newJobs = []
        for job in jobs:
            self.checkNewlyLoadedJob(job)
            if self.calculateNextRunTime(job):
                newJobs.append(job)

        newJobs.sort(key=lambda job: job['nextRunTime'])
        with self.jobsLock:
            self.jobs = newJobs

    def calculateNextRunTime(self, job):
        """Calculates nextRunTime for a job, depending on time, weekday and timezone."""
        if not job['active'] or not job['weekdays']:
            job['nextRunTime'] = 253402214400  #set to max value, only run just before the end of time
            # just delete the job, until it's possible to edit schedules locally, inactive jobs has
            # no place at all here
            self.deleteJob(job['id'])
            return False
        today = datetime.now(timezone(self.timezone)).weekday()  # normalize?
        weekdays = [int(n) for n in job['weekdays'].split(',')]
        runToday = False
        firstWeekdayToRun = None
        nextWeekdayToRun = None
        runDate = None

        for weekday in weekdays:
            weekday = weekday - 1  #weekdays in python: 0-6, weekdays in our database: 1-7
            if weekday == today:
                runToday = True
            elif today < weekday and (nextWeekdayToRun is None
                                      or nextWeekdayToRun > weekday):
                nextWeekdayToRun = weekday
            elif today > weekday and (firstWeekdayToRun is None
                                      or weekday < firstWeekdayToRun):
                firstWeekdayToRun = weekday

        todayDate = datetime.now(timezone(self.timezone)).date()  # normalize?
        if runToday:
            #this weekday is included in the ones that this schedule should be run on
            runTimeToday = self.calculateRunTimeForDay(todayDate, job)
            if runTimeToday > time.time():
                job['nextRunTime'] = runTimeToday + random.randint(
                    0, job['random_interval']) * 60
                return True
            elif len(weekdays) == 1:
                #this job should only run on this weekday, since it has already passed today, run it next week
                runDate = todayDate + timedelta(days=7)

        if not runDate:
            if nextWeekdayToRun is not None:
                runDate = self.calculateNextWeekday(todayDate,
                                                    nextWeekdayToRun)

            else:
                runDate = self.calculateNextWeekday(todayDate,
                                                    firstWeekdayToRun)

            if not runDate:
                #something is wrong, no weekday to run
                job['nextRunTime'] = 253402214400
                # just delete the job, until it's possible to edit schedules locally, inactive jobs
                # has no place at all here
                self.deleteJob(job['id'])
                return False

        job['nextRunTime'] = self.calculateRunTimeForDay(runDate, job) \
                             + random.randint(0, job['random_interval']) * 60
        return True

    @staticmethod
    def calculateNextWeekday(todayDate, weekday):
        days_ahead = weekday - todayDate.weekday()
        if days_ahead <= 0:  # Target day already happened this week
            days_ahead += 7
        return todayDate + timedelta(days_ahead)

    def calculateRunTimeForDay(self, runDate, job):
        """
		Calculates and returns a timestamp for when this job should be run next.
		Takes timezone into consideration.
		"""
        runDate = datetime(runDate.year, runDate.month, runDate.day)
        if job['type'] == 'time':
            # TODO, sending timezone from the server now, but it's really a client setting, can I
            # get it from somewhere else?
            tzone = timezone(self.timezone)
            # won't random here, since this time may also be used to see if it's passed today or not
            runDate = runDate + timedelta(hours=job['hour'],
                                          minutes=job['minute'])
            # returning a timestamp, corrected for timezone settings
            return timegm(tzone.localize(runDate).utctimetuple())
        elif job['type'] == 'sunrise':
            sunCalc = SunCalculator()
            riseSet = sunCalc.nextRiseSet(timegm(runDate.utctimetuple()),
                                          float(self.latitude),
                                          float(self.longitude))
            return riseSet['sunrise'] + job['offset'] * 60
        elif job['type'] == 'sunset':
            sunCalc = SunCalculator()
            riseSet = sunCalc.nextRiseSet(timegm(runDate.utctimetuple()),
                                          float(self.latitude),
                                          float(self.longitude))
            return riseSet['sunset'] + job['offset'] * 60

    def checkNewlyLoadedJob(self, job):
        """Checks if any of the jobs (local or initially loaded) should be running right now"""
        if not job['active'] or not job['weekdays']:
            return

        weekdays = [int(n) for n in job['weekdays'].split(',')]
        i = 0
        while i < 2:
            #Check today and yesterday (might be around 12 in the evening)
            currentDate = date.today() + timedelta(days=-i)
            if (currentDate.weekday() + 1) in weekdays:
                #check for this day (today or yesterday)
                runTime = self.calculateRunTimeForDay(currentDate, job)
                runTimeMax = runTime + job['reps'] * 3 \
                             + job['retry_interval'] * 60 * (job['retries'] + 1) \
                             + 70 \
                             + job['random_interval'] * 60
                jobId = job['id']
                executedJobs = self.settings.get('executedJobs', {})
                if (str(jobId) not in executedJobs or executedJobs[str(jobId)] < runTime) \
                   and time.time() > runTime \
                   and time.time() < runTimeMax:
                    # run time for this job was passed during downtime, but it was passed within the
                    # max-runtime, and the last time it was executed (successfully) was before this
                    # run time, so it should be run again...
                    jobCopy = copy.deepcopy(job)
                    jobCopy['originalRepeats'] = job['reps']
                    jobCopy['nextRunTime'] = runTime
                    jobCopy[
                        'maxRunTime'] = runTimeMax  #approximate maxRunTime, sanity check
                    self.runningJobs[jobId] = jobCopy
                    return
            i = i + 1

    def deleteJob(self, jobId):
        with self.jobsLock:
            # Test this! It should be fast and keep original reference, they say (though it will
            # iterate all, even if it could end after one)
            self.jobs[:] = [x for x in self.jobs if x['id'] != jobId]
            if jobId in self.runningJobs:  #TODO this might require a lock too?
                self.runningJobs[jobId]['retries'] = 0

            executedJobs = self.settings.get('executedJobs', {})
            if str(jobId) in executedJobs:
                del executedJobs[str(jobId)]
                self.settings['executedJobs'] = executedJobs

    def deviceRemoved(self, deviceId):
        jobsToDelete = []
        for job in self.jobs:
            if job['id'] == deviceId:
                jobsToDelete.append[job['id']]
        for jobId in jobsToDelete:
            self.deleteJob(jobId)

    def fetchLocalJobs(self):
        """Fetch local jobs from settings"""
        try:
            jobs = self.settings.get('jobs', [])
        except ValueError:
            jobs = [
            ]  #something bad has been stored, just ignore it and continue?
            print "WARNING: Could not fetch schedules from local storage"
        self.calculateJobs(jobs)

    def liveRegistered(self, msg):
        if 'latitude' in msg:
            self.latitude = msg['latitude']
        if 'longitude' in msg:
            self.longitude = msg['longitude']
        if 'tz' in msg:
            self.timezone = msg['tz']

        self.requestJobsFromServer()

    @TelldusLive.handler('scheduler-remove')
    def removeOneJob(self, msg):
        if len(msg.argument(0).toNative()) != 0:
            scheduleDict = msg.argument(0).toNative()
            jobId = scheduleDict['id']
            self.deleteJob(jobId)
            self.settings['jobs'] = self.jobs  #save to storage
            self.live.pushToWeb('scheduler', 'removed', jobId)

    @TelldusLive.handler('scheduler-report')
    def receiveJobsFromServer(self, msg):
        """Receive list of jobs from server, saves to settings and calculate nextRunTimes"""
        if len(msg.argument(0).toNative()) == 0:
            jobs = []
        else:
            scheduleDict = msg.argument(0).toNative()
            jobs = scheduleDict['jobs']
        self.settings['jobs'] = jobs
        self.calculateJobs(jobs)

    @TelldusLive.handler('scheduler-update')
    def receiveOneJobFromServer(self, msg):
        """Receive one job from server, add or edit, save to settings and calculate nextRunTime"""
        if len(msg.argument(0).toNative()) == 0:
            jobs = []
        else:
            scheduleDict = msg.argument(0).toNative()
            job = scheduleDict['job']

        active = self.calculateNextRunTime(job)
        self.deleteJob(
            job['id'])  #delete the job if it already exists (update)
        if active:
            with self.jobsLock:
                self.jobs.append(job)
                self.jobs.sort(key=lambda job: job['nextRunTime'])
        self.settings['jobs'] = self.jobs  #save to storage
        # TODO is this a good idea? Trying to avoid cache problems where updates haven't come through?
        # But this may not work if the same schedule is saved many times in a row, or if changes
        # wasn't saved correctly to the database (not possible yet, only one database for schedules)
        # self.live.pushToWeb('scheduler', 'updated', job['id'])

    def requestJobsFromServer(self):
        self.live.send(LiveMessage("scheduler-requestjob"))

    def run(self):
        self.running = True
        while self.running:
            maintenanceJob = None
            with self.maintenanceJobsLock:
                if len(
                        self.maintenanceJobs
                ) > 0 and self.maintenanceJobs[0]['nextRunTime'] < time.time():
                    maintenanceJob = self.maintenanceJobs.pop(0)
            self.runMaintenanceJob(maintenanceJob)

            jobCopy = None
            with self.jobsLock:
                if len(self.jobs
                       ) > 0 and self.jobs[0]['nextRunTime'] < time.time():
                    #a job has passed its nextRunTime
                    job = self.jobs[0]
                    jobId = job['id']
                    jobCopy = copy.deepcopy(
                        job)  #make a copy, don't edit the original job

            if jobCopy:
                jobCopy['originalRepeats'] = job['reps']
                # approximate maxRunTime, sanity check
                jobCopy['maxRunTime'] = jobCopy['nextRunTime'] \
                                        + jobCopy['reps'] * 3 \
                                        + jobCopy['retry_interval'] * 60 * (jobCopy['retries'] + 1) \
                                        + 70 \
                                        + jobCopy['random_interval'] * 60
                self.runningJobs[jobId] = jobCopy
                self.calculateNextRunTime(job)
                with self.jobsLock:
                    self.jobs.sort(key=lambda job: job['nextRunTime'])

            jobsToRun = [
            ]  # jobs to run in a separate list, to avoid deadlocks (necessary?)
            # Iterating using .keys(9 since we are modifiyng the dict while iterating
            for runningJobId in self.runningJobs.keys():  # pylint: disable=C0201
                runningJob = self.runningJobs[runningJobId]
                if runningJob['nextRunTime'] < time.time():
                    if runningJob['maxRunTime'] > time.time():
                        if 'client_device_id' not in runningJob:
                            print "Missing client_device_id, this is an error, perhaps refetch jobs? "
                            print runningJob
                            continue
                        device = self.deviceManager.device(
                            runningJob['client_device_id'])
                        if not device:
                            print "Missing device, b: " + str(
                                runningJob['client_device_id'])
                            continue
                        if device.typeString(
                        ) == '433' and runningJob['originalRepeats'] > 1:
                            #repeats for 433-devices only
                            runningJob['reps'] = int(runningJob['reps']) - 1
                            if runningJob['reps'] >= 0:
                                runningJob['nextRunTime'] = time.time() + 3
                                jobsToRun.append(runningJob)
                                continue

                        if runningJob['retries'] > 0:
                            runningJob['nextRunTime'] = time.time() + (
                                runningJob['retry_interval'] * 60)
                            runningJob['retries'] = runningJob['retries'] - 1
                            runningJob['reps'] = runningJob['originalRepeats']
                            jobsToRun.append(runningJob)
                            continue

                    del self.runningJobs[
                        runningJobId]  #max run time passed or out of retries

            for jobToRun in jobsToRun:
                self.runJob(jobToRun)

            # TODO decide on a time (how often should we check for jobs to run, what resolution?)
            time.sleep(5)

    def stop(self):
        self.running = False

    def successfulJobRun(self, jobId, state, stateValue):
        """
		Called when job run was considered successful (acked by Z-Wave or sent away from 433),
		repeats should still be run
		"""
        del state, stateValue
        # save timestamp for when this was executed, to avoid rerun within maxRunTime on restart
        # TODO is this too much writing?
        executedJobs = self.settings.get('executedJobs', {})
        executedJobs[str(jobId)] = time.time(
        )  #doesn't work well with int type, for some reason
        self.settings['executedJobs'] = executedJobs
        #executedJobsTest = self.settings.get('executedJobs', {})
        if jobId in self.runningJobs:
            self.runningJobs[jobId]['retries'] = 0

    @mainthread
    def runJob(self, jobData):
        device = self.deviceManager.device(jobData['client_device_id'])
        if not device:
            print "Missing device: " + str(jobData['client_device_id'])
            return
        method = jobData['method']
        value = None
        if 'value' in jobData:
            value = jobData['value']

        device.command(method,
                       value=value,
                       origin='Scheduler',
                       success=self.successfulJobRun,
                       callbackArgs=[jobData['id']])

    @mainthread
    def runMaintenanceJob(self, jobData):
        if not jobData:
            return
        if jobData['recurrence']:
            # readd the job for another run
            self.addMaintenanceJob(time.time() + jobData['recurrence'],
                                   jobData['callback'], jobData['recurrence'])
        jobData['callback']()
Beispiel #6
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 #7
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