WifiSmokeDetector

Wifi Smoke Detector by Nikhil Kela and Samantak Ray

Project Abstract

This project uses a combination of a dust sensor, a temperature and humidity sensor to trigger an alarm when a threshold is crossed. It also comprises of a website that displays real time sensor values, an option to remotely trigger the alarm, and a message warning the status of the alarm.

Components and Peripherals

  • Mbed LPC1768
  • Adafruit HUZZAH ESP8266 Breakout
  • DHT 11 Temperature/Humidity Sensor
  • Shinyei PPD2NS Dust Sensor
  • SparkFun microSD Transflash Breakout
  • Transcend microSD card
  • SparkFun PCB/Breadboard Mount Speaker
  • SparkFun Mono Audio Amp Breakout (TI TPA2005D1)
  • 10K Ohm Resistor
  • 5V DC Regulated External Power Supply

Connections

Mbed pin...............ESP8266 Breakout pin...........External 5V Regulated Power
p26Reset......................Reset
p9 (Tx)...........................Rx
p10 (Rx).........................Tx
n/a.................................V+...............................................+
gnd..............................gnd................................................-

Mbed Pin.................SD card breakout
p11........................................DI
p12 ......................................DO
p13.......................................SCK
p14........................................CS
gnd........................................gnd
Vout(3.3V)............................Vcc

Mbed PIn..........DHT11.......External 5V Regulated Power
gnd.........................p4...............gnd
p22..........................p2*
.................................p1...............Regulated 3.3V or 5V
*Requires pull-up resistor of 1k-10k Ohm.

Mbed pin..................Amplifier............Speaker
p18...............................In +
gnd..........................In-, pwr-
.....................................out+.......................+
.....................................out-........................-

The Shinyei dust sensor is connected to 3.3-5V regulated DC supply.

/media/uploads/nkela6/screen_shot_2016-11-07_at_10.40.40_pm.jpg Red power rail is connected to mbed Vout (3.3V DC). Blue rail is ground. The 4 wires connected at the bottom of the picture in series are all connected to 5V DC. The Shinyei dust sensor is not connected in this demonstration.

Website and Operation

First the wifi SSID and password need to be hard coded. After downloading the program and running it on mbed open a serial monitor to view the IP address displayed at the end. Copy this IP address to your browser to view the website. (Note: The mbed and the device need to be on the same network).The temperature and humidity are continuously polled by the mbed program. When these numbers pass a hard coded threshold the alarm is triggered. The website has a capability to control the alarm remotely as well as to flip an LED for debugging purposes. It displays the temperature and humidity data and an alarm status message. When the alarm is sounded, it displays a 'Smoke' warning. The program does not update information automatically. There is a refresh button to push and/or pull any data to the website. There is a slight delay until the change is reflected on both the hardware and the website side.

/media/uploads/nkela6/screen_shot_2016-11-07_at_4.24.08_pm.jpg

Code

<< code main.cpp>>

//  Mbed ESP8266 Wifi enabled smoke detector and controller
// Created by Nikhil Kela and Samantak Ray
// ECE 4180: Lab 4
// Georgia Institute of Technology

#include "mbed.h"
#include "wave_player.h"
#include "SDFileSystem.h"
#include "DHT11.h" // Created by  Shigenori Inoue (there are multiple libraries with the same name)

Serial pc(USBTX, USBRX);// for serial monitor on PC
Serial esp(p9, p10); // tx, rx

AnalogOut DACout(p18); // Analog output for amplifier
wave_player waver(&DACout);

SDFileSystem sd(p11, p12, p13, p14, "sd"); //SD card

DHT11 d(p22);


// Standard Mbed LED definitions
DigitalOut  led1(LED1);
DigitalOut  led2(LED2);
DigitalOut  led3(LED3);
DigitalOut  led4(LED4);

//AnalogIn   Ain2(p19);//Dust




char ssid[32] = "WIFI SSID";     // enter WiFi router ssid inside the quotes
char pwd [32] = "PASSWORD"; // enter WiFi router password inside the quotes

float temperature, tempC, HDTY;
char Ht;
float R1=100000, R2=10000; // resistor values to give a 10:1 reduction of measured AnalogIn voltage
char Vcc[10];
char Temp[10];


// things for sending/receiving data over serial
volatile int tx_in=0;
volatile int tx_out=0;
volatile int rx_in=0;
volatile int rx_out=0;
const int buffer_size = 4095;
char tx_buffer[buffer_size+1];
char rx_buffer[buffer_size+1];
void Tx_interrupt();
void Rx_interrupt();
void send_line();
void read_line();

int DataRX;
int update;
int astate = 1;//NEW NEW
int count;
char cmdbuff[1024];
char replybuff[4096];
char webdata[4096]; // This may need to be bigger depending on WEB browser used
char webbuff[4096];     // Currently using 1986 characters, Increase this if more web page data added
char timebuf[30];
void SendCMD(),getreply(),ReadWebData(),startserver();
void gettime(),setRTC(),gettemp(),getHumidity(),SDsound();
char rx_line[1024];
int port        =80;  // set server port
int SERVtimeout =5;    // set server timeout in seconds in case link breaks.
struct tm t;
// manual set RTC values
int minute      =00;    // 0-59
int hour        =12;    // 2-23
int dayofmonth  =26;    // 1-31
int month       =8;     // 1-12
int year        =15;    // last 2 digits

void SDsound()
{      if(astate) {       
        FILE *wave_file;
        wave_file=fopen("/sd/alarm.wav","r"); // change name of sound file and location. 16kHz, 16bit encoding.
        waver.play(wave_file);
        fclose(wave_file); 
        void exit();
  }

}

int main()
{
    pc.baud(9600);
    esp.baud(9600);
    led1=1,led2=0,led3=0, led4=0;
    // Setup a serial interrupt function to receive data
    esp.attach(&Rx_interrupt, Serial::RxIrq);
    // Setup a serial interrupt function to transmit data
    esp.attach(&Tx_interrupt, Serial::TxIrq);
    if (time(NULL) < 1420070400) {
        setRTC();
    }
    startserver();
    DataRX=0;
    count=0;
    while(1) {
        if(DataRX==1) {
            ReadWebData();
            esp.attach(&Rx_interrupt, Serial::RxIrq);
        }
        if(update==1) // update time, hit count, and analog levels in the HUZZAH chip
        {
            // get new values
            gettime();
            HDTY = d.readHumidity();
             tempC=d.readTemperature();
        if(tempC >=22){ // state all conditions for alarm trigger here
                astate=1;
                SDsound();
            sprintf(Vcc,"Smoke!");
         }
        else {
            sprintf(Vcc,"Normal");   
         }
            
            count++;
            // send new values
            sprintf(cmdbuff, "count,time,analog1,analog2=%d,\"%s\",\"%s\",\"%s\"\r\n",count,timebuf,Temp,Vcc);
            SendCMD();
            getreply();
            update=0;   
        }
    }
}


// Reads and processes GET and POST web data
void ReadWebData()
{
    wait_ms(150);
    esp.attach(NULL,Serial::RxIrq);
    DataRX=0;
    memset(webdata, '\0', sizeof(webdata));
    strcpy(webdata, rx_buffer);
    memset(rx_buffer, '\0', sizeof(rx_buffer));
    rx_in = 0;
    rx_out = 0;
    // check web data for form information
    if( strstr(webdata, "check=led1v") != NULL ) {
        //led4=!led4;
        astate=1;
        SDsound();
        led4=!led4;
        wait(5);
        led4=1;led3=1;
        wait(5);
        led4=0;led3=0;
        wait(5);
        led4=1;led3=1;
        wait(5);
    }
    
    if( strstr(webdata, "check=led2v") != NULL ) {
        led2 = !led2;
        astate=0;
    }
   if( strstr(webdata, "check=led3v") != NULL ) {
        led3=!led3;
    }

    
    if( strstr(webdata, "POST") != NULL ) { // set update flag if POST request
        update=1;
    }
    if( strstr(webdata, "GET") != NULL && strstr(webdata, "favicon") == NULL ) { // set update flag for GET request but do not want to update for favicon requests
        update=1;
    }
}
// Starts webserver
void startserver()
{
    gettime();
    gettemp();
    getHumidity();
    pc.printf("++++++++++ Resetting ESP ++++++++++\r\n");
    strcpy(cmdbuff,"node.restart()\r\n");
    SendCMD();
    wait(2);
    getreply();
    
    pc.printf("\n++++++++++ Starting Server ++++++++++\r\n> ");

    // initial values
    sprintf(cmdbuff, "count,time,analog1,analog2=0,\"%s\",\"%s\",\"%s\"\r\n",timebuf,Temp,Vcc);
    SendCMD();
    getreply();
    wait(0.5);

    //create server
    sprintf(cmdbuff, "srv=net.createServer(net.TCP,%d)\r\n",SERVtimeout);
    SendCMD();
    getreply();
    wait(0.5);
    strcpy(cmdbuff,"srv:listen(80,function(conn)\r\n");
    SendCMD();
    getreply();
    wait(0.3);
        strcpy(cmdbuff,"conn:on(\"receive\",function(conn,payload) \r\n");
        SendCMD();
        getreply();
        wait(0.3);
        
        //print data to mbed
        strcpy(cmdbuff,"print(payload)\r\n");
        SendCMD();
        getreply();
        wait(0.2);
       
        //web page data
        strcpy(cmdbuff,"conn:send('<!DOCTYPE html><html><body><h1>ECE 4180 - Mbed Smoke Detector Web Controller</h1>')\r\n");
        SendCMD();
        getreply();
        wait(0.4);
        strcpy(cmdbuff,"conn:send('Refresh count: '..count..'')\r\n");
        SendCMD();
        getreply();
        wait(0.2);
        strcpy(cmdbuff,"conn:send('<br>Last hit (based on mbed RTC time): '..time..'<br><hr>')\r\n");
        SendCMD();
        getreply();
        wait(0.4);
        strcpy(cmdbuff,"conn:send('Humidity: '..analog1..' <br>Status: '..analog2..' <br><hr>')\r\n");
        SendCMD();
        getreply();
        wait(0.3);
        strcpy(cmdbuff,"conn:send('<form method=\"POST\"')\r\n");
        SendCMD();
        getreply();
        wait(0.3);
        strcpy(cmdbuff, "conn:send('<p><input type=\"checkbox\" name=\"check\" value=\"led1v\"> Sound Alarm')\r\n");
        SendCMD();
        getreply();
        wait(0.3);
        strcpy(cmdbuff, "conn:send('<p><input type=\"checkbox\" name=\"check\" value=\"led2v\"> Stop Alarm')\r\n");
        SendCMD();
        getreply();
        wait(0.3);
        strcpy(cmdbuff, "conn:send('<p><input type=\"checkbox\" name=\"check\" value=\"led3v\"> flip LED3')\r\n");
        SendCMD();
        getreply();
        wait(0.3);
        strcpy(cmdbuff,"conn:send('<p><input type=\"submit\" value=\"send-refresh\"></form>')\r\n");
        SendCMD();
        getreply();
        wait(0.3);
        strcpy(cmdbuff, "conn:send('<p><h2>How to use:</h2><ul><li>Select a checkbox to flip on/off</li><li>Click Send-Refresh to send data and refresh values</li></ul></body></html>')\r\n");
        SendCMD();
        getreply();
        wait(0.5); 
        // end web page data
        strcpy(cmdbuff, "conn:on(\"sent\",function(conn) conn:close() end)\r\n"); // close current connection
        SendCMD();
        getreply();
        wait(0.3);
        strcpy(cmdbuff, "end)\r\n");
        SendCMD();
        getreply();
        wait(0.2);
    strcpy(cmdbuff, "end)\r\n");
    SendCMD();
    getreply();
    wait(0.2);

    strcpy(cmdbuff, "tmr.alarm(0, 1000, 1, function()\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    strcpy(cmdbuff, "if wifi.sta.getip() == nil then\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    strcpy(cmdbuff, "print(\"Connecting to AP...\\n\")\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    strcpy(cmdbuff, "else\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    strcpy(cmdbuff, "ip, nm, gw=wifi.sta.getip()\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    strcpy(cmdbuff,"print(\"IP Address: \",ip)\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    strcpy(cmdbuff,"tmr.stop(0)\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    strcpy(cmdbuff,"end\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    strcpy(cmdbuff,"end)\r\n");
    SendCMD();
    getreply();
    wait(0.2);
    
    pc.printf("\n\n++++++++++ Ready ++++++++++\r\n\n");
}


// ESP Command data send
void SendCMD()
{
    int i;
    char temp_char;
    bool empty;
    i = 0;
// Start Critical Section - don't interrupt while changing global buffer variables
    NVIC_DisableIRQ(UART1_IRQn);
    empty = (tx_in == tx_out);
    while ((i==0) || (cmdbuff[i-1] != '\n')) {
// Wait if buffer full
        if (((tx_in + 1) % buffer_size) == tx_out) {
// End Critical Section - need to let interrupt routine empty buffer by sending
            NVIC_EnableIRQ(UART1_IRQn);
            while (((tx_in + 1) % buffer_size) == tx_out) {
            }
// Start Critical Section - don't interrupt while changing global buffer variables
            NVIC_DisableIRQ(UART1_IRQn);
        }
        tx_buffer[tx_in] = cmdbuff[i];
        i++;
        tx_in = (tx_in + 1) % buffer_size;
    }
    if (esp.writeable() && (empty)) {
        temp_char = tx_buffer[tx_out];
        tx_out = (tx_out + 1) % buffer_size;
// Send first character to start tx interrupts, if stopped
        esp.putc(temp_char);
    }
// End Critical Section
    NVIC_EnableIRQ(UART1_IRQn);
    return;
}

// Get Command and ESP status replies
void getreply()
{
    read_line();
    sscanf(rx_line,replybuff);
}
 
// Read a line from the large rx buffer from rx interrupt routine
void read_line() {
    int i;
    i = 0;
// Start Critical Section - don't interrupt while changing global buffer variables
    NVIC_DisableIRQ(UART1_IRQn);
// Loop reading rx buffer characters until end of line character
    while ((i==0) || (rx_line[i-1] != '\r')) {
// Wait if buffer empty
        if (rx_in == rx_out) {
// End Critical Section - need to allow rx interrupt to get new characters for buffer
            NVIC_EnableIRQ(UART1_IRQn);
            while (rx_in == rx_out) {
            }
// Start Critical Section - don't interrupt while changing global buffer variables
            NVIC_DisableIRQ(UART1_IRQn);
        }
        rx_line[i] = rx_buffer[rx_out];
        i++;
        rx_out = (rx_out + 1) % buffer_size;
    }
// End Critical Section
    NVIC_EnableIRQ(UART1_IRQn);
    rx_line[i-1] = 0;
    return;
}
 
 
// Interupt Routine to read in data from serial port
void Rx_interrupt() {
    DataRX=1;
    //led3=1;
// Loop just in case more than one character is in UART's receive FIFO buffer
// Stop if buffer full
    while ((esp.readable()) && (((rx_in + 1) % buffer_size) != rx_out)) {
        rx_buffer[rx_in] = esp.getc();
// Uncomment to Echo to USB serial to watch data flow
        pc.putc(rx_buffer[rx_in]);
        rx_in = (rx_in + 1) % buffer_size;
    }
    //led3=0;
    return;
}
 
 
// Interupt Routine to write out data to serial port
void Tx_interrupt() {
    //led2=1;
// Loop to fill more than one character in UART's transmit FIFO buffer
// Stop if buffer empty
    while ((esp.writeable()) && (tx_in != tx_out)) {
        esp.putc(tx_buffer[tx_out]);
        tx_out = (tx_out + 1) % buffer_size;
    }
    //led2=0;
    return;
}

void gettime()
{
    time_t seconds = time(NULL);
    strftime(timebuf,50,"%H:%M:%S %a %d %b %y", localtime(&seconds));
}

void setRTC()
{
    t.tm_sec = (0);             // 0-59
    t.tm_min = (minute);        // 0-59
    t.tm_hour = (hour);         // 0-23
    t.tm_mday = (dayofmonth);   // 1-31
    t.tm_mon = (month-1);       // 0-11  "0" = Jan, -1 added for Mbed RCT clock format
    t.tm_year = ((year)+100);   // year since 1900,  current DCF year + 100 + 1900 = correct year
    set_time(mktime(&t));       // set RTC clock
}

void getHumidity()   
{
    int s;  
    int err=01;
    wait_ms(2000);
    Ht = d.readHumidity();
    s = d.readData();
    if (s != DHT11::OK) {
        sprintf(Temp,"%2.3f",err);
    }
    else {
       sprintf(Temp,"%d",Ht);
    }

}
 

void gettemp()
{
    int s;  
    int err=01;
    wait_ms(2000);
    Ht = d.readTemperature();
    s = d.readData();
    if (s != DHT11::OK) {
        sprintf(Temp,"%2.3f",err);
    }
    else {
       sprintf(Temp,"%d",Ht);
    }

}

Video Demonstration

Flips LED3 first to test. Then DHT11 records temperature above threshold and triggers the alarm.


Please log in to post comments.