1
0
Fork 0
ContactPi/buttond.py

129 lines
4.2 KiB
Python
Executable File

#!/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()')