From 0889e9a1ec6bda2c4b16dabf0ab40793ac17756c Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
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.39.5