How to hack a doorbell and connect it to Twitter - Part 7: Adding it all together

After combining the sender, receiver and both Twitter sketches (and making some adjustments), I now present to you... the final result.

IMG_20130718_142140

The following sketch

  • checks for tweets with a specific hashtag every 40 seconds. When it finds one, it makes the doorbell ring and posts the screen name of the tweep as a new tweet;
  • posts a tweet when someone pushes the doorbell button.

To avoid posting a duplicate tweet (which isn't allowed by Twitter), the program appends a timestamp to each tweet.

(By the way... I'm well aware that the following code could use some serious optimization...)

#include <SPI.h>
#include <WiFi.h>
#include <TextFinder.h>
#include <Twitter_WiFi.h>
#include <string.h> 

#define RF_RECV_PIN 2 // RF receiver component to digital pin 2
#define RF_SEND_PIN 3 // RF receiver component to digital pin 3

#define SHORT_DELAY_SEND 417
#define LONG_DELAY_SEND  (3*SHORT_DELAY_SEND)
#define TOTAL_DELAY_SEND (SHORT_DELAY_SEND + LONG_DELAY_SEND)
#define SYNC_DELAY_SEND  (38*SHORT_DELAY_SEND)

#define SHORT_DELAY 464
#define SHORT_DEV   200
#define SHORT_MIN   (SHORT_DELAY - SHORT_DEV)
#define SHORT_MAX   (SHORT_DELAY + SHORT_DEV)
#define LONG_DELAY  1480
#define LONG_DEV    300
#define LONG_MIN    (LONG_DELAY - LONG_DEV)
#define LONG_MAX    (LONG_DELAY + LONG_DEV)
#define SYNC_DELAY  19760
#define SYNC_DEV    1000
#define SYNC_MIN    (SYNC_DELAY - SYNC_DEV)
#define SYNC_MAX    (SYNC_DELAY + SYNC_DEV)

#define F_WAITING         1               // 1 = waiting for sync     0 = receiving data
#define F_SIGNAL          2               // 1 = a signal found       0 = no signal found
#define F_RIGHT_SIGNAL    3               // 1 = right signal found   0 = incorrect signal

/**********************
 * WiFi variables
 ***/

char ssid[] = "";
char pass[] = ""; 

WiFiClient client;

/**********************
 * RF variables
 ***/


const unsigned long glitch_length = 150;  // Anything below this value is a glitch and will be ignored.

unsigned long fall_time = 0;              // Microsecond time when last falling edge occured.
unsigned long rise_time = 0;              // Microsecond time when last rising edge occured.

unsigned long length_low = 0;
unsigned long length_high = 0;
unsigned long length_sync = 0;

unsigned long buffer = 0;
byte bitCount = 0;
const unsigned long signal = 0b010111110110001000001000;  // The doorbell signal to look for: 0101 1111 0110 0010 0000 100
const byte nBits = 23;                                    // Number of bits to detect (from left to right). The last (24th) bit is discarded
                                                          // because the low part of this bit is followed by the sync signal, which is also low.

volatile byte flags = 0;

/**********************
 * Twitter variables
 ***/

char tweet[140] = "", oldTweet[140] = ""; // Tweet found
unsigned long checkTwitterTime;           // Timestamp to determine when to check for new tweets

// Your Token to Tweet (get it from http://arduino-tweet.appspot.com/)
Twitter twitter("");

/**********************
 * RF functions
 ***/

void chime() { // Ding dong
  
  unsigned long signal = 0b010111110110001000001000;

  for (unsigned char i=0; i<30; i++) { // repeat signal 30 times
    for (unsigned char k=0; k<24; k++) { unsigned long d = ((bitRead(signal, 23-k)) == 1 ? LONG_DELAY_SEND : SHORT_DELAY_SEND); digitalWrite(RF_SEND_PIN, HIGH); delayMicroseconds(d); digitalWrite(RF_SEND_PIN, LOW); delayMicroseconds(TOTAL_DELAY_SEND - d); } delayMicroseconds(SYNC_DELAY_SEND); } } void change() { // Interrupt handler for RF receiver pin unsigned long time = micros(); if (bitRead(flags,F_WAITING)) { // waiting for sync if (digitalRead(RF_RECV_PIN) == LOW) { // falling if (time > (rise_time + glitch_length)) { // no glitch
        fall_time = time;
      }
    }
    
    else { // Rising - digitalRead(RF_RECV_PIN) == HIGH
      if (time > (fall_time + glitch_length)) { // no glitch
        rise_time = time;
        length_low = rise_time - fall_time;
        if ((length_low >= SYNC_MIN) && (length_low <= SYNC_MAX)) { // found sync, start receiving data length_sync = length_low; bitClear(flags, F_WAITING); } } } } else { //receiving data if (digitalRead(RF_RECV_PIN) == LOW) { // falling if (time > (rise_time + glitch_length)) { // no glitch
        
        fall_time = time;
        length_high = fall_time - rise_time;
        
        if ((length_high >= SHORT_MIN) && (length_high <= SHORT_MAX)) { // found short high = 0
          bitCount++;
          buffer = buffer << 1; } else if ((length_high >= LONG_MIN) && (length_high <= LONG_MAX)) { // found long high = 1
          bitCount++;
          buffer = buffer << 1; bitSet(buffer,0); // set rightmost bit to 1 } else { // found nothing - start waiting for sync again bitClear(flags, F_SIGNAL); bitClear(flags, F_RIGHT_SIGNAL); buffer = 0; bitCount = 0; bitSet(flags, F_WAITING); } if (bitCount == nBits) { bitSet(flags, F_SIGNAL); if (buffer == signal) { bitSet(flags, F_RIGHT_SIGNAL); } } } } else { // Rising - digitalRead(2) == HIGH if (time > (fall_time + glitch_length)) { // no glitch
        rise_time = time;
      }
    }        
  }  

}

/**********************
 * Twitter functions
 ***/

void tweetStatus(char* status) { // Sends tweet
  
  char message[140];
  String s = String(status) + " " + String(millis());
  s.toCharArray(message,140);

  Serial.print("Trying to tweet message: ");
  Serial.println(message);
  Serial.println("Connecting to Twitter...");
  if (twitter.post(message)) {
    int response = twitter.wait(&Serial);
    if (response == 200) {
      Serial.println("OK.");
    }
    else {
      Serial.print("Failed to tweet. Code: ");
      Serial.println(response);
    }
  } else {
    Serial.println("Connection failed.");
  }
  
}

void foundHashtag(char* user) { // Actions to perform when hashtag found

  char message[140]; 
  
  Serial.println("Chime!");
  chime();
  
  String s = "Ding dong! " + String(user) + " rang the doorbell. ";
  s.toCharArray(message,140);
  tweetStatus(message);

}

void checkTwitter() { // Search Twitter for hashtag

  int i;
  char user[140];
  
  Serial.println("Checking for tweets...");
  if (client.connect("doorbell.crutzen.eu", 80)) {
  
    client.println("GET /index.php HTTP/1.1");
    client.println("Host: doorbell.crutzen.eu");
    client.println("User-Agent: Arduino/1.0");
    client.println();

    TextFinder finder(client);
    while (client.connected()) {
      if (client.available()) {
        if ( (finder.getString("", "", tweet, 140) != 0) &&
             (finder.getString("", "",   user,  140) != 0) ) {
          for (i = 0; i < 140; i++)
              if(oldTweet[i] != tweet[i])
                break;
          if (i != 140) {
            Serial.println(tweet);
            foundHashtag(user);
            for (i = 0; i < 140; i++)
              oldTweet[i] = tweet[i];
            break;
          }
        }
      }
    }
    delay(1);
    client.stop();
  }
  
}

/**********************
 * Arduino functions
 ***/

void setup() {

  pinMode(RF_SEND_PIN, OUTPUT);
  pinMode(RF_RECV_PIN, INPUT);
  
  WiFi.begin(ssid, pass);
  
  bitSet(flags, F_WAITING);         // waiting for sync
  bitClear(flags, F_SIGNAL);        // no signal found yet
  bitClear(flags, F_RIGHT_SIGNAL);  // right signal not found yet
  
  attachInterrupt(0, change, CHANGE);
  Serial.begin(9600);

  for(int i = 0; i < 140; i++) { oldTweet[i] = 0; tweet[i] = 0; } checkTwitterTime = millis(); //checkTwitter(); } void loop() { // Check Twitter if (millis() >= checkTwitterTime + 40000) {
    checkTwitter();
    checkTwitterTime = millis();   
  }
  
  // Check doorbell
  if (bitRead(flags, F_SIGNAL) == 1) {
 
    Serial.println(buffer); // print found signal
    
    if (bitRead(flags, F_RIGHT_SIGNAL) == 1) {
      Serial.println("Tweeting...");
      tweetStatus("Ding Dong - Someone at the door!");
    }
    
    bitClear(flags, F_SIGNAL);
    bitClear(flags, F_RIGHT_SIGNAL);
    buffer = 0;
    bitCount = 0;    
    bitSet(flags, F_WAITING);
 
  }
}

In conclusion

I hope that my explanations were clear enough. If not, feel free to ask!

Sources:

Share Button

2 gedachten over “How to hack a doorbell and connect it to Twitter - Part 7: Adding it all together”

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Deze website gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie-gegevens worden verwerkt.