Alarm with Push Notification

In this example the Arduino compatible Wi-Fi board TOP03  is used to build a simple antitheft station using a PIR module to detect a movement.

When the movement is detected, is possible to comand a lamp (in the example is a white LED) and an active piezo buzzer.
Moreover, the Arduino can be set to send a PUSH notification to all the mobile devices in which that miuPanel module is registered. The push notifications will be received in real time even when the app is closed.

The time and date are syncronized automatically with the smarphone: a specific panel command permit to Arduino to ask this info directly to smartphone.

Of course, you can use a different detection module (like a magnetic door sensor, a tilt sensor…).
With little changes in the sketch, you could use a ARDUINO UNO with SCF-01 module instead of TOP03.

Concept of detection station

Hardware

  • TOP03 Arduino Compatible Wi-Fi Board
  • Power supply (for example a 5V smartphone charger with micro-USB jack)
  • PIR Module (detection sensor)
  • Active piezo Buzzer (3-5V,  max 25 mA)
  • n.2 LED and n.2 Resistors (>= 150 ohm)
  • wires for connections
Supply the TOP03 Board from its usb connector OR the RAW pin (5 Volt)

µPanel definition 

Using the Online Panel Simulator you can easily design and check the panel layout before loading it on Arduino.

 

Dw!FFF;-0{%100,y6!062Tf*15d2:µPanel Alarm;}{~1^%100,y25!9E6#333{%50,y60M1*40fb:00:00;_M2*15:12/05/2015;}|{%35,y60T*12fb:Last Alarm:;_M3*15:-;_M4*15:-;}}{%100,y2!FFF}{%100,y0.1!FFF}{^t%100,y66!DDD#333{%90,y5}{m<%90T*15:LAMP;|>W0F:0;}{%90,y5}{m<%90T*15:ALARM;|>W1F:0;}{%90,y5}{m<%90T*15:Notification;|~2>o20W2F:0;}{%90,y5}{m<%90T*15:Buzzer;|~3>o20W3F:0;}{%90,y5}={m%90,y20B1!AAA%22,15r10-20^fb:TEST PUSH;|B2!AAA%22,15r10-20^fb:SYNC TIME;|B3!AAA%22,15r10-20^fb:TEST BUZZER;}{m<%90T*15:Lamp: ;M5*15:10;T*15:s;|%60R1:0:60:1:10:100;}}

Single Panel layout

Arduino will change dinamically the style “opacity” of the two switch “notification” and “buzzer” depending if the alarm is set. Moreover, arduino will change the color of the green container dinamically when the alarm is detected. To do this, the “panel commands” object have been used.  

 

TOP03 code (Arduino Lilypad USB)

To build in Arduino IDE this project, you have to install the Time.zip library. This library is compatible also for the precise external DS1307 real time clock chip. In this example, we use the internal clock of Arduino (less precise). See the details of the library here:  http://playground.arduino.cc/Code/Time

You can find both library and complete sketch for TOP03 in the following zipped folder:

IMPORTANT: before loading your sketch, please select the board “LilyPad Arduino USB” in the boards menu.
If you have accidentally selected another board, and already tried loading your sketch, read here: 
www.arduino.cc/en/Guide/ArduinoLilyPadUSB

Arduino Code

/**************************************************

 Used Time Library to calculate data and time:  http://playground.arduino.cc/Code/Time
 
 --- IMPORTANT ---: before to load your sketch, please select the board "LilyPad Arduino USB" in the boards menu.
 If you have accidentally select another board, and load your sketch, read here:
 www.arduino.cc/en/Guide/ArduinoLilyPadUSB
  
 Connection table:
 
 * ESP8266  Cactus Micro Rev2
 * GPIO0    12
 * ENABLE   13
 * RX       TX
 * TX       RX
 * GND      GND
 

 About Serial
 The "Lilypad USB" (and the board derived from it) use "Serial1" to communicate via TTL serial on pins 0 (RX) and 1 (TX). 
 "Serial" is reserved for USB CDC communication.

 ***************************************************/

#include <Time.h>

#define ESP_PROGRAM_PIN  12
#define ESP_ENABLE_PIN  13
#define LAMP_PIN 21
#define BUZZER_PIN 20
#define PUSH_PERIOD_MS 30000 // min allowed interval [ms] between two push 

unsigned char lamp_set = 0;
unsigned char alarm_set = 0;
unsigned char push_set = 0;
unsigned char buzzer_set = 0;
unsigned char clock_sync = 0;
unsigned char flag_alarm = 0;

unsigned int lamp_timer_ms = 10; // timer in seconds
unsigned int counter_test_push = 1;
unsigned long LastPush_Time = 0x0FFFFFFF; 
unsigned long TriggerAlarm_Time = 0;
unsigned long CurrentTime =0;

unsigned char hours;
unsigned char minutes;
unsigned char seconds;
unsigned char days;
unsigned char months;
unsigned int years;

String Msg;

time_t rtc_time = 0;
time_t old_rtc_time = 0;


void setup() {

  Serial1.begin(57600);        // Initialise serial 1 (WiFi Module)
   
  pinMode(ESP_ENABLE_PIN, OUTPUT);
  pinMode(ESP_PROGRAM_PIN, OUTPUT);
  pinMode(LAMP_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  
  // Set ESP module in RUN mode on reset 
  digitalWrite(ESP_PROGRAM_PIN, HIGH);  
  digitalWrite(ESP_ENABLE_PIN, HIGH);

  delay(5000);                 // Let's the module start
  
  // Discharge old partial messages
  Serial1.println("");
  
  // Send Panel discharging old partial messages  
  SendPanel();

  // Interrupt on PIN 7 (will be called the function "IsrAlarm()" )
  attachInterrupt(digitalPinToInterrupt(7), IsrAlarm, RISING); 
}


void loop() {
  
  int c;
  while ((c = Serial1.read()) > '\n') Msg += (char) c;  // Read incoming chars, if any, until new line
  
  if (c == '\n')  // is message complete?
  { 
    // has the slider been moved? 
    if (Msg.substring(0,4).equals("#R1:") || Msg.substring(0,4).equals("#r1:")){                  
        lamp_timer_ms = (int) Msg.substring(4).toInt();              // Read 
        Serial1.print("#M5"); Serial1.println(lamp_timer_ms, DEC);   // Update message   
    }   
    else if (Msg.substring(0,4).equals("#W01")){ // Enable LAMP
      lamp_set = 1;
    }
    else if (Msg.substring(0,4).equals("#W00")){  // Disable LAMP
     lamp_set = 0;
    }    
    else if (Msg.substring(0,4).equals("#W11")){ // Enable ALARM
      alarm_set = 1;
      Serial1.println("#C3:s~2:z1d0");
      Serial1.println("#C4:s~3:z1d0");
    }
    else if (Msg.substring(0,4).equals("#W10")){  // Disable ALARM
      alarm_set = 0;
      Serial1.println("#C4:s~2:z-1d0");
      Serial1.println("#C5:s~3:z-1d0");  
      digitalWrite(BUZZER_PIN, LOW);  // Secure quite buzzer 
    }   
    else if (Msg.substring(0,4).equals("#W21")){  // Enable PUSH
      push_set = 1;
    }
    else if (Msg.substring(0,4).equals("#W20")){  // Disable PUSH   
      push_set = 0;
    }
    else if (Msg.substring(0,4).equals("#W31")){  // Enable BUZZER
      buzzer_set = 1;
    }
    else if (Msg.substring(0,4).equals("#W30")){  // Disable BUZZER
      buzzer_set = 0;
      digitalWrite(BUZZER_PIN, LOW);  // Secure quite buzzer 
    }    
    else if (Msg.substring(0,4).equals("#B1P"))   // TEST PUSH
    {
       Serial1.print("$CLOUD SEND:PUSH: Test Push n."); 
       Serial1.println(counter_test_push, DEC);
       counter_test_push ++;
    }
    else if (Msg.substring(0,4).equals("#B2P")) // SYNC TIME
    {
      // "ask date and time to smartphone" (using the virtual object "panel command")
      Serial1.println("#C9:S:_da(1);;"); 
    }
    else if (Msg.substring(0,4).equals("#B3P")) // TEST BUZZER
    {
      digitalWrite(BUZZER_PIN, HIGH);
      delay (2000);
      digitalWrite(BUZZER_PIN, LOW);  
    }
    else if (Msg.substring(0,7).equals("#:DATE:"))
    {
      // the entire message received has the form: 
      // #:DATE:1453635745818:2016:01:24:12:42:25:818
      // where the fields are: Java Time, year, month, day, hour, minute, second, millisecond 
    
      years = Msg.substring(21,25).toInt();
      months = Msg.substring(26,28).toInt();
      days = Msg.substring(29,31).toInt();
      hours = Msg.substring(32,34).toInt();
      minutes = Msg.substring(35,37).toInt();
      seconds = Msg.substring(38,40).toInt();
      
      setTime(hours, minutes, seconds, days, months, years); // Method of library "Time"
      
      old_rtc_time = now(); // Reads the current time, as a time_t number. 
      clock_sync = 1;  
      DisplayClock();
    }
    else if (Msg.equals("$RES")){ // WiFi Module unwanted RESET >>>>>>> send panel again
      SendPanel();
    }  
    
    Msg = ""; // Clean message string
  } 

  // check in polling
  
  if (flag_alarm == 1) // During a detected alarm
  {
     // Switch off alarm
     if (millis() - TriggerAlarm_Time >= (unsigned long)(lamp_timer_ms *1000)) {  
       flag_alarm = 0;
       Serial1.println("#C3:s~1:!9E6");
       digitalWrite(LAMP_PIN, LOW);
       digitalWrite(BUZZER_PIN, LOW);     
     }
  }
  CheckClock();
}

// ----------------------------------------------------------------

// Interrupt Service Routine function (called when PIR detected an alarm)

void IsrAlarm (void){
  
  if (flag_alarm == 0){ // NOT Retriggering Mode 
    TriggerAlarm_Time = millis();
    flag_alarm = 1;
    
    if (alarm_set == 1){
      Serial1.println("#C3:s~1:!F55");
      DisplayAlarm();  
      
      if (buzzer_set == 1) 
        digitalWrite(BUZZER_PIN, HIGH);   
      
      if (push_set == 1) 
      {                   
        CurrentTime = millis();

        if (CurrentTime - LastPush_Time >= (unsigned long)PUSH_PERIOD_MS ){

          Serial1.println("$CLOUD SEND:PUSH: ALARM Detected!");
          LastPush_Time = CurrentTime; // save sending instant    
        }  
      }
    }
    if (lamp_set == 1) 
      digitalWrite(LAMP_PIN, HIGH);
  }
}

//----------------------------------------------------------------


void CheckClock(void){
  
    rtc_time = now(); // Store the current time in time 
      
    if ( rtc_time - old_rtc_time >= 60)   // Sync each 60 seconds
    { 
      old_rtc_time = rtc_time;
          
      years = year(rtc_time);
      months = month (rtc_time);
      days = day(rtc_time);
      hours = hour(rtc_time);
      minutes = minute(rtc_time);
      seconds = second(rtc_time);
     
      DisplayClock();
    }
}

//-------------------------------------------------------------


 void DisplayClock(void)
 {
    if (clock_sync == 1)
    {
     Serial1.print("#M1");
     if (hours < 10) Serial1.print('0'); 
     Serial1.print(String(hours) + ":");
     if (minutes < 10) Serial1.print('0'); 
     Serial1.println(String(minutes));

     Serial1.print("#M2");
     if (days < 10) Serial1.print('0'); 
     Serial1.print(String(days) + "/");
     if (months < 10) Serial1.print('0'); 
     Serial1.print(String(months) + "/");
     Serial1.println(String(years));
    }
    else
    {
     Serial1.println("#M1--:--"); 
     Serial1.println("#M2--/--/--");   
     }
 }

//-----------------------------------------------------------


 void DisplayAlarm(void)
 {
     if (clock_sync == 1)
    {
     Serial1.print("#M3");
     if (hours < 10) Serial1.print('0'); 
     Serial1.print(String(hours) + ":");
     if (minutes < 10) Serial1.print('0'); 
     Serial1.println(String(minutes));

     Serial1.print("#M4");
     if (days < 10) Serial1.print('0'); 
     Serial1.print(String(days) + "/");
     if (months < 10) Serial1.print('0'); 
     Serial1.print(String(months) + "/");
     Serial1.println(String(years));
    }
    else
    {
      Serial1.println("#M3Alarm detected!");
      Serial1.println("#M4Time not available");
    }
 }

//--------------------------------------------------------


void SendPanel(void)
{
  Serial1.println("\n$P:Dw!FFF;-0{%100,y6!062Tf*15d2:µPanel Alarm;}{~1^%100,y25!9E6#333{%50,y60M1*40fb:--:--;_M2*15:--/--/----;}|{%35,y60T*12fb:Last Alarm:;_M3*15:-;_M4*15:-;}}{%100,y2!FFF}{%100,y0.1!FFF}{^t%100,y66!DDD#333{%90,y5}{m<%90T*15:LAMP;|>W0F:0;}{%90,y5}{m<%90T*15:ALARM;|>W1F:0;}{%90,y5}{m<%90T*15:Notification;|z-1d0~2>W2F:0;}{%90,y5}{m<%90T*15:Buzzer;|z-1d0~3>W3F:0;}{%90,y5}=S1!AAA%32,10^fb;{m%95,y20B1s1:TEST PUSH;|B2s1:SYNC TIME;|B3s1:TEST BUZZER;}{m<%90T*15:Lamp: ;M5*15:10;T*15:s;|%60R1:0:60:1:10:100;}}");

  // Check the status of all the panel objects (useful in case of unwanted RESET of the wifi module only)
  
  if (lamp_set == 1) Serial1.println("#W01");
  if (push_set == 1) Serial1.println("#W21"); 
  if (buzzer_set == 1) Serial1.println("#W31"); 
  if (alarm_set == 1){
      Serial1.println("#W11");
      Serial1.println("#C3:s~2:z1d0");
      Serial1.println("#C4:s~3:z1d0");
  }
  Serial1.print("#M5"); Serial1.println(lamp_timer_ms, DEC);  // Update message
  DisplayClock(); // Display time
}