X-Git-Url: https://git.realraum.at/?p=svn42.git;a=blobdiff_plain;f=switch-power.py;fp=switch-power.py;h=0000000000000000000000000000000000000000;hp=94b0deeae9bd1460bb30684770a59f75094679d5;hb=ff9137d257207a3a4b03c4f453cc1b7ce1e3cf17;hpb=a34e51d757fe52cb19de2937ae1b211894167524 diff --git a/switch-power.py b/switch-power.py deleted file mode 100755 index 94b0dee..0000000 --- a/switch-power.py +++ /dev/null @@ -1,367 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -import os -import os.path -import sys -import logging -import logging.handlers -import urllib -import time -import signal -import json -import zmq -import ConfigParser -import datetime -import random -import traceback - -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('powerswitching') - self.config_parser.set('powerswitching','secs_movement_before_presence_to_launch_event','1') - self.config_parser.set('powerswitching','secs_presence_before_movement_to_launch_event','120') - self.config_parser.set('powerswitching','max_secs_since_movement','600') - 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','lightleveluri','http://slug.realraum.at/cgi-bin/lightlevel.cgi') - self.config_parser.set('slug','ids_logo','logo') - self.config_parser.set('slug','ids_present_day_bright_room','ymhpoweron werkzeug ymhcd') - self.config_parser.set('slug','ids_present_day_dark_room','ymhpoweron decke werkzeug ymhcd') - self.config_parser.set('slug','ids_present_night','ymhpoweron werkzeug schreibtisch spots1 labor ymhcd') - self.config_parser.set('slug','ids_panic','spots1 ymhmute labor werkzeug deckevorne deckehinten') - self.config_parser.set('slug','ids_decke','deckevorne deckehinten') - self.config_parser.set('slug','ids_nonpresent_off','ymhvoldown ymhvoldown ymhvoldown ymhvoldown ymhvoldown ymhvoldown ymhvoldown ymhvoldown ymhvoldown ymhvoldown ymhvoldown ymhvoldown lichter ymhpoweroff lichter') - self.config_parser.set('slug','light_threshold_brightness','400') - self.config_parser.set('slug','light_difference_decke','100') - #self.config_parser.set('slug','time_day','6:00-17:00') - self.config_parser.add_section('debug') - self.config_parser.set('debug','enabled',"False") - self.config_parser.add_section('broker') - self.config_parser.set('broker','uri',"tcp://torwaechter.realraum.at:4244") - 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 getLightValueNow(): - lvalue = touchURL(uwscfg.slug_lightleveluri) - try: - return int(lvalue) - except: - return None - -def haveDaylight(): - dawn_per_month = {1:8, 2:7, 3:6, 4:6, 5:5, 6:5, 7:5, 8:6, 9:7, 10:8, 11:8, 12:8} - dusk_per_month = {1:15, 2:16, 3:17, 4:19, 5:20, 6:20, 7:20, 8:19, 9:17, 10:17, 11:16, 12:15} - hour = datetime.datetime.now().hour - month = datetime.datetime.now().month - return (hour >= dawn_per_month[month] and hour < dusk_per_month[month]) - -def isWolfHour(): - hour = datetime.datetime.now().hour - return (hour >= 2 and hour < 6) - -######### ALGOS ############### - -def switchLogo(status_presence): - logo_action=None - if status_presence: - logo_action=True - else: - if haveDaylight(): - logo_action=False - else: - if isWolfHour(): - logo_action=False - else: - logo_action=True - if not logo_action is None: - logging.info("switchLogo: logo_action:%s" % str(logo_action)) - for id in uwscfg.slug_ids_logo.split(" "): - switchPower(id,logo_action) - -######### EVENTS ############### -unixts_last_movement=0 -unixts_last_presence=0 -status_presence=None -room_is_bright=None - - -def eventRoomGotBright(): - global room_is_bright - logging.debug("eventRoomGotBright()") - room_is_bright=True - -def eventRoomGotDark(): - global room_is_bright - logging.debug("eventRoomGotDark()") - room_is_bright=False - -def eventMovement(): - global unixts_last_movement, unixts_last_presence - unixts_last_movement=time.time() - if (time.time() - unixts_last_presence) <= float(uwscfg.powerswitching_secs_presence_before_movement_to_launch_event): - eventPresentAndMoved() - unixts_last_presence=0 # so that eventPresentAndMoved will only launch once per presence event (i.e. supress multiple movement events) - - -# global unixts_last_movement -# if status_presence is True and unixts_last_movement + int(uwscfg.powerswitching_max_secs_since_movement) >= time.time(): -# presumed_state=not (haveDaylight() or isWolfHour()) -# for id in uwscfg.slug_ids_logo.split(" "): -# switchPower(id,not presumed_state) -# time.sleep(1); -# switchPower(id,presumed_state) - -def eventPresent(): - global status_presence,room_is_bright,unixts_last_movement,uwscfg,unixts_last_presence - unixts_last_presence=time.time() - logging.debug("eventPresent()"); - status_presence=True - if haveDaylight(): - if room_is_bright is False: - present_ids=uwscfg.slug_ids_present_day_dark_room - else: - present_ids=uwscfg.slug_ids_present_day_bright_room - else: - present_ids=uwscfg.slug_ids_present_night - logging.info("event: someone present, switching on: "+present_ids) - for id in present_ids.split(" "): - switchPower(id,True) - switchLogo(status_presence) - if ( time.time() - unixts_last_movement ) <= float(uwscfg.powerswitching_secs_movement_before_presence_to_launch_event): - unixts_last_movement=0 - eventPresentAndMoved() - -def eventPresentAndMoved(): - global status_presence,room_is_bright - pass - -def eventNobodyHere(): - global status_presence - logging.debug("eventNobodyHere()"); - status_presence=False - present_ids=uwscfg.slug_ids_nonpresent_off - logging.info("event: noone here, switching off: "+present_ids) - present_id_list=present_ids.split(" ") - for id in present_id_list: - time.sleep(0.15) - switchPower(id,False) - present_id_list.reverse() - time.sleep(0.15) - switchLogo(status_presence) - time.sleep(2) - for id in present_id_list: - time.sleep(0.15) - switchPower(id,False) - -##def eventPanic(): -## logging.info("eventPanic(): switching around: "+uwscfg.slug_ids_panic) -## lst1 = uwscfg.slug_ids_panic.split(" ") -## lst2 = map(lambda e:[e,False], lst1) -## for id in lst1: -## switchPower(id,False) -## for delay in map(lambda e: (40-e)/33.0,range(10,33)): -## e = random.choice(lst2) -## e[1]=not e[1] -## switchPower(e[0],e[1]) -## time.sleep(delay) -## random.shuffle(lst1) -## for id in lst1: -## switchPower(id,False) -## time.sleep(1.2) -## eventPresent() - -def eventPanic(): - global light_value - logging.info("eventPanic(): switching around: "+uwscfg.slug_ids_panic) - lst1 = uwscfg.slug_ids_panic.split(" ") - lst2 = map(lambda e:[e,False], lst1) - deckenlicht_ids = uwscfg.slug_ids_decke.split(" ") - ceiling_light_was_on = False - #guess main light state: - if len(list(set(deckenlicht_ids) & set(lst1))) > 0: - light_value_before = light_value - for id in deckenlicht_ids: - switchPower(id,False) - time.sleep(2.8) - light_value_after = getLightValueNow() - if not (light_value_before is None or light_value_after is None): - ceiling_light_was_on = ((light_value_before - light_value_after) > int(uwscfg.slug_light_difference_decke)) - logging.debug("eventPanic: light_value_before: %d, light_value_after: %d, ceiling_light_was_on: %s" % (light_value_before,light_value_after,str(ceiling_light_was_on))) - for id in lst1: - switchPower(id,False) - for times in range(1,6): - delay = random.choice([0.3,1.4,0.9,0.5,0.3,1.4,0.9,0.5,2.2]) - time.sleep(delay) - for e in lst2: - e[1]=not e[1] - switchPower(e[0],e[1]) - for id in lst1: - switchPower(id,False) - time.sleep(1.2) - eventPresent() - #we can only test if it was on, we don't any other informatino - if ceiling_light_was_on: - for id in deckenlicht_ids: - switchPower(id,True) - - -######################## - -def decodeR3Message(multipart_msg): - try: - return (multipart_msg[0], json.loads(multipart_msg[1])) - except Exception, e: - logging.debug("decodeR3Message:"+str(e)) - return ("",{}) - -def exitHandler(signum, frame): - logging.info("Power Switch Daemon stopping") - try: - zmqsub.close() - zmqctx.destroy() - 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() - - -daylight=None -wolfhour=None -light_value=0 -while True: - try: - #Start zmq connection to publish / forward sensor data - zmqctx = zmq.Context() - zmqctx.linger = 0 - zmqsub = zmqctx.socket(zmq.SUB) - zmqsub.setsockopt(zmq.SUBSCRIBE, "") - zmqsub.connect(uwscfg.broker_uri) - - while True: - - data = zmqsub.recv_multipart() - (structname, dictdata) = decodeR3Message(data) - logging.debug("Got data: " + structname + ":"+ str(dictdata)) - - uwscfg.checkConfigUpdates() - - if structname == "PresenceUpdate" and "Present" in dictdata: - if dictdata["Present"]: - eventPresent() - else: - eventNobodyHere() - continue - elif structname == "BoreDoomButtonPressEvent": - eventPanic() - continue - elif structname == "MovementSensorUpdate" or structname == "DoorAjarUpdate": - eventMovement() - continue - elif structname == "IlluminationSensorUpdate" and "Value" in dictdata: - light_value = dictdata["Value"] - light_threshold = int(uwscfg.slug_light_threshold_brightness) - #logging.debug("photo value: %d threshold: %s" % (light_value,light_threshold)) - if light_value >= light_threshold: - eventRoomGotBright() - else: - eventRoomGotDark() - continue - - except Exception, ex: - logging.error("main: "+str(ex)) - traceback.print_exc(file=sys.stdout) - try: - zmqsub.close() - zmqctx.destroy() - except: - pass - time.sleep(5)