added fallback mode, TODO: test&debug
authorConstantin Berhard <constantin@exxxtremesys.lu>
Thu, 24 Oct 2013 13:45:14 +0000 (15:45 +0200)
committerConstantin Berhard <constantin@exxxtremesys.lu>
Thu, 24 Oct 2013 13:45:14 +0000 (15:45 +0200)
mode for when some of the sensors don't work, just using one state in the statemachine and using only the space switch sensor
in this mode the red LED blinks, use this mode only if it is really necessary,
use it with parameter --fallback

statemachine.py
tuerd

index d8b7c537ff6cdf88362646f39c2ea35d5cc410c3..3a27adaf8c58a5cd384c417283bf82236450e706 100644 (file)
@@ -1,6 +1,6 @@
 from libtuer import ThreadFunction, logger, fire_and_forget
 from actor import Actor
-import os, random, time
+import os, random, time, threading
 
 # logger.{debug,info,warning,error,critical}
 
@@ -22,6 +22,10 @@ OPEN_REPEAT_NUMBER = 3
 CLOSE_REPEAT_TIMEOUT = 7
 CLOSE_REPEAT_NUMBER = 3
 
+# StateFallback constants
+FALLBACK_BLINK_SPEED = 0.5 # seconds
+FALLBACK_LEAVE_DELAY_LOCK = 5 # seconds
+
 # StateAboutToOpen constants
 ABOUTOPEN_NERVLIST = [(5, lambda : play_sound("flipswitch")), (5, lambda:play_sound("flipswitch")), (0, lambda:logger.warning("Space open but switch not flipped for 10 seconds")),\
        (10, lambda:play_sound("flipswitch")), (10, lambda:play_sound("flipswitch")), (0, lambda:logger.error("Space open but switch not flipped for 30 seconds")),\
@@ -133,16 +137,63 @@ class StateMachine():
                        return super().handle_pins_event()
        
        class StateStart(State):
+               def __init__(self, sm, nervlist = None, fallback=False):
+                       super().__init__(self, sm, nervlist)
+                       self.fallback = fallback
                def handle_pins_event(self):
                        pins = self.pins()
                        if not (pins.door_locked is None or pins.door_closed is None or pins.space_active is None or pins.bell_ringing is None):
                                logger.info("All sensors got a value, switching to a proper state")
+                               if self.fallback:
+                                       logger.info("Going to StateFallback because running in fallback mode")
+                                       return StateMachine.StateFallback(self.state_machine)
                                if pins.door_locked:
                                        return StateMachine.StateZu(self.state_machine)
                                else:
                                        return StateMachine.StateAboutToOpen(self.state_machine)
                        return super().handle_pins_event()
        
+       class StateFallback(State):
+               def __init__(self, sm, nervlist = None):
+                       super().__init__(self, sm, nervlist)
+                       self._last_blink_time = time.time()
+                       self._red_state = False
+               def handle_pins_event(self):
+                       pins = self.pins()
+                       # buzz if open and bell rang
+                       if pins.space_active and pins.bell_ringing and not self.old_pins().bell_ringing:
+                               logger.info("StateFallback: Space switch on and door bell rung => buzzing")
+                               self.actor().act(Actor.CMD_BUZZ)
+                       # set green LED according to space switch
+                       if pins.space_active:
+                               self.actor().act(Actor.CMD_GREEN_ON)
+                       else:
+                               self.actor().act(Actor.CMD_GREEN_OFF)
+                       # primitive leaving procedure if space switch turned off
+                       if not pins.space_active and self.old_pins().space_active:
+                               def _close_after_time():
+                                       time.sleep(FALLBACK_LEAVE_DELAY_LOCK)
+                                       self.actor().act(Actor.CMD_LOCK)
+                               t = threading.Thread(target=_close_after_time)
+                               t.start()
+                       # without return because we want to stay in fallback mode
+                       super().handle_pins_event()
+               def handle_wakeup_event(self):
+                       # blink red LED
+                       now = time.time()
+                       if now - self._last_blink_time < FALLBACK_BLINK_SPEED:
+                               if self._red_state:
+                                       self.actor().act(Actor.CMD_RED_OFF)
+                                       self._red_state = False
+                               else:
+                                       self.actor().act(Actor.CMD_RED_ON)
+                                       self._red_state = True
+                               self._last_blink_time = now
+               def handle_cmd_unlock_event(self,arg):
+                       if arg is not None:
+                               arg("298 Fallback Okay: Trying to unlock the door. The System is in fallback mode, success information is not available.")
+                       self.actor().act(Actor.CMD_UNLOCK)
+       
        class StateZu(AbstractLockedState):
                def handle_cmd_unlock_event(self,callback):
                        return StateMachine.StateUnlocking(self.state_machine, callback)
@@ -254,10 +305,10 @@ class StateMachine():
                                return StateMachine.StateAuf(self.state_machine)
                        return super().handle_pins_event()
        
-       def __init__(self, actor):
+       def __init__(self, actor, fallback = False):
                self.actor = actor
                self.callback = ThreadFunction(self._callback, name="StateMachine")
-               self.current_state = StateMachine.StateStart(self)
+               self.current_state = StateMachine.StateStart(self, fallback)
                self.pins = None
                self.old_pins = None
        
diff --git a/tuerd b/tuerd
index 1bee788341c776acbb894475409707ea2e78a611..50fe03f8b08a8e058c1fc093a1aa826d8d4791d9 100755 (executable)
--- a/tuerd
+++ b/tuerd
@@ -9,17 +9,25 @@ parser = argparse.ArgumentParser(description='Run a door')
 parser.add_argument("-d", "--debug",
                                        action="store_true", dest="debug",
                                        help="Don't send emails")
+parser.add_argument("-f", "--fallback",
+                                       action="store_true", dest="fallback",
+                                       help="Fallback mode for unfunctional hardware: Depend on less sensor input")
 args = parser.parse_args()
 if args.debug:
        import libtuer
        libtuer.mailAddress = []
+if args.fallback:
+       logger.info("Starting in fallback mode")
+else:
+       # to avoid exceptions or getting None
+       args.fallback = False
 
 # initialize GPIO stuff
 GPIO.setmode(GPIO.BOARD)
 
 # bring 'em all up
 the_actor = actor.Actor()
-the_machine = statemachine.StateMachine(the_actor)
+the_machine = statemachine.StateMachine(the_actor, args.fallback)
 the_socket = tysock.TySocket(the_machine)
 the_pins = pins.PinsWatcher(the_machine)
 the_waker = waker.Waker(the_machine)