Commit ea58fbe8 authored by Ralf's avatar Ralf
Browse files

lots of fixes:

* configuration tuning
* less annoying SpaceAPI logging
* statemachine: try to close the door after some minutes
parent e993ea62
......@@ -23,7 +23,6 @@ class SpaceApi:
def _do_request(self, state):
state_val = 1 if state else 0
try:
logger.info("Setting SpaceAPI to %d" % state_val)
url = "https://spaceapi.hacksaar.de/status.php?action=update&key=%s&status=%d" % (spaceApiKey, state_val)
response = urllib.request.urlopen(url, timeout=5.0)
responseText = response.read().decode('utf-8').strip()
......@@ -44,6 +43,7 @@ class SpaceApi:
now = time.time()
if self._local_state is not None and (self._local_state != self._remote_state or now > self._last_set_at+HEARTBEAT_TIME):
# take action!
(logger.info if self._local_state != self._remote_state else logger.debug)("Setting SpaceAPI to %d" % self._local_state)
success = self._do_request(self._local_state)
if success:
self._remote_state = self._local_state
......
......@@ -12,7 +12,7 @@ def play_sound (what):
return
soundfile = SOUNDS_DIRECTORY + what + '/' + random.choice(soundfiles)
hour = datetime.datetime.time(datetime.datetime.now()).hour
volume = 60 if hour >= 22 or hour <= 6 else 90
volume = 60 if hour >= 21 or hour <= 6 else 85
fire_and_forget_cmd ([SOUNDS_PLAYER, "-volume", str(volume), soundfile], "StateMachine: ")
# convert an absolute nervlist to a relative one
......@@ -26,7 +26,7 @@ def nervlist_abs2rel(nervlist_abs):
return nervlist_rel
# StateAuf constants
HELLO_PROBABILITY = 0.2
HELLO_PROBABILITY = 0.1
# StateUnlocking constants
OPEN_REPEAT_TIMEOUT = 7
......@@ -41,15 +41,9 @@ FALLBACK_LEAVE_DELAY_LOCK = 5 # seconds
# StateAboutToOpen constants
SWITCH_PRAISE_PROBABILITY = 0.5
ABOUTOPEN_NERVLIST = nervlist_abs2rel([(10, lambda:play_sound("flipswitch")),\
(20, lambda:play_sound("flipswitch")), (30, lambda:play_sound("flipswitch")), (30, lambda:logger.error("Space open but switch not flipped for 30 seconds")),\
(40, lambda:play_sound("flipswitch")), (50, lambda:play_sound("flipswitch")), (60, lambda:play_sound("mail_sent")),
(60, lambda:logger.critical("Space open but switch not flipped for 60 seconds")), (120, lambda:play_sound("mail_sent")),
(10*60, lambda:logger.critical("Space open but switch not flipped for 10 minutes")),
(60*60, lambda:logger.critical("Space open but switch not flipped for one hour"))])
# Timeout we wait after the switch was switched to "Closed", until we assume nobody will open the door and we just lock it
# ALso the time we wait after the door was opend, till we assume something went wrong and start nerving
# Also the time we wait after the door was opend, till we assume something went wrong and start nerving
LEAVE_TIMEOUT = 20
# play_sound constants
......@@ -109,7 +103,7 @@ class StateMachine():
arg("412 Precondition Failed: If not in fallback mode, use the hardware switch to lock the space.")
def handle_cmd_fallback_on_event(self,arg):
arg("200 okay: Entering fallback mode and notifying admins.")
logger.critical("Entering fallback mode. Somebody thinks, the hardware sensors are broken.")
logger.critical("Entering fallback mode. Somebody thinks the hardware sensors are broken.")
return StateMachine.StateFallback(self.state_machine)
def handle_cmd_fallback_off_event(self,arg):
arg("412 Precondition Failed: Not in fallback mode!")
......@@ -174,7 +168,7 @@ class StateMachine():
if self.pins().door_locked:
logger.info("Door locked, closing space")
if self.pins().space_active:
logger.warning("StateMachine: door manually locked, but space switch is still on - going to StateZu")
logger.warning("StateMachine: door manually locked, but space switch is still on - going to StateZu nevertheless")
play_sound("manual_lock")
return StateMachine.StateZu(self.state_machine)
return super().handle_pins_event()
......@@ -201,6 +195,7 @@ class StateMachine():
def __init__(self, sm, nervlist = None):
super().__init__(sm, nervlist)
self._red_state = False
self.api().set_state(False)
def handle_pins_event(self):
pins = self.pins()
# set green LED according to space switch
......@@ -210,10 +205,11 @@ class StateMachine():
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)
fire_and_forget(_close_after_time)
self._nerver = Nerver([(FALLBACK_LEAVE_DELAY_LOCK, lambda:self.actor().act(Actor.CMD_LOCK))])
if pins.space_active and pins.bell_ringing and not self.old_pins().bell_ringing:
# someone just pressed the bell
logger.info("StateMachine: buzzing because of bell ringing in StateFallback")
self.actor().act(Actor.CMD_BUZZ)
# not calling superclass because we want to stay in fallback mode
def handle_wakeup_event(self):
# blink red LED
......@@ -223,6 +219,7 @@ class StateMachine():
else:
self.actor().act(Actor.CMD_RED_ON)
self._red_state = True
return super().handle_wakeup_event()
def handle_cmd_unlock_event(self,arg):
if arg is not None:
arg("200 okay: Trying to unlock the door. The System is in fallback mode, success information is not available.")
......@@ -235,7 +232,7 @@ class StateMachine():
arg("412 Precondition Failed: Fallback mode already active.")
def handle_cmd_fallback_off_event(self,arg):
arg("200 okay: Leaving fallback mode and notifying admins.")
logger.critical("Leaving fallback mode. Somebody thinks, the sensors are working again.")
logger.critical("Leaving fallback mode. Somebody thinks the sensors are working again.")
return StateMachine.StateStart(self.state_machine)
class StateZu(AbstractLockedState):
......@@ -278,8 +275,21 @@ class StateMachine():
self.actor().act(Actor.CMD_UNLOCK)
class StateAboutToOpen(AbstractStateWhereUnlockingIsRedundant):
def __init__(self, sm):
super().__init__(sm, ABOUTOPEN_NERVLIST)
def __init__(self, sm, close_attempts = 0):
self.close_attempts = close_attempts
# nervlist, and when it's done, try closing the door
nervlist = nervlist_abs2rel([(10 , lambda:play_sound("flipswitch")),
(20 , lambda:play_sound("flipswitch")),
(30 , lambda:play_sound("flipswitch")),
(30 , lambda:logger.error("Space open but switch not flipped for 30 seconds")),
(40 , lambda:play_sound("flipswitch")),
(50 , lambda:play_sound("flipswitch")),
(60 , lambda:play_sound("flipswitch")),
(90 , lambda:play_sound("flipswitch")),
(110, lambda:play_sound("mail_sent")),
(120, lambda:play_sound("mail_sent"))])
nervlist.append((0, self.waited_long_enough))
super().__init__(sm, nervlist)
def handle_pins_event(self):
pins = self.pins()
if pins.space_active:
......@@ -288,6 +298,11 @@ class StateMachine():
play_sound("success")
return StateMachine.StateAuf(self.state_machine)
return super().handle_pins_event()
def waited_long_enough(self):
attempt = self.close_attempts+1
msg = "Space open but switch not flipped for two minutes, starting {0}. attempt to close the door".format(attempt)
(logger.critical if attempt < 4 or attempt % 10 == 0 else logger.error)(msg)
return StateMachine.StateLeaving(self.state_machine, attempt)
class StateAuf(AbstractStateWhereUnlockingIsRedundant):
def __init__(self,sm):
......@@ -311,7 +326,8 @@ class StateMachine():
self.api().set_state(False)
class StateLocking(AbstractUnlockedState):
def __init__(self,sm):
def __init__(self, sm, close_attempts = 0):
self.close_attempts = close_attempts
# construct a nervlist
nervlist = [(CLOSE_REPEAT_TIMEOUT, lambda: self.actor().act(Actor.CMD_LOCK)) for t in range(CLOSE_REPEAT_NUMBER)]
nervlist += [(CLOSE_REPEAT_TIMEOUT, self.could_not_close)]
......@@ -323,35 +339,38 @@ class StateMachine():
if not pins.door_closed:
# TODO play a sound? This shouldn't happen, door was opened while we are locking
logger.warning("StateMachine: door manually opened during locking")
return StateMachine.StateAboutToOpen(self.state_machine)
return StateMachine.StateAboutToOpen(self.state_machine, self.close_attempts)
# TODO do anything here if the switch is activated now?
return super().handle_pins_event()
def handle_cmd_unlock_event(self,callback):
callback("409 conflict: The sphinx is currently trying to lock the door. Try again later.")
def could_not_close(self):
logger.critical("StateMachine: Couldn't close door after %d tries. Going back to StateAboutToOpen." % CLOSE_REPEAT_NUMBER)
return StateMachine.StateAboutToOpen(self.state_machine)
if self.close_attempts == 0:
logger.critical("StateMachine: Couldn't close door after %d tries. Going back to StateAboutToOpen." % CLOSE_REPEAT_NUMBER)
return StateMachine.StateAboutToOpen(self.state_machine, self.close_attempts)
class StateAboutToLeave(AbstractUnlockedState):
def __init__(self, sm):
nervlist = [(LEAVE_TIMEOUT, lambda: StateMachine.StateLocking(self.state_machine))]
def __init__(self, sm, close_attempts = 0):
self.close_attempts = close_attempts
nervlist = [(LEAVE_TIMEOUT, lambda: StateMachine.StateLocking(self.state_machine, self.close_attempts))]
super().__init__(sm, nervlist)
def handle_pins_event(self):
if not self.pins().door_closed:
return StateMachine.StateLeaving(self.state_machine)
return StateMachine.StateLeaving(self.state_machine, self.close_attempts)
if self.pins().space_active:
logger.info("Space re-activated, cancelling leaving procedure")
return StateMachine.StateAuf(self.state_machine)
return super().handle_pins_event()
class StateLeaving(AbstractUnlockedState):
def __init__(self, sm):
nervlist = [(LEAVE_TIMEOUT, lambda: StateMachine.StateAboutToOpen(self.state_machine))]
def __init__(self, sm, close_attempts = 0):
self.close_attempts = close_attempts
nervlist = [(LEAVE_TIMEOUT, lambda: StateMachine.StateAboutToOpen(self.state_machine, self.close_attempts))]
super().__init__(sm, nervlist)
def handle_pins_event(self):
if self.pins().door_closed:
logger.info("The space was left, locking the door")
return StateMachine.StateLocking(self.state_machine)
return StateMachine.StateLocking(self.state_machine, self.close_attempts)
if self.pins().space_active:
logger.info("Space re-activated, cancelling leaving procedure")
return StateMachine.StateAuf(self.state_machine)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment