import time from platypush.backend import Backend from platypush.message.event.sensor import SensorDataChangeEvent, \ SensorDataAboveThresholdEvent, SensorDataBelowThresholdEvent class SensorBackend(Backend): """ Abstract backend for polling sensors. Triggers: * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have gone above a configured threshold * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have gone below a configured threshold """ def __init__(self, thresholds=None, poll_seconds=None, *args, **kwargs): """ :param thresholds: Thresholds can be either a scalar value or a dictionary (e.g. ``{"temperature": 20.0}``). Sensor threshold events will be fired when measurements get above or below these values. Set it as a scalar if your get_measurement() code returns a scalar, as a dictionary if it returns a dictionary of values. For instance, if your sensor code returns both humidity and temperature in a format like ``{'humidity':60.0, 'temperature': 25.0}``, you'll want to set up a threshold on temperature with a syntax like ``{'temperature':20.0}`` to trigger events when the temperature goes above/below 20 degrees. :param poll_seconds: If set, the thread will wait for the specificed number of seconds between a read and the next one. :type poll_seconds: float """ super().__init__(**kwargs) self.data = None self.thresholds = thresholds self.poll_seconds = poll_seconds def get_measurement(self): """ To be implemented in the derived classes """ raise NotImplementedError('To be implemented in a derived class') def run(self): super().run() self.logger.info('Initialized {} sensor backend'.format(self.__class__.__name__)) while not self.should_stop(): new_data = self.get_measurement() if self.data is None or self.data != new_data: self.bus.post(SensorDataChangeEvent(data=new_data)) data_below_threshold = {} data_above_threshold = {} if self.thresholds: if isinstance(self.thresholds, dict) and isinstance(new_data, dict): for (measure, thresholds) in self.thresholds.items(): if measure not in new_data: continue if not isinstance(thresholds, list): thresholds = [thresholds] for threshold in thresholds: if new_data[measure] > threshold and (self.data is None or ( measure in self.data and self.data[measure] <= threshold)): data_above_threshold[measure] = new_data[measure] elif new_data[measure] < threshold and (self.data is None or ( measure in self.data and self.data[measure] >= threshold)): data_below_threshold[measure] = new_data[measure] if data_below_threshold: self.bus.post(SensorDataBelowThresholdEvent(data=data_below_threshold)) if data_above_threshold: self.bus.post(SensorDataAboveThresholdEvent(data=data_above_threshold)) self.data = new_data if self.poll_seconds: time.sleep(self.poll_seconds) # vim:sw=4:ts=4:et: