class PumpController(StateMachine): def __init__(self, loop): super(PumpController, self).__init__(loop) self.pfd = PiFaceDigital() self.listener = InputEventListener(chip=self.pfd) self.listener.register(0, IODIR_BOTH, self.in_upper) self.listener.register(1, IODIR_RISING_EDGE, self.in_lower) self.listener.register(3, IODIR_RISING_EDGE, self.in_button) self.listener.activate() def stop(self): self.pfd.output_port.all_off() self.listener.deactivate() def set_pump_state(self, state): self.pfd.relays[0].value = state def in_upper(self, event): self.logger.info('Input event pin0 (upper)') self.loop.call_soon_threadsafe( self.handle_upper_sensor, event.direction != 1 ) def in_lower(self, event): self.logger.info('Input event pin1 (lower)') self.loop.call_soon_threadsafe(self.handle_lower_sensor, False) def in_button(self, event): self.logger.info('Input event pin3 (button)') self.loop.call_soon_threadsafe(self.handle_button, True)
def run(self): """initialize and run the chip interface and event listener""" logger.debug("initializing chip") self.chip = PiFaceDigital() logger.debug("chip initialized") logger.debug("creating InputEventListener") self.listener = InputEventListener(chip=self.chip) self.register_callbacks() logger.debug("activating listener") self.listener.activate()
def __init__(self, loop): super(PumpController, self).__init__(loop) self.pfd = PiFaceDigital() self.listener = InputEventListener(chip=self.pfd) self.listener.register(0, IODIR_BOTH, self.in_upper) self.listener.register(1, IODIR_RISING_EDGE, self.in_lower) self.listener.register(3, IODIR_RISING_EDGE, self.in_button) self.listener.activate()
class Listener(object): def __init__(self): self.config = Config() logger.info("Initializing listener") if len(self.config.PINS) < 4: logger.critical("ERROR - please configure all 4 pins") raise SystemExit(1) self.write_files = True self.current_values = [] def run(self): """initialize and run the chip interface and event listener""" logger.debug("initializing chip") self.chip = PiFaceDigital() logger.debug("chip initialized") logger.debug("creating InputEventListener") self.listener = InputEventListener(chip=self.chip) self.register_callbacks() logger.debug("activating listener") self.listener.activate() def register_callbacks(self): """record current pin state and register the event callbacks""" logger.debug("registering callbacks") self.current_values = [None] * 4 for i in range(4): self.current_values[i] = self.chip.input_pins[i].value logger.debug("registering callback for %s ON", i) self.listener.register(i, IODIR_ON, self.handle_input_on) logger.debug("registering callback for %s OFF", i) self.listener.register(i, IODIR_OFF, self.handle_input_off) logger.debug("done registering callbacks") logger.info("Initial pin states: %s", self.current_values) def handle_input_on(self, event): """ InputEventListener callback function for IODIR_ON (pin on) :param event: the event that was detected :type event: pifacecommon.interrupts.InterruptEvent """ if self.no_state_change(event.pin_num, 1): logger.info("Ignoring duplicate event for pin %s state %s", event.pin_num, 1) return else: self.current_values[event.pin_num] = 1 logger.info("Received ON event for pin %s", event.pin_num) self.handle_change(event.pin_num, 1, event.timestamp) self.set_output(event.pin_num, 1) def handle_input_off(self, event): """ InputEventListener callback function for IODIR_OFF (pin off) :param event: the event that was detected :type event: pifacecommon.interrupts.InterruptEvent """ if self.no_state_change(event.pin_num, 0): logger.info("Ignoring duplicate event for pin %s state %s", event.pin_num, 0) return else: self.current_values[event.pin_num] = 0 logger.info("Received OFF event for pin %s", event.pin_num) self.handle_change(event.pin_num, 0, event.timestamp) self.set_output(event.pin_num, 0) def no_state_change(self, pin, new_state): """ Return True if the pin's state has changed, False otherwise. :param pin: the pin number :type pin: int :param new_state: the new pin state/value :type state: int :rtype: bool """ if self.current_values[pin] == new_state: return True return False def handle_change(self, pin_num, state, timestamp): """ Handler for pin state change. :param pin_num: the pin number that changed :type pin_num: int :param state: the new state of the pin (1==on, 0==off) :type state: int :param timestamp: timestamp when the event happened (Float unix TS) :type timestamp: float """ fname = 'pinevent_%s_pin%s_state%s' % (timestamp, pin_num, state) fpath = os.path.join(self.config.QUEUE_PATH, fname) if not self.write_files: logger.warning('Would create event file: %s', fpath) return # touch the file with open(fpath, 'a'): os.utime(fpath, None) logger.debug('Created event file: %s', fpath) def set_output(self, pin_num, state): """ Change the state of an output pin in response to an input change. Set the output to the same state as the input, unless ``config.INVERT_LED is True``, in which case set it to the opposite. :param pin_num: the pin number to change :type pin_num: int :param state: the new state - 0=off, 1=on :type state: int """ if self.config.NO_LEDS: logger.debug("Not lighting LEDs") return if self.config.INVERT_LED: if state == 0: state = 1 else: state = 0 if state == 1: logger.debug("Setting output %s on", pin_num) self.chip.output_pins[pin_num].turn_on() else: logger.debug("Setting output %s off", pin_num) self.chip.output_pins[pin_num].turn_off() def console_entry_point(self): """entry point to handle args and call run function""" args = self.parse_args(sys.argv[1:]) if args.version: print("pyface-webhooks %s " "<https://github.com/jantman/piface_webhooks>" % VERSION) raise SystemExit(0) if args.verbose == 1: logger.warning("Setting log level to INFO") logger.setLevel(logging.INFO) elif args.verbose > 1: logger.warning("Setting log level to DEBUG") # debug-level logging hacks FORMAT = "[%(asctime)s][%(levelname)s %(filename)s:%(lineno)s - " \ "%(name)s.%(funcName)s() ] %(message)s" debug_formatter = logging.Formatter(fmt=FORMAT) logger.handlers[0].setFormatter(debug_formatter) logger.setLevel(logging.DEBUG) self.write_files = args.write_files self.run() def parse_args(self, argv): """ parse arguments/options :param argv: argument list to parse, usually ``sys.argv[1:]`` :type argv: list :returns: parsed arguments :rtype: :py:class:`argparse.Namespace` """ desc = 'Listen for PiFace input changes and queue them to disk' p = argparse.ArgumentParser(description=desc) p.add_argument('-w', '--no-write', dest='write_files', action='store_false', default=True, help='do not write queue files; just log changes') p.add_argument('-v', '--verbose', dest='verbose', action='count', default=0, help='verbose output. specify twice for debug-level ' 'output.') p.add_argument('-V', '--version', dest='version', action='store_true', default=False, help='print version number and exit.') args = p.parse_args(argv) return args