''' Devices Created on 23 août 2022 @author: denis@e-educ.fr Flow and Frequency output of the YF-S201 Flow(L/H) Frequency(Hz) 120 16 240 32.5 360 49.3 480 65.5 600 82 720 90.2 F = 7.5 Q Q: l/mn ''' import logging, threading, random from modules import sensors as dev, utils, gpiolib as gpio logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) class YF_S201(dev.InputDevice): waterflow_timeout = 2 pulse_counter = 0 start_counter = False stop_counter = None def __init__(self, pin, register=None, publish=None): super().__init__(pin, register=register, callback=self.on_count_pulse, pull_up_down=gpio.IO_PULL_UP,) self.publish = publish threading.Thread(target=self.waterflow_process, args=()).start() def waterflow_publish(self, flow=None): if self.publish is not None: self.publish(dict( uuid=self.key, topic="waterflow", ts=utils.ts_now(), flow=flow, ) ) def on_count_pulse(self, channel): if self.start_counter: self.pulse_counter += 1 def wait_for_counts(self, timeout): self.pulse_counter = 0 self.start_counter = True threading.Event().wait(timeout) self.start_counter = False def waterflow_process(self): self.stop_counter = threading.Event() while not self.stop_counter.is_set(): self.wait_for_counts(self.waterflow_timeout) flow = self.pulse_counter / 7.5 if flow: logger.info(f'\nwaterflow_process flow = {flow}') self.waterflow_publish(flow) def stop(self): self.stop_counter.set() class Relay(dev.RelayFromShiftOut): def __init__(self, shift_out_register, register=None, publish=None): super().__init__(shift_out_register, register, relay_timeout=1.0) self.publish = publish self.start_time, self.end_time = 0, 0 self.started = False self.duration_timer = threading.Event() self.water_flow_timer = threading.Event() self.flow, self.rate = 0.00, 0.00 self.flow_meter_start() self.relay_publish('init', index=self.index, label=self.label, dev_type=self.dev_type) def now(self): return utils.ts_now_s() def relay_publish(self, topic, **kwargs): if self.publish is not None: self.publish(topic, **dict( uuid=self.key, ts=utils.ts_now_s(), relay_state=self.is_on(), elapsed=self.time_elapsed(), remaining=self.time_remaining(), flow=self.flow, rate=self.rate, **kwargs ) ) def time_elapsed(self): elapsed = self.now() - self.start_time if self.start_time <= 0 or elapsed <= 0: elapsed = 0 return elapsed def time_remaining(self): remaining = self.end_time - self.now() if remaining < 0: remaining = 0 return remaining def is_it_over(self, timeout): elapsed = self.now() - self.start_time if elapsed > timeout: self.duration_timer.set() def _open(self, timeout): self.duration_timer = threading.Event() self.started = True while not self.duration_timer.is_set(): try: if self.started: self.is_it_over(timeout) threading.Event().wait(1.0) except Exception as e: logger.error(f'run error {e}') self.start_time = 0 self.relay_stop() def relay_start(self, duration=0): self.start_time = self.now() self.end_time = self.start_time + duration self.open() if duration > 0: threading.Thread(target=self._open, args=(duration, )).start() self.rate, self.flow = 0.00, 0.00 self.begin = self.now() self.water_flow_timer.set() self.relay_publish('start') def relay_stop(self): self.duration_timer.set() self.close() self.started = False self.water_flow_timer.clear() self.relay_publish('stop') def relay_halt(self): if self.is_on(): self.started = False def relay_restart(self): if self.is_on(): self.started = True def relay_status(self): self.relay_publish('status') def _flow_meter(self): while True: try: self.water_flow_timer.wait() elapsed = (self.now() - self.begin)/60 self.flow = random.randint(1050, 1065)/100 * elapsed self.rate = self.flow / elapsed if elapsed > 0 else 0.00 threading.Event().wait(1.0) except Exception as e: logger.error(f'flow_meter_process error {e}') threading.Event().wait(1.0) def flow_meter_start(self): self.begin = self.now() threading.Thread(target=self._flow_meter).start()