-
Notifications
You must be signed in to change notification settings - Fork 0
/
startTimerv2.py
291 lines (246 loc) · 9.09 KB
/
startTimerv2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#!/usr/bin/env python3
#
# Version 0.4 21st July 2015
#
# 0.1 - the initial version which used shell to control GPIO pin 17
# 0.2 - uses file io to control GPIO pin 17 so there no 'shelling'
# 0.3 - fixed timing loop and extended functional logic
# 0.4 - added threading for control of the the external relay
#
import sys
import subprocess
import time
import datetime
import queue
from time import localtime, strftime, sleep
import threading
#from threading import Timer
import pifacecad
import pifacerelayplus
PY3 = sys.version_info[0] >= 3
if not PY3:
print("startTimer only works with `python3`.")
sys.exit(1)
switchlistener = 0
# global flags
g_horn_time = 1.5 # number of seconds to sound the horn
g_horn = 0
g_running = 1 # loop until exit
g_started = 0 # not started the count
g_stop_timer = 5 # not started the count
g_timer_started = 0
g_race_started = 0 # has the race started?
g_def_time = 300
g_start_time = 300 # 5 minutes
#g_fileid = 0
ONE_MIN = 60
FOUR_MINS = 4 * ONE_MIN
ltime = localtime() # the local time
# define the 'commands'
TURN_ON = 1
TURN_OFF = 0
#TURN_ON = "echo '1' > /sys/class/gpio/gpio17/value"
#TURN_OFF = "echo '0' > /sys/class/gpio/gpio17/value"
# routine that is run as a thread to control external relay
def Sound_horn():
while (True):
delay = Horn_queue.get()
#g_fileid.write("1\n") # turn external device on
pfr.relays[0].toggle()
time.sleep (delay)
#g_fileid.write("0\n") # and turn it off
pfr.relays[0].toggle()
Horn_queue.task_done()
time.sleep (0.3) # wait 1/3 sec so there is a definite 'gap' between execution
# functions to run the commands - cmd would be TURN_ON or TURN_OFF
def run_cmd(cmd):
#return subprocess.check_output(cmd, shell=True).decode('utf-8')
if (cmd == TURN_ON):
#g_fileid.write("1\n")
pfr.relays[0].turn_on()
else:
pfr.relays[0].turn_off()
#g_fileid.write("0\n")
#
# uses the toggle switch on the back of the unit - has guard condition so no exit if count started
# intention is to extend this with menu (one option - exit) so that horn duraction can be changed
#
def button_menu(event):
global g_running
global g_started
if g_started == 0: # if stopped/reset then
g_running = 0 # stop, that is exit for now
#
# note screen update calls removed as there appeared to be a race condition on the interrupts
# this button could be used for general recalls in the final system
#
def button_recall(event):
global g_running
global g_started
global g_horn
#cad.lcd.clear()
#event.chip.lcd.set_cursor(15,1)
#event.chip.lcd.write("Stop") # str(event.pin_num))
Horn_queue.put(g_horn_time)
#if g_started == 1:
# sound horn should also put a guard here as we should only allow this if we have started!
# if we haven't started this could be used for AP
#run_cmd(TURN_ON)
#g_horn = 1
#else:
#g_running = 0 # stop, that is exit for now
# start or stop the start timer
def button_start_stop(event):
global g_started
global g_timer_started
global g_horn
#event.chip.lcd.set_cursor(15,1)
#event.chip.lcd.write(str(event.pin_num))
if g_started == 0:
g_started = 1
g_stop_timer = 5 # reset to ensure it 5 seconds
if (g_timer_started == 0): # have pressed the start for the first time
g_timer_started = 1
#run_cmd(TURN_ON)
Horn_queue.put(g_horn_time)
#g_horn = 1
else:
g_started = 0
# if stopped reset count
def button_reset(event):
global g_running
global g_start_time
global g_stop_timer
global g_timer_started
global g_race_started
if g_started == 0:
g_race_started = 0
g_timer_started = 0
g_stop_timer = 5
g_start_time = g_def_time
def button_incr(event):
global g_start_time
#event.chip.lcd.set_cursor(15,1)
#event.chip.lcd.write(str(event.pin_num))
if (g_started == 0 and g_start_time < g_def_time * 3):
g_start_time = g_start_time + 300 # add 5 minutes
#update_display()
def button_decr(event):
global g_start_time
#event.chip.lcd.set_cursor(15,1)
#event.chip.lcd.write(str(event.pin_num))
if (g_started == 0 and g_start_time >= g_def_time * 2):
g_start_time = g_start_time - 300 # sub 5 minutes
#update_display()
# display the current count and time
def update_display():
global ltime
global g_race_started
#cad.lcd.clear()
t_hr = int(g_start_time/3600)
t_min = int((g_start_time - (t_hr * 3600))/60)
t_sec = int(g_start_time - (t_hr * 3600) - (t_min * 60))
d = datetime.datetime (1970, 1, 1, t_hr, t_min, t_sec)
#lt = localtime()
cad.lcd.set_cursor(0,0)
if (g_started == 0 and g_race_started == 0):
cad.lcd.write("Start: {:%M:%S} ".format(d)) # cad.lcd.write("Start: {0:2d}:{1:2d}".format(*min_sec))
if (g_started == 1):
cad.lcd.set_cursor(0,0)
if (g_race_started == 1):
cad.lcd.write("Race : {:%H:%M:%S}".format(d)) # cad.lcd.write("Start: {0:2d}:{1:2d}".format(*min_sec))
else:
cad.lcd.write("Start: {:%M:%S} ".format(d)) # cad.lcd.write("Start: {0:2d}:{1:2d}".format(*min_sec))
cad.lcd.set_cursor(0,1)
cad.lcd.write("Time : " + strftime("%H:%M:%S", ltime))
#cad.lcd.write("Time : " + strftime("%H:%M:%S", localtime()))
def init():
global switchlistener
#global g_fileid
#global cad
#cad = pifacecad.PiFaceCAD()
cad.lcd.blink_off()
cad.lcd.cursor_off()
cad.lcd.backlight_on()
# open for read/write non-buffered - old prior to pfr
#g_fileid = open ("/sys/class/gpio/gpio17/value", "r+", 1)
# define the listener
switchlistener = pifacecad.SwitchEventListener(chip=cad)
# register the button 0 = start/stop, 1 = reset, 2 = incr, 3 = decr, 4 = exit
switchlistener.register(0, pifacecad.IODIR_FALLING_EDGE, button_start_stop)
switchlistener.register(1, pifacecad.IODIR_FALLING_EDGE, button_incr)
switchlistener.register(2, pifacecad.IODIR_FALLING_EDGE, button_decr)
switchlistener.register(3, pifacecad.IODIR_FALLING_EDGE, button_reset)
switchlistener.register(4, pifacecad.IODIR_FALLING_EDGE, button_recall)
switchlistener.register(5, pifacecad.IODIR_FALLING_EDGE, button_menu)
# ensure external signal is off
run_cmd(TURN_OFF)
# start the listeners
switchlistener.activate()
# main()
if __name__ == "__main__":
# define the thread for external control and related queue
Horn_queue = queue.Queue()
t = threading.Thread(target=Sound_horn)
t.daemon = True # note that this is not deamon!
t.start()
# initialise display and relay etc
cad = pifacecad.PiFaceCAD()
pfr = pifacerelayplus.PiFaceRelayPlus(pifacerelayplus.RELAY)
init()
# note the current time before entering loop and increment it by 1 second
next_call = time.time()
next_call = next_call + 1 # 1 second
# while loop - display time
while (g_running == 1):
# need to extend this to allow for a 'long' sound, that is a couple of seconds
if g_horn > 0:
g_horn = g_horn - 1
if (g_horn == 0):
run_cmd(TURN_OFF)
if (g_timer_started == 1 and g_race_started == 0): # decrement the seconds
if (g_started == 1): # if counting
g_start_time -= 1
elif (g_timer_started == 1 and g_race_started == 1):
g_start_time += 1
if (g_started == 0): # counting stopped
g_stop_timer = g_stop_timer - 1
if (g_stop_timer == 0):
g_started = 1 # restart the display
g_stop_timer = 5 # reset the count
update_display()
if (g_race_started == 0 and (g_start_time == FOUR_MINS or g_start_time == ONE_MIN or g_start_time == 0)):
#run_cmd(TURN_ON)
if (g_start_time == ONE_MIN):
#g_horn = 2 # long sound
Horn_queue.put(2 * g_horn_time)
else:
#g_horn = 1 # standard sound
Horn_queue.put(g_horn_time)
if (g_start_time == 0): # time to start!
g_race_started = 1
# this is the tricky bit we increment the time and once we've slept we check the time so that we know what 1 second will be
# this removes the 'cost' of the display updates and ensures that we only sleep till the next second and not possibly longer
# but this still results in a drift 2-3 seconds in an hour so the count gets out of step with the 'time'
# guard condition for IOError 22 doesn't occur if the code execution is unnormally long
if ((next_call - time.time()) > 0.0):
time.sleep(next_call - time.time())
next_call = time.time()
next_call = next_call + 1 # 1 second
ltime = localtime()
# reset the display so cursor at left of display
#cad.lcd.clear()
#cad.lcd.write("\nDemo finished.")
#sleep(1)
# tidyup
switchlistener.deactivate()
cad.lcd.clear()
cad.lcd.display_off()
cad.lcd.backlight_off()
# close the GPIO control file
#g_fileid.close()
# no exit for pfr
# ensure queue drained
Horn_queue.join()
# exit
sys.exit(0)