Building a Magic Mirror; Nifty Opto-Isolator Tricks

After seeing a critical mass of Magic Mirror builds online, I caved and built one as a Christmas gift for my girlfriend – I made a few innovations on top of the other builds I’ve seen, so I’ve documented them here.  I drew much of the inspiration from Dylan Pierce in particular, so be sure to check out his build log as well!  Here’s the finished product, before wall-mounting:

 

mirror2

Build Process:

As I did not have the patience to spec out my own LCD panel, I decided to purchase a used victim TV, and worked from there.  The first step was to pop the bezel off and take a few measurements:

 

20161221_002223

 

With measurements of the LCD panel itself, I was able to mount the LCD panel in a basic 2×4 frame:

20161222_203728

The LCD Panel did not have any usable mounting holes that could mate with the 2×4, so I held it in place with some small angle brackets.

20161222_210831
After installing the brackets, I realized the single-screw mounting hole would be prone to rotation – some flank screws made for a quick fix.  Also pictured: speed holes

 

20161222_211047
I eventually added small metal mending plates to sandwich the LCD bezel in the frame (not pictured)

The TV I had cannibalised did not support HDMI/CEC control via the raspi, so I patched in to the power button with an opto-isolator (Sharp PC817).  By using an opto-isolator, the raspi only “sees” an LED as the load, allowing for safe coupling between the raspi and the TV circuitry.  The pin spacing on the PC817 was conducive to patching in directly to the tactile switches.  I also replaced the TV’s “off” LED with an opto-isolator connected in the opposite direction – this lets the raspi know if the TV is on or not.  This is important, because the power button is of the on/off toggle type; the raspi wouldn’t be able to know if it was turning it “on” or “off” otherwise, it would only know that it is changing the state.

 

20161222_213606

 

Originally, I was going to power the TV on and off via cron job, until a coworker suggested putting a sensor in to turn the mirror on when someone is in front of it.  I just happened to have a spare ultrasonic sensor around, so I mounted it into the frame and wired it up via GPIO pins on the rpi:

20161224_172106

With all the electronics connected + working, I glued the fancy mirror-glass in place (Actually, it’s acrylic), and added a nice aesthetic touch with some faux-oak molding and iron-on veneer (ran out of veneer, so the bottom got the thin piece).  I measured the mirror piece to have a 0.5″ margin beyond the viewable LCD portion so that I could affix it to the LCD bezel for a tight fit.  Mirror glass was the same used by Dylan Pierce available at TAP Plastics:

20161224_231110
The notch is in place to accommodate a power cable while wall-mounted.  Also pictured: speed holes

 

The ultrasonic sensors were a bit tricky; I drilled holes in the moulding and adjusted them with a dremel.  They are by no means perfect…

20161224_231134

 

And here’s a view of the rear/electronics – the intention is that this will be wall-mounted, so I didn’t bother with a protective cover.  Zip ties were applied liberally.

20161224_231116

 

Schematic

mirror_schem
Note: The optoisolator / ultrasonic sensor circuitry was soldered onto a piece of perfboard that mated with the RPi’s GPIO header

Software

The base software installation uses raspbian jessie and MagicMirror², and raspbian packages python-gpiozero and wiringpi (i.e. install via sudo apt-get install _____).  All GPIO control code is below.

Note: all .sh and .py files live in /home/pi, the .service files live in /etc/systemd/system/, enable via:

  • cd /etc/systemd/system
  • sudo systemctl enable detect_person.service
  • sudo systemctl enable tv.service

This allows for control via, e.g. sudo service tv [start|stop].  The tv.service serves to turn on the tv during the boot process (as well as for general debugging), while the detect_person service performs the ongoing operation for person detection.   Note that the particulars in detect_person.py need to be tuned to the environment that the mirror is installed in!

I also had to play with some settings /boot/config.txt to get the right screen orientation, see the comments in that file for details.