close-circle
Close

Phase 3 - Alarm Clock

A project log for LighTouch - Control music with the wave of a hand

A touch-less, streaming radio/alarm clock

Thomas Clauser 08/16/2014 at 05:030 Comments

The next step along the path was to include the alarm clock functionality in addition to standard music controls making this a bedside gadget.

Making an alarm clock in python is fairly straightforward so I wanted to focus instead on the controls. The alarm goes off daily according to the time you set in the python script.  

When that timestamp is hit the current song will play, the LCD will turn on displaying the current date/time, and the LED will go to full brightness.

To turn off the alarm you have two choices; snooze or off

Sticking with the idea of a 100% touch-less interface and wanting to leverage the controls that are already built in for music control I settled on the following for now:

Snooze = Waving your hand over 10cm above the device pauses the playback for 7 minutes and leaves the LCD with date/time on.  The motion is similar to quickly swiping the air above the clock

Alarm Off = Bringing your hand down to 0cm on the device turns off the playback, turns off the LCD backlight and LED, and resets the alarm for the next day.  The motion is similar to bringing your hand down onto the device (like hitting off button on your alarm clock)

I'm merging this capability in the existing code but I'm leaving the lightouch.py code untouched so you have the option of music player or music player+alarm clock.

lightouch_alarm.py

import serial
import mpd
import subprocess
import alsaaudio
import os
import datetime
import time


ser = serial.Serial('/dev/ttyS0', 9600) # Change /dev/* value to match your arduino serial interface device
ser.timeout=.05 						# Timeout reduces CPU usage
mixer = alsaaudio.Mixer('PCM', 0)		# Which audio mixer to control
changecheck=" "							# variable that 'watches' to see if the song has changed
counter=0    							# variable used to delay the time to redisplay the Artist/Song after changing volume
#alarmhour=int(input("Enter Alarm Hour: "))
#alarmminute=int(input("Enter Alarm Minute: "))
alarmhour=0 #	#Enter alarm hour
alarmminute=36	#Enter alarm minute
snooze=0
flag=0
masteralarmhour=alarmhour		#Keep track of a universal alarm hour
masteralarmminute=alarmminute	#Keep track of a universal alarm minute




client = mpd.MPDClient()				
client.connect("localhost", "6600")




def translate(value, leftMin, leftMax, rightMin, rightMax): # Used to translate the value of volume to a 0-100 range for accurate display
    # Figure out how 'wide' each range is
    leftSpan = leftMax - leftMin
    rightSpan = rightMax - rightMin
    # Convert the left range into a 0-1 range (float)
    valueScaled = float(value - leftMin) / float(leftSpan)
    # Convert the 0-1 range into a value in the right range.
    return rightMin + (valueScaled * rightSpan)




while True:


	now=datetime.datetime.now()	#get current time
	dt = list(time.localtime())	#break down into list
	hour = dt[3]				#set hour
	minute = dt[4]				#set minute
	second = dt[5]				#set second


	if hour == alarmhour and minute == alarmminute and second == 0 and flag==0:	
	
		client.play()								#Play music
		mixer.setvolume(100)						#At max volume
		ser.write(now.strftime("%a, %b %d %Y"))		#Display date to LCD
		ser.write('@')								#Trigger to skip to next LCD row
		ser.write(now.strftime("     %H:%M     "))	#Display time to LCD
		ser.write('@')								#Trigger to skip to next LCD row
		ser.write('%')								#Trigger to pause ultrasonic inputs
		print now.strftime("%Y-%m-%d %H:%M")
		flag=1;										#Alarm is playing
		snooze=1;									#Snooze is available
		
	snafu=ser.readline().decode('utf-8','ignore')[:-2] 	#Read serial input
	SongInfo=client.currentsong()						#Pulls information from MPD
	artist=SongInfo['artist']							#Artist info
	song=SongInfo['title']								#Song info
	if len(song) > 16:									#Chops artist length to LCD width (16 characters)
		choppedsong = song[0:15]
	else:
		choppedsong = song[0:(len(song))]
	if len(artist) > 16:								#Chops artist length to LCD width (16 characters)
		choppedartist = artist[0:15]
	else:
		choppedartist = artist[0:(len(artist))]
	
		
	if counter==20:										#Amount of time to redisplay the Artist/Song after volume change
		changecheck=''
	
	counter=counter+1
	
	if counter>=21:
		counter=21


	if changecheck != choppedsong:						#If counter met or song changed write to LCD
		ser.write(choppedsong)
		ser.write('@')
		ser.write(choppedartist)
		ser.write('@')
		print choppedsong
		print choppedartist
		
	changecheck=choppedsong
	
	if snafu == 'Pause':								#Read serial input for Pause, Next, or Volume
		client.pause(1)
		print(snafu)
		ser.write('     Paused')						#Print to LCD
		ser.write('@')									#'@' symbol tells the arduino to move to the next row on the LCD
		counter=21;										
		flag=0;											#Alarm already triggered
		snooze=0;										#Turn off snooze
		alarmhour=masteralarmhour						#Reset alarm hour
		alarmminute=masteralarmminute					#Reset alarm minute
	
	elif snafu == 'Next':							
		client.next()
		print(snafu)
	
	elif snafu.isdigit() and snooze==1:					#If in volume spectrum and alarm is playing
		client.pause(1)
		alarmminute=minute+9 								#Reset alarm for 9 minutes from now
		if alarmminute>=60:									#Make sure it doesn't go outside of time format
			alarmminute=0
			alarmhour=alarmhour+1
		print "Snooze"				
		ser.write('     Snooze     ')					#Write Snooze to the LCD
		#ser.write('~')									#Trigger code to pause all input from arduino for a short time
		flag=0;											#Flag alarm to go off again 
		#snooze=0;										#Flag snooze to go off again
	
	elif snafu.isdigit() and snooze==0:					#If in volume and alarm is not playing
		client.play()									#Standard music controls
		mixer.setvolume(int(snafu))						#Set raspi volume according to ultrasonic distance
		counter=0
		ser.write('Vol: ')								#Print volume level to LCD
		print(int(translate(int(snafu),70,100,0,100)))
		ser.write(snafu)
		ser.write('@')								
		flag=1;											#Tell alarm not to go off when playing normally


<br>

Discussions