Compare commits
9 Commits
v0.2.0
...
124ab39f82
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
124ab39f82 | ||
|
|
eaaeadf642 | ||
|
|
ce9a4837e1 | ||
|
|
c25733b64c | ||
|
|
88dce016de | ||
|
|
20f0eb71b9 | ||
|
|
4a5498866c | ||
|
|
1555050909 | ||
|
|
3edf9ba34c |
10
README.md
10
README.md
@@ -38,6 +38,16 @@ Say what the step will be
|
||||
Give the example
|
||||
```
|
||||
|
||||
### Users Manual
|
||||
|
||||
Button 1:
|
||||
short press: show alarm time
|
||||
long press: enter edit mode
|
||||
|
||||
Button 1 & Button 2 simutaneous:
|
||||
long press: turn alarm off
|
||||
|
||||
|
||||
### Hardware
|
||||
|
||||
Overview of used hardware:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import time
|
||||
import RPi.GPIO as GPIO
|
||||
@@ -16,7 +16,8 @@ class Button:
|
||||
presstime=0
|
||||
ignore=0
|
||||
|
||||
def __init__(self, gpio):
|
||||
def __init__(self, gpio,verbose=False):
|
||||
if verbose:
|
||||
print("initialize button on gpio %d" %gpio)
|
||||
self.gpio = gpio
|
||||
GPIO.setup(self.gpio, GPIO.IN, pull_up_down = GPIO.PUD_UP)
|
||||
|
||||
10
changes.txt
10
changes.txt
@@ -1,15 +1,15 @@
|
||||
|
||||
|
||||
|
||||
v0.2.5 * Changed readmp3s routine to clockytracklist (merge)
|
||||
|
||||
v0.2.0 * Adjusted code for python 3
|
||||
|
||||
|
||||
0.1.0:
|
||||
v0.1.0 * added max7219 support, added signal handling
|
||||
* Added additional logging messages for end of alarm
|
||||
* implemented SIGINT (Ctrl-C) handling to exit gracefully
|
||||
|
||||
0.0.5:
|
||||
* initial working version
|
||||
v0.0.5 * initial working version
|
||||
* show alarmtime in startup
|
||||
|
||||
------------------------------------------------------------
|
||||
@@ -24,5 +24,5 @@ issues
|
||||
|
||||
todo
|
||||
----
|
||||
add SIGHUP handling for reload config
|
||||
changes config file format to json
|
||||
make documentation
|
||||
|
||||
173
clocky.py
173
clocky.py
@@ -1,26 +1,29 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import pickle
|
||||
import os.path
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
import tm1637
|
||||
import max7219
|
||||
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
|
||||
import pygame
|
||||
from time import sleep,strftime
|
||||
import RPi.GPIO as GPIO
|
||||
import button
|
||||
import signal
|
||||
import clockytracklist
|
||||
|
||||
VERBOSE=False
|
||||
settings= {}
|
||||
looptype=0
|
||||
quit=0
|
||||
|
||||
|
||||
print("\n +----------+\n | Clocky |\n | v0.2.0 |\n +----------+\n")
|
||||
print("\n +----------+\n | Clocky |\n | v0.2.5 |\n +----------+\n")
|
||||
|
||||
o_configfilename = "clocky.conf"
|
||||
o_defaultalarmtime = 60*13+24 # hh*60+mm
|
||||
o_defaultalarmtime = 60*14+10 # hh*60+mm
|
||||
o_showalarmtime=3 # time that the alarmtime shows after short press
|
||||
o_showtracktime=2 # note that this is per track, so total time is 10 times longer
|
||||
o_editdelaytime=3 # time it takes to qualify as longpress
|
||||
@@ -34,13 +37,29 @@ o_defaultbrightness=0
|
||||
o_loopdelay=0.25
|
||||
track=0
|
||||
|
||||
stopprogram=0
|
||||
reload=False
|
||||
|
||||
#GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering
|
||||
#GPIO.setup(16, GPIO.IN, pull_up_down = GPIO.PUD_UP)
|
||||
|
||||
def signal_handler(signal,frame):
|
||||
global quit
|
||||
#def signal_handler(signal,frame):
|
||||
# global quit
|
||||
# print("")
|
||||
# quit=1
|
||||
|
||||
def receive_signal(signum, stack):
|
||||
global stopprogram
|
||||
global reload
|
||||
if VERBOSE:
|
||||
print('Received signal: %d' %signum)
|
||||
else:
|
||||
print("")
|
||||
quit=1
|
||||
if signum == signal.SIGHUP:
|
||||
reload=True
|
||||
if signum == signal.SIGINT:
|
||||
stopprogram=1
|
||||
|
||||
|
||||
def stamp():
|
||||
sys.stdout.write(strftime("[%Y%m%d %H%M%S] "))
|
||||
@@ -51,29 +70,10 @@ def writesettings():
|
||||
pickle.dump(settings, handle)
|
||||
handle.close()
|
||||
|
||||
def readmp3list():
|
||||
c=0
|
||||
mp3s=[]
|
||||
dirs=os.listdir('.')
|
||||
|
||||
for ent in os.listdir('.'):
|
||||
if ent.lower().endswith(".mp3") and os.access(ent,os.R_OK):
|
||||
mp3s.append(ent)
|
||||
mp3s.sort()
|
||||
for m in mp3s:
|
||||
c+=1
|
||||
if c>99: break
|
||||
|
||||
if c:
|
||||
return(mp3s)
|
||||
else:
|
||||
return(0)
|
||||
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
looptype=0
|
||||
colon=0
|
||||
count=0
|
||||
digit=1
|
||||
showtime=0
|
||||
playtime=0
|
||||
@@ -84,35 +84,49 @@ tvol=0
|
||||
volume=0.0
|
||||
brightness=0
|
||||
snooze=0
|
||||
count=0
|
||||
|
||||
signal.signal(signal.SIGINT,signal_handler)
|
||||
#display=tm1637.TM1637(CLK=14, DIO=4, brightness=1)
|
||||
display=max7219.MAX7219(brightness=1)
|
||||
if VERBOSE:
|
||||
print('My PID is %d' %os.getpid())
|
||||
signal.signal(signal.SIGHUP, receive_signal)
|
||||
signal.signal(signal.SIGINT, receive_signal)
|
||||
|
||||
display.Clear()
|
||||
display.SetBrightnessRaw(o_defaultbrightness)
|
||||
but1=button.Button(21,verbose=VERBOSE)
|
||||
but2=button.Button(20,verbose=VERBOSE)
|
||||
but3=button.Button(26,verbose=VERBOSE)
|
||||
|
||||
print("")
|
||||
print("reading mp3s from directory:")
|
||||
allmp3s=readmp3list()
|
||||
if allmp3s==0:
|
||||
print("ERROR: No mp3's found!")
|
||||
display.showclock(" E rr")
|
||||
sleep(30)
|
||||
sys.exit()
|
||||
#------------------------------------------------------------------
|
||||
#------------------------------------------------------------------
|
||||
|
||||
c=0
|
||||
for m in allmp3s:
|
||||
print(" %2d : %s"%(c+1,m))
|
||||
while not stopprogram:
|
||||
if VERBOSE:
|
||||
print("Load config...")
|
||||
reload=False
|
||||
|
||||
display=tm1637.TM1637(CLK=14, DIO=4, brightness=1)
|
||||
# display=max7219.MAX7219(brightness=1)
|
||||
|
||||
display.Clear()
|
||||
display.SetBrightnessRaw(o_defaultbrightness)
|
||||
|
||||
if VERBOSE:
|
||||
print("Reading mp3s from directory:")
|
||||
tracks=clockytracklist.ClockyTracklist("mp3",recursive=True,verbose=VERBOSE)
|
||||
allmp3s=tracks.tracklist
|
||||
|
||||
c=0
|
||||
if VERBOSE:
|
||||
print("\nTracks:")
|
||||
for m in allmp3s:
|
||||
print("%2d : %s"%(c+1,m))
|
||||
c+=1
|
||||
|
||||
print("")
|
||||
but1=button.Button(21)
|
||||
but2=button.Button(20)
|
||||
but3=button.Button(26)
|
||||
print("")
|
||||
stamp()
|
||||
print("Started")
|
||||
sys.stdout.flush()
|
||||
|
||||
if not os.path.isfile(o_configfilename):
|
||||
# .................................................................
|
||||
if not os.path.isfile(o_configfilename):
|
||||
print("Createconf: \""+o_configfilename+"\":")
|
||||
|
||||
settings = {'track0':1, 'track1':2, 'track2':3, 'track3':4, 'track4':5, 'track5':6, 'track6':7, 'track7':8, 'track8':9, 'track9':10 }
|
||||
@@ -124,39 +138,44 @@ if not os.path.isfile(o_configfilename):
|
||||
pickle.dump(settings, handle)
|
||||
handle.close()
|
||||
|
||||
else:
|
||||
else:
|
||||
if VERBOSE:
|
||||
print("Configfile: \""+o_configfilename+"\":")
|
||||
|
||||
with open(o_configfilename, 'rb') as handle:
|
||||
settings = pickle.load(handle)
|
||||
handle.close()
|
||||
|
||||
a_mins=settings['alarmtime']%60
|
||||
a_hour=(settings['alarmtime']-a_mins)/60
|
||||
print("Alarmtime : %02d:%02d"%(a_hour,a_mins))
|
||||
print("Alarmdisable: %d"%(settings['alarmdisabled']))
|
||||
print("Starttrack : %d"%(settings['starttrack']))
|
||||
a_mins=int(settings['alarmtime']%60)
|
||||
a_hour=int((settings['alarmtime']-a_mins)/60)
|
||||
if VERBOSE:
|
||||
print("Alarmtime : %02d:%02d"%(a_hour,a_mins))
|
||||
print("Alarmdisable: %d"%(settings['alarmdisabled']))
|
||||
print("Starttrack : %d"%(settings['starttrack']))
|
||||
|
||||
for i in range(0,10):
|
||||
for i in range(0,10):
|
||||
if i==settings['starttrack']:
|
||||
if VERBOSE:
|
||||
print("=>",end='')
|
||||
else:
|
||||
if VERBOSE:
|
||||
print(" ",end='')
|
||||
if VERBOSE:
|
||||
print(" [T%01dM%02d] "%(i,settings["track%d"%i]),end='')
|
||||
if settings["track%d"%i] and (settings["track%d"%i]-1 < len(allmp3s)):
|
||||
if VERBOSE:
|
||||
print("\""+allmp3s[settings["track%d"%i]-1]+"\"")
|
||||
else:
|
||||
if VERBOSE:
|
||||
print("")
|
||||
settings["track%d"%i]=0
|
||||
writesettings()
|
||||
writesettings()
|
||||
|
||||
print("")
|
||||
stamp()
|
||||
print("Started")
|
||||
sys.stdout.flush()
|
||||
#------------------------------------------------------------------
|
||||
#------------------------------------------------------------------
|
||||
while quit!=True:
|
||||
|
||||
|
||||
# .................................................................
|
||||
|
||||
while not reload and not stopprogram:
|
||||
count+=1;
|
||||
sleep(o_loopdelay)
|
||||
|
||||
@@ -226,8 +245,8 @@ while quit!=True:
|
||||
|
||||
if looptype==1: # show alarmtime
|
||||
if not settings["alarmdisabled"]==1:
|
||||
a_mins=settings['alarmtime']%60
|
||||
a_hour=(settings['alarmtime']-a_mins)/60
|
||||
a_mins=int(settings['alarmtime']%60)
|
||||
a_hour=int((settings['alarmtime']-a_mins)/60)
|
||||
|
||||
if colon:
|
||||
tim="%02d:%02d" % (a_hour, a_mins)
|
||||
@@ -254,11 +273,12 @@ while quit!=True:
|
||||
|
||||
if looptype==2: # edit alarmtime
|
||||
|
||||
|
||||
delta=0
|
||||
sm=settings['alarmtime']%10
|
||||
dm=((settings['alarmtime']-sm)/10)%6
|
||||
sh=(settings['alarmtime']-dm)/60%10
|
||||
dh=(settings['alarmtime']-sh)/600
|
||||
sm=int(settings['alarmtime']%10)
|
||||
dm=int(((settings['alarmtime']-sm)/10)%6)
|
||||
sh=int((settings['alarmtime']-dm)/60%10)
|
||||
dh=int((settings['alarmtime']-sh)/600)
|
||||
|
||||
if colon:
|
||||
tim="%0d%0d:%0d%0d" % (dh,sh,dm,sm)
|
||||
@@ -366,8 +386,8 @@ while quit!=True:
|
||||
soundpreview=1
|
||||
|
||||
tr=track
|
||||
tl=settings["track%d"%tr]%10
|
||||
th=(settings["track%d"%tr]-tl)/10
|
||||
tl=int(settings["track%d"%tr]%10)
|
||||
th=int((settings["track%d"%tr]-tl)/10)
|
||||
|
||||
if colon:
|
||||
tim="%d=:%d%d" % (tr,th,tl)
|
||||
@@ -408,8 +428,8 @@ while quit!=True:
|
||||
|
||||
delta=0
|
||||
tr=track
|
||||
tl=settings["track%d"%tr]%10
|
||||
th=(settings["track%d"%tr]-tl)/10
|
||||
tl=int(settings["track%d"%tr]%10)
|
||||
th=int((settings["track%d"%tr]-tl)/10)
|
||||
|
||||
if colon:
|
||||
tim="%d=:%d%d" % (tr,th,tl)
|
||||
@@ -469,7 +489,7 @@ while quit!=True:
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if looptype==5: # Alarm!
|
||||
if looptype==5: # Alarm loop!
|
||||
#o_timetomaxvol = 60 # seconds it takes to go from 0% to 100% volume
|
||||
|
||||
if colon:
|
||||
@@ -585,6 +605,11 @@ while quit!=True:
|
||||
settings['starttrack']=track;
|
||||
writesettings()
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if count % 40 == 0: # every 10 seconds
|
||||
if tracks.CheckTrackList():
|
||||
reload = True;
|
||||
|
||||
#------------------------------------------------------------------
|
||||
if pygame.mixer.get_init():
|
||||
|
||||
92
clockytracklist.py
Normal file
92
clockytracklist.py
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
EXTENSIONS=(".mp3",".ogg",".wav",".mpa",".m4a",".flac")
|
||||
|
||||
class ClockyTracklist:
|
||||
"""read and monitor directory with audio files"""
|
||||
def __init__(self,path=".",recursive=False,sort=True,verbose=False):
|
||||
"""Read (current or supplied) path for all audio files. Add recursive=True to check all subdirectories too"""
|
||||
self.recursive=recursive
|
||||
self.path=path
|
||||
self.__verbose=verbose
|
||||
self.__sort=sort
|
||||
self.__reloaded=False
|
||||
self.supportedformats=EXTENSIONS
|
||||
|
||||
p=Path(self.path)
|
||||
if not p.exists():
|
||||
print("ERROR: directory \""+path+"\" does not exist")
|
||||
exit();
|
||||
if not p.is_dir():
|
||||
print("ERROR: \""+path+"\" is not an directory")
|
||||
exit();
|
||||
|
||||
self.__ReadTrackList()
|
||||
|
||||
if self.count==0:
|
||||
print("ERROR: no (supported) files found in directory \""+path+"\"")
|
||||
exit();
|
||||
|
||||
if(self.__verbose):
|
||||
self.ShowTrackList()
|
||||
|
||||
|
||||
def __ReadTrackList(self):
|
||||
"""do the actual reading"""
|
||||
self.tracklist=[]
|
||||
self.count=0
|
||||
path=Path(self.path)
|
||||
|
||||
if(self.recursive):
|
||||
selection='**/*'
|
||||
else:
|
||||
selection='*'
|
||||
for entry in path.glob(selection):
|
||||
if entry.suffix in EXTENSIONS:
|
||||
self.tracklist.append(entry.as_posix())
|
||||
self.count+=1
|
||||
if self.__sort:
|
||||
self.tracklist.sort()
|
||||
|
||||
|
||||
def ShowTrackList(self):
|
||||
"""Print the list"""
|
||||
print("Tracklist:")
|
||||
print(" path = %s" %self.path)
|
||||
print(" recursive = %s" %self.recursive)
|
||||
print(" count = %d" %self.count)
|
||||
print(" tracks:")
|
||||
for track in self.tracklist:
|
||||
print(" "+track)
|
||||
f=open(track,"r")
|
||||
if(f):
|
||||
f.close()
|
||||
|
||||
def CheckTrackList(self):
|
||||
"""Check path for filechanges"""
|
||||
newtracklist=[]
|
||||
newcount=0
|
||||
|
||||
if self.__reloaded:
|
||||
self.__reloaded=False
|
||||
|
||||
newpath=Path(self.path)
|
||||
if(self.recursive):
|
||||
selection='**/*'
|
||||
else:
|
||||
selection='*'
|
||||
for newentry in newpath.glob(selection):
|
||||
if newentry.suffix in EXTENSIONS:
|
||||
newtracklist.append(newentry.as_posix())
|
||||
newcount+=1
|
||||
if self.__sort:
|
||||
newtracklist.sort()
|
||||
if(newcount != self.count) or (newtracklist != self.tracklist):
|
||||
if(self.__verbose):
|
||||
print("Changes in filenames or number of files detected! Re-read tracklist.")
|
||||
self.__ReadTrackList()
|
||||
self.__reloaded=True
|
||||
|
||||
return self.__reloaded
|
||||
@@ -1,8 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017-18 Richard Hull and contributors
|
||||
# See LICENSE.rst for details.
|
||||
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
Reference in New Issue
Block a user