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.
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.
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.