Thursday, October 19, 2017

Magic Mirror - build part 2

Quick modification this. I wanted my magic mirror to play a sound effect on the hour, but for that, it would need some speakers. I found the cheapest USB powered speakers I could find on eBay to experiment with, and if I broke them, it wouldn't be the end of the world.

  • Cheap USB speakers £2.69

They were surprisingly quite chunky, but were easy enough to open and unscrew...



However, I had to break the back end of each speaker box because the wires were threaded through a tiny hole, which wouldn't allow the plug ends through, and I also didn't want to have to desolder the wires. Two pairs of pliers made short work of breaking apart the moulded plastic, and removing the hot glue that held the volume knob PCB in place.


Next, after a few attempts to work out optimal positioning for the speakers, and to keep everything OCD symmetrical (very important) the mounting holes were marked and drilled and cut...



Superey dupery! Next, the plan required that I was to bolt the speaker cones inside the mirror, however... catastrophe! They were several millimetres too tall to fit inside the case! Daaahhh!

There really was no other option than to mount the speakers on the outside of the backing board, which meant that I had to desolder the wires anyway, taking care to remember which way round the wires went originally.


Some delicately balanced soldering later, the speakers were rewired, and even though they're mounted on the outside, they don't protrude too much, and don't affect how it hangs on the wall.



I first tried plugging the audio plug straight into the Pi's audio out, but it was way too hissy. Luckily, the screen driver board also has a standard audio out socket, and all that was required was to fiddle with some configuration files* to force audio out of the HDMI lead. Luckier still, it's no where near as hissy as the Pi direct audio connection.

(* This earlier incarnation of the magic mirror used an older vanilla version of Raspbian Jesse. I think I had to uncomment or add some specific HDMI options in /boot/config.txt to get the audio to work properly through the screen driver board, though I didn't leave myself any notes and can't remember exactly what I did)

So, now to the business of automating a python script to play audio on the hour.

I've only used python a little, but from what I have done, I was able to reuse some previously written functions to get things moving along. The hardest part, as with every software engineering project, is to come up with a suitable name. After thinking long and hard about it, it was named "timebonger.py"!
#!/usr/bin/env python

#import libraries
import sys
import time
import signal
import datetime
import subprocess

from time import sleep

#define global variables
blnStopped=False

#exit when received SIGTERM or SIGHUP
def stop(sig, frame):
    global blnStopped
    blnStopped=True
    print "caught signal ", sig, " exiting"

signal.signal(signal.SIGTERM, stop) #-15
signal.signal(signal.SIGHUP, stop) #-1

def runcmd(strCommand):
    print "runcmd() strCommand='" + strCommand + "'"
    try:
        output = subprocess.check_output(strCommand, shell=True)
        output = output.strip('\n')
        output = output.strip('\r')
        output = output.strip('\t')
        output = output.strip(' ')
        #print "output=" + output
    except Exception:
        return "error"

    return output

def mainloop():
    global blnStopped

    print "mainloop() started"

    dteNow=datetime.datetime.now()
    intHourNow=dteNow.hour
    intNextHour=intHourNow+1
    if(intNextHour>=24):
        intNextHour=0

    intMinuteNow=dteNow.minute
    intNextMinute=intMinuteNow+1
    if(intNextMinute>=60):
        intNextMinute=0

    try:
        while(not blnStopped):
            dteNow=datetime.datetime.now()
            intHourNow=dteNow.hour
            intMinuteNow=dteNow.minute
            #print "mainloop() dteNow=" + str(dteNow) + " intNextHour=" + str(intNextHour) + " intNextMinute=" + str(intNextMinute)

            if(intMinuteNow==intNextMinute or intHourNow==intNextHour):
                #print "mainloop() New minute!"

                #prepare time output
                strMinute=str(intMinuteNow)
                if(intMinuteNow==0):
                    strMinute="o'clock"

                strHour=str(intHourNow)
                if(intHourNow==0):
                    strHour="midnight"
                    strMinute=""
                if(intHourNow==12):
                    strHour="midday"
                    strMinute=""

                #do we run now?
                if(intHourNow>=7 and intHourNow<=23 and intMinuteNow==0):
                    print "mainloop() Bing Bong! The time is " + strHour + " " + strMinute
                    runcmd("aplay --device=sysdefault /home/pi/timebonger/cuckoo_clock1_x.wav")

                #calculate next minute
                if(intMinuteNow==intNextMinute):
                    intNextMinute=intNextMinute+1
                    if(intNextMinute>=60):
                        intNextMinute=0
                if(intHourNow==intNextHour):
                    intNextHour=intNextHour+1
                    if(intNextHour>=24):
                        intNextHour=0

            sleep(1)

        sys.exit(1)

    except KeyboardInterrupt:
        print "mainloop() Keyboard Interrupt!"
        sys.exit(1)

mainloop()


Not very elegant, I'm sure you'll agree, but it gets the job done, and makes me giggle EVERY SINGLE TIME. Can't remember where I got the sound effect from (it took me a while trying to find a suitably funny one, eventually I settled on a cartoon sounding cuckoo clock), but you could probably Google the filename to locate it. You may also notice that I've limited the script to only play the sound between the hours of 7am to 11pm, because I don't want it to 'bong' throughout the night and piss my family off!

To get the timebonger script to auto run on restart, I used the pm2 scheduler that I'd previously installed to get the Magic Mirror package to auto run. As the recommended method for the magic mirror suggests, I created a small shell script, /home/pi/timebonger/tb.sh which contained the single line:

python /home/pi/timebonger/timebonger.py

...which executes python and passes a fully qualified directory path to the timebonger script, then I made it executable with:

sudo chmod +rwx timebonger.py

...then added it to pm2 with:

pm2 start tb.sh
pm2 save

pm2 is itself already autostarted from /etc/rc.local (which I believe I setup by executing 'pm2 startup systemd' because Raspbian uses systemd) so that's job done! Everything auto runs on reboot without me having to touch anything.

So, the last part was to carefully measure out exactly where the wall hooks had to go so I could drill holes for wall plugs and mount it over the fireplace in the living room, leaving everything level and symmetrical. After much headscratching, measuring multiple times, umming, ahhhing, pencil marks, and aching arms, I managed to get it right first time!



Coming up in part three - the Google AIY (Artificial It Yourself) version!

No comments:

Post a Comment