to github
[svn42.git] / track-presence.py
diff --git a/track-presence.py b/track-presence.py
deleted file mode 100755 (executable)
index 3877c5c..0000000
+++ /dev/null
@@ -1,624 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-from __future__ import with_statement
-import os
-import os.path
-import sys
-import threading
-import logging
-import logging.handlers
-import time
-import signal
-import re
-import socket
-import select
-import subprocess
-import types
-import ConfigParser
-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('track-presence.py: %(levelname)s %(message)s'))
-logger.addHandler(lh_syslog)
-lh_stderr = logging.StreamHandler()
-logger.addHandler(lh_stderr)
-
-######## Config File Data Class ############
-
-class UWSConfig:
-  def __init__(self,configfile=None):
-    #Synchronisation
-    self.lock=threading.Lock()
-    self.finished_reading=threading.Condition(self.lock)
-    self.finished_writing=threading.Condition(self.lock)
-    self.currently_reading=0
-    self.currently_writing=False
-    #Config Data
-    self.configfile=configfile
-    self.config_parser=ConfigParser.ConfigParser()
-    self.config_parser.add_section('door')
-    self.config_parser.set('door','cmd_socket',"/var/run/tuer/door_cmd.socket")
-    self.config_parser.add_section('sensors')
-    self.config_parser.set('sensors','remote_cmd',"ssh -i /flash/tuer/id_rsa -o PasswordAuthentication=no -o StrictHostKeyChecking=no %RHOST% %RSHELL% %RSOCKET%")
-    self.config_parser.set('sensors','remote_host',"root@slug.realraum.at")
-    self.config_parser.set('sensors','remote_socket',"/var/run/powersensordaemon/cmd.sock")
-    self.config_parser.set('sensors','remote_shell',"usocket")
-    self.config_parser.add_section('tracker')
-    self.config_parser.set('tracker','sec_wait_after_close_using_cardphone',"4.2")
-    self.config_parser.set('tracker','sec_wait_for_movement_before_warning',"60")
-    self.config_parser.set('tracker','sec_wait_after_close_using_manualswitch',"22.0")
-    self.config_parser.set('tracker','sec_movement_before_manual_switch',"-3.0")  #neg duration means: movement has to occur _after_ door was closed manually
-    self.config_parser.set('tracker','sec_general_movement_timeout',"3600")
-    self.config_parser.set('tracker','num_movements_req_on_nonpresence_until_present',"3")
-    self.config_parser.set('tracker','server_socket',"/var/run/tuer/presence.socket")
-    self.config_parser.set('tracker','photo_flashlight',"1020")
-    self.config_parser.set('tracker','photo_artif_light',"970")
-    self.config_parser.add_section('debug')
-    self.config_parser.set('debug','enabled',"False")
-    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 guardReading(self):
-    with self.lock:
-      while self.currently_writing:
-        self.finished_writing.wait()
-      self.currently_reading+=1
-
-  def unguardReading(self):
-    with self.lock:
-      self.currently_reading-=1
-      self.finished_reading.notifyAll()
-      
-  def guardWriting(self):
-    with self.lock:
-      self.currently_writing=True
-      while self.currently_reading > 0:
-        self.finished_reading.wait()
-    
-  def unguardWriting(self):
-    with self.lock:
-      self.currently_writing=False
-      self.finished_writing.notifyAll()
-    
-  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")
-      self.guardWriting()
-      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))
-      self.unguardWriting()
-      self.guardReading()
-      if self.config_parser.get('debug','enabled') == "True":
-        logger.setLevel(logging.DEBUG)
-      else:
-        logger.setLevel(logging.INFO)
-      self.unguardReading()
-
-  def writeConfigFile(self):
-    if self.configfile is None:
-      return
-    logging.debug("Writing Configfile "+self.configfile)
-    self.guardReading()
-    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
-    self.unguardReading()
-
-  def __getattr__(self, name):
-    underscore_pos=name.find('_')
-    if underscore_pos < 0:
-      raise AttributeError
-    rv=None
-    self.guardReading()
-    try:
-      rv = self.config_parser.get(name[0:underscore_pos], name[underscore_pos+1:])
-    except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
-      self.unguardReading()
-      raise AttributeError
-    self.unguardReading()
-    return rv
-
-
-######## Status Listener Threads ############
-threads_running=True
-
-def trackSensorStatusThread(uwscfg,status_tracker,connection_listener):
-  global sshp, threads_running
-  #RE_TEMP = re.compile(r'temp\d: (\d+\.\d+)')
-  RE_PHOTO = re.compile(r'photo\d: [^0-9]*?(\d+)',re.I)
-  RE_MOVEMENT = re.compile(r'movement|button\d?|PanicButton',re.I)
-  RE_ERROR = re.compile(r'Error: (.+)',re.I)
-  while threads_running:
-    uwscfg.checkConfigUpdates()
-    sshp = None
-    try:
-      cmd = uwscfg.sensors_remote_cmd.replace("%RHOST%",uwscfg.sensors_remote_host).replace("%RSHELL%",uwscfg.sensors_remote_shell).replace("%RSOCKET%",uwscfg.sensors_remote_socket).split(" ")
-      logging.debug("trackSensorStatusThread: Executing: "+" ".join(cmd))
-      sshp = subprocess.Popen(cmd, bufsize=1024, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False)
-      logging.debug("trackSensorStatusThread: pid %d: running=%d" % (sshp.pid,sshp.poll() is None))
-      if not sshp.poll() is None:
-        raise Exception("trackSensorStatusThread: subprocess %d not started ?, returncode: %d" % (sshp.pid,sshp.returncode))
-      #sshp.stdin.write("listen movement\nlisten button\nlisten sensor\n")
-      time.sleep(5) #if we send listen bevor usocket is running, we will never get output
-      #sshp.stdin.write("listen all\n")
-      logging.debug("trackSensorStatusThread: send: listen movement, etc")
-      sshp.stdin.write("listen movement\n")
-      sshp.stdin.write("listen button\n")
-      sshp.stdin.write("listen sensor\n")
-      #sshp.stdin.write("sample temp0\n")
-      sshp.stdin.flush()
-      while threads_running:
-        if not sshp.poll() is None:
-          raise Exception("trackSensorStatusThread: subprocess %d finished, returncode: %d" % (sshp.pid,sshp.returncode))
-        line = sshp.stdout.readline()
-        if len(line) < 1:
-          raise Exception("EOF on Subprocess, daemon seems to have quit, returncode: %d",sshp.returncode)
-        logging.debug("trackSensorStatusThread: Got Line: " + line)
-        if not line.startswith("Warning: Permanently added"):
-          connection_listener.distributeData(line)
-        m = RE_MOVEMENT.match(line)
-        if not m is None:
-          status_tracker.movementDetected()
-          continue
-        m = RE_PHOTO.match(line)
-        if not m is None:
-          status_tracker.currentLightLevel(int(m.group(1)))
-          continue
-        m = RE_ERROR.match(line)
-        if not m is None:
-          logging.error("trackSensorStatusThread: got: "+line) 
-    except Exception, ex:
-      logging.error("trackSensorStatusThread: "+str(ex)) 
-      traceback.print_exc(file=sys.stdout)
-      if not sshp is None and sshp.poll() is None:
-        if sys.hexversion >= 0x020600F0:
-          sshp.terminate()
-        else:
-          subprocess.call(["kill",str(sshp.pid)])
-        time.sleep(1.5)
-        if sshp.poll() is None:
-          logging.error("trackSensorStatusThread: subprocess still alive, sending SIGKILL to pid %d" % (sshp.pid))
-          if sys.hexversion >= 0x020600F0:
-            sshp.kill()
-          else:
-            subprocess.call(["kill","-9",str(sshp.pid)])
-      time.sleep(5)  
-
-door_sockhandle=None
-door_socklock=threading.Lock()
-def trackDoorStatusThread(uwscfg, status_tracker,connection_listener):
-  global door_sockhandle, door_socklock, threads_running
-  #socket.setdefaulttimeout(10.0) #affects all new Socket Connections (urllib as well)
-  RE_STATUS = re.compile(r'Status: (closed|opened), (opening|waiting|closing|idle), (ajar|shut).*',re.I)
-  RE_REQUEST = re.compile(r'Request: (\w+) (?:(Card|Phone|SSH|ssh) )?(.+)',re.I)
-  RE_ERROR = re.compile(r'Error: (.+)',re.I)
-  while threads_running:
-    uwscfg.checkConfigUpdates()
-    with door_socklock:
-      conn=None
-      door_sockhandle=None
-    try:
-      if not os.path.exists(uwscfg.door_cmd_socket):
-        logging.debug("Socketfile '%s' not found, waiting 5 secs" % uwscfg.door_cmd_socket)
-        time.sleep(5)
-        continue
-      with door_socklock:
-        door_sockhandle = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        door_sockhandle.connect(uwscfg.door_cmd_socket)
-        conn = os.fdopen(door_sockhandle.fileno())
-        door_sockhandle.send("listen\n")
-        door_sockhandle.send("status\n")
-
-      last_who = None
-      last_how = None
-      while threads_running:
-        #no lock here, we're just blocking and reading
-        line = conn.readline()
-        logging.debug("trackDoorStatusThread: Got Line: " + line)
-        
-        if len(line) < 1:
-          raise Exception("EOF on Socket, daemon seems to have quit")
-        
-        connection_listener.distributeData(line)
-        
-        m = RE_STATUS.match(line)
-        if not m is None:
-          (status, current_operation, ajar_status) = m.group(1,2,3)
-          #REALLY: doorOpen/Closed should be called before doorLocked/Unlocked
-          if ajar_status == "ajar":
-            status_tracker.doorOpen()
-          else:
-            status_tracker.doorClosed()
-          if current_operation == "idle":
-            if status == "opened":
-              status_tracker.doorUnlocked(last_who, last_how)
-            if status == "closed":
-              status_tracker.doorLocked(last_who, last_how)
-            last_who = None
-            last_how = None
-          continue
-        m = RE_REQUEST.match(line)
-        if not m is None:  
-          last_who = m.group(3)
-          last_how = m.group(2)
-          continue
-    except Exception, ex:
-      logging.error("main: "+str(ex))
-      traceback.print_exc(file=sys.stdout) 
-      try:
-        with door_socklock:
-          if not door_sockhandle is None:
-            door_sockhandle.close()
-      except:
-        pass
-      with door_socklock:
-        conn=None
-        door_sockhandle=None      
-      time.sleep(5)
-
-def updateDoorStatus():
-  global door_sockhandle, door_socklock
-  with door_socklock:
-    if not door_sockhandle is None:
-      door_sockhandle.send("status\n")
-
-############ Status Tracker Class ############
-
-class StatusTracker: #(threading.Thread):
-  def __init__(self, uwscfg):
-    self.uwscfg=uwscfg
-    self.status_change_handler = None
-    #State locked by self.lock
-    self.door_unlocked_previously=None
-    self.door_unlocked=False
-    self.door_closed=True
-    self.door_manual_switch_used=False
-    self.door_physically_present=True
-    self.door_who=None
-    self.last_door_operation_unixts=0
-    self.last_movement_unixts=0
-    self.last_light_value=0
-    self.last_light_unixts=0
-    self.lock=threading.RLock()
-    #Notify State locked by self.presence_notify_lock
-    self.last_somebody_present_result=False
-    self.last_warning=None
-    self.count_same_warning=0
-    self.who_might_be_here=None
-    self.presence_notify_lock=threading.RLock()
-    #timer
-    self.timer=None
-    self.timer_timeout=0
-    self.num_movements_during_nonpresences = 0
-
-  def doorOpen(self):
-    logging.debug("doorOpen()")
-    self.door_closed=False
-    #future other stuff
-
-  def doorClosed(self):
-    logging.debug("doorClosed()")
-    self.door_closed=True
-    #future other stuff
-
-  def doorUnlocked(self,who,how):
-    self.uwscfg.checkConfigUpdates()
-    self.lock.acquire()
-    self.door_unlocked=True
-    self.door_closed=True
-    if self.door_unlocked != self.door_unlocked_previously:
-      self.door_who=who
-      self.lock.release()
-      self.updateWhoMightBeHere(who)
-      self.lock.acquire()
-      self.door_manual_switch_used=(who is None or len(who) == 0)
-      self.door_physically_present=(self.door_manual_switch_used or (not how is None and how.startswith("Card")))
-      if not self.door_unlocked_previously is None:
-        self.last_door_operation_unixts=time.time()
-      self.lock.release()
-      self.checkPresenceStateChangeAndNotify()
-      self.lock.acquire()
-      self.door_unlocked_previously = self.door_unlocked
-    self.lock.release()
-    logging.debug("doorUnlocked: open: %s, who: %s, how: %s, manual_switch: %s; physically_present: %s" % (self.door_unlocked,self.door_who,how,self.door_manual_switch_used,self.door_physically_present))
-    
-  def doorLocked(self,who,how):
-    self.uwscfg.checkConfigUpdates()
-    self.lock.acquire()
-    self.door_unlocked=False
-    if self.door_unlocked != self.door_unlocked_previously:
-      self.door_who=who
-      self.lock.release()
-      self.updateWhoMightBeHere(who)
-      self.lock.acquire()
-      self.door_manual_switch_used=(who is None or len(who) == 0)
-      self.door_physically_present=(self.door_manual_switch_used or (not how is None and how.startswith("Card")))
-      if not self.door_unlocked_previously is None:
-        self.last_door_operation_unixts=time.time()
-      self.lock.release()
-      self.checkPresenceStateChangeAndNotify()
-      self.lock.acquire()
-      self.door_unlocked_previously = self.door_unlocked
-    self.lock.release()
-    logging.debug("doorLocked: open: %s, who: %s, how:%s, manual_switch: %s; physically_present: %s" % (self.door_unlocked,self.door_who,how,self.door_manual_switch_used,self.door_physically_present))
-
-  def movementDetected(self):
-    self.uwscfg.checkConfigUpdates()
-    self.lock.acquire()
-    self.last_movement_unixts=time.time()
-    self.lock.release()
-    #FIXME: QUICKFIX ignore movement
-    return
-    self.checkPresenceStateChangeAndNotify()
-
-  def currentLightLevel(self, value):
-    self.uwscfg.checkConfigUpdates()
-    self.last_light_unixts=time.time()
-    self.last_light_value=value
-    self.checkPresenceStateChangeAndNotify()
-  
-  def checkLight(self, somebody_present=None):
-    if somebody_present is None:
-      somebody_present=self.somebodyPresent()
-    
-    if self.last_light_value > int(self.uwscfg.tracker_photo_flashlight):
-      return "Light: flashlight"
-    elif self.last_light_value > int(self.uwscfg.tracker_photo_artif_light):
-      if not somebody_present and self.last_light_unixts > self.last_door_operation_unixts:
-        return "Light: forgotten"
-      else:
-        return "Light: on"      
-    else:
-      return "Light: off"
-
-  def checkAgainIn(self, sec):
-    if sec <= 0.0:
-        return
-    if self.timer_timeout < time.time():
-      logging.debug("checkAgainIn: starting Timer with timeout %fs" % sec)
-      self.timer=threading.Timer(sec, self.checkPresenceStateChangeAndNotify)
-      self.timer.start()
-      self.timer_timeout = time.time() + sec
-    else:
-      logging.debug("checkAgainIn: not starting timer, already one scheduled in %fs" % (time.time() - self.timer_timeout))
-  
-  def somebodyPresent(self):
-    with self.lock:
-      #door unlocked:
-      if self.door_unlocked:
-        self.num_movements_during_nonpresences = 0
-        if self.door_physically_present:
-          return True
-        #door is ajar and unlocked then we are here for sure:
-        elif self.door_closed == False: 
-          return True
-        elif self.last_movement_unixts > self.last_door_operation_unixts:
-          return True
-        else:
-          return False
-      # door locked but still ajar:
-      elif self.door_closed == False:   #and elf.door_unlocked == False
-        return True
-      # door not locked from inside, but with card/phone .. check again in ...
-      elif not self.door_manual_switch_used and time.time() - self.last_door_operation_unixts <= float(self.uwscfg.tracker_sec_wait_after_close_using_cardphone):
-        self.num_movements_during_nonpresences = 0
-        self.checkAgainIn(float(self.uwscfg.tracker_sec_wait_after_close_using_cardphone))
-        return self.last_somebody_present_result      
-      # door locked from inside, and door not ajar
-      elif self.door_manual_switch_used and self.door_closed:
-        return True
-#      # door locked from inside, stay on last status ....
-#      elif self.door_manual_switch_used and time.time() - self.last_door_operation_unixts <= float(self.uwscfg.tracker_sec_wait_after_close_using_manualswitch):
-#        self.num_movements_during_nonpresences = 0
-#        self.checkAgainIn(float(self.uwscfg.tracker_sec_wait_after_close_using_manualswitch))
-#        return self.last_somebody_present_result
-#      # door locked from inside and movement detected around that time
-#      elif self.door_manual_switch_used and self.last_movement_unixts > self.last_door_operation_unixts - float(self.uwscfg.tracker_sec_movement_before_manual_switch):
-#        self.num_movements_during_nonpresences = 0
-#        return True
-      ##door was closed and nobody here But movement is dedected:
-      #elif self.last_movement_unixts > self.last_door_operation_unixts and time.time() - self.last_movement_unixts < float(self.uwscfg.tracker_sec_general_movement_timeout):
-      #  self.num_movements_during_nonpresences += 1
-      #  if self.num_movements_during_nonpresences >= int(self.uwscfg.tracker_num_movements_req_on_nonpresence_until_present):
-      #    return True
-      #  else:
-      #    return False
-      else:
-        self.num_movements_during_nonpresences = 0
-        return False
-  def getPossibleWarning(self):
-    with self.lock:
-      somebody_present=self.last_somebody_present_result
-      if not somebody_present and not self.door_closed:
-        return "Nobody here but door ajar !"
-      elif self.door_unlocked and not somebody_present and time.time() - self.last_door_operation_unixts >= float(self.uwscfg.tracker_sec_wait_for_movement_before_warning):
-        return "Door unlocked recently but nobody present"
-      elif self.door_unlocked and not somebody_present:
-        self.checkAgainIn(float(self.uwscfg.tracker_sec_wait_for_movement_before_warning))
-        return None
-#      elif not somebody_present and self.last_light_unixts > self.last_door_operation_unixts and self.last_light_value > int(self.uwscfg.tracker_photo_artif_light):
-#return "Nobody here but light is still on"
-      else:
-        return None
-  def updateWhoMightBeHere(self, who):
-    with self.presence_notify_lock:
-      self.who_might_be_here = who
-
-  def forgetWhoMightBeHere(self, somebody_present):
-    with self.presence_notify_lock:
-      if not somebody_present:
-        self.who_might_be_here = None
-
-  def checkPresenceStateChangeAndNotify(self):
-    #no acquiring of self.lock, "just" reading. chance wrong reads in favour of avoiding race conditions (is python var _read_ threadsafe ?)
-    with self.presence_notify_lock:
-      somebody_present = self.somebodyPresent()
-      logging.debug("checkPresenceStateChangeAndNotify: somebody_present=%s, door_locked=%s, door_ajar=%s, door_who=%s, who=%s, light=%s" % (somebody_present,not self.door_unlocked, not self.door_closed, self.door_who,self.who_might_be_here, str(self.last_light_value)))
-      if somebody_present != self.last_somebody_present_result:
-        self.last_somebody_present_result = somebody_present
-        if not self.status_change_handler is None:
-          self.status_change_handler(somebody_present, door_open=self.door_unlocked, who=self.who_might_be_here)
-        self.forgetWhoMightBeHere(somebody_present)
-      warning = self.getPossibleWarning()
-      if warning == self.last_warning:
-        self.count_same_warning+=1
-      else:
-        self.last_warning=warning
-        self.count_same_warning=0
-      if not warning is None and self.count_same_warning < 3:
-        logging.debug("checkPresenceStateChangeAndNotify: warning: " + str(warning))
-        if not self.status_change_handler is None:
-          self.status_change_handler(somebody_present=None, door_open=self.door_unlocked, who=self.who_might_be_here, warning=warning)
-############ Connection Listener ############
-class ConnectionListener:
-  def __init__(self, uwscfg, status_tracker):
-    self.uwscfg=uwscfg
-    self.status_tracker=status_tracker
-    self.server_socket=None
-    self.running=True
-    #register update handler with StatusTracker
-    status_tracker.status_change_handler = self.updateStatus
-    #Lock protected data:
-    self.client_sockets=[]
-    self.lock=threading.Lock()
-  
-  def shutdown(self):
-    self.running=False
-    try:
-      self.server_socket.close()
-    except:
-      pass
-    with self.lock:
-      for sock_to_close in self.client_sockets:
-        try:
-          sock_to_close.close()
-        except:
-          pass
-  
-  def statusString(self,somebody_present, door_open=None, who=None):
-    details=""
-    if not who is None:
-      if door_open:
-        details=", opened, "
-      else:
-        details=", closed, "
-      details += who
-    if somebody_present:
-      return "Presence: yes" + details + "\n"
-    else:
-      return "Presence: no" + details + "\n"
-  
-  def updateStatus(self,somebody_present=None,door_open=None,who=None,warning=None):
-    if not somebody_present is None:
-      self.distributeData(self.statusString(somebody_present, door_open, who))
-    if not warning is None:
-      self.distributeData("Warning: " + warning + "\n")
-    
-  def distributeData(self,data):
-    with self.lock:
-      for socket_to_send_to in self.client_sockets:
-        socket_to_send_to.send(data)
-    
-  def serve(self):
-    self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-    try:
-        os.remove(self.uwscfg.tracker_server_socket)
-    except OSError:
-        pass
-    self.server_socket.bind(self.uwscfg.tracker_server_socket)
-    self.server_socket.listen(2)
-    while (self.running):
-      (ready_to_read, ready_to_write, in_error) = select.select([self.server_socket]+self.client_sockets, [],  [])
-      for socket_to_read in ready_to_read:
-        if socket_to_read == self.server_socket:
-          newsocketconn, addr = self.server_socket.accept()
-          newsocketconn.send(self.statusString(self.status_tracker.somebodyPresent()))
-          with self.lock:
-            self.client_sockets.append(newsocketconn)
-          updateDoorStatus()
-        else:
-          #drop all recieved data and watch for closed sockets
-          if not socket_to_read.recv(256):
-            with self.lock:
-              self.client_sockets.remove(socket_to_read)
-            try:
-              socket_to_read.close()
-            except:
-              pass
-    if self.server_socket:
-      self.server_socket.shutdown(socket.SHUT_RDWR)
-############ Main Routine ############
-
-def exitHandler(signum, frame):
-  global threads_running, connection_listener, sshp, door_sockhandle
-  logging.info("Track Presence stopping")
-  threads_running=False
-  connection_listener.shutdown()
-  try:
-    if sys.hexversion >= 0x020600F0:
-      sshp.terminate()
-    else:
-      subprocess.call(["kill",str(sshp.pid)])
-  except:
-    pass
-  try:
-    door_sockhandle.close()
-  except:
-    pass
-  time.sleep(0.1)
-  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("Presence Tracker started")
-
-#option and only argument: path to config file
-if len(sys.argv) > 1:
-  uwscfg = UWSConfig(sys.argv[1])
-else:
-  uwscfg = UWSConfig()
-
-#Status Tracker keeps track of stuff and derives peoples presence from current state
-status_tracker = StatusTracker(uwscfg)
-#ConnectionListener servers incoming socket connections and distributes status update
-connection_listener = ConnectionListener(uwscfg, status_tracker)
-#Thread listening for door status changes
-track_doorstatus_thread = threading.Thread(target=trackDoorStatusThread,args=(uwscfg,status_tracker,connection_listener),name="trackDoorStatusThread")
-track_doorstatus_thread.start()
-#Thread listening for movement
-track_sensorstatus_thread = threading.Thread(target=trackSensorStatusThread,args=(uwscfg,status_tracker,connection_listener),name="trackSensorStatusThread")
-track_sensorstatus_thread.start()
-
-#main routine: serve connections
-connection_listener.serve()