Interactive Magic Mirror With Candy Dispenser
by noelportugal in Circuits > Arduino
29467 Views, 202 Favorites, 0 Comments
Interactive Magic Mirror With Candy Dispenser
For Halloween 2012 I created an interactive Magic Mirror. The Magic Mirror has a sonar (PING)))) sensor that detects when kids are are close. Then the mirror says a few random phrases and automatically drops candy to the bucket. I repurposed my Automatic Candy Dispenser from two years ago. The PING))) sensor, fog and red lights are controlled by an Arduino.
You can text "say [your name]" to a SMS short code and the Magic Mirror will say your name, drop candy, take a Dropcam snapshot and send it back to your mobile phone (MMS). The SMS/MMS capability was handled by an awesome API from Mogreet, that makes MMS really easy to use. The Magic Mirror can also be controlled by a PHP web application hosted on Apache2 in the Mac Mini.
The Mirror Mirror software is made by the folks at ImaginEERIEing and I bought it two years ago. Last year I used it to do an interactive photobooth (which sadly I did not document!). I highly recommend it. You can get a free version but the $15 version is much nicer and pretty affordable.
Now, before you go dismissing this project as a simple copy of previous (and great) Instructables like DIY Magic Mirror and others that use the same software. Please consider the interactive features such as the SMS and candy dispenser. And ultimately I hope to provide inspiration for similar and improved mirrors!
You can text "say [your name]" to a SMS short code and the Magic Mirror will say your name, drop candy, take a Dropcam snapshot and send it back to your mobile phone (MMS). The SMS/MMS capability was handled by an awesome API from Mogreet, that makes MMS really easy to use. The Magic Mirror can also be controlled by a PHP web application hosted on Apache2 in the Mac Mini.
The Mirror Mirror software is made by the folks at ImaginEERIEing and I bought it two years ago. Last year I used it to do an interactive photobooth (which sadly I did not document!). I highly recommend it. You can get a free version but the $15 version is much nicer and pretty affordable.
Now, before you go dismissing this project as a simple copy of previous (and great) Instructables like DIY Magic Mirror and others that use the same software. Please consider the interactive features such as the SMS and candy dispenser. And ultimately I hope to provide inspiration for similar and improved mirrors!
Materials
Magic Mirror Wall
- Mirror frame
- Sheet rock panel
- 2x4's to build a frame
- Black, gray and golden spray paint
- Popcorn ceiling finish
- Zodiac cutouts
- Please refer to my Instructables here to see how I buit it.
- Arduino Uno
- Adafruit prototype shield
- PING))) Paralax sensor
- Servo motor
- Mac or PC.
- Computer LCD monitor.
- Mini Fog machine
- X10 appliance relay
- Red Flood light
- Flood light socket
Mirror Wall Construction
Construction of the wall was "mostly" simple. I used the thinnest sheet rock I could find and made the required openings. I soon learned that the sheet rock by itself was not going to be enough (It actually fell once and cracked). So I build a frame to give it more support. Sheet rock was not my first choice. I actually first build the wall with a very thin wood panel. This option could work but my initial plan did not include blocking the whole door. I was planning to put it on the side corner. When I realized that It was better to use the whole door I had to retire the wood panel.
Once the sheet rock had its frame I used the popcorn finish and spray paints to give it texture. I printed silhouettes of the 12 zodiac signs and meticulously cut each one of them. Then I used cardboard to cut squares to place the cutouts and then sprayed painted with the golden spray paint.
I also spray painted the mirror frame since it used to be green instead of golden.
Once the sheet rock had its frame I used the popcorn finish and spray paints to give it texture. I printed silhouettes of the 12 zodiac signs and meticulously cut each one of them. Then I used cardboard to cut squares to place the cutouts and then sprayed painted with the golden spray paint.
I also spray painted the mirror frame since it used to be green instead of golden.
Computer Software
An Apache2 webserver running on a older Mac Mini took care of incoming external request to talk (via Web or SMS API). The Magic Mirror voice was generated by the OSX "say" command. This is the PHP Script I used. Note I had to use sudo as I needed the Applescript and Say commands to run as the same user that the Mirror Mirror software was running.
events.scpt
speak.php <?php $body = file_get_contents("php://input"); shell_exec("sudo -u [username] echo 0 > state.txt"); shell_exec("sudo -u [username] arch -i386 osascript events.scpt g"); shell_exec("sudo -u [username] say " . $body); ?>This is the Applescript that took care of down "key downs" to animate the Mirror Mirror puppet. In the PHP script I made sure I "woke up" the puppet with the key press of "g"
events.scpt
on run argv tell application "System Events" key down (item 1 of argv) delay 2 key up (item 1 of argv) end tell end runIn the next step you can see the main Applescript script that received inputs from the Arduino USB Serial connection.
Arduino
The Arduino used the following sketch. Look at the comments for the pin connections.
>mirrormirror.ino
>animate.scpt
>mirrormirror.ino
#includeThe following Applescript takes care of the Arduino-USB Serial connection. Note that I used Xports to connect Applescript to serial port.#include Servo myservo; // New instance of Servo.h int servoPin = 7; // Servo used to rotate the CD int pingPin = 4; // Ping pin int dtrPin = 3; // DTR line for C17A - DB9 pin 4 int rtsPin = 2; // RTS line for C17A - DB9 pin 7 int buttonState = 0; // Initialize button state to low int bitDelay = 1; // mS delay between bits (1 mS OK) int counter = 0; // counter used to change/toogle lcd message char code[32] = ""; boolean isEngaged = false; int isitreal = 0; void setup(){ myservo.attach(servoPin); Serial.begin(9600); X10.init(rtsPin, dtrPin, bitDelay); // Initialize X10 C17A myservo.write(0); dropCandy(); } void loop(){ long duration, cm; pinMode(pingPin, OUTPUT); digitalWrite(pingPin, LOW); delayMicroseconds(2); digitalWrite(pingPin, HIGH); delayMicroseconds(5); digitalWrite(pingPin, LOW); pinMode(pingPin, INPUT); duration = pulseIn(pingPin, HIGH); cm = microsecondsToCentimeters(duration); if (cm < 120){ isitreal ++; if (isitreal = 2){ Serial.print("A"); delay(8 * 1000); dropCandy(); delay(15 * 1000); isitreal = 0; } } else if (cm > 120 && cm < 200){ X10.sendCmd( hcA, 2, cmdOff ); } //Listen if computer send signal to drop candy. if (Serial.available()) { char c = (char)Serial.read(); if (c == '1'){ dropCandy(); } } delay(100); } void dropCandy(){ //Turn on X10 light and fog X10.sendCmd( hcA, 1, cmdOn ); X10.sendCmd( hcA, 3, cmdOn ); myservo.write(180); delay(500); myservo.write(0); //Wait 30 seconds before next candy //Turn on X10 light and fog X10.sendCmd( hcA, 1, cmdOff ); //delay(10 * 1000); X10.sendCmd( hcA, 3, cmdOff ); } long microsecondsToCentimeters(long microseconds) { return microseconds / 29 / 2; }
set zonea to {"Who are you", "I like your costume", "Spin around for me","Who is the fairest of them all, you of course.", "What is the magic word?", "Do a dance for me","Trick or treat, Smell my feet"} set zoneb to {"Happy Halloween!", "Hasta la vista baby", "So long, farewell, auf Wiedersehen, good night", "Thanks for stopping by, happy halloween" } set onMode to false set use_port to "/dev/cu.usbmodem1d11" repeat until (get serialport list) contains use_port delay 3 end repeat if (get serialport list) contains use_port then set onMode to true set myPort to serialport open use_port bps rate 9600 data bits 8 parity 0 stop bits 1 handshake 0 delay 1 if myPort is equal to -1 then display dialog "could not open port" else repeat while onMode is true set state to (do shell script "cat '/full/path/of/file/state.txt'") if state is equal to "1" then set x to serialport read myPort if x is not equal to "" then if x is equal to "A" then set randomPhraseA to some item of zonea say randomPhraseA do shell script ("sudo -u [username] arch -i386 osascript /full/path/of/file/animate.scpt &> /dev/null &") delay 10 set randomPhraseB to some item of zoneb say randomPhraseB end if end if else serialport write "1" to myPort delay 5 do shell script ("sudo -u [username] echo 1 > /full/path/of/file/state.txt") do shell script ("sudo -u [username] arch -i386 osascript /full/path/of/file/animate.scpt &> /dev/null &") end if end repeat end if serialport close myPort end ifI used the following script to virtually press down/lef/right arrow keys. This made the Mirror Mirror puppet move his head.
>animate.scpt
tell application "System Events" key down (ASCII character 31) delay 1 key up (ASCII character 31) key down (ASCII character 28) delay 1 key up (ASCII character 28) key down (ASCII character 29) delay 1 key up (ASCII character 29) end tell
SMS/MMS Setup
One of the most exciting features of this project was the ability to allow my neighbors to easily interact with the Magic Mirror. This is not the first time I have done SMS integration (see Automatic Halloween Candy Dispenser), but finally I was able to do it with a short code. Setting up a short code with my previous SMS API (twilio) is prohibitively expensive. But now thanks to Mogreet is pretty easy.
So basically when on of my neighbors send a Text message with the following workd "say [your name] the Mogreet server contacted my callbackurl (halloween.php) which in turn grabbed a snapshot from the front facing Dropcam and send it back to the sender.
Another neat feature I added was a "profanity filter". I just new it could be too tempting for some teenagers to send some inappropriate words.
halloween.php
So basically when on of my neighbors send a Text message with the following workd "say [your name] the Mogreet server contacted my callbackurl (halloween.php) which in turn grabbed a snapshot from the front facing Dropcam and send it back to the sender.
Another neat feature I added was a "profanity filter". I just new it could be too tempting for some teenagers to send some inappropriate words.
halloween.php
<?php $xml = file_get_contents("php://input"); $mo = new SimpleXMLElement($xml , 0, false); $mobile = $mo->msisdn; $msg = $mo->message; $strArray = explode(' ',$msg); $name = trim($strArray[1]); $tmpdate = date ("mdy-His"); $filename = $name."-".$tmpdate.".jpeg"; downloadDropcam($filename); $geturl = 'http://www.wdyl.com/profanity?q='.urlencode($name); $json_output = json_decode(httpGet($geturl)); $response = $json_output->{'response'}; if ($response == 'false'){ $message = "Hello ". $name . ". I am the magic mirror and I have some candy for you. Happy Halloween!"; httpPost("http://[Server running on Mac Mini/speak.php", $message); echo "Message sent: ".$msg; }else{ echo "Sorry. Profanity not allowed!"; } $url = "http://[hosted server].com/halloween/".$filename; $params = "client_id=XXXX&token=XXXXX&campaign_id=XXXXX&to=".$mobile."&message=".urlencode("Happy Halloween")."&content_url=".$url; $smsResponse = httpGet("https://api.mogreet.com/moms/transaction.send?".$params); function downloadDropcam($file){ $url = "https://nexusapi.dropcam.com/get_image?width=800&uuid=XXXXXXX"; $path = "halloween/".$file; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $data = curl_exec($ch); curl_close($ch); file_put_contents($path, $data); } function httpGet($url){ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); curl_close($ch); return $output; } function httpPost($url,$data){ $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); curl_setopt($ch, CURLOPT_TIMEOUT, 1); $output = curl_exec($ch); curl_close($ch); return $output; } ?>
Lights and Music Setup
To add to the ambiance I created a small lights and music show using a Raspberry Pi. Check my Instructables here.