Internet of Things - Smoke, temperature & PIR Sensor plus Aircon cand RGB LED control with ESP8266

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:

Nice project @yahya_khaled !! Looks like you are also using IFTTT for controlling your device! Did you managed to create a dashboard showing your data?

I bought a nice enclosure today (off the shelf hanging LED light) cool shape will fit purposely for the purpose. I will post more photos once finished.
Yes, I’m mainly relying on IFTTT for the interaction simply because the App is available for iOS. I had the control (with IFTT) working before but not anymore - I will investigate this later.
I did use bucket in Thinger to log the room temperature - working fine. I also lightly used the Dashboard but I noticed an issue. the pson vector RGB has three variables R, G and B. I’m unable to set these variables individually through the dashboard.

  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
  };

Can you confirm please?

Hello Alvarold - sorry I didnt post the dashboard earlier. I also added power metering capability using RTL-SDR & Efergy. The Efergy transmits power usage every 6 seconds. These messages are captured by a software defined radio (RTL based) processed and transmitted with the help of the Linux Thing Client (C++).