#! /usr/bin/env python # -*- 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.daemon import stddlib.configuration from adafruit_7segment.sevensegment import SevenSegment PARSER = OptionParser(prog="stdd", version="%prog 0.9.2", 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.write_digit(0, 0) DISPLAY.write_digit(1, 0) DISPLAY.write_digit(3, 0) DISPLAY.write_digit(4, 0) if OPTIONS.daemon is True: if DAEMON.stop() is True: 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 is True: LOGGER.addHandler(SYSLOG_HANDLER) else: LOGGER.addHandler(CONSOLE_HANDLER) if OPTIONS.daemon is True: if os.access("/run", os.F_OK & os.W_OK) is True: DAEMON = stddlib.daemon.Daemon("/run/stdd", "stdd.pid") else: DAEMON = stddlib.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(CONFIG.hw_address) LOGGER.debug("opened hardware 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 is True: 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.write_digit(0, int(position1)) DISPLAY.write_digit(1, int(position2)) DISPLAY.write_digit(3, int(position3)) DISPLAY.write_digit(4, int(position4)) minute_written = minute time.sleep(1) if __name__ == "__main__": main()