I would like to share with the public my small IoT project using ESP8266.
Project components:
1- ESP8266MOD (Wemos mini D1 breakout - $4)
2- Spare commercial Smoke alarm - please dont use existing one($15)
3- TMP102 temperature sensor (I2C - 3$)
4- RGB LED ($3)
5- IR transmitter
6- PIR sensor
7- Optocoupler for interfacing the smoke alarm to ESP8266
8- Smart phone with IFTTT installed
Libraries:
1- RGBLED
2- ESP8266WiFi & ThingerWifi
3- WIRE
4- IRremoteESP8266
For internet notification - I used IFTT maker.
For Smoke alarm interface I ended up measuring the low-pulse duration using interrupt connected to opto-coupler which is also connected to the smoke sensor LED pins.
Code:
/*ESP8266-MOD + PIR Motion sensor + TM102 temperature sensor + RGB LED + IR transmitter + Thinger support */
/*Version: 1.0 */
/*Wiring
* GYTMP102<-> D1 mini i2c via Wire library
* 3v3<->3v3
* GND<->G
* SCL<->D1
* SDA<->D2
* ALERT<->D7
* IR<->D7
* SMOKE SENSOR <-> D4 (2)
*/
#define _DEBUG_
#include <rgbled.h>
#include <ESP8266WiFi.h>
#include <ThingerWifi.h>
#include <Wire.h>
#include <IRremoteESP8266.h>
//#include <ThingerSmartConfig.h>
#define USERNAME "----"
#define DEVICE_ID "----"
#define DEVICE_CREDENTIAL "-----"
#define SSID "-----"
#define SSID_PASSWORD "-------"
int MOTION_SENSOR = 13; //D7
int SMOKE_ALARM_SENSOR = 2; // Need to find free port
const int IR_PIN = 15; //GPIO15 = D8
int tmp102Address = 0x48;
bool NOTIFICATION = HIGH; // "HIGH" the handle will call endpoint and hence notify user. In the future initialize from cloud
bool MOTION_DETECTED = false;
bool SMOKE_DETECTED = false;
int SMOKE_ALARM_PULSES = 0;
unsigned long LAST_TIME = 0;
unsigned long AVG_PULSE = 0;
bool SWITCH = LOW;
const int red_led_pin = 12;
const int g_led_pin = 14;
const int blue_led_pin = 16;
int redStrength = 0;
int greenStrength = 0;
int blueStrength = 0;
ThingerWifi thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);
//ThingerSmartConfig thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);
void pinChanged() {
MOTION_DETECTED = true;
}
void smokeSensorPinChanged() {
detachInterrupt(SMOKE_ALARM_SENSOR); // Avoid recursive interrupts
unsigned long time_lapse = millis() - LAST_TIME;
LAST_TIME = millis();
Serial.print("Pulse duration: ");
Serial.println(time_lapse);
if (time_lapse > 900 && time_lapse < 1500 ) { // 1016 is optimum time
SMOKE_DETECTED = true;
}
attachInterrupt(SMOKE_ALARM_SENSOR, smokeSensorPinChanged, FALLING);
}
float getTemperature(){
Wire.requestFrom(tmp102Address,2);
byte MSB = Wire.read();
byte LSB = Wire.read();
//it's a 12bit int, using two's compliment for negative
int TemperatureSum = ((MSB << 8) | LSB) >> 4;
float celsius = TemperatureSum*0.0625;
return celsius;
}
IRsend irsend(IR_PIN);
unsigned int rawCodes[] = {8996,4480,644,1652,644,556,644,556,640,1656,640,560,644,1652,640,1656,640,560,668,532,668,532,664,540,640,560,640,560,640,536,664,564,612,588,612,588,616,588,612,588,612,560,640,588,612,1684,620,1676,648,552,672,528,676,524,648,556,648,552,648,1648,648,552,648,1648,648,552,648,552,648,1648,648,552,648,19928,676,1648,644,556,644,556,648,552,648,556,644,556,648,552,648,552,648,556,648,552,648,552,648,552,648,552,652,1644,648,552,648,556,648,552,648,552,648,556,644,556,648,552,644,556,648,552,648,556,644,556,648,552,648,552,648,556,648,1644,648,556,644,1648,652,552,648};
int code = 0;
//sizeof(rawCodes)/sizeof(int)
RGBLED led(red_led_pin, g_led_pin, blue_led_pin);
void setup() {
// Quick demo mode: cycle between red, green, blue, white, off.
led.colorIs(255, 0, 0); // red
delay(1000); // 1 second
led.colorIs(0, 255, 0); // green
delay(1000);
led.colorIs(0, 0, 255); // blue
delay(1000);
led.colorIs(255, 255, 255); // white
delay(1000);
led.colorIs(0, 0, 0); // off
Serial.begin(115200);
Wire.begin();
irsend.begin();
delay(200);
pinMode(MOTION_SENSOR, INPUT);
pinMode(SMOKE_ALARM_SENSOR, INPUT);
attachInterrupt(MOTION_SENSOR, pinChanged, RISING);
attachInterrupt(SMOKE_ALARM_SENSOR, smokeSensorPinChanged, FALLING);
thing.add_wifi(SSID, SSID_PASSWORD);
thing["NOTIFICATION"] << inputValue(NOTIFICATION,{
/* here you could even attach/detach the interruption based on the updated NOTIFICATION
value, turn off the PIR sensor, etc., but it is not really necessary */
if (!NOTIFICATION) {
detachInterrupt(MOTION_SENSOR);
}
else {
attachInterrupt(MOTION_SENSOR, pinChanged, RISING);
}
});
thing["TEMPERATURE"] >> [](pson& out){
out = getTemperature();
};
thing["AC"] << inputValue(SWITCH,{
/* here you could even attach/detach the interruption based on the updated NOTIFICATION
value, turn off the PIR sensor, etc., but it is not really necessary */
if (!SWITCH) {
Serial.println("Siwtch off");
}
else {
Serial.println("Siwtch on");
irsend.sendRaw(rawCodes, 139, 38);
}
});
thing["RGB"] << [](pson& in){
if(in.is_empty())
{
in["R"] = redStrength;
in["G"] = greenStrength;
in["B"] = blueStrength;
}
led.colorIs(in["R"],in["G"],in["B"]); // 0-255
};
thing["ANALOGUE"] >> [](pson & out){
out = (unsigned int) analogRead(A0);
};
LAST_TIME = millis();
}
void loop() {
thing.handle();
if(MOTION_DETECTED & NOTIFICATION){
thing.call_endpoint("MOTION_SENSOR");
led.colorIs(255, 0, 255); // red+Blue
Serial.println("Motion detected.");
delay(1000); // 1 second
led.colorIs(redStrength, greenStrength, blueStrength);
MOTION_DETECTED = false;
}
if(SMOKE_DETECTED & NOTIFICATION){
detachInterrupt(SMOKE_ALARM_SENSOR); // Avoid recursive interrupts
Serial.println("Smoke detected.");
thing.call_endpoint("SMOKE_DETECTED");
redStrength = 255;
greenStrength = 0;
blueStrength = 0;
led.colorIs(redStrength, greenStrength, blueStrength); // red
SMOKE_DETECTED = false;
attachInterrupt(SMOKE_ALARM_SENSOR, smokeSensorPinChanged, FALLING);
}
}
API by Thinger:
Smoke sensor with Optocoupler integrated (Vcc, Ground, Interrupt)
Entire system (bit messy for now)
Device token created under the device with Thinger:
IFTTT applets:
Smoke alarm applet configuration: