From ca7fca90a555eb086bae2a6d5fc4f1fc63e3f6ea Mon Sep 17 00:00:00 2001 From: realraum Date: Tue, 23 Mar 2010 13:33:50 +0000 Subject: [PATCH] Switch Power --- switch-power.py | 193 ++++++++++++++++++++++++++++++++++++++++++++++++ tuer_status.initscript | 10 +++ 2 files changed, 203 insertions(+) create mode 100755 switch-power.py diff --git a/switch-power.py b/switch-power.py new file mode 100755 index 0000000..131361a --- /dev/null +++ b/switch-power.py @@ -0,0 +1,193 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import os +import os.path +import sys +#import threading +import logging +import logging.handlers +import urllib +import time +import signal +import re +import socket +import subprocess +import types +import ConfigParser + +logger = logging.getLogger() +logger.setLevel(logging.INFO) +lh_syslog = logging.handlers.SysLogHandler(address="/dev/log",facility=logging.handlers.SysLogHandler.LOG_LOCAL2) +lh_syslog.setFormatter(logging.Formatter('switch-power.py: %(levelname)s %(message)s')) +logger.addHandler(lh_syslog) +lh_stderr = logging.StreamHandler() +logger.addHandler(lh_stderr) + +class UWSConfig: + def __init__(self,configfile=None): + self.configfile=configfile + self.config_parser=ConfigParser.ConfigParser() + self.config_parser.add_section('slug') + self.config_parser.set('slug','cgiuri','http://slug.realraum.at/cgi-bin/switch.cgi?id=%ID%&power=%ONOFF%') + self.config_parser.set('slug','ids_present','logo werkzeug') + self.config_parser.set('slug','ids_panic','idee schreibtisch labor werkzeug') + self.config_parser.add_section('debug') + self.config_parser.set('debug','enabled',"True") + self.config_parser.add_section('tracker') + self.config_parser.set('tracker','socket',"/var/run/tuer/presence.socket") + self.config_mtime=0 + if not self.configfile is None: + try: + cf_handle = open(self.configfile,"r") + cf_handle.close() + except IOError: + self.writeConfigFile() + else: + self.checkConfigUpdates() + + def checkConfigUpdates(self): + global logger + if self.configfile is None: + return + logging.debug("Checking Configfile mtime: "+self.configfile) + try: + mtime = os.path.getmtime(self.configfile) + except (IOError,OSError): + return + if self.config_mtime < mtime: + logging.debug("Reading Configfile") + try: + self.config_parser.read(self.configfile) + self.config_mtime=os.path.getmtime(self.configfile) + except (ConfigParser.ParsingError, IOError), pe_ex: + logging.error("Error parsing Configfile: "+str(pe_ex)) + if self.config_parser.get('debug','enabled') == "True": + logger.setLevel(logging.DEBUG) + else: + logger.setLevel(logging.INFO) + + def writeConfigFile(self): + if self.configfile is None: + return + logging.debug("Writing Configfile "+self.configfile) + try: + cf_handle = open(self.configfile,"w") + self.config_parser.write(cf_handle) + cf_handle.close() + self.config_mtime=os.path.getmtime(self.configfile) + except IOError, io_ex: + logging.error("Error writing Configfile: "+str(io_ex)) + self.configfile=None + + def __getattr__(self, name): + underscore_pos=name.find('_') + if underscore_pos < 0: + raise AttributeError + try: + return self.config_parser.get(name[0:underscore_pos], name[underscore_pos+1:]) + except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): + raise AttributeError + +def touchURL(url): + try: + f = urllib.urlopen(url) + rq_response = f.read() + logging.debug("touchURL: url: "+url) + #logging.debug("touchURL: Response "+rq_response) + f.close() + return rq_response + except Exception, e: + logging.error("touchURL: "+str(e)) + +def switchPower(powerid,turn_on=False): + if turn_on: + onoff="on" + else: + onoff="off" + touchURL(uwscfg.slug_cgiuri.replace("%ID%",powerid).replace("%ONOFF%",onoff)) + +def eventPresent(somebody_present=False): + for id in uwscfg.slug_ids_present.split(" "): + switchPower(id,somebody_present) + +def eventPanic(): + lst1 = uwscfg.slug_ids_panic.split(" ") + lst2 = lst1 + lst2.append(lst2.pop(0)) + #guarantee list has even number of elements by multiplying it with a factor of 2 + lst=zip(lst1,lst2) * 4 + lst2=None + switchPower(lst[0][0],True) + for (id1,id2) in lst: + switchPower(id2,True) + time.sleep(0.3) + switchPower(id1,False) + time.sleep(0.6) + for id in lst1: + switchPower(id,False) + +def exitHandler(signum, frame): + logging.info("Power Switch Daemon stopping") + try: + conn.close() + except: + pass + try: + sockhandle.close() + except: + pass + sys.exit(0) + +#signals proapbly don't work because of readline +#signal.signal(signal.SIGTERM, exitHandler) +signal.signal(signal.SIGINT, exitHandler) +signal.signal(signal.SIGQUIT, exitHandler) + +logging.info("Power Switch Daemon started") + +if len(sys.argv) > 1: + uwscfg = UWSConfig(sys.argv[1]) +else: + uwscfg = UWSConfig() + +#socket.setdefaulttimeout(10.0) #affects all new Socket Connections (urllib as well) +RE_PRESENCE = re.compile(r'Presence: (yes|no)') +RE_BUTTON = re.compile(r'PanicButton|button\d?') +while True: + try: + if not os.path.exists(uwscfg.tracker_socket): + logging.debug("Socketfile '%s' not found, waiting 5 secs" % uwscfg.tracker_socket) + time.sleep(5) + continue + sockhandle = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sockhandle.connect(uwscfg.tracker_socket) + conn = os.fdopen(sockhandle.fileno()) + #sockhandle.send("listen\n") + while True: + line = conn.readline() + logging.debug("Got Line: " + line) + + uwscfg.checkConfigUpdates() + + if line == "": + raise Exception("EOF on Socket, daemon seems to have quit") + + m = RE_PRESENCE.match(line) + if not m is None: + status = m.group(1) + eventPresent(status == "yes") + continue + m = RE_BUTTON.match(line) + if not m is None: + eventPanic() + continue + + except Exception, ex: + logging.error("main: "+str(ex)) + try: + sockhandle.close() + except: + pass + conn=None + sockhandle=None + time.sleep(5) diff --git a/tuer_status.initscript b/tuer_status.initscript index af584fd..e31b5eb 100755 --- a/tuer_status.initscript +++ b/tuer_status.initscript @@ -12,20 +12,24 @@ EXE_TRACK=/flash/tuer/track-presence.py EXE_UWEB=/flash/tuer/update-web-status.py EXE_XMPP=/flash/tuer/update-xmpp-status.py +EXE_SWITCH=/flash/tuer/switch-power.py CFG_TRACK=/flash/tuer/track-presence.cfg CFG_UWEB=/flash/tuer/update-web-status.cfg CFG_XMPP=/flash/tuer/update-xmpp-status.cfg +CFG_SWITCH=/flash/tuer/switch-power.cfg . /etc/default/tuer PIDFILE_TRACK=${DIR_RUN}/track-presence.pid PIDFILE_UWEB=${DIR_RUN}/update-web-status.pid PIDFILE_XMPP=${DIR_RUN}/update-xmpp-status.pid +PIDFILE_SWITCH=${DIR_RUN}/switch-power.pid test -f $EXE_TRACK || exit 1 test -f $EXE_UWEB || exit 1 test -f $EXE_XMPP || exit 1 +test -f $EXE_SWITCH || exit 1 if [ ! -d $DIR_RUN ]; then mkdir -p $DIR_RUN || exit 2 chown -R $DOOR_USR:$DOOR_GRP $DIR_RUN @@ -48,6 +52,9 @@ start) log_daemon_msg "Starting door daemon" "update-xmpp-status" start-stop-daemon --start --quiet --pidfile $PIDFILE_XMPP -b -m -c $DOOR_USR --name update-xmpp-status.py --startas $EXE_XMPP -- $CFG_XMPP log_end_msg $? + log_daemon_msg "Starting door daemon" "switch-power" + start-stop-daemon --start --quiet --pidfile $PIDFILE_SWITCH -b -m -c $DOOR_USR --name update-xmpp-status.py --startas $EXE_SWITCH -- $CFG_SWITCH + log_end_msg $? ;; stop) log_daemon_msg "Stopping door daemon" "update-web-status" @@ -56,6 +63,9 @@ stop) log_daemon_msg "Stopping door daemon" "update-xmpp-status" start-stop-daemon --stop --quiet --pidfile $PIDFILE_XMPP -m --retry TERM/1/TERM/1/KILL log_end_msg $? + log_daemon_msg "Stopping door daemon" "switch-power" + start-stop-daemon --stop --quiet --pidfile $PIDFILE_SWITCH -m --retry TERM/1/TERM/1/KILL + log_end_msg $? log_daemon_msg "Stopping door daemon" "track-presence" start-stop-daemon --stop --quiet --pidfile $PIDFILE_TRACK -m --retry TERM/1/TERM/1/KILL log_end_msg $? -- 1.7.10.4