#! /usr/bin/env python3 # -*- coding: utf8 -*- # # This file is part of stdd, the simple time display daemon, # written by Helmut Pozimski 2013-2014, # licensed under the 3-clause BSD license """ Main script for stdd, puts all the modules together, starts the daemon and takes care of sending the right values to the display. """ import datetime import time import sys import signal import os import logging import logging.handlers from optparse import OptionParser import stddlib.configuration from stddlib import daemon from Adafruit_LED_Backpack import SevenSegment PARSER = OptionParser(prog="stdd", version="%prog 0.9.8", add_help_option=True) PARSER.add_option("-d", "--daemon", action="store_true", dest="daemon", help="run stdd as daemon") PARSER.add_option("-u", "--user", dest="user", help="define an unprivileged \ user to run the daemon") PARSER.add_option("-g", "--group", dest="group", help="define an unprivileged\ group to run the daemon") PARSER.add_option("-c", "--config", dest="config", help="define an\ alternative path to the configuration file") (OPTIONS, ARGUMENTS) = PARSER.parse_args() """ define a sighandler to properly catch signals """ def sighandler(signum, frame): """ Catches signals and ensures a clean exit. """ if signum == 2: LOGGER.info("received SIGINT, stopping daemon") elif signum == 15: LOGGER.info("received SIGTERM, stopping daemon") DISPLAY.set_digit(0, 0) DISPLAY.set_digit(1, 0) DISPLAY.set_digit(2, 0) DISPLAY.set_digit(3, 0) DISPLAY.write_display() if OPTIONS.daemon: if DAEMON.stop(): sys.exit(0) else: LOGGER.error("stopping daemon failed, PID file was not deleted!") sys.exit(1) sys.exit(0) # create the configuration object according to the given parameters and # read the file itself signal.signal(signal.SIGTERM, sighandler) signal.signal(signal.SIGINT, sighandler) CONFIG = stddlib.configuration.Conf() if OPTIONS.config is not None: CONFIG.read(OPTIONS.config) else: CONFIG.read() CONFIG.analyze() # create a logger to log errors according to configuration LOGGER = logging.getLogger("stdd") if CONFIG.syslog_level == "debug": LOGGER.setLevel(logging.DEBUG) elif CONFIG.syslog_level == "error": LOGGER.setLevel(logging.ERROR) else: LOGGER.setLevel(logging.INFO) if CONFIG.syslog_facility == "daemon": SYSLOG_HANDLER = logging.handlers.SysLogHandler( "/dev/log", facility=logging.handlers.SysLogHandler.LOG_DAEMON) else: SYSLOG_HANDLER = logging.handlers.SysLogHandler("/dev/log") CONSOLE_HANDLER = logging.StreamHandler() FORMATTER = logging.Formatter("%(name)s[" + str(os.getpid()) + "]: %(message)s") SYSLOG_HANDLER.setFormatter(FORMATTER) CONSOLE_HANDLER.setFormatter(FORMATTER) if OPTIONS.daemon: LOGGER.addHandler(SYSLOG_HANDLER) else: LOGGER.addHandler(CONSOLE_HANDLER) if OPTIONS.daemon: if os.access("/run", os.F_OK & os.W_OK): DAEMON = daemon.Daemon("/run/stdd", "stdd.pid") else: DAEMON = daemon.Daemon("/var/run/stdd", "stdd.pid") DAEMON.daemonize() DAEMON.start() LOGGER.info("daemon started") CMDLINE = "" CMDCOUNTER = 0 for element in sys.argv: if CMDCOUNTER > 0: CMDLINE = CMDLINE + " " + element else: CMDLINE = CMDLINE + element CMDCOUNTER += 1 DAEMON.set_name("stdd", CMDLINE) if OPTIONS.user is not None and OPTIONS.group is not None: DAEMON.drop_privileges(OPTIONS.user, OPTIONS.group) LOGGER.debug("dropped privileges, now running as " + OPTIONS.user + " and group" + OPTIONS.group) # Initialize the display object DISPLAY = SevenSegment.SevenSegment(address=int(CONFIG.hw_address)) DISPLAY.begin() LOGGER.debug("opened hardware address %s", CONFIG.hw_address) # Set the brightness according to the configuration if CONFIG.set_brightness_high < datetime.datetime.now().time()\ < CONFIG.set_brightness_low: LOGGER.debug("setting display brightness high") DISPLAY.set_brightness(CONFIG.brightness_high) else: LOGGER.debug("setting display brightness low") DISPLAY.set_brightness(CONFIG.brightness_low) # Define the main loop def main(): """ Main loop of the daemon. """ minute_written = 61 while True: date_now = datetime.datetime.now() LOGGER.debug("got datetime: " + str(date_now)) minute = date_now.minute hour = date_now.hour if CONFIG.blink_colon: LOGGER.debug("blinking middle colon") DISPLAY.set_colon(date_now.second % 2) else: DISPLAY.set_colon(True) # set the display brightness high or low when the point in time # defined is reached. if CONFIG.set_brightness_low.hour == hour: if CONFIG.set_brightness_low.minute == minute: LOGGER.debug("setting display brightness low") DISPLAY.set_brightness(CONFIG.brightness_low) if CONFIG.set_brightness_high.hour == hour: if CONFIG.set_brightness_high.minute == minute: LOGGER.debug("setting display brightness high") DISPLAY.set_brightness(CONFIG.brightness_high) if minute_written != minute: try: position2 = str(hour)[1] except IndexError: position2 = str(hour)[0] position1 = "0" else: position1 = str(hour)[0] try: position4 = str(minute)[1] except IndexError: position4 = str(minute)[0] position3 = "0" else: position3 = str(minute)[0] LOGGER.debug("writing time to display") DISPLAY.set_digit(0, position1) DISPLAY.set_digit(1, position2) DISPLAY.set_digit(2, position3) DISPLAY.set_digit(3, position4) minute_written = minute DISPLAY.write_display() time.sleep(1) if __name__ == "__main__": main()