def test_function_filter(self): """Verify the function filter class """ s = ValueListSensor(1, value_stream) st = SensorAsOutputThing(s) captured_list_ref = [[]] got_completed_ref = [ False, ] def on_next(self, x): captured_list_ref[0].append(x.val) self._dispatch_next(x) def on_completed(self): got_completed_ref[0] = True self._dispatch_completed() ff = FunctionFilter(st, on_next=on_next, on_completed=on_completed) vo = ValidationInputThing(value_stream, self.test_function_filter) ff.connect(vo) st.print_downstream() scheduler = Scheduler(asyncio.get_event_loop()) scheduler.schedule_periodic(st, 0.5) # sample twice every second scheduler.run_forever() self.assertTrue( vo.completed, "Schedule exited before validation observer completed") self.assertEqual(value_stream, captured_list_ref[0]) self.assertTrue(got_completed_ref[0]) print("That's all folks")
def test_gpio(self): import thingflow.adapters.rpi.gpio o = thingflow.adapters.rpi.gpio.GpioPinOut() sensor_thing = SensorAsOutputThing(ValueListSensor("sensor-1", values)) sensor_thing.map(lambda evt: evt.val > 0).passthrough( output()).connect(o) s = Scheduler(asyncio.get_event_loop()) s.schedule_periodic(sensor_thing, 1.0) s.run_forever()
def test_client_only(self): SENSOR_ID = 'sensor-1' TOPIC = get_topic_name(self) sensor = SensorAsOutputThing(ValueListSensor(SENSOR_ID, VALUES)) td = sensor.transduce(PeriodicMedianTransducer(period=3)) qw = QueueWriter(td, URL, TOPIC, self.sched) qw.output() self.sched.schedule_periodic(sensor, 0.5) self.sched.run_forever() self.assertFalse( qw.has_pending_requests(), "QueueWriter has pending requests: %s" % qw.dump_state()) print("test_client_only completed")
def setup(broker, threshold): lux = SensorAsOutputThing(LuxSensor()) lux.connect(print) led = GpioPinOut() actions = lux.map(lambda event: event.val > threshold) actions.connect(led) actions.connect(lambda v: print('ON' if v else 'OFF')) lux.to_json().connect(MQTTWriter(broker, topics=[('bogus/bogus', 0)])) lux.print_downstream() return (lux, led)
def setup(threshold=25): lux = SensorAsOutputThing(LuxSensor()) lux.connect(print) lux.csv_writer(os.path.expanduser('~/lux.csv')) led = GpioPinOut() actions = lux.map(lambda event: event.val > threshold) actions.connect(led) actions.connect(lambda v: print('ON' if v else 'OFF')) lux.print_downstream() return (lux, led)
def test_passthrough_as_a_method(self): """Verify that, when passthrough is used as a method, it can still take thunks. """ scheduler = Scheduler(asyncio.get_event_loop()) luxpub = SensorAsOutputThing(ValueListSensor('lux-2', lux_data)) vs1 = ValidationInputThing([450, 600], self) vs2 = ValidationInputThing(lux_data, self) luxpub.passthrough(compose(where(lambda evt: evt.val > 300), vs1)).connect(vs2) scheduler.schedule_periodic(luxpub, 0.5) scheduler.run_forever() self.assertTrue(vs1.completed) self.assertTrue(vs2.completed)
def test_periodic(self): s = SensorAsOutputThing(RandomSensor(1)) PrintAndDeschedule(s) scheduler = Scheduler(asyncio.get_event_loop()) scheduler.schedule_periodic(s, 0.25) scheduler.run_forever() print("Exited successfully")
def test_tsl2591(self): import thingflow.sensors.rpi.lux_sensor sensor = SensorAsOutputThing( thingflow.sensors.rpi.lux_sensor.LuxSensor()) s = Scheduler(asyncio.get_event_loop()) stop = s.schedule_periodic(sensor, 1.0) StopAfterN(sensor, stop, N=4).output() s.run_forever()
def test_where(self): """In this version, we create a publisher and use method chaining to compose the filters""" s = ValueListSensor(1, value_stream) p = SensorAsOutputThing(s) w = p.where(predicate) w.output() vo = ValidationInputThing(expected_stream, self.test_where) w.connect(vo) scheduler = Scheduler(asyncio.get_event_loop()) scheduler.schedule_periodic(p, 0.5) # sample twice every second p.print_downstream() scheduler.run_forever() self.assertTrue( vo.completed, "Schedule exited before validation observer completed") print("That's all folks")
def test_influx_output(self): loop = asyncio.get_event_loop() s = ValueListSensor(1, value_stream) p = SensorAsOutputThing(s) b = InfluxDBWriter(msg_format=Sensor(series_name='Sensor', fields=['val', 'ts'], tags=['sensor_id']), generate_timestamp=False, username=INFLUXDB_USER, password=INFLUXDB_PASSWORD, database=INFLUXDB_DATABASE) p.connect(b) scheduler = Scheduler(loop) scheduler.schedule_periodic(p, 0.2) # sample five times every second scheduler.run_forever() # Now play back rs = self.c.query('SELECT * FROM Sensor;').get_points() for d in rs: print(d) # Play back using an output thing p = InfluxDBReader('SELECT * FROM Sensor;', database=INFLUXDB_DATABASE, username=INFLUXDB_USER, password=INFLUXDB_PASSWORD) p.connect(CallableAsInputThing(print)) scheduler = Scheduler(loop) scheduler.schedule_periodic(p, 0.2) # sample five times every second scheduler.run_forever() print("That's all folks")
def send_and_recv_body(self, sleep_timeout): SENSOR_ID = 'sensor-1' TOPIC = get_topic_name(self) sensor = SensorAsOutputThing(ValueListSensor(SENSOR_ID, VALUES)) td = sensor.transduce(PeriodicMedianTransducer(period=3)) qw = QueueWriter(td, URL, TOPIC, self.sched) qw.output() qr = QueueReader(URL, TOPIC, self.sched, timeout=sleep_timeout) self.sched.schedule_periodic(sensor, 0.5) stop_qr = self.sched.schedule_on_main_event_loop(qr) vs = ValidateAndStopInputThing(EXPECTED, self, stop_qr) qr.select(msg_to_event).connect(vs) self.sched.run_forever() self.assertFalse( qw.has_pending_requests(), "QueueWriter has pending requests: %s" % qw.dump_state()) self.assertEqual(qr.state, QueueReader.FINAL_STATE) self.assertEqual(vs.next_idx, len(EXPECTED)) print("send_and_recv_bod(%s) completed" % sleep_timeout)
def test_function_filter_error_handling(self): """Verify the error handling functionality of the function filter. We do this by connecting two downstream paths to the sensor. The first includes a function filter that throws an error when it encouters a sensor reading of 120. This should disconnect th stream at this point. The second is a normal validation input thing. It is connected directly to the sensor, and thus should not see any errors. """ s = ValueListSensor(1, value_stream) st = SensorAsOutputThing(s) captured_list_ref = [[]] got_completed_ref = [ False, ] got_on_error_ref = [ False, ] def on_next_throw_exc(self, x): if x.val == 120: raise Exception("expected exc") else: captured_list_ref[0].append(x.val) self._dispatch_next(x) def on_completed(self): got_completed_ref[0] = True self._dispatch_completed() def on_error(self, e): got_on_error_ref[0] = True self._dispatch_error(e) ff = FunctionFilter(st, on_next=on_next_throw_exc, on_completed=on_completed, on_error=on_error) ct = CaptureInputThing(expecting_error=True) ff.map(lambda x: x.val).connect(ct) vo = ValidationInputThing(value_stream, self.test_function_filter_error_handling) st.connect(vo) st.print_downstream() scheduler = Scheduler(asyncio.get_event_loop()) scheduler.schedule_periodic(st, 0.5) # sample twice every second scheduler.run_forever() self.assertTrue( vo.completed, "Schedule exited before validation observer completed") self.assertFalse(ct.completed, "Capture thing should not have completed") self.assertTrue(ct.errored, "Capture thing should have seen an error") self.assertFalse(got_completed_ref[0]) self.assertTrue(got_on_error_ref[0]) self.assertEqual([20, 30, 100], ct.events, "Capture thing event mismatch") self.assertEqual([20, 30, 100], captured_list_ref[0], "captured_list_ref mismatch") print("That's all folks")
def test_pandas(self): s = ValueListSensor(1, value_stream) p = SensorAsOutputThing(s) import thingflow.adapters.pandas import numpy w = thingflow.adapters.pandas.PandasSeriesWriter() p.connect(w) sch = Scheduler(asyncio.get_event_loop()) sch.schedule_recurring(p) sch.run_forever() self.assertTrue(w.result is not None, "Result of pandas never set") # now we verify each element for (i, v) in enumerate(value_stream): pv = w.result[i] self.assertTrue( isinstance(pv, numpy.int64), "Expecting pandas value '%s' to be numpy.int64, but instead was %s" % (pv, repr(type(pv)))) self.assertEqual( v, pv, "Pandas value '%s' not equal to original value '%s'" % (repr(pv), repr(v))) print("Validate pandas array")
def run_example(): sensor = SensorAsOutputThing(DummyTempSensor('temp-1', input_sequence)) sensor.output() # let us see the raw values dispatcher = sensor.transduce(RunningAvg(4))\ .passthrough(lambda evt: print("Running avg temp: %s" % round(evt.val, 2))) \ .dispatch([(lambda v: v[2]>=T_high, 't_high'), (lambda v: v[2]<=T_low, 't_low')]) controller = Controller() dispatcher.connect(controller, port_mapping=('t_high', 't_high')) dispatcher.connect(controller, port_mapping=('t_low', 't_low')) dispatcher.connect(controller, port_mapping=('default', 'between')) controller.connect(BypassValveActuator()) sensor.print_downstream() scheduler = Scheduler(asyncio.get_event_loop()) scheduler.schedule_periodic(sensor, 0.5) scheduler.run_forever() print("got to the end")
if self.events_since_last == self.period: val = median(self.samples) event = SensorEvent(sensor_id=v.sensor_id, ts=v.ts, val=val) self.events_since_last = 0 return event else: self.last_event = v # save in case we complete before completing a period return None def complete(self): if self.events_since_last > 0: # if we have some partial state, we emit one final event that # averages whatever we saw since the last emission. return SensorEvent(sensor_id=self.last_event.sensor_id, ts=self.last_event.ts, val=median( self.samples[0:self.events_since_last])) SENSOR_ID = 'sensor-1' scheduler = Scheduler(asyncio.get_event_loop()) sensor = SensorAsOutputThing( RandomSensor(SENSOR_ID, mean=10, stddev=5, stop_after_events=12)) sensor.csv_writer('raw_data.csv').connect( lambda x: print("raw data: %s" % repr(x))) sensor.transduce(PeriodicMedianTransducer()).mqtt_async_send( URL, SENSOR_ID, scheduler).output() scheduler.schedule_periodic(sensor, 0.5) scheduler.run_forever() print("that's all folks")
while True: yield random.gauss(mean, stddev) self.generator = generator() def sample(self): return self.generator.__next__() def __repr__(self): if self.stop_after_events is None: return 'RandomSensor(%s, mean=%s, stddev=%s)' % \ (self.sensor_id, self.mean, self.stddev) else: return 'RandomSensor(%s, mean=%s, stddev=%s, stop_after_events=%s)' % \ (self.sensor_id, self.mean, self.stddev, self.stop_after_events) scheduler = Scheduler(asyncio.get_event_loop()) sensor = SensorAsOutputThing( RandomSensor(1, mean=10, stddev=5, stop_after_events=10)) mtthing = MultiPortOutputThing(sensor) mtthing.connect(lambda v: print("even: %s" % v), port_mapping=('divisible_by_two', 'default')) mtthing.connect(lambda v: print("divisible by three: %s" % v), port_mapping=('divisible_by_three', 'default')) mtthing.connect(lambda v: print("not divisible: %s" % v), port_mapping=('other', 'default')) mtthing.print_downstream() scheduler.schedule_recurring(sensor) scheduler.run_forever()
if self.events_left > 0: data = random.gauss(self.mean, self.stddev) self.events_left -= 1 return data else: raise StopIteration def __str__(self): return "RandomSensor(%s, %s, %s)" % \ (self.sensor_id, self.mean, self.stddev) # Instantiate our sensor MEAN = 100 STDDEV = 10 sensor = SensorAsOutputThing(RandomSensor(1, MEAN, STDDEV, stop_after=5)) # Now, we will define a pretend LED as a subscriber. Each time is it passed # True, it will print 'On'. Each time it is passed False, it will print 'Off'. from thingflow.base import InputThing class LED(InputThing): def on_next(self, x): if x: print("On") else: print("Off") def on_error(self, e): print("Got an error: %s" % e)
def output_thing(sensor_id, num_events): return SensorAsOutputThing(TestSensor(sensor_id, num_events))
# Sensor ids for the remote sensors. Used to dispatch. REMOTE_SENSORS = ['front-room', 'back-room'] def create_dispatch_rule(sensor_id): return (lambda evt: evt.sensor_id == sensor_id, sensor_id) dispatch_rules = [ create_dispatch_rule(remote_id) for remote_id in REMOTE_SENSORS ] scheduler = Scheduler(asyncio.get_event_loop()) if HAS_LOCAL_SENSOR: sensor = SensorAsOutputThing(LuxSensor(sensor_id=LOCAL_SENSOR_ID)) sensor.rolling_csv_writer(DIRECTORY, LOCAL_SENSOR_ID) sensor.output() scheduler.schedule_periodic_on_separate_thread(sensor, 60) mqtt_reader = MQTTReader('localhost', client_id='rpi', topics=[ ('remote-sensors', 0), ]) # we convert the tuple received into a SensorEvent, overwriting the timestamp. dispatcher = mqtt_reader.map(lambda m:(m.payload).decode("utf-8"))\ .from_json()\ .map(lambda tpl: SensorEvent(sensor_id=tpl[0], ts=time.time(), val=tpl[2]))\ .dispatch(dispatch_rules) # For each remote sensor, we create a separate csv writer
def schedule(self): self.logger.info("Scheduling sensors...") informer = Informer(data=self.data, id=self.id, conn=self.conn) informer_out = SensorAsOutputThing(informer) informer_out.connect(StdoutConnector(informer.info)) informer_out.connect( self.conn.writer('informer', informer.info, topic='micronet/devices/' + self.id + '/online')) self.scheduler.schedule_periodic(informer_out, 5) for k, v in self.sensors.items(): id = k.split(':')[0] unit = id if 'unit' in v: unit = v['unit'] try: module = __import__("sensor_" + unit) SensorClass = getattr(module, to_pascal_case(id + "_sensor")) v['id'] = k sensor = SensorClass(**v) sensor_output = SensorAsOutputThing(sensor) self.data['sensors'][k] = sensor.info sensor_output.connect(StdoutConnector(sensor.info)) sensor_output.connect(self.conn.writer(k, sensor.info)) self.scheduler.schedule_periodic(sensor_output, v['freq']) self.logger.info("Sensor '{0}' sampling every {1}s".format( k, v['freq'])) except Exception as e: self.logger.warning(e)