Dash Button Santa with Arduino MKR1000

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

Dash Button Santa with Arduino MKR1000

Things used in this project

Hardware components

Arduino MKR1000
Arduino MKR1000
× 1
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
× 1
Jumper wires (generic)
Jumper wires (generic)
× 1
Resistor 10k ohm
Resistor 10k ohm
× 1
NeoPixel strip
NeoPixel strip
× 1

Software apps and online services

Arduino IDE
Arduino IDE
Maker service
IFTTT Maker service
Google Firebase
Google Maps
Google Maps

Story

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.

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

You can access the web that is published in this URL.

mapa-tracking-santa_W9JQwDcGxQ

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 [email protected] with the longitude and latitude.
  • Recipe 3: Once Santa has left the gifts at home, he publishes that the gifts have already been delivered.

twitter-count_VHzQOEn0wx

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.

Schematics

Dash Button Santa – Schematics

It looks great if you use a button on the nose of a Rudolf or Santa Claus doll

Main Sketch

Arduino

/*
  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 [email protected] 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 web

HTML

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>

JavaScript

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.

A convenient way to store data into Flash memory on the ATSAMD21 — Read More

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.

Wifi library for the Arduino WiFi 101 Shield — Read More

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.

Google GeoLocation API wrapper for Arduino MKR1000, ESP8266 and ESP32 — Read More

 


About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:
LinkedinTwitter

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top