How many times have you asked Santa to bring you an Arduino kit, a 3D printer or a set of tools and only brought you a pair of socks? Well, this is going to end.
Santa Claus has hired us to run a project based on IoT and Arduino MKR1000, which will help you to have more control over where to deliver the gifts.
The first thing you have to do is be good, do the dishes, help at home and the elderly ladies, make the purchase and, of course, send the letter to Santa.
Once you have fulfilled all the requirements, you are ready to press the magic button that will send to Santa's Twitter (@dashbuttonsanta) the coordinates where you have to leave the gifts.
In addition, he will send an email to the department that has been created with this project, Dash Button Department.
Finally, once Santa Claus leaves the gifts in your house, will make the confirmation of the delivery in your Twitter account and you will be able to see the updated map in this web page.
This way Santa will never forget to stop by your house and you will know where to take your Makers gifts.
General operation of the systemThe system will work with 4 different states depending on the situation of the Dash Button Santa.
Status 1: Disabled
In this state no notification has been sent to Santa from the location of where we want to leave the gifts.
The first thing you have to do is to be good, from the dishes, help at home and the elderly ladies, make the purchase and, of course, send the letter to Santa.
Then, you can send the location to Santa to leave the gifts in your house. Pressing the button will move to the next state.
Status 2: sent location
When you enter this state, a Tweet is sent to Santa Twitter (@dashbuttonsanta) and an email to the account dashbuttonsanta@gmail.com.
The Dash Button Santa will remain in this state until Christmas Day. Even if you press the button it will not do anything.
When it is December 25th, the lights will start flashing. This means that we are ready to receive Santa. Only he can press the button again to change to the next state.
State 3: Gifts delivered
Santa will press the button and confirm that the gifts have been delivered.
When you wake up in the morning you can check whether or not it has happened because the Dash Button Santa will be green.
System ArchitectureThe architecture is very simple. We rely on different services all of them free of charge.
Of course the central axis of the project revolves around Arduino MKR1000. It can be divided into 4 large blocks:
- Location finding
- Save information in the cloud
- Post to Twitter and send an email
- The circuit
Dash Button Santa goes with you. You don't know in advance where are you going to be on Christmas day. Use Dash Button Santa to tell Santa where are you.
It listens what WiFi networks are around and gets precise location using Google Maps Geolocation API.
WiFi101 library, as it is now, does not allow getting a list of access points MAC addresses (BSSID). We needed to modify library in order to enable the feature to get a detailed list of WiFi networks in the neighborhood.
Store information in the cloudAfter testing several services and platforms in the cloud for IoT, the simplest we have found to implement this project has been Firebase.
This service has a simple database based on JSON and accessible through its API. By simply making a PUT request with a JSON, you can generate your own data structure on the fly.
You need to have a Google account to access the free service with limitations that they offer.
The JSON that we have used is the following:
{
"persons" : {
"A9:D8:F5:05:F0:F8" : {
"lat" : 38.3685,
"lon" : -0.4219,
"prec" : 100999,
"status" : "2"
}
}
}
Everything hangs from persons. As a unique identifier we have used the MAC of the Arduino MKR100.
Then we send the latitude, longitude, precision and status of the button.
The goal of storing location information is to be able to track Dash Button Santa around the world.
In a web page we will be able to see all connected Dash Buttons. This web is made with jQuery that accesses the Firebase API to obtain the information.
It consists of two files, one .html and one .js. Then you can see the code.
<!DOCTYPE html>
<html>
<head>
<title>Dash Button Tracking Santa Claus</title>
<style type="text/css">
html, body { height: 100%; margin: 0; padding: 0; }
#map { height: 100%; }
</style>
<meta name="robots" content="noindex">
</head>
<body>
<!--<ul id="costumers" class="list-group">
</ul>-->
<div id="map"></div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- Latest compiled and minified Bootstrap -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<!-- Include Firebase Library -->
<script src='https://cdn.firebase.com/js/client/2.2.1/firebase.js'></script>
<!-- Tracking Store JavaScript -->
<script src="script.js"></script>
<!-- API Google Maps -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyABRsKsE4ISjkikM96Hn7RIv9nW-oice8Q&callback=initMap">
</script>
</body>
</html>
And the JavaScript file.
// Create a firebase reference
var dbRef = new Firebase('https://dash-button-arduino.firebaseio.com/');
var costumersRef = dbRef.child('persons');
var markers = {}
//load persons
costumersRef.on("child_added", function(snap) {
// Print to map
addNewPerson(snap.val().lat,snap.val().lon,snap.val().status, snap.key());
});
//change persons
costumersRef.on("child_changed", function (snap) {
changePerson(snap.val().lat, snap.val().lon, snap.val().status);
});
/******** GOOGLE MAPS *********/
var map;
function initMap() {
// Center map
var myLatLng = {lat: 38.392101, lng: -0.525467};
map = new google.maps.Map(document.getElementById('map'), {
center: myLatLng,
zoom: 3
});
}
function addNewPerson(lat, lon,status, key){
console.log("status",status);
var image
if(status==0)
{
image='images/santa-icon-1.png';
}
else if(status==1)
{
image='images/santa-icon-2.png';
}
else if(status==2)
{
image='images/santa-icon-3.png';
}
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat,lon),
icon: image,
map: map,
title: key // Tooltip = MAC address
});
markers[key] = marker;
}
function changePerson(lat, lon, status, key) {
console.log("status", status);
var image;
if (status == 0) {
image = 'images/santa-icon-1.png';
}
else if (status == 1) {
image = 'images/santa-icon-2.png';
}
else if (status == 2) {
image = 'images/santa-icon-3.png';
}
marker = markers[key];
marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lon),
icon: image,
map: map,
title: key // Tooltip = MAC address
});
markers[key] = marker;
}
To show the information on the map according to the state we have used the following images.
You can access the web that is published in this URL.
In this block is where more difficulties we could find, but thanks to the service offered by IFTTT, this task has been very simple :).
They have recently enabled a service called IFTTT Maker that lets you launch events and triggers through an API. With a simple GET call and a well configured recipes it is very simple.
This makes it much easier to publish in any social network and open channels of communication between objects or machines, giving free rein to IoT technologies.
In this project we will use 3 recipes.
- Recipe 1: sends the information to the @dashbuttonsanta account with the length and latitude of the Dash Button.
- Recipe 2: send an email to the account dashbuttonsanta@gmail.com with the longitude and latitude.
- Recipe 3: Once Santa has left the gifts at home, he publishes that the gifts have already been delivered.
The basic scheme is to connect a pushbutton to the Arduino MKR1000 and 3 pixels Neopixel.
Then we can decorate it as we want. In our case we used a teddy of Rudolf, the reindeer of Santa Claus.
We took advantage of a button inside and the Neopixel strip in the scarf.
The pixels tell us the status of the Dash Button Santa.
- Pixel 1 red, pixel 2 blue and pixel 3 green, attemping to connect to WiFi.
- 3 pixels orange blink, WiFi error.
- 3 pixels red blink, error RTC.
- 3 pixels red, device off. Location not sent to Santa.
- 3 pixels blue, location sent to Santa.
- 3 pixels blue blinking, Christmas Day !!!!!
- 3 pixels green, Santa claus left the presents and pressed the button.
All this you can see in the next section where we talk about the code.
Arduino SketchIn the sketch several libraries are used that facilitate the task of managing the connections with the services and controlling the time to know when it is Christmas.
You will need different accounts to use the service. We are working on improving it and not depend on third parties :).
You will need the following to make it work:
- Google API key
- IFTTT key
- SSID WiFi
- Password WiFi
The whole code is very well explained. Any questions you can leave in the comments of this article.
To store the state in local and to be able to know in which state it was if it is disconnected we have used FlashStorage that simulates an EEPROM memory.
To control the day and the month, we have done it through RTCZero.
In addition we leave you two links so that you download the WiFi101 modified library and the WifiLocation.
You can find the links to the libraries in GitHub, in the section of libraries of this article.
/*
DashButtonSanta
Send information to Santa Claus about the status of the gift request. It uses the geolocation through the WiFi,
of the Google API, and it is sent to Firebase, along with the state and with the MAC (key value) of the Arduino MKR1000.
It also sends the information to Twitter @ dashbuttonsanta and to the email dashbuttonsanta@gmail.com through IFTTT.
On the web https://programarfacil.com/proyectos/dashbuttonsanta/tracking-santa.html you can follow the status of all requests.
When at the end Santa leaves the gifts on the site sent to Twitter and the email, press the button and gives the delivery finished.
States:
0 => Device OFF (LED color red)
1 => I have behaved well, I have made the bed, I have cleaned the dishes, I have helped an old lady, I pray every night, etc ...
and I have sent the letter :) (LED color blue)
2 => Is Christmas Day (LED blink color blue)
3 => Santa claus left the presents and pressed the button (LED blink color green)
Errors:
Wifi shield not present => LED blink Color(233, 149, 16)
NTP unreachable => LED blink Color(150, 0, 0)
The circuit:
Arduino MKR1000
Pushbutton to pin 6
pull-down resistor to pushbutton
3 addressable LEDs
Created 2017
By https://programarfacil.com
Luis del Valle @ldelvalleh
Germán Martín @gmag12
*/
#include <Adafruit_NeoPixel.h>
#include <WiFi101.h>
#include <WiFiUdp.h>
#include <RTCZero.h>
#include <FlashStorage.h>
#include "WifiLocation.h"
// Fill these fields with your data
#define GOOGLE_API_KEY "YOURGOOGLEAPIKEY"
#define IFTTTKEY "YOURIFTTTKEY"
#define SSID "WIFISID"
#define PASS "WIFPASS"
// Constants
#define DASHBUTTON 6 // Button
#define PINNEO 7 // Pin Neopixel
#define NUMPIXELS 3 // Num pixels
#define HOST "dash-button-arduino.firebaseio.com" // Host Firebase
#define HOSTIFTTT "maker.ifttt.com" // Host IFTTT to send tweet and email
#define TWITTEREVENT "tweet_santa" // Event name IFTTT Twitter
#define EMAILEVENT "email_santa" // Event name IFTTT email
#define SANTAEVENT "santa_santa" // Event name IFTTT Twitter Santa Claus
#define D_DAY 25 // Christmas Day
#define M_MONTH 12 // Christmas Month
#define LOC_PRECISSION 4 // Accuracy of location data to control privacy
// Neopixel
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PINNEO, NEO_GRB + NEO_KHZ800);
// Dash Button States
int dashButtonState = 0;
volatile bool makeUpdate = false;
// Reserve a portion of flash memory to store an "int" variable
// and call it "state_dashbutton".
FlashStorage(state_dashbutton, int);
// RTC with WiFi
RTCZero rtc;
const int GMT = 1;
int status = WL_IDLE_STATUS;
WiFiClient client;
// Info person
byte mac[6];
location_t location;
void setup() {
// Init Neopixel
pixels.begin();
// Read the content of state_dashbutton
dashButtonState = state_dashbutton.read();
pixels.setPixelColor(0, pixels.Color(150, 0, 0));
pixels.show();
pixels.setPixelColor(1, pixels.Color(0, 0, 150));
pixels.show();
pixels.setPixelColor(2, pixels.Color(0, 150, 0));
pixels.show();
// WiFi configuration
configWiFi();
// Get location using WiFi networks around
getLocation();
// Update Dash Button state
putRequest(dashButtonState);
// Init Dash Button
pinMode(DASHBUTTON, INPUT);
// Init interrupt
attachInterrupt(digitalPinToInterrupt(DASHBUTTON), dashbuttonAction, RISING);
// RTC configuration
configRTC();
// Random seed
randomSeed(analogRead(A0));
}
void loop() {
// Off
if (dashButtonState == 0)
{
for (int i = 0; i < NUMPIXELS; i++) {
// pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
pixels.setPixelColor(i, pixels.Color(150, 0, 0));
pixels.show();
}
}
// Location sended but not Christmas day
else if (dashButtonState == 1 && rtc.getDay() != D_DAY && rtc.getMonth() != M_MONTH)
{
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, 150));
pixels.show();
}
}
// Location sended and Christmas day
else if (dashButtonState == 1 && rtc.getDay() == D_DAY && rtc.getMonth() == M_MONTH)
{
blinkNeopixel(pixels.Color(0, 0, 150));
}
// Shipping
else if (dashButtonState == 2)
{
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 150, 0));
pixels.show();
}
}
// If need update
if (makeUpdate)
{
// Change Dash Button State
if (dashButtonState == 0)
{
pixels.setPixelColor(0, pixels.Color(150, 0, 0));
pixels.show();
pixels.setPixelColor(1, pixels.Color(0, 0, 150));
pixels.show();
pixels.setPixelColor(2, pixels.Color(0, 0, 150));
pixels.show();
if (putRequest(1))
{
// Send Email
sendEmail();
delay(2000);
// Send Twitter
sendToTwitterPerson();
dashButtonState = 1;
}
}
// Only Christmas Day
else if (dashButtonState == 1 && rtc.getDay() == D_DAY && rtc.getMonth() == M_MONTH)
{
pixels.setPixelColor(0, pixels.Color(0, 0, 150));
pixels.show();
pixels.setPixelColor(1, pixels.Color(0, 150, 0));
pixels.show();
pixels.setPixelColor(2, pixels.Color(0, 150, 0));
pixels.show();
if (putRequest(2))
{
sendToTwitterSanta();
dashButtonState = 2;
}
}
// Change state in FlashStorage
state_dashbutton.write(dashButtonState);
}
makeUpdate = false;
}
// Callback interruption
void dashbuttonAction()
{
noInterrupts();
if (!makeUpdate)
makeUpdate = true;
interrupts();
}
void blinkNeopixel(uint32_t c)
{
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
pixels.show();
}
delay(500);
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, c);
pixels.show();
}
delay(500);
}
/**************** WiFi Connection ****************/
void configWiFi()
{
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
// don't continue:
while (true)
{
// Show error shield not present
blinkNeopixel(pixels.Color(233, 149, 16));
}
}
// attempt to connect to Wifi network:
while (status != WL_CONNECTED) {
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(SSID, PASS);
// wait 10 seconds for connection:
delay(10000);
}
// Get mac
WiFi.macAddress(mac);
}
/**************** RTCZero ****************/
void configRTC()
{
// Init RTC
rtc.begin();
unsigned long epoch;
int numberOfTries = 0, maxTries = 6;
do {
epoch = WiFi.getTime();
numberOfTries++;
}
while ((epoch == 0) || (numberOfTries > maxTries));
if (numberOfTries > maxTries) {
while (1)
{
{
// Show error RTC
blinkNeopixel(pixels.Color(150, 0, 0));
}
}
}
else {
rtc.setEpoch(epoch);
}
}
/**************** HTTP PUT Request to Firebase ****************/
bool putRequest(int newDashButtonState)
{
String keyMac = "";
for (int i = 0; i < 6; i++)
{
String pos = String((uint8_t)mac[i], HEX);
if (mac[i] <= 0xF)
pos = "0" + pos;
pos.toUpperCase();
keyMac += pos;
if (i < 5)
keyMac += ":";
}
// close any connection before send a new request.
client.stop();
client.flush();
// send SSL request
if (client.connectSSL(HOST, 443)) {
// PUT request
String toSend = "PUT /persons/";
toSend += keyMac;
toSend += ".json HTTP/1.1\r\n";
toSend += "Host:";
toSend += HOST;
toSend += "\r\n" ;
toSend += "Content-Type: application/json\r\n";
String payload = "{\"lat\":";
payload += String(location.lat, LOC_PRECISSION);
payload += ",";
payload += "\"lon\":";
payload += String(location.lon, LOC_PRECISSION);
payload += ",";
payload += "\"prec\":";
payload += String(location.accuracy);
payload += ",";
payload += "\"status\": \"";
payload += newDashButtonState;
payload += "\"}";
payload += "\r\n";
toSend += "Content-Length: " + String(payload.length()) + "\r\n";
toSend += "\r\n";
toSend += payload;
client.println(toSend);
client.println();
client.flush();
client.stop();
return true;
} else {
// if you couldn't make a connection:
client.flush();
client.stop();
return false;
}
}
/**************** Send to Twitter IFTTT ****************/
void sendToTwitterPerson()
{
requestIFTTT(TWITTEREVENT);
}
void sendToTwitterSanta()
{
requestIFTTT(SANTAEVENT);
}
/**************** Send email IFTTT ****************/
void sendEmail()
{
requestIFTTT(EMAILEVENT);
}
/**************** Request IFTTT ****************/
void requestIFTTT(String eventName)
{
for (int i = 0; i < 3; i++)
{
// close any connection before send a new request.
if (client.connected())
{
client.stop();
}
client.flush();
// Random request: from IFTTT Twitter publish Cannot send duplicate tweet.
long randomRequest = random(1, 10000);
// send SSL request
if (client.connectSSL(HOSTIFTTT, 443)) {
// Make a HTTP request:
String toSend = "GET /trigger/";
toSend += eventName;
toSend += "/with/key/";
toSend += IFTTTKEY;
toSend += "?value1=";
toSend += String(location.lat, LOC_PRECISSION);
toSend += "&value2=";
toSend += String(location.lon, LOC_PRECISSION);
toSend += "&value3=";
toSend += randomRequest;
toSend += " HTTP/1.1\r\n";
toSend += "Host: maker.ifttt.com\r\n";
toSend += "Connection: close\r\n\r\n";
client.print(toSend);
break;
} else {
// if you couldn't make a connection:
}
}
client.flush();
client.stop();
}
/**************** Get Location info ****************/
bool getLocation() {
WifiLocation gLocation(GOOGLE_API_KEY);
location = gLocation.getGeoFromWiFi();
return (location.accuracy < 100);
}
ConclusionsIn this project we wanted to demonstrate that simply with a little ingenuity and an Arduino MKR1000, we can track anything.
We have used free services that allow us to prototype and create technology in a simple and economical way.
An interesting improvement would be to use a NodeMCU ESP8266.
Although this is just a project for The Arduino Internet of Holiday Things, we hope that we can inspire you so that you can create your own project based on our idea.
We would appreciate any comments and suggestions. Many thanks for your attention and Oh Oh Oh Merry Christmas!
Comments