2018-06-12 00:36:43 +02:00
|
|
|
import time
|
|
|
|
|
2018-06-11 21:07:54 +02:00
|
|
|
from platypush.backend import Backend
|
|
|
|
from platypush.message.event.sensor import SensorDataChangeEvent, \
|
|
|
|
SensorDataAboveThresholdEvent, SensorDataBelowThresholdEvent
|
|
|
|
|
|
|
|
|
|
|
|
class SensorBackend(Backend):
|
2018-06-26 00:16:39 +02:00
|
|
|
"""
|
|
|
|
Abstract backend for polling sensors.
|
|
|
|
|
|
|
|
Triggers:
|
2018-06-12 00:36:43 +02:00
|
|
|
|
2018-06-26 00:16:39 +02:00
|
|
|
* :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed
|
2019-07-02 14:04:25 +02:00
|
|
|
* :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
|
2018-06-26 00:16:39 +02:00
|
|
|
"""
|
2018-06-11 21:07:54 +02:00
|
|
|
|
2019-07-02 14:04:25 +02:00
|
|
|
def __init__(self, thresholds=None, poll_seconds=None, **kwargs):
|
2018-06-26 00:16:39 +02:00
|
|
|
"""
|
2019-07-02 14:04:25 +02:00
|
|
|
: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.
|
2018-06-11 21:07:54 +02:00
|
|
|
|
2018-06-26 00:16:39 +02:00
|
|
|
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.
|
2018-06-11 21:07:54 +02:00
|
|
|
|
2019-07-02 14:04:25 +02:00
|
|
|
:param poll_seconds: If set, the thread will wait for the specified number of seconds between a read and the
|
|
|
|
next one.
|
2018-06-26 00:16:39 +02:00
|
|
|
:type poll_seconds: float
|
2018-06-11 21:07:54 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
super().__init__(**kwargs)
|
2018-06-12 00:36:43 +02:00
|
|
|
|
2018-06-11 22:12:25 +02:00
|
|
|
self.data = None
|
2018-06-11 21:07:54 +02:00
|
|
|
self.thresholds = thresholds
|
2018-06-12 00:36:43 +02:00
|
|
|
self.poll_seconds = poll_seconds
|
2018-06-11 21:07:54 +02:00
|
|
|
|
|
|
|
def get_measurement(self):
|
2019-07-02 14:04:25 +02:00
|
|
|
""" To be implemented by derived classes """
|
2018-06-11 21:07:54 +02:00
|
|
|
raise NotImplementedError('To be implemented in a derived class')
|
|
|
|
|
2018-10-25 20:45:58 +02:00
|
|
|
def run(self):
|
|
|
|
super().run()
|
2018-06-11 23:49:37 +02:00
|
|
|
self.logger.info('Initialized {} sensor backend'.format(self.__class__.__name__))
|
2018-06-11 21:07:54 +02:00
|
|
|
|
|
|
|
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))
|
|
|
|
|
2018-07-15 17:28:13 +02:00
|
|
|
data_below_threshold = {}
|
|
|
|
data_above_threshold = {}
|
|
|
|
|
2018-06-11 21:07:54 +02:00
|
|
|
if self.thresholds:
|
|
|
|
if isinstance(self.thresholds, dict) and isinstance(new_data, dict):
|
2018-08-25 12:29:20 +02:00
|
|
|
for (measure, thresholds) in self.thresholds.items():
|
2018-06-11 21:07:54 +02:00
|
|
|
if measure not in new_data:
|
|
|
|
continue
|
|
|
|
|
2018-08-25 12:29:20 +02:00
|
|
|
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]
|
2018-07-15 17:28:13 +02:00
|
|
|
|
|
|
|
if data_below_threshold:
|
|
|
|
self.bus.post(SensorDataBelowThresholdEvent(data=data_below_threshold))
|
|
|
|
|
|
|
|
if data_above_threshold:
|
|
|
|
self.bus.post(SensorDataAboveThresholdEvent(data=data_above_threshold))
|
|
|
|
|
2018-06-11 21:07:54 +02:00
|
|
|
self.data = new_data
|
|
|
|
|
2018-06-12 00:36:43 +02:00
|
|
|
if self.poll_seconds:
|
|
|
|
time.sleep(self.poll_seconds)
|
|
|
|
|
2018-06-11 21:07:54 +02:00
|
|
|
|
|
|
|
# vim:sw=4:ts=4:et:
|