#!/usr/bin/env python3 # -*- coding: utf-8 -*- """buttond.py: Watch a Rasberry Pi GPIO button. Exec Hog4 comment macros.""" __author__ = "Kevin Matz" __copyright__ = "Copyright 2019, Company 235, LLC" __credits__ = ["Kevin Matz"] __license__ = "MIT" __version__ = "1.1" __maintainer__ = "Kevin Matz" __email__ = "kevin@company235.com" __status__ = "Prototype" import argparse import configparser import logging from signal import pause from baconscript import comment, HogNet, LISTENER, load_servers from gpiozero import Button, GPIODeviceError # use mock pins when not working on Pi hardware # from gpiozero.pins.mock import MockFactory # from gpiozero import Device # Device.pin_factory = MockFactory() log = logging.getLogger(__name__) def main(): """Entry point for direct execution.""" ## parse the command line args = get_command_arguments() ## configure logging log_levels = { 0: logging.CRITICAL, 1: logging.ERROR, 2: logging.WARN, 3: logging.INFO, 4: logging.DEBUG, } if args.verbosity is None: args.verbosity = 0 if args.quiet else 3 logging.basicConfig(level=log_levels.get(args.verbosity, logging.DEBUG)) ## output header print(f"Version: {__version__}\t{__copyright__}") ## load config files LISTENER.osc = HogNet(load_servers(args.servers)) load_config(args.buttons) ## run the event loop try: pause() except KeyboardInterrupt: print() def get_command_arguments(): """Parse the command line arguments.""" parser = argparse.ArgumentParser( description='Exec Hog4 comment macros on RasPi GPIO activity.', epilog=__copyright__) parser.add_argument('-b', '--buttons', default="buttons.cfg", help="button configuration file") parser.add_argument('-s', '--servers', default="server.cfg", help="OSC servers configuration file") parser.add_argument('-q', '--quiet', action='store_true', help="sets the default log level to 0, otherwise 3.") parser.add_argument("-v", dest="verbosity", action="count", default=None, help="verbosity (between 1-4 with more printing more " " verbose logging). " "CRITICAL=0, ERROR=1, WARN=2, INFO=3, DEBUG=4") parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}') return parser.parse_args() def load_config(file): """Load a configuration file.""" config = configparser.ConfigParser(allow_no_value=True) log.debug("Loading config from %s", file) config.read(file) # set up each buttons for button in config.get('button', 'names').split(','): try: # move to config section cfg = config[button] # read from settings pin = cfg.get('pin', None) closed = cfg.get('close', None) opened = cfg.get('open', None) # set up button on pin log.debug('init %s on GPIO %s', button, pin) _buttons[button] = Button(pin) # connect button callbacks to anonymous functions log.info('connecting %s "closed" to macro %s', button, closed) _buttons[button].when_pressed = lambda macro=closed: activate(macro) log.info('connecting %s "opened" to macro %s', button, opened) _buttons[button].when_released = lambda macro=opened: activate(macro) except (KeyError, GPIODeviceError) as error: log.error('Error configuring button %s: %s', button, error) continue def activate(macro): """Sanitize user configured macros.""" if macro is None: return macro = macro.strip('\"').upper() if macro == "": return # pass macro to baconscript log.debug("doing macro %s", macro) comment(macro) # empty button directory _buttons = {} # when run directly, sleep until button signal or KeyboardInterrupt if __name__ == '__main__': main() else: # indicate prefered method of sleeping when laoded as a module log.debug('call signal.pause() instead of time.sleep()')