From 0889e9a1ec6bda2c4b16dabf0ab40793ac17756c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Oct 2013 21:02:25 +0100 Subject: [PATCH] complete SpaceAPI integration --- .gitignore | 1 + libtuer.py | 2 +- concept_spaceapi.py => spaceapi.py | 29 +++++++++++++++++++++++------ statemachine.py | 12 ++++++++++-- tuerd | 6 ++++-- 5 files changed, 39 insertions(+), 11 deletions(-) rename concept_spaceapi.py => spaceapi.py (52%) diff --git a/.gitignore b/.gitignore index bee8a64..3afd512 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ __pycache__ +config.py diff --git a/libtuer.py b/libtuer.py index 835bf6d..01c04ae 100644 --- a/libtuer.py +++ b/libtuer.py @@ -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 diff --git a/concept_spaceapi.py b/spaceapi.py similarity index 52% rename from concept_spaceapi.py rename to spaceapi.py index 0f251d7..89e3678 100644 --- a/concept_spaceapi.py +++ b/spaceapi.py @@ -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() diff --git a/statemachine.py b/statemachine.py index 12e8bd5..a937f50 100644 --- a/statemachine.py +++ b/statemachine.py @@ -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 8290c83..220b2bc 100755 --- 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 -- 2.30.2