complete SpaceAPI integration
authorRalf Jung <post@ralfj.de>
Wed, 30 Oct 2013 20:02:25 +0000 (21:02 +0100)
committerRalf Jung <post@ralfj.de>
Wed, 30 Oct 2013 20:02:25 +0000 (21:02 +0100)
.gitignore
libtuer.py
spaceapi.py [moved from concept_spaceapi.py with 52% similarity]
statemachine.py
tuerd

index bee8a64b79a99590d5303307144172cfe824fbf7..3afd512b15dc7b19d25f4a366967a09e74267747 100644 (file)
@@ -1 +1,2 @@
 __pycache__
+config.py
index 835bf6d51003e22dd8a2d5e3b9ed72e85fae0577..01c04ae5d725863fecefe6fceddcae4f931833d2 100644 (file)
@@ -5,7 +5,7 @@ import email.mime.text, email.utils
 # Logging configuration
 syslogLevel = logging.INFO
 mailLevel   = logging.CRITICAL # must be "larger" than syslog level!
-mailAddress = ['post+tuer'+'@'+'ralfj.de', 'vorstand@lists.hacksaar.de']
+from config import mailAddress
 printLevel  = logging.DEBUG
 
 # Mail logging handler
similarity index 52%
rename from concept_spaceapi.py
rename to spaceapi.py
index 0f251d7d4b3c1e3b065566ef407c0180c4a62ba4..89e3678290e652773306d697aa642a364b2c1e55 100644 (file)
@@ -1,7 +1,11 @@
 from threading import Lock
+from libtuer import ThreadFunction, logger
+import urllib.request
+
+from config import spaceApiKey
 
 class SpaceApi:
-       __init__ (self, waker):
+       def __init__ (self, waker):
                self._state_to_set = None
                self._state_last_set = None
                self._running = True
@@ -12,6 +16,20 @@ class SpaceApi:
        def stop (self):
                self.set_state.stop()
        
+       def _do_request(self, state):
+               state_val = 1 if state else 0
+               try:
+                       logger.info("Setting SpaceAPI to %d" % state_val)
+                       url = "http://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()
+                       if response.getcode() == 200 and responseText == "UpdateSuccessful": return True
+                       logger.error("SpaceAPI returned unexpected code %d, content %s" % (response.getcode(), responseText))
+                       return False
+               except urllib.request.URLError as e:
+                       logger.error("SpaceAPI update returned error: %s" % str(e))
+                       return False
+       
        # set_state is the asynchronous version of _set_state (see __init__)
        def _set_state (self, state = None):
                '''Sets the state, if None: leave state unchanged and re-try if previous attempts failed'''
@@ -31,10 +49,9 @@ class SpaceApi:
                                # check if there's something we need to do
                                if self._state_last_set == state: return
                                # take action!
-                               error = do_request(stts) # TODO
-                               #TODO logging
-                               #TODO error too often -> log critical to send mails
-                               if not error:
-                                       self.state_last_set = stts
+                               success = self._do_request(state)
+                               # TODO error too often -> log critical to send mails
+                               if success:
+                                       self._state_last_set = state
                        finally:
                                self._set_state_lock.release()
index 12e8bd5b79280e9601e3050839f3ab7bfddaa436..a937f50c035140cef91d504006a0dbbce60f7014 100644 (file)
@@ -1,4 +1,4 @@
-from libtuer import ThreadFunction, logger, fire_and_forget
+from libtuer import ThreadFunction, logger, fire_and_forget, fire_and_forget_cmd
 from actor import Actor
 import os, random, time, threading
 
@@ -90,6 +90,8 @@ class StateMachine():
                        return self.state_machine.old_pins
                def actor(self):
                        return self.state_machine.actor
+               def api(self):
+                       return self.state_machine.api
                def handle_event(self,ev,arg): # don't override
                        if ev == StateMachine.CMD_PINS:
                                return self.handle_pins_event()
@@ -241,6 +243,7 @@ class StateMachine():
                        nervlist = [(24*60*60, lambda: logger.critical("Space is now open for 24h. Is everything all right?"))]
                        super().__init__(sm, nervlist)
                        self.last_buzzed = None
+                       self.api().set_state(True)
                def handle_pins_event(self):
                        pins = self.pins()
                        if pins.bell_ringing and not self.old_pins().bell_ringing: # first thing to check: edge detection
@@ -251,6 +254,8 @@ class StateMachine():
                                logger.info("StateMachine: space switch turned off - starting leaving procedure")
                                return StateMachine.StateAboutToLeave(self.state_machine)
                        return super().handle_pins_event()
+               def on_leave(self):
+                       self.api().set_state(False)
        
        class StateLocking(AbstractUnlockedState):
                def __init__(self,sm):
@@ -299,13 +304,16 @@ class StateMachine():
                                return StateMachine.StateAuf(self.state_machine)
                        return super().handle_pins_event()
        
-       def __init__(self, actor, waker, fallback = False):
+       def __init__(self, actor, waker, api, fallback = False):
                self.actor = actor
+               self.api = api
                self.callback = ThreadFunction(self._callback, name="StateMachine")
                self.current_state = StateMachine.StateStart(self, fallback=fallback)
                self.pins = None
                self.old_pins = None
                waker.register(lambda: self.callback(StateMachine.CMD_WAKEUP), 1.0) # wake up every second
+               # initially, the space is closed
+               api.set_state(False)
        
        def stop (self):
                self.callback.stop()
diff --git a/tuerd b/tuerd
index 8290c83cf718fa0f22c1357ef7f50cca89361da9..220b2bca8078dd1efe57be8d1105d0154123846b 100755 (executable)
--- a/tuerd
+++ b/tuerd
@@ -1,6 +1,6 @@
 #!/usr/bin/python3
 import RPi.GPIO as GPIO
-import statemachine, actor, pins, tysock, waker
+import statemachine, actor, pins, tysock, waker, spaceapi
 from libtuer import logger
 import argparse
 
@@ -31,7 +31,8 @@ GPIO.setmode(GPIO.BOARD)
 # bring 'em all up
 the_actor = actor.Actor()
 the_waker = waker.Waker()
-the_machine = statemachine.StateMachine(the_actor, the_waker, args.fallback)
+the_api   = spaceapi.SpaceApi(the_waker)
+the_machine = statemachine.StateMachine(the_actor, the_waker, the_api, args.fallback)
 the_socket = tysock.TySocket(the_machine)
 the_pins = pins.PinsWatcher(the_machine)
 
@@ -47,6 +48,7 @@ except KeyboardInterrupt:
 the_waker.stop() # this one first, it "randomly" calls other threads
 the_pins.stop() # as does this
 the_machine.stop()
+the_api.stop()
 the_actor.stop()
 
 # shutdown GPIO stuff