A Magic Mirror Powered by AIY Projects and the Raspberry Pi

Machine Learning imprisoned behind a sheet of glass

This the first post in a series of three posts building a simple voice controlled Magic Mirror. This first post in the series shows how to put the mirror together, while the second post in the series looks at how to use Machine Learning locally on the device to do custom hotword recognition without using the cloud. The final post in the series looks at integrating the Voice and Vision Kits together to build a mirror that recognises when you’re looking at it.

The completed Magic Mirror along with my previous Google AIY Project Voice Kit builds.

Gathering your Tools and Materials

This project has more woodworking than electronics. You’ll need a small Philips “00” watch maker’s screwdriver, a craft knife, scissors, a set of small wire snips, black electrical tape, a saw, mitre block, speed square, and possibly some Sugru and a spudger if you’re feeling ambitious.

Getting your hands on Two-Way Acrylic

While you might have pretty much everything else to hand, unless you’re in an interesting line of work, you won’t have any two-way acrylic. However it’s actually pretty easy to get your hands on, you can order it in custom sizes online in the United States and in the United Kingdom and it’ll arrive in a few days pre-cut and ready. If you’re unsure about your carpentry skills, put your enclosure together first before ordering the two-way acrylic and then you can order the exact size you need to fit your enclosure.

Building the Enclosure

If you’re not entirely sure what you’re doing it’s often easier to start with something pre-built, and then go ahead and then modify it to your own purposes than it is to start entirely from scratch.

The lip of the box picture frame.
Deepening the frame with additional .
Cutting the extending wood pieces
Fixing and gluing.
Painting with wood stain.

Opening the Box

Ahead of the new Voice Kit hitting the shelves at the weekend I managed to get my hands on a few pre-production kits. The new AIY Voice Kit comes comes in a box very similar to the original kit distributed with the Mag Pi magazine. The box might be a bit thinner, but otherwise things look much the same.

The new AIY Project Voice Kit.

Preparing the 7-inch Display

Embedded behind glass, our 7-inch display really doesn’t need it’s digitizer panel. So I decided to remove it, and very carefully with a spudger I pried the digitizer away from the display panel. I then used black electrical tape to cover the metal edges—this will both prevent scratching when we put it up against the mirror, but more vitally it’ll help reduce the amount of reflected light behind the mirror.

The official Raspberry Pi 7-inch display, without the front digitizer panel.
Cable to the digitizer disconnected from the main LCD panel.

Putting Everything Together

We’ve reached the point where everything starts to come together quickly. Grab your two-way acrylic panel and insert it into your box frame. Then take your display panel and tape onto the inside of the mirror.

The back side of the mirror. With the 7-inch display taped in place at bottom left with a blackout sheet above it.
All of the blackout shielding in place and Raspberry Pi connected to the display.
All of the electronics taped in place inside the mirror.
The completed mirror booted into the Raspbian.

Connecting to the Cloud

We can go ahead and set up Google Cloud Platform as we’ve done before on other Voice Kit builds using the console.cloud.google.com developer console. However for this build, as well as the Google Assistant API, we’ll also be using the Google Cloud Speech API.

Enabling Google Cloud Speech API
Google Cloud Speech is not free!
If you’ve never set up billing before you’ll need to do that now.
Picking up $300 of free services for signing up for billing.
Even once your $300 of credit is used up, you won’t be automatically billed.
The Google Cloud Speech API is now enabled.
Creating a Service Account key.
Creating a Service Account key.

Installing the Magic Mirror

Now we have everything in place to work with the Voice Assistant and Cloud Speech API, let’s take a step back and take a look at the Magic Mirror software we’re going to use in the build.

$ bash -c "$(curl -sL https://raw.githubusercontent.com/MichMich/MagicMirror/master/installers/raspberry.sh)"
var config = {
address: "0.0.0.0",
port: 8080,
ipWhitelist: [],
language: "en",
timeFormat: 24,
units: "metric",

modules: [
{
module: "clock",
position: "bottom_left"
},
]

};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}
$ cd MagicMirror
$ npm start
First run for the Magic Mirror with just the Clock module configured and active.

Adding Remote Control

Hit Ctrl-Q to close the Magic Mirror and go ahead and install the Remote Control third-party module directly from its Git repo.

$ cd ~/MagicMirror/modules
$ git clone https://github.com/Jopyth/MMM-Remote-Control.git
$ cd MMM-Remote-Control
$ npm install
{
module: 'MMM-Remote-Control',
position: 'bottom_right'
},
$ cd ~/MagicMirror
$ npm start
My magic mirror with its new remote control.

Adding Weather

To make use of the Current Weather and Weather Forecast modules we need to go ahead and sign up for a OpenWeatherMap account. Signing up for an account is free, and will automatically create the API Key we need to use the weather modules included with MagicMirror².

After signing up for OpenWeatherMap an API Key is created by default.
{
module: "currentweather",
position: "top_right",
config: {
location: "CITY,COUNTRY",
locationID: "XXXXXX",
appid: "YOUR_API_KEY"
}
},
{
module: "weatherforcast",
position: "top_right",
config: {
location: "CITY,COUNTRY",
locationID: "XXXXXX",
appid: "YOUR_API_KEY"
}
},
{
module: "currentweather",
position: "top_right",
config: {
location: "Exeter, GB",
locationID: "2649808",
appid: "YOUR_API_KEY"
}
},

A Working Mirror

If you’ve configured everything correctly restarting the Mirror software you should see something like this,

The MagicMirror² running on with Clock, Weather, Forecast, and Remote modules on screen.
var config = {
address: "0.0.0.0",
port: 8080,
ipWhitelist: [],
language: "en",
timeFormat: 24,
units: "metric",
modules: [
{
module: "clock",
position: "bottom_left"
},
{
module: "MMM-Remote-Control",
position: "bottom_right"
},
{
module: "currentweather",
position: "top_right",
config: {
location: "Exeter, GB",
locationID: "2649808",
appid: "YOUR_API_KEY"
}
},
{
module: "weatherforecast",
position: "top_right",
config: {
location: "Exeter, GB",
locationID: "2649808",
appid: "YOUR_API_KEY"
}
}]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}

Using AIY Projects SDKs from SSH

Unfortunately now that we have our Magic Mirror running, we can’t get to the AIY Projects dev console. The easiest thing to do here is to SSH into our Raspberry Pi from out laptop and then type the following,

$ cd ~/AIY-voice-kit-python
$ source env/bin/activate

Using the Voice Assistant to Control our Mirror

Probably the easiest way to control the mirror is using Google Voice Assistant as we did for the our retro computing build using the GPO 746 rotary phone.

{
"moduleData": [
{
"hidden": false,
"lockStrings": [

],
"name": "clock",
"identifier": "module_0_clock",
"position": "bottom_left",
"config": {
"displayType": "digital",
"timeFormat": 24,
"displaySeconds": true,
"showPeriod": true,
"showPeriodUpper": false,
"clockBold": false,
"showDate": true,
"showWeek": false,
"dateFormat": "dddd, LL",
"analogSize": "200px",
"analogFace": "simple",
"analogPlacement": "bottom",
"analogShowDate": "top",
"secondsColor": "#888888",
"timezone": null
},
"path": "modules\/default\/clock\/"
},
{
"hidden": false,
"lockStrings": [

],
"name": "MMM-Remote-Control",
"identifier": "module_1_MMM-Remote-Control",
"position": "bottom_right",
"config": {

},
"path": "modules\/MMM-Remote-Control\/"
},
{
"hidden": false,
"lockStrings": [

],
"name": "currentweather",
"identifier": "module_2_currentweather",
"position": "top_right",
"config": {
"location": "Exeter, GB",
"locationID": "2649808",
"appid": "YOUR_API_KEY",
"units": "metric",
"updateInterval": 600000,
"animationSpeed": 1000,
"timeFormat": 24,
"showPeriod": true,
"showPeriodUpper": false,
"showWindDirection": true,
"showWindDirectionAsArrow": false,
"useBeaufort": true,
"lang": "en",
"showHumidity": false,
"degreeLabel": false,
"showIndoorTemperature": false,
"showIndoorHumidity": false,
"initialLoadDelay": 0,
"retryDelay": 2500,
"apiVersion": "2.5",
"apiBase": "http:\/\/api.openweathermap.org\/data\/",
"weatherEndpoint": "weather",
"appendLocationNameToHeader": true,
"calendarClass": "calendar",
"onlyTemp": false,
"roundTemp": false,
"iconTable": {
"01d": "wi-day-sunny",
"02d": "wi-day-cloudy",
"03d": "wi-cloudy",
"04d": "wi-cloudy-windy",
"09d": "wi-showers",
"10d": "wi-rain",
"11d": "wi-thunderstorm",
"13d": "wi-snow",
"50d": "wi-fog",
"01n": "wi-night-clear",
"02n": "wi-night-cloudy",
"03n": "wi-night-cloudy",
"04n": "wi-night-cloudy",
"09n": "wi-night-showers",
"10n": "wi-night-rain",
"11n": "wi-night-thunderstorm",
"13n": "wi-night-snow",
"50n": "wi-night-alt-cloudy-windy"
}
},
"path": "modules\/default\/currentweather\/"
},
{
"hidden": false,
"lockStrings": [

],
"name": "weatherforecast",
"identifier": "module_3_weatherforecast",
"position": "top_right",
"config": {
"location": "Exeter, GB",
"locationID": "2649808",
"appid": "YOUR_API_KEY",
"units": "metric",
"maxNumberOfDays": 56,
"showRainAmount": false,
"updateInterval": 600000,
"animationSpeed": 1000,
"timeFormat": 24,
"lang": "en",
"fade": true,
"fadePoint": 0.25,
"colored": false,
"scale": false,
"initialLoadDelay": 2500,
"retryDelay": 2500,
"apiVersion": "2.5",
"apiBase": "http:\/\/api.openweathermap.org\/data\/",
"forecastEndpoint": "forecast",
"appendLocationNameToHeader": true,
"calendarClass": "calendar",
"roundTemp": false,
"iconTable": {
"01d": "wi-day-sunny",
"02d": "wi-day-cloudy",
"03d": "wi-cloudy",
"04d": "wi-cloudy-windy",
"09d": "wi-showers",
"10d": "wi-rain",
"11d": "wi-thunderstorm",
"13d": "wi-snow",
"50d": "wi-fog",
"01n": "wi-night-clear",
"02n": "wi-night-cloudy",
"03n": "wi-night-cloudy",
"04n": "wi-night-cloudy",
"09n": "wi-night-showers",
"10n": "wi-night-rain",
"11n": "wi-night-thunderstorm",
"13n": "wi-night-snow",
"50n": "wi-night-alt-cloudy-windy"
}
},
"path": "modules\/default\/weatherforecast\/"
}
],
"brightness": 100,
"settingsVersion": 2
}

Using the Cloud Speech API to Control our Mirror

Which is why we enabled the Google Cloud Speech API for this project earlier in the build. Unlike the Voice Assistant API, which has a hardwired hotword that is processed on the device, we can use the Cloud Speech API to send all our speech to the cloud and—thanks to a recent SDK update—listen for a custom hotword.

#!/usr/bin/env python3import aiy.audio
import aiy.cloudspeech
import aiy.voicehat
def main():
recognizer = aiy.cloudspeech.get_recognizer()
recognizer.expect_phrase('repeat after me')
button = aiy.voicehat.get_button()
aiy.audio.get_recorder().start()
while True:
print('Press the button and speak')
button.wait_for_press()
print('Listening...')
text = recognizer.recognize()
if text is None:
print('Sorry, I did not hear you.')
else:
print('You said "', text, '"')
if 'repeat after me' in text:
to_repeat = text.replace('repeat after me', '', 1)
aiy.audio.say(to_repeat)
if __name__ == '__main__':
main()
The final build.
$ cd AIY-voice-kit-python/
$ git pull

Controlling the Screen Backlight

One of the things I found after using the mirror for a while is that the screen backlight makes a lot of difference to how seamless the mirror appears.

(Re-)Securing the Mirror

In the MagicMirror/config/config.js file we opened up network access to the mirror so we could easily test and configure it. We need to close those holes up. Since we’re now controlling the mirror entirely from localhost using our Python we can edit the config file to reflect that,

var config = {address: “localhost”,
port: 8080,
ipWhitelist: [“127.0.0.1”, “::ffff:127.0.0.1”, “::1”],
.
.
.
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}

Adding more Modules

Even though I’m British, I’m not just restricted to just talking about the weather. There’s a large number of third party modules available for the MagicMirror² platform, ranging from modules to displaying news and currency exchange rates and stock prices, to monitoring your internet speed—something I’ve been rather concerned about in the past—and even with our small screen there are plenty of positioning regions available to display additional modules.

The Two Elephants in the Room

However there are two huge elephants in the room with out current approach to the magic mirror.

The API Dashboard showing the API usage over the last few days as I put the project together.

Now on Shelves

The new kits are being produced by Google, and arrived onto shelves at Micro Center at the weekend. The AIY Voice Kit is priced at $25 on its own, but you can pick one up for free if you order a Raspberry Pi 3 at $35 for in-store pickup from Micro Center.

The completed mirror and other Google AIY Project Voice Kit projects.

Scientist, Author, Hacker, Maker, and Journalist.

Scientist, Author, Hacker, Maker, and Journalist.