-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlapem.py
534 lines (425 loc) · 14.2 KB
/
lapem.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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
# ========================================================
# Projet : Lapem = Lecteur Audio Pour Ecole Maternelle
# Author : Christian Klugesherz
# Mars 2022
#
# To run at the start : /etc/rc.local
# add before exit 0
# /usr/bin/python3 /home/pi/lapem/lapem.py &
#
# Before to code, check that no process is running !
# ps -ef | grep lapem
# if there should be, kill it
# sudo kill -9 [process]
#
# When the program is launched in the event of a :
# GPIO.add_event_detect(BUT_PLAY_PAUSE, GPIO.RISING, callback=state_machine, bouncetime=300)
# RuntimeError: Failed to add edge detection
# I solved the problem by installing the new gpio library:
#
# sudo apt remove python3-rpi.gpio
# sudo apt install python3-rpi-lgpio
# ========================================================
# ========================================================
# Import
# ========================================================
from time import sleep, monotonic
from common import setApplicationDebugLevel, pError, pDbg0, pDbg1, pDbg2
import RPi.GPIO as GPIO
import subprocess
import os
import json
from pygame import mixer # sudo apt-get install python3-pygame
# ========================================================
# Declarations
# ========================================================
# --------------------------------
# DEBUG_LEVEL
# --------------------------------
DEBUG_LEVEL = 0
# --------------------------------
# Will check every 20 seconds the Mode Status
# --------------------------------
LOOP_MODE_TIME = 20
# --------------------------------
# Button
# --------------------------------
# Play-Pause Button
# set GPIO25 as input (button)
# Internal Pull Down to avoid external resistors
# 3,3 V
BUT_PLAY_PAUSE = 25
# Back Button
# set GPIO24 as input (button)
# Internal Pull Down to avoid external resistors
# 3,3 V
BUT_BACK = 24
# --------------------------------
# Threshold before to access to Specific Mode
# --------------------------------
BUTTON_BACK_THRESHOLD= 5
# --------------------------------
# Led
# --------------------------------
# Play Led
# set GPIO18 as an output (LED)
# 5V
LED_PLAY = 18
# Power Led
# set GPIO17 as an output (LED)
# 5V
LED_POWER = 17
# --------------------------------
# Index for LedState
# Usage : LedState[STATE_PLAY][ID_PLAY]["LedMode"]
# --------------------------------
STATE_STOP = 0
STATE_PLAY = 1
STATE_PAUSE = 2
# --------------------------------
# Led Index
# Usage : LedState[STATE_PLAY][ID_PLAY]["LedMode"]
# --------------------------------
ID_PLAY = 0
ID_POWER = 1
# --------------------------------
# Led Mode
# For STATIC we will take the "ONT" status > 0 --> 1
# Take care to think to programm the Good value for Blink and Infinity
# For BLINK we will Loop with the ONT & OFFT NbL times, and we will end with a 0
# For INFINITY we will Loop with the ONT & OFFT infinity
#
# Usage : LedState[STATE_PLAY][ID_PLAY]["LedMode"] = BLINK
#
# --------------------------------
STATIC = 0
BLINK = 1
INFINITY = 2
# ========================================================
# Variables LED
# ========================================================
# -------------
# Led Stop
# -------------
LedPlayStop = {
"LedMode" : BLINK,
"ONT" : 0.08,
"OFFT" : 0.08,
"NbL" : 4
}
LedPowerStop = {
"LedMode" : STATIC,
"ONT" : 0.5,
"OFFT" : 0.5,
"NbL" : 1
}
LedStop = [LedPlayStop, LedPowerStop ]
# -------------
# Led Play
# -------------
LedPlayPlay = {
"LedMode" : STATIC,
"ONT" : 1,
"OFFT" : 0,
"NbL" : 1,
}
LedPowerPlay = {
"LedMode" : STATIC,
"ONT" : 0.5,
"OFFT" : 0.5,
"NbL" : 1,
}
LedPlay = [LedPlayPlay, LedPowerPlay]
# -------------
# Led Pause
# -------------
LedPlayPause = {
"LedMode" : STATIC,
"ONT" : 0,
"OFFT" : 0,
"NbL" : 1
}
LedPowerPause = {
"LedMode" : STATIC,
"ONT" : 0.5,
"OFFT" : 0.5,
"NbL" : 1
}
LedPause = [LedPlayPause, LedPowerPause]
# --------------------------------
# LED State
# Usage :
# : c_State = STATE_PAUSE
# : if LedState[c_State][ID_PLAY]["LedMode"] == BLINK
# --------------------------------
LedState = [ LedStop, LedPlay, LedPause]
# ========================================================
# Variables
# ========================================================
# General Timer
now = 0
# Swicht between Play and Pause
sw_PlayPause = 0
# Led Power timer
t_LPower = -1
# Led Play timer
t_LPlay = -1
# Timer Mode
t_Mode = 0
# Current Lapem Led State
c_State = STATE_STOP
# Blink Counter for Led Play
cnt_BlinkLedPlay = 0
# Blink Counter for Led Power
cnt_BlinkLedPower = 0
# Audio level
v_audio_level = 1
# ========================================================
# Functions
# ========================================================
# ---------------------------------------------
# init function
# All your initialization here
# ---------------------------------------------
def init():
# Input declaration Mode : BCM GPIO numbering
GPIO.setmode(GPIO.BCM)
# Leds
GPIO.setup(LED_PLAY, GPIO.OUT)
GPIO.setup(LED_POWER, GPIO.OUT)
# Default status
GPIO.output(LED_PLAY, 0)
GPIO.output(LED_POWER, 1)
# Button
GPIO.setup(BUT_PLAY_PAUSE, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(BUT_BACK, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
# Add an interrupt on pin on rising edge
GPIO.add_event_detect(BUT_PLAY_PAUSE, GPIO.RISING, callback=state_machine, bouncetime=300)
GPIO.add_event_detect(BUT_BACK, GPIO.RISING, callback=state_machine, bouncetime=300)
mixer.init() #Initialzing pyamge mixer
#Loading Music File
path = '/home/pi/lapem/music/audio.mp3'
# Verify
if os.path.isfile(path) :
mixer.music.load('/home/pi/lapem/music/audio.mp3')
else:
mixer.music.load('/home/pi/lapem/music/audio.wav')
v_audio_level = read_volume()
mixer.music.set_volume(v_audio_level)
mixer.music.play() #Playing Music with Pygame
mixer.music.pause() #pausing music file
# ---------------------------------------------
# Read Volume in file : volume.cfg, and return the value.
# ---------------------------------------------
def read_volume():
string1 = 'Volume'
# opening a text file
file1 = open("/home/pi/lapem/music/volume.cfg", "r")
# setting flag and index to 0
flag = 0
# Loop through the file line by line
for line in file1:
# checking string is present in line or not
if string1 in line:
flag = 1
break
# checking condition for string found or not
if flag == 0:
pError('String', string1 , 'Not Found')
else:
#pDbg0("Line : {}".format(line))
res = ""
for possibility in line.split():
try:
res = str(float(possibility.replace(',', '.')))
except ValueError:
pass
# closing text file
file1.close()
return(float(res))
# ---------------------------------------------
# Button Callback function
# function which call when a signal rising edge on pin
# This will set the current state and current mode
# ---------------------------------------------
def state_machine(vbut):
global c_State
global sw_PlayPause
global cnt_BlinkLedPlay
global cnt_BlinkLedPower
global v_audio_level
# Reinit Blink Counters
cnt_BlinkLedPower=0
cnt_BlinkLedPlay=0
if vbut == BUT_PLAY_PAUSE:
# Button Play or Pause
if sw_PlayPause == 0:
sw_PlayPause = 1
c_State = STATE_PLAY
pDbg1("State Play")
mixer.music.unpause() #unpausing music file
else:
sw_PlayPause = 0
c_State = STATE_PAUSE
pDbg1("State Pause")
mixer.music.pause() #pausing music file
else: #Button Back Pressed
# Force Button Play/Pause as Pause
sw_PlayPause = 0
pDbg1("State Stop")
c_State = STATE_STOP
mixer.music.stop()
#Loading Music File
path = '/home/pi/lapem/music/audio.mp3'
# Verify
if os.path.isfile(path) :
mixer.music.load('/home/pi/lapem/music/audio.mp3')
else:
mixer.music.load('/home/pi/lapem/music/audio.wav')
v_audio_level = read_volume()
mixer.music.set_volume(v_audio_level)
mixer.music.play() #Playing Music with Pygame
mixer.music.pause() #pausing music file
# ---------------------------------------------
# Check Mode change every 10 secondes
# ---------------------------------------------
def p_Mode():
global t_Mode
ip_address = ""
if now >= t_Mode + LOOP_MODE_TIME:
t_Mode = now
# Get IP Address of wan0
routes = json.loads(os.popen("ip -j -4 route").read())
for r in routes:
if r.get("dev") == "wlan0" and r.get("prefsrc"):
ip_address = r["prefsrc"]
continue
pDbg2("IP: {}".format(ip_address))
LedState[c_State][ID_POWER]["LedMode"] = STATIC
pDbg1("AP Mode : IP = {}".format(ip_address))
# c_Mode = MODE_CLIENT
# LedState[c_State][ID_POWER]["LedMode"] = INFINITY
# pDbg1("Client Mode : IP = {}".format(ip_address))
# ---------------------------------------------
#
# ---------------------------------------------
def p_LED():
# Clarifications
# If you set a value of a variable inside the function, python understands it as creating a local variable with that name.
# This local variable masks the global variable.
global t_LPlay
global t_LPower
global cnt_BlinkLedPlay
global cnt_BlinkLedPower
# ------------
# PLAY STATIC
# ------------
if LedState[c_State][ID_PLAY]["LedMode"] == STATIC :
out = LedState[c_State][ID_PLAY]["ONT"]
if out > 0 :
GPIO.output(LED_PLAY, 1)
else:
GPIO.output(LED_PLAY, 0)
# ------------
# PLAY BLINK
# ------------
elif LedState[c_State][ID_PLAY]["LedMode"] == BLINK :
onT = LedState[c_State][ID_PLAY]["ONT"]
offT = LedState[c_State][ID_PLAY]["OFFT"]
if cnt_BlinkLedPlay < 2 * LedState[c_State][ID_PLAY]["NbL"] :
if GPIO.input(LED_PLAY) == False:
if now >= t_LPlay + offT:
GPIO.output(LED_PLAY, 1)
t_LPlay = now
cnt_BlinkLedPlay = cnt_BlinkLedPlay + 1
#pDbg1(cnt_BlinkLedPlay )
if GPIO.input(LED_PLAY) == True:
if now >= t_LPlay + onT:
GPIO.output(LED_PLAY, 0)
t_LPlay = now
cnt_BlinkLedPlay = cnt_BlinkLedPlay + 1
#pDbg1(cnt_BlinkLedPlay )
else : # For BLINK, we will stop with LED Turn Off
GPIO.output(LED_PLAY, 0)
# ------------
# PLAY INFINITY
# ------------
elif LedState[c_State][ID_PLAY]["LedMode"] == INFINITY :
onT = LedState[c_State][ID_PLAY]["ONT"]
offT = LedState[c_State][ID_PLAY]["OFFT"]
if GPIO.input(LED_PLAY) == False:
if now >= t_LPlay + offT:
GPIO.output(LED_PLAY, 1)
t_LPlay = now
if GPIO.input(LED_PLAY) == True:
if now >= t_LPlay + onT:
GPIO.output(LED_PLAY, 0)
t_LPlay = now
else :
pError("Here We got an ERROR in p_LED for ID_PLAY !")
pError("(p_LED) c_State= {}".format(c_State))
pError("(p_LED) Led State= {}".format(LedState[c_State][ID_PLAY]["LedMode"]))
# ------------
# POWER STATIC
# ------------
if LedState[c_State][ID_POWER]["LedMode"] == STATIC :
out = LedState[c_State][ID_POWER]["ONT"]
if out > 0 :
GPIO.output(LED_POWER, 1)
else:
GPIO.output(LED_POWER, 0)
# ------------
# POWER BLINK
# ------------
elif LedState[c_State][ID_POWER]["LedMode"] == BLINK :
onT = LedState[c_State][ID_POWER]["ONT"]
offT = LedState[c_State][ID_POWER]["OFFT"]
if cnt_BlinkLedPower <= 2 * LedState[c_State][ID_POWER]["NbL"] :
if GPIO.input(LED_POWER) == False:
if now >= t_LPower + offT:
GPIO.output(LED_POWER, 1)
t_LPower = now
cnt_BlinkLedPower = cnt_BlinkLedPower + 1
if GPIO.input(LED_POWER) == True:
if now >= t_LPower + onT:
GPIO.output(LED_POWER, 0)
t_LPower = now
cnt_BlinkLedPower = cnt_BlinkLedPower + 1
else : # For BLINK, we will stop with LED Turn Off
GPIO.output(LED_POWER, 0)
# ------------
# POWER INFINITY
# ------------
elif LedState[c_State][ID_POWER]["LedMode"] == INFINITY :
onT = LedState[c_State][ID_POWER]["ONT"]
offT = LedState[c_State][ID_POWER]["OFFT"]
if GPIO.input(LED_POWER) == False:
if now >= t_LPower + offT:
GPIO.output(LED_POWER, 1)
t_LPower = now
if GPIO.input(LED_POWER) == True:
if now >= t_LPower + onT:
GPIO.output(LED_POWER, 0)
t_LPower = now
else :
pError("Here We got an ERROR in p_LED for ID_POWER !")
pError("(p_LED) c_State= {}".format(c_State))
pError("(p_LED) Led State= {}".format(LedState[c_State][ID_POWER]["LedMode"]))
# ---------------------------------------------
# ---------------------------------------------
if __name__ == '__main__':
# call init
setApplicationDebugLevel(DEBUG_LEVEL)
init()
try:
# looping infinitely
while True:
# monotonic only available in Python3 !
now = monotonic()
p_Mode()
p_LED()
sleep(0.1)
# this block will run no matter how the try block exits
except KeyboardInterrupt:
GPIO.cleanup() # clean up after yourself