1818
1919import sys
2020import os
21+ import datetime
2122from enum import Enum
2223import logging as log
2324import RPi .GPIO as GPIO
@@ -41,35 +42,35 @@ class InitialPinBehavior(Enum):
4142 UNMODIFIED = 3
4243
4344
44- host = os .getenv (' SERVER_HOST' ) or ' 0.0.0.0'
45- port = os .getenv (' SERVER_PORT' ) or 5000
46- log_level = os .getenv (' SERVER_LOG_LEVEL' ) or log .INFO
45+ host = os .getenv (" SERVER_HOST" ) or " 0.0.0.0"
46+ port = os .getenv (" SERVER_PORT" ) or 5000
47+ log_level = os .getenv (" SERVER_LOG_LEVEL" ) or log .WARN
4748debug = False
4849gpio_pins = (7 , 11 , 12 , 13 , 15 , 16 , 18 , 22 , 29 , 31 , 32 , 33 , 35 , 36 , 37 , 38 , 40 )
50+ gpio_pin_history = {}
4951initial_pin_state = InitialPinBehavior .DEFAULT
5052app = Flask (__name__ )
5153CORS (app )
5254app .url_map .strict_slashes = False
5355
56+
5457log .basicConfig (
5558 level = log_level ,
5659 format = "%(asctime)s [%(levelname)s] %(message)s" ,
57- handlers = [
58- log .StreamHandler (sys .stdout )
59- ]
60+ handlers = [log .StreamHandler (sys .stdout )],
6061)
6162
6263
63- @app .route (' /healthz' )
64+ @app .route (" /healthz" )
6465def health_check ():
6566 """Health check
6667
6768 Returns a value to ensure the service is up.
6869 """
69- return ' healthy'
70+ return " healthy"
7071
7172
72- @app .route (' /version' )
73+ @app .route (" /version" )
7374def version ():
7475 """Version
7576
@@ -78,22 +79,24 @@ def version():
7879 return __version__
7980
8081
81- @app .route (' /pins' )
82+ @app .route (" /pins" )
8283def get_all_pins ():
8384 """Get pins
8485
8586 Retries a list of all GPIO pins and their current values.
8687 """
8788 result = []
8889 for pin in gpio_pins :
89- pin_result = {'pin' : pin , 'value' : get_pin_value (pin )}
90+ pin_result = {"pin" : pin , "value" : get_pin_value (pin )}
91+ history = get_pin_history (pin )
92+ pin_result .update (history )
9093 result .append (pin_result )
9194
9295 log .info ("Retrieved values for all pins" )
9396 return jsonify (result )
9497
9598
96- @app .route (' /pins/all/<int:value>' )
99+ @app .route (" /pins/all/<int:value>" )
97100def set_all_pins (value ):
98101 """Set pins to value
99102
@@ -103,45 +106,50 @@ def set_all_pins(value):
103106 for pin in gpio_pins :
104107 new_value = set_get_pin_value (pin , value )
105108 changed = value != new_value
106- pin_result = {'pin' : pin , 'value' : get_pin_value (
107- pin ), 'changed' : changed }
109+ pin_result = {"pin" : pin , "value" : get_pin_value (pin ), "changed" : changed }
110+
111+ history = get_pin_history (pin )
112+ pin_result .update (history )
108113 result .append (pin_result )
109114
110115 log .info ("Set value of all pins to {}" .format (value ))
111116 return jsonify (result )
112117
113118
114- @app .route (' /pins/<int:pin>' )
119+ @app .route (" /pins/<int:pin>" )
115120def get_pin (pin ):
116121 """Get pin value
117122
118123 Gets the current value for a given GPIO pin.
119124 """
120125 pin_value = get_pin_value (pin )
121- log .info ("Retrieved value for pin '{}' (value: {})" .format (
122- str (pin ), str (pin_value )))
126+ log .info (
127+ "Retrieved value for pin '{}' (value: {})" .format (str (pin ), str (pin_value ))
128+ )
129+
123130 return str (pin_value )
124131
125132
126- @app .route (' /pins/<int:pin>/<int:value>' )
133+ @app .route (" /pins/<int:pin>/<int:value>" )
127134def set_pin (pin , value ):
128135 """Set pin value
129136
130137 Sets a GPIO pin to a specified value.
131138 """
132139 pin_value = set_get_pin_value (pin , value )
133140
134- if ( value != pin_value ) :
141+ if value != pin_value :
135142 msg = "Failed to set pin '{}'. Expected {} to be {}" .format (
136- pin , pin_value , value )
143+ pin , pin_value , value
144+ )
137145 log .exception (msg )
138146 raise Exception (msg )
139147
140148 log .info ("Set value for pin '{}' (value: {})" .format (pin , pin_value ))
141149 return str (pin_value )
142150
143151
144- @app .route (' /sensors/dht11/<int:pin>' )
152+ @app .route (" /sensors/dht11/<int:pin>" )
145153def get_sensor_dht11 (pin ):
146154 """Get DHT11 sensor reading
147155
@@ -154,20 +162,27 @@ def get_sensor_dht11(pin):
154162 return jsonify (result .to_dict ())
155163
156164
157- @app .route (' /sensors/hcsr04/<int:trigger_pin>/<int:echo_pin>' )
165+ @app .route (" /sensors/hcsr04/<int:trigger_pin>/<int:echo_pin>" )
158166def get_sensor_hcsr04 (trigger_pin , echo_pin ):
159167 """Get HC-SR04 sensor reading
160168 Gets a reading for a HC-SR04 ultrasonic sonar distance sensor.
161169 See: https://adafru.it/3942
162170 """
163171 log .info (
164- "Reading HC-SR04 sensor for pin 'trigger: {}, echo: {}'" .format (trigger_pin , echo_pin ))
165- args = {'trigger_pin' : trigger_pin , 'echo_pin' : echo_pin }
172+ "Reading HC-SR04 sensor for pin 'trigger: {}, echo: {}'" .format (
173+ trigger_pin , echo_pin
174+ )
175+ )
176+ args = {"trigger_pin" : trigger_pin , "echo_pin" : echo_pin }
166177 args .update (request .args )
167178
168179 sensor = HCSR04 (** args )
169180 result = sensor .read ()
170- log .info ("Retrieved HC-SR04 sensor reading for pin 'trigger: {}, echo: {}'" .format (trigger_pin , echo_pin ))
181+ log .info (
182+ "Retrieved HC-SR04 sensor reading for pin 'trigger: {}, echo: {}'" .format (
183+ trigger_pin , echo_pin
184+ )
185+ )
171186 return jsonify (result )
172187
173188
@@ -194,6 +209,7 @@ def set_pin_value(pin, value):
194209 Sets a GPIO pin value.
195210 """
196211 GPIO .output (pin , value )
212+ set_pin_history (pin )
197213
198214
199215def set_get_pin_value (pin , value ):
@@ -205,6 +221,19 @@ def set_get_pin_value(pin, value):
205221 return get_pin_value (pin )
206222
207223
224+ def get_pin_history (pin ):
225+ return gpio_pin_history [pin ] or {"lastValue" : None }
226+
227+
228+ def set_pin_history (pin ):
229+ history = {"lastChange" : datetime .datetime .now ()}
230+ if not gpio_pin_history [pin ]:
231+ gpio_pin_history [pin ] = history
232+
233+ record = gpio_pin_history [pin ]
234+ record .update (history )
235+
236+
208237def setup_gpio ():
209238 """Sets up the GPIO pins
210239
@@ -236,15 +265,18 @@ def set_initial_state(pin):
236265 GPIO .output (pin , state )
237266
238267
239- if __name__ == '__main__' :
240- log .info ('Starting app at {}:{} (debug:{}). Version {}' .format (
241- host , port , debug , __version__ ))
268+ if __name__ == "__main__" :
269+ log .info (
270+ "Starting app at {}:{} (debug:{}). Version {}" .format (
271+ host , port , debug , __version__
272+ )
273+ )
242274 try :
243275 setup_gpio ()
244276 app .run (debug = debug , host = host , port = port )
245277 except Exception as e :
246- log .error (' Fatal application error occurred: {}' .format (e ))
278+ log .error (" Fatal application error occurred: {}" .format (e ))
247279 finally :
248- log .debug (' App is shutting down, cleaning up GPIO' )
280+ log .debug (" App is shutting down, cleaning up GPIO" )
249281 GPIO .cleanup ()
250- log .info (' GPIO has been cleaned up' )
282+ log .info (" GPIO has been cleaned up" )
0 commit comments