import time from platypush.plugins import action from platypush.plugins.gpio import GpioPlugin from platypush.plugins.gpio.sensor import GpioSensorPlugin class GpioSensorDistancePlugin(GpioPlugin, GpioSensorPlugin): """ You can use this plugin to interact with a distance sensor on your Raspberry Pi (tested with a HC-SR04 ultrasound sensor). Requires: * ``RPi.GPIO`` (``pip install RPi.GPIO``) """ def __init__(self, trigger_pin: int, echo_pin: int, timeout: float = 1.0, warmup_time: float = 2.0, *args, **kwargs): """ :param trigger_pin: GPIO PIN where you connected your sensor trigger PIN (the one that triggers the sensor to perform a measurement). :param echo_pin: GPIO PIN where you connected your sensor echo PIN (the one that will listen for the signal to bounce back and therefore trigger the distance calculation). :param timeout: The echo-wait will terminate and the plugin will return null if no echo has been received after this time (default: 1 second). :param warmup_time: Number of seconds that should be waited on plugin instantiation for the sensor to be ready (default: 2 seconds). """ GpioPlugin.__init__(self, *args, **kwargs) self.trigger_pin = trigger_pin self.echo_pin = echo_pin self.timeout = timeout self.warmup_time = warmup_time self._initialized = False self._init_gpio() def _init_gpio(self): if self._initialized: return import RPi.GPIO as gpio gpio.setmode(self.mode) gpio.setup(self.trigger_pin, gpio.OUT) gpio.setup(self.echo_pin, gpio.IN) gpio.output(self.trigger_pin, gpio.LOW) self.logger.info('Waiting {} seconds for the sensor to be ready'.format(self.warmup_time)) time.sleep(self.warmup_time) self.logger.info('Sensor ready') self._initialized = True def _get_data(self): import RPi.GPIO as gpio pulse_start = pulse_end = pulse_on = pulse_off = time.time() self._init_gpio() gpio.output(self.trigger_pin, gpio.HIGH) time.sleep(0.00001) # 1 us pulse to trigger echo measurement gpio.output(self.trigger_pin, gpio.LOW) while gpio.input(self.echo_pin) == 0: pulse_on = time.time() if pulse_on - pulse_start > self.timeout: raise TimeoutError('Distance sensor echo timeout after {} seconds: 0'. format(self.timeout)) pulse_start = pulse_on pulse_end = pulse_off = time.time() while gpio.input(self.echo_pin) == 1: pulse_off = time.time() if pulse_off - pulse_end > self.timeout: raise TimeoutError('Distance sensor echo timeout after {} seconds: 1'. format(self.timeout)) pulse_end = pulse_off pulse_duration = pulse_end - pulse_start # s = vt where v = 1/2 * avg speed of sound in mm/s return round(pulse_duration * 171500.0, 2) @action def get_measurement(self): """ Extends :func:`.GpioSensorPlugin.get_measurement` :returns: Distance measurement as a scalar (in mm): """ try: return self._get_data() except TimeoutError as e: self.logger.warning(str(e)) return except Exception as e: self.close() raise e @action def close(self): import RPi.GPIO as gpio if self._initialized: gpio.cleanup() self._initialized = False def __enter__(self): self._init_gpio() def __exit__(self): self.close() # vim:sw=4:ts=4:et: