Arduino Project Hub

Dash Button Santa with Arduino MKR1000

Send information to Santa Claus about the status of the gift request.

  • 627 views
  • 0 comments
  • 6 respects

Components and supplies

Apps and online services

About this project

Introduction

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 system

The 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 Architecture

The 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

Location finding

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 cloud

After 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.

Post to Twitter and send email

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 circuit

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 Sketch

In 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); 
} 

Conclusions

In 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.

Although this is just a project for The Arduino Internet of Holyday 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 !!!!!!!!

Schematics

Dash Button Santa - Schematics
It looks great if you use a button on the nose of a Rudolf or Santa Claus doll
Dashbuttonsanta bb bfj3qpkabf

Code

Main SketchArduino
/*
  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
  Germn Martn @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 "YOURIFTTKEY"

#define SSID "WIFISSID"
#define PASS "WIFIPASS"


// 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);

}
Tracking webHTML
Is the web page to show de map.
<!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>
JavaScriptJavaScript
JavaScript to connect Firebase and show the map
// 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;
}
FlashStorage
The FlashStorage library aims to provide a convenient way to store and retrieve user's data using the non-volatile flash memory of microcontrollers.
RTCZero
The RTC library enables an Arduino Zero or MKR1000 board to take control of the internal RTC.
WiFi101 modified
Modification of the WiFi101 library to access the MACs of neighboring routers.
WifiLocation
This is a library that sends Google Maps Geolocaion API a request with a list of all WiFi AP's BSSID that your microcontroller listens to. Google, then answer with location and accuracy in JSON format.

Comments

Similar projects you might like

Caravaggio, a Drawing Machine

Project showcase by michele1993

  • 2,956 views
  • 3 comments
  • 28 respects

Arduino Wireless Weather Station

Project tutorial by Nick Koumaris

  • 7,851 views
  • 3 comments
  • 34 respects

Transformer's Baby - Arduino Avoiding Obstacle Robot

Project tutorial by diyProjectsStepByStep

  • 151 views
  • 0 comments
  • 2 respects

Virtual Arduino Tennis

Project tutorial by Arduino “having11” Guy

  • 693 views
  • 4 comments
  • 4 respects

Ghostbusters Trap Armband

Project showcase by Danielle Gormley

  • 137 views
  • 0 comments
  • 2 respects

ADITI: Affordable Diagnostic Thermal Incubator

Project tutorial by Team ADITI

  • 320 views
  • 0 comments
  • 1 respect
Add projectSign up / Login