Smart Mirror complete walkthrough

Required Equipment:

Step 1: Setting up the Pi

Meteor:

The Raspberry Pi came with instructions on getting it up and running but to install the Meteor Platform I used for creating the app I had to follow this guide. Most other smart mirror tutorials don’t use Meteor so don’t have this step.

Chromium:

You need this web browser because it is easy to get it set up in “kiosk” (full screen) mode. It’s also useful since it has a javascript console so that made it easy to add documents into the Mongo DB. The link above was the best way I could find to get it installed. Next I needed to get Chromium to launch in kiosk mode when the Raspberry Pi boots up (without the spaces, wordpress won’t let me post that string of text for some reason):

 

sudo nano / etc / xdg / lxsession /  LXDE-pi / autostart

 

Disable the screen saver by commenting out the following line:

#screensaver -no-splash

Then add the following line to the end of the file:

@xset s off @xset -dpms @xset s noblank / usr / bin / chromium --noerrdialogs --kiosk --incognito "http://localhost:3000"

To get rid of the mouse cursor:

 sudo apt-get install unclutter

Rotating the display:

 sudo nano / boot / config.txt

At the bottom of this file add:

 DISPLAY_ROTATE=X

Where X is: 0, 1, 2, 3 corresponding to no rotation, 90 degrees, 180 degrees, 270 degrees of rotation.

Step 2: The application

The code for my application was based on the code from github user lambtron. The biggest change I made was to add the random compliment at the bottom of the mirror. The javascript to do this:


if (Meteor.isClient){
   var ONE_MIN = 1 * 60 * 1000;
   var chooseRandom = function() {
   var compliments = Compliments.find().fetch();
   var randomComp = Random.choice(compliments);
   Session.set('currentComp', randomComp);
};
Template.compliments.helpers({
   compliment: function() {
      var c = Compliments.findOne(Session.get('currentComp'));
      return c.text;
      }
});
Template.compliments.created = function() {
   this.handle = Meteor.setInterval(chooseRandom, ONE_MIN);
};
Template.compliments.destroyed = function() {
   Meteor.clearInterval(this.handle);
   };
}

I’ve been running the app locally on the raspberry pi and just pointing the browser to localhost:3000. I can update the app via ssh when I am at home on my local wifi but I don’t seem to be able to ssh to the pi from anywhere else. I’ve also had problems adding content to the database from a command prompt. I can however attach a mouse and keyboard and update the database through a javascript console in the browser.

So far this has been working well but I have since updated the app to include an admin panel and I could move it to a digital ocean droplet for $5/month which would give me better access to the database.

Motion sensor

I purchased a motion sensor from Lee’s Electronics in Vancouver for ~$15.

Connecting the sensor to the Pi was simple enough with some female-to-female connectors. The three wires plug into Pin 2 (5V), Pin 6 (ground) and Pin 7 (GPIO 4). GPIO 4 is then monitored by the Pi to detect motion. I followed an online tutorial for creating a Python script to detect motion and turn on/off the monitor. I made a few modifications to the script for my own purposes:

import sys

import time

import RPi.GPIO as io

import subprocess

io.setmode(io.BCM)

SHUTOFF_DELAY = 60 # seconds

PIR_PIN = 4

def main():

io.setup(PIR_PIN, io.IN)

io.setup(LED_PIN, io.OUT)

turned_off = False

last_motion_time = time.time()

while True:

if io.input(PIR_PIN):

last_motion_time = time.time()

sys.stdout.flush()

if turned_off:

turned_off = False

turn_on()

else:

if not turned_off and time.time() > (last_motion_time + SHUTOFF_DELAY):

turned_off = True

turn_off()

if not turned_off and time.time() > (last_motion_time + 1):

io.output(LED_PIN, io.HIGH)

time.sleep(.1)

def turn_on():

subprocess.call(“sh /home/pi/mirror/monitor_on.sh”, shell=True)

def turn_off():

subprocess.call(“sh /home/pi/mirror/monitor_off.sh”, shell=True)

if __name__ == ‘__main__’: try: main() except KeyboardInterrupt:

io.cleanup()