18
18
19
19
import sys
20
20
import os
21
+ import datetime
21
22
from enum import Enum
22
23
import logging as log
23
24
import RPi .GPIO as GPIO
@@ -41,35 +42,35 @@ class InitialPinBehavior(Enum):
41
42
UNMODIFIED = 3
42
43
43
44
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
47
48
debug = False
48
49
gpio_pins = (7 , 11 , 12 , 13 , 15 , 16 , 18 , 22 , 29 , 31 , 32 , 33 , 35 , 36 , 37 , 38 , 40 )
50
+ gpio_pin_history = {}
49
51
initial_pin_state = InitialPinBehavior .DEFAULT
50
52
app = Flask (__name__ )
51
53
CORS (app )
52
54
app .url_map .strict_slashes = False
53
55
56
+
54
57
log .basicConfig (
55
58
level = log_level ,
56
59
format = "%(asctime)s [%(levelname)s] %(message)s" ,
57
- handlers = [
58
- log .StreamHandler (sys .stdout )
59
- ]
60
+ handlers = [log .StreamHandler (sys .stdout )],
60
61
)
61
62
62
63
63
- @app .route (' /healthz' )
64
+ @app .route (" /healthz" )
64
65
def health_check ():
65
66
"""Health check
66
67
67
68
Returns a value to ensure the service is up.
68
69
"""
69
- return ' healthy'
70
+ return " healthy"
70
71
71
72
72
- @app .route (' /version' )
73
+ @app .route (" /version" )
73
74
def version ():
74
75
"""Version
75
76
@@ -78,22 +79,24 @@ def version():
78
79
return __version__
79
80
80
81
81
- @app .route (' /pins' )
82
+ @app .route (" /pins" )
82
83
def get_all_pins ():
83
84
"""Get pins
84
85
85
86
Retries a list of all GPIO pins and their current values.
86
87
"""
87
88
result = []
88
89
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 )
90
93
result .append (pin_result )
91
94
92
95
log .info ("Retrieved values for all pins" )
93
96
return jsonify (result )
94
97
95
98
96
- @app .route (' /pins/all/<int:value>' )
99
+ @app .route (" /pins/all/<int:value>" )
97
100
def set_all_pins (value ):
98
101
"""Set pins to value
99
102
@@ -103,45 +106,50 @@ def set_all_pins(value):
103
106
for pin in gpio_pins :
104
107
new_value = set_get_pin_value (pin , value )
105
108
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 )
108
113
result .append (pin_result )
109
114
110
115
log .info ("Set value of all pins to {}" .format (value ))
111
116
return jsonify (result )
112
117
113
118
114
- @app .route (' /pins/<int:pin>' )
119
+ @app .route (" /pins/<int:pin>" )
115
120
def get_pin (pin ):
116
121
"""Get pin value
117
122
118
123
Gets the current value for a given GPIO pin.
119
124
"""
120
125
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
+
123
130
return str (pin_value )
124
131
125
132
126
- @app .route (' /pins/<int:pin>/<int:value>' )
133
+ @app .route (" /pins/<int:pin>/<int:value>" )
127
134
def set_pin (pin , value ):
128
135
"""Set pin value
129
136
130
137
Sets a GPIO pin to a specified value.
131
138
"""
132
139
pin_value = set_get_pin_value (pin , value )
133
140
134
- if ( value != pin_value ) :
141
+ if value != pin_value :
135
142
msg = "Failed to set pin '{}'. Expected {} to be {}" .format (
136
- pin , pin_value , value )
143
+ pin , pin_value , value
144
+ )
137
145
log .exception (msg )
138
146
raise Exception (msg )
139
147
140
148
log .info ("Set value for pin '{}' (value: {})" .format (pin , pin_value ))
141
149
return str (pin_value )
142
150
143
151
144
- @app .route (' /sensors/dht11/<int:pin>' )
152
+ @app .route (" /sensors/dht11/<int:pin>" )
145
153
def get_sensor_dht11 (pin ):
146
154
"""Get DHT11 sensor reading
147
155
@@ -154,20 +162,27 @@ def get_sensor_dht11(pin):
154
162
return jsonify (result .to_dict ())
155
163
156
164
157
- @app .route (' /sensors/hcsr04/<int:trigger_pin>/<int:echo_pin>' )
165
+ @app .route (" /sensors/hcsr04/<int:trigger_pin>/<int:echo_pin>" )
158
166
def get_sensor_hcsr04 (trigger_pin , echo_pin ):
159
167
"""Get HC-SR04 sensor reading
160
168
Gets a reading for a HC-SR04 ultrasonic sonar distance sensor.
161
169
See: https://adafru.it/3942
162
170
"""
163
171
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 }
166
177
args .update (request .args )
167
178
168
179
sensor = HCSR04 (** args )
169
180
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
+ )
171
186
return jsonify (result )
172
187
173
188
@@ -194,6 +209,7 @@ def set_pin_value(pin, value):
194
209
Sets a GPIO pin value.
195
210
"""
196
211
GPIO .output (pin , value )
212
+ set_pin_history (pin )
197
213
198
214
199
215
def set_get_pin_value (pin , value ):
@@ -205,6 +221,19 @@ def set_get_pin_value(pin, value):
205
221
return get_pin_value (pin )
206
222
207
223
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
+
208
237
def setup_gpio ():
209
238
"""Sets up the GPIO pins
210
239
@@ -236,15 +265,18 @@ def set_initial_state(pin):
236
265
GPIO .output (pin , state )
237
266
238
267
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
+ )
242
274
try :
243
275
setup_gpio ()
244
276
app .run (debug = debug , host = host , port = port )
245
277
except Exception as e :
246
- log .error (' Fatal application error occurred: {}' .format (e ))
278
+ log .error (" Fatal application error occurred: {}" .format (e ))
247
279
finally :
248
- log .debug (' App is shutting down, cleaning up GPIO' )
280
+ log .debug (" App is shutting down, cleaning up GPIO" )
249
281
GPIO .cleanup ()
250
- log .info (' GPIO has been cleaned up' )
282
+ log .info (" GPIO has been cleaned up" )
0 commit comments