Chris
Published

Spark Doorbell

Smart Doorbell plays polyphonic ringtone, connects to XBMC and sends an e-mail

Work in progress8,754
Spark Doorbell

Story

Read more

Custom parts and enclosures

DoorBell.stl

Sketchfab still processing.

DoorBellCover.stl

Sketchfab still processing.

DoorBellButtonpart2.stl

Sketchfab still processing.

DoorBellButtonpart1.stl

Sketchfab still processing.

DoorBellBase.stl

Sketchfab still processing.

Code

Doorbell.ino

Plain text
Doorbell.ino
#include "application.h"

// XBMC Setup
char xbmcServer[] = "your server"; // XBMC Server
int xbmcPort = 80; // XBMC Port
char xbmcScript[] = "/jsonrpc?request={%22jsonrpc%22:%222.0%22,%22method%22:%22Addons.ExecuteAddon%22,%22params%22:{%22addonid%22:%22script.securitycam%22},%22id%22:%221%22}}"; // Script to run
char xbmcLogon[] = "Base64encoded"; // Username:Password base64 encoded


// Pushing Box Setup
char serverName[] = "api.pushingbox.com"; // Pushingbox Server
char deviceID[] = "/pushingbox?devid=YOURDEVIDHERE"; // Get request 

// Select a Tune from below

//char *song = (char *)"The Simpsons:d=4,o=5,b=168:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g,8p,8p,8f#,8f#,8f#,8g,a#.,8c6,8c6,8c6,c6";
//char *song = (char *)"Indiana:d=4,o=5,b=250:e,8p,8f,8g,8p,1c6,8p.,d,8p,8e,1f,p.,g,8p,8a,8b,8p,1f6,p,a,8p,8b,2c6,2d6,2e6,e,8p,8f,8g,8p,1c6,p,d6,8p,8e6,1f.6,g,8p,8g,e.6,8p,d6,8p,8g,e.6,8p,d6,8p,8g,f.6,8p,e6,8p,8d6,2c6";
//char *song = (char *)"TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5";
//char *song = (char *)"Entertainer:d=4,o=5,b=140:8d,8d#,8e,c6,8e,c6,8e,2c.6,8c6,8d6,8d#6,8e6,8c6,8d6,e6,8b,d6,2c6,p,8d,8d#,8e,c6,8e,c6,8e,2c.6,8p,8a,8g,8f#,8a,8c6,e6,8d6,8c6,8a,2d6";
//char *song = (char *)"Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c";
//char *song = (char *)"Xfiles:d=4,o=5,b=125:e,b,a,b,d6,2b.,1p,e,b,a,b,e6,2b.,1p,g6,f#6,e6,d6,e6,2b.,1p,g6,f#6,e6,d6,f#6,2b.,1p,e,b,a,b,d6,2b.,1p,e,b,a,b,e6,2b.,1p,e6,2b.";
//char *song = (char *)"Looney:d=4,o=5,b=140:32p,c6,8f6,8e6,8d6,8c6,a.,8c6,8f6,8e6,8d6,8d#6,e.6,8e6,8e6,8c6,8d6,8c6,8e6,8c6,8d6,8a,8c6,8g,8a#,8a,8f";
//char *song = (char *)"20thCenFox:d=16,o=5,b=140:b,8p,b,b,2b,p,c6,32p,b,32p,c6,32p,b,32p,c6,32p,b,8p,b,b,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,g#,32p,a,32p,b,8p,b,b,2b,4p,8e,8g#,8b,1c#6,8f#,8a,8c#6,1e6,8a,8c#6,8e6,1e6,8b,8g#,8a,2b";
//char *song = (char *)"Bond:d=4,o=5,b=80:32p,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d#6,16d#6,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d6,16c#6,16c#7,c.7,16g#6,16f#6,g#.6";
//char *song = (char *)"MASH:d=8,o=5,b=140:4a,4g,f#,g,p,f#,p,g,p,f#,p,2e.,p,f#,e,4f#,e,f#,p,e,p,4d.,p,f#,4e,d,e,p,d,p,e,p,d,p,2c#.,p,d,c#,4d,c#,d,p,e,p,4f#,p,a,p,4b,a,b,p,a,p,b,p,2a.,4p,a,b,a,4b,a,b,p,2a.,a,4f#,a,b,p,d6,p,4e.6,d6,b,p,a,p,2b";
//char *song = (char *)"StarWars:d=4,o=5,b=45:32p,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#.6,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#6";
//char *song = (char *)"GoodBad:d=4,o=5,b=56:32p,32a#,32d#6,32a#,32d#6,8a#.,16f#.,16g#.,d#,32a#,32d#6,32a#,32d#6,8a#.,16f#.,16g#.,c#6,32a#,32d#6,32a#,32d#6,8a#.,16f#.,32f.,32d#.,c#,32a#,32d#6,32a#,32d#6,8a#.,16g#.,d#";
//char *song = (char *)"TopGun:d=4,o=4,b=31:32p,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,16f,d#,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,g#";
//char *song = (char *)"A-Team:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#";
//char *song = (char *)"Flinstones:d=4,o=5,b=40:32p,16f6,16a#,16a#6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c6,d6,16f6,16a#.,16a#6,32g6,16f6,16a#.,32f6,32f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c6,a#,16a6,16d.6,16a#6,32a6,32a6,32g6,32f#6,32a6,8g6,16g6,16c.6,32a6,32a6,32g6,32g6,32f6,32e6,32g6,8f6,16f6,16a#.,16a#6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,32f6,16a#6,16c7,8a#.6";
//char *song = (char *)"Jeopardy:d=4,o=6,b=125:c,f,c,f5,c,f,2c,c,f,c,f,a.,8g,8f,8e,8d,8c#,c,f,c,f5,c,f,2c,f.,8d,c,a#5,a5,g5,f5,p,d#,g#,d#,g#5,d#,g#,2d#,d#,g#,d#,g#,c.7,8a#,8g#,8g,8f,8e,d#,g#,d#,g#5,d#,g#,2d#,g#.,8f,d#,c#,c,p,a#5,p,g#.5,d#,g#";
char *song = (char *)"Gadget:d=16,o=5,b=50:32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,32d#,32f,32f#,32g#,a#,d#6,4d6,32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,8d#";
//char *song = (char *)"Smurfs:d=32,o=5,b=200:4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8b,p,4g#,16p,4c#6,p,16a#,p,8f#,p,8a#,p,4g#,4p,g#,p,a#,p,b,p,c6,p,4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8b,p,4g#,16p,4c#6,p,16a#,p,8b,p,8f,p,4f#";
//char *song = (char *)"MahnaMahna:d=16,o=6,b=125:c#,c.,b5,8a#.5,8f.,4g#,a#,g.,4d#,8p,c#,c.,b5,8a#.5,8f.,g#.,8a#.,4g,8p,c#,c.,b5,8a#.5,8f.,4g#,f,g.,8d#.,f,g.,8d#.,f,8g,8d#.,f,8g,d#,8c,a#5,8d#.,8d#.,4d#,8d#.";
//char *song = (char *)"LeisureSuit:d=16,o=6,b=56:f.5,f#.5,g.5,g#5,32a#5,f5,g#.5,a#.5,32f5,g#5,32a#5,g#5,8c#.,a#5,32c#,a5,a#.5,c#.,32a5,a#5,32c#,d#,8e,c#.,f.,f.,f.,f.,f,32e,d#,8d,a#.5,e,32f,e,32f,c#,d#.,c#";
//char *song = (char *)"MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d";
//char *song = (char *)"SMBtheme:d=4,o=5,b=100:16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,8g,8p,8c6,16p,8g,16p,8e,16p,8a,8b,16a#,8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,16c6,16d6,8b,16p,8c6,16p,8g,16p,8e,16p,8a,8b,16a#,8a,16g.,16e6,16g6,8a6,16f6,8g6,8e6,16c6,16d6,8b,8p,16g6,16f#6,16f6,16d#6,16p,16e6,16p,16g#,16a,16c6,16p,16a,16c6,16d6,8p,16g6,16f#6,16f6,16d#6,16p,16e6,16p,16c7,16p,16c7,16c7,p,16g6,16f#6,16f6,16d#6,16p,16e6,16p,16g#,16a,16c6,16p,16a,16c6,16d6,8p,16d#6,8p,16d6,8p,16c6";
//char *song = (char *)"SMBunderground:d=16,o=6,b=100:c,c5,a5,a,a#5,a#,2p,8p,c,c5,a5,a,a#5,a#,2p,8p,f5,f,d5,d,d#5,d#,2p,8p,f5,f,d5,d,d#5,d#,2p,32d#,d,32c#,c,p,d#,p,d,p,g#5,p,g5,p,c#,p,32c,f#,32f,32e,a#,32a,g#,32p,d#,b5,32p,a#5,32p,a5,g#5";
//char *song = (char *)"SMBwater:d=8,o=6,b=225:4d5,4e5,4f#5,4g5,4a5,4a#5,b5,b5,b5,p,b5,p,2b5,p,g5,2e.,2d#.,2e.,p,g5,a5,b5,c,d,2e.,2d#,4f,2e.,2p,p,g5,2d.,2c#.,2d.,p,g5,a5,b5,c,c#,2d.,2g5,4f,2e.,2p,p,g5,2g.,2g.,2g.,4g,4a,p,g,2f.,2f.,2f.,4f,4g,p,f,2e.,4a5,4b5,4f,e,e,4e.,b5,2c.";
//char *song = (char *)"SMBdeath:d=4,o=5,b=90:32c6,32c6,32c6,8p,16b,16f6,16p,16f6,16f.6,16e.6,16d6,16c6,16p,16e,16p,16c";
//char *song = (char *)"RickRoll:d=4,o=5,b=200:8g,8a,8c6,8a,e6,8p,e6,8p,d6.,p,8p,8g,8a,8c6,8a,d6,8p,d6,8p,c6,8b,a.,8g,8a,8c6,8a,2c6,d6,b,a,g.,8p,g,2d6,2c6.,p,8g,8a,8c6,8a,e6,8p,e6,8p,d6.,p,8p,8g,8a,8c6,8a,2g6,b,c6.,8b,a,8g,8a,8c6,8a,2c6,d6,b,a,g.,8p,g,2d6,2c6.";
//char *song = (char *)"2.34kHzBeeps:d=4,o=7,b=240:d,p,d,p,d,p,d,p";
//char *song = (char *)"Satellit:d=8,o=6,b=112:g,e,16f,16e,d,c,g,c7,c";

// Input and Output Pins 

int16_t tonePin = D6; //Dorrbell Sound Output 
int doorbell = D0; // Doorbell button connects to D0 on the core
int LED = D7; // Built in LED

boolean DEBUG = false; // enable or disable Debug
int Retrys = 5; // Number of times to retry connecting

// RTTTL setup

int notes[] =
{0,
3817,3597,3401,3205,3030,2857,2703,2551,2404,2273,2146,2024,
1908,1805,1701,1608,1515,1433,1351,1276,1205,1136,1073,1012,
956,903,852,804,759,716,676,638,602,568,536,506,
478,451,426,402,379,358,338,319,301,284,268,253,
239,226,213,201,190,179,169,159,151,142,134,127};

#define OCTAVE_OFFSET 0 

boolean playing = false;
byte default_dur = 4;
byte default_oct = 6;
byte lowest_oct = 3;
int bpm = 63;
int num;
long wholenote;
long duration;
byte note;
byte scale;
bool songDone = false;
char *songPtr;


unsigned long Lockout; // used to stop flooding servers

void setup() {

    pinMode(tonePin,OUTPUT);
    pinMode(doorbell, INPUT_PULLUP); // other side of doorbell will connect to ground to pull low
    Lockout = millis();
    pinMode(LED, OUTPUT); // sets LED as output
    if(DEBUG){
        digitalWrite(LED,HIGH); // Light the onboard LED so you know it's time to open your Serial Terminal
        Serial.begin(9600);
        while(!Serial.available()); // wait here for user to press ENTER in Serial Terminal
        digitalWrite(LED,LOW);

        Serial.print("SSID: ");
        Serial.println(Network.SSID());
        Serial.print("Core IP: ");
        Serial.println(Network.localIP());
        Serial.print("Gateway: ");
        Serial.println(Network.gatewayIP());
        Serial.print("Mask: ");
        Serial.println(Network.subnetMask());
        Serial.print("WiFi RSSI: ");
        Serial.println(Network.RSSI());
    }
    

}

void loop() {

    if (millis() >= Lockout){  // check how long its been since last pushed
        if(digitalRead(doorbell) == LOW) {  //read the doorbell button
            delay(50);
            if(digitalRead(doorbell) == LOW) {  // debounce check again to make sure 
                Lockout = millis() + 15000; // set up the lockout period 15 seconds before it will run again
                RGB.control(true);
                RGB.color(0,255,0);
                playing = true;
                while(playing) {
                if(!songDone) { // Start song
                    songDone = true;
                    begin_rtttl(song);
                }
                if(!next_rtttl()) { // Play next note
                    songDone = false;
                    playing = false;
                    delay(2000);
                }
               
            }
                runXbmcScript(xbmcServer, xbmcPort, xbmcScript, xbmcLogon, Retrys);  // opens up a script in xbmc that displays an ip camera 
                sendToPushingBox(serverName, deviceID, Retrys); // sends push notification to mobile phone or sends email using pushingbox
                RGB.control(false);
            }
        }
    }

}


void runXbmcScript(char *hostname, int port, char *url, char *xbmclogon, int retry) {
    
    TCPClient client;
    char line[255];
    client.stop();
    //digitalWrite(LED, HIGH); // sets the LED on
    
    if(DEBUG){Serial.print("connecting... ");}
    if (client.connect(hostname, port)) {
        if(DEBUG){
            Serial.print("connected to ");
            Serial.println(hostname);
        }
        delay(500);
        digitalWrite(LED, LOW);
        strcpy(line, "GET ");
        strcat(line, url);
        strcat(line, " HTTP/1.1\r\n");
        client.print(line);
        if(DEBUG){Serial.print(line);}
        
        strcpy(line, "Host: ");
        strcat(line, hostname);
        strcat(line, "\r\n");
        client.print(line);
        if(DEBUG){Serial.print(line);}
        
        strcpy(line, "Authorization: Basic ");
        strcat(line, xbmclogon);
        strcat(line, "\r\n");
        strcat(line, "Connection: close\r\n\r\n");
        client.print(line);
        delay(500);
        if(DEBUG){
            Serial.print(line);
            while (!client.available());
            while (client.available()) {
            char c = client.read();
            Serial.print(c);
            }
        Serial.println();
        }

        
        client.flush();

        delay(200);
        if(DEBUG){Serial.println("closing...");}
        client.stop();
        //digitalWrite(LED, LOW); // sets the LED off
        
    }
    else{
        digitalWrite(LED, HIGH); // sets the LED on. If always on, last connexion was failed
        if(DEBUG){Serial.println("connection failed");}
        if (retry > 0) {
            retry--;
            delay(1000);
            runXbmcScript(hostname, port, url, xbmclogon, retry);
        }    
        digitalWrite(LED, LOW);
    }
}

void sendToPushingBox(char *serverpbName, char *devid, int retry) {

    TCPClient clientx;    
    char line[255];
    clientx.stop();
    //digitalWrite(LED, HIGH); // sets the LED on
    
    if(DEBUG){Serial.print("connecting... ");}
    if (clientx.connect(serverpbName, 80)) {
        
        if(DEBUG){
            Serial.print("connected to ");
            Serial.println(serverpbName);
        }
        delay(500);
        digitalWrite(LED, LOW);
        strcpy(line, "GET ");
        strcat(line, devid);
        strcat(line, " HTTP/1.1\r\n");
        clientx.print(line);
        if(DEBUG){Serial.print(line);}
        //delay(1000);
        strcpy(line, "Host: ");
        strcat(line, serverpbName);
        strcat(line, "\r\n");
        clientx.print(line);
        if(DEBUG){Serial.print(line);}
        //delay(1000);
        strcpy(line, "Connection: close\r\n");
        //strcat(line, "Accept: text/html, text/plain\r\n");
        //strcat(line, "Content-Length: 0\r\n");
        strcat(line, "User-Agent: Spark\r\n\r\n");
        clientx.print(line);
        delay(500);
        if(DEBUG){
            Serial.print(line);
            while (!clientx.available());
            while (clientx.available()) {
            char c = clientx.read();
            Serial.print(c);
            }
        Serial.println();
        }
        
        clientx.flush();
        delay(200);
        if(DEBUG){Serial.println("closing...");}
        clientx.stop();

        //digitalWrite(LED, LOW); // sets the LED off
    }
    else{
        digitalWrite(LED, HIGH); // sets the LED on. If always on, last connexion was failed
        if(DEBUG){Serial.println("connection failed");}
        if (retry > 0) {
            retry--;
            sendToPushingBox(serverpbName, devid, retry);
            delay(1000);
        } 
        digitalWrite(LED, LOW);
    }
}


void begin_rtttl(char *p)
{
  while(*p != ':') p++; // ignore name
  p++; // skip ':'
  if(*p == 'd')
  {
    p++; p++; // skip "d="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    if(num > 0) default_dur = num;
    p++; // skip comma
  }
  // get default octave
  if(*p == 'o')
  {
    p++; p++; // skip "o="
    num = *p++ - '0';
    if(num >= 3 && num <=7) default_oct = num;
    p++; // skip comma
  }
  // get BPM
  if(*p == 'b')
  {
    p++; p++; // skip "b="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    bpm = num;
    p++; // skip colon
  }
  // BPM usually expresses the number of quarter notes per minute
  wholenote = (60 * 1000L / bpm) * 2; // this is the time for whole note (in milliseconds)
  // Save current song pointer...
  songPtr = p;
}

bool next_rtttl() {

  char *p = songPtr;
  // if notes remain, play next note
  if(*p)
  {
    // first, get note duration, if available
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    
    if(num) duration = wholenote / num;
    else duration = wholenote / default_dur; // we will need to check if we are a dotted note after

    // now get the note
    note = 0;

    switch(*p)
    {
      case 'c':
        note = 1;
        break;
      case 'd':
        note = 3;
        break;
      case 'e':
        note = 5;
        break;
      case 'f':
        note = 6;
        break;
      case 'g':
        note = 8;
        break;
      case 'a':
        note = 10;
        break;
      case 'b':
        note = 12;
        break;
      case 'p':
      default:
        note = 0;
    }
    p++;
    if(*p == '#') // now, get optional '#' sharp
    {
      note++;
      p++;
    }
    if(*p == '.') // now, get optional '.' dotted note
    {
      duration += duration/2;
      p++;
    }
    if(isdigit(*p)) // now, get scale
    {
      scale = *p - '0';
      p++;
    }
    else {
      scale = default_oct;
    }
    scale += OCTAVE_OFFSET;
    if(*p == ',')
      p++; // skip comma for next note (or we may be at the end)
    songPtr = p; // Save current song pointer...
    if(note){ // now play the note
      tone(tonePin, notes[(scale - lowest_oct) * 12 + note], duration);
    }
    else {
      delay(duration);
    }
    return 1; // note played successfully.
  }
  else {
    return 0; // all done
  }
}

void tone(int pin, int16_t note, int16_t duration) {
  for(int16_t x=0;x<(duration*1000/note);x++) {
    PIN_MAP[pin].gpio_peripheral->BSRR = PIN_MAP[pin].gpio_pin; // HIGH
    delayMicroseconds(note);
    PIN_MAP[pin].gpio_peripheral->BRR = PIN_MAP[pin].gpio_pin; // LOW
    delayMicroseconds(note);
  }
}

Credits

Chris

Chris

1 project • 7 followers

Comments