8 Nodes/1 Base house surveillance with Nano and ESP8266

House sensors by Markus Rohner 11.2015
Have the house observed and controlled by Arduino Nanos with ESP8266 as
WiFi shield and multiple sensors and relays (referenced as Sensor 1-11)

  • Same program for all nodes and Master node
  • Digital and Analog Pins are used the same way for all nodes
  • Virtual Pins for Blynk are shared amongst all nodes and master through Bridge Widget
  • In Vacation mode lights are switched on and off automatically
    beeing derived from actual light levels and a random number of
    minutes until lights are switched off again.
  • Arduino nodes and master must have loaded parameters into EEPROM such as
    id, sensors and auth tokens. See separate program.
  • The IRREmote library to control TV etc. could not be implemented successfully
    It seems to be incompatible with Blynk or just uses more memory to influence
    connection with Blynk server.
  • A soft reset function was implemented if it all hangs.
  • A small PCB board was developped for all nodes. (see separate File)
    including a 3.3V Power supply for the ESP8266.
  • Notifies my iPhone when Alarm (Water, Fire, Door, CO2 and movements)

Arduino Pins:
D0: (RX) ESP8266 TX
D1: (TX) ESP8266 RX 3.3V!
D2: PIR (Sensor 1)
D3: IR transmitter (Sensor 11)
D4: Relays1 default LOW e.g. Coffee machine, TV (Sensor 9)
D5: SO High temp (Sensor 6)
D6: SCK High temp (Sensor 6)
D7: CS High temp (Sensor 6)
D8: Relays 2 / MOC3021 vacation lights default HIGH (Sensor 2)
D9: Vacation Pin (only used for master)
D10: Master Slide for reset
D11: Master Switch for reset
D12:
D13:Switch input i.e Garage door (Sensor 3)
A0: Light measurement (Sensor 8)
D15 (A1):
(D16) A2: floating when Lightsensor installed used for Random number generator
(D17) A3: Availability bin
D18 (A4): DHT11 (Sensor 4)
(D19) A5: Water/Rain measurement (Sensor 7)
A6: CO2 measurement MQ-7 (Sensor 5)
A7: Flame sensor (Sensor 10)
RST:To Reset button
GND:Ground
5V: Power supply 5V

Blynk shared virtual ports
V0:Temp Bedroom
V1-V8: LEDs Up
V9:LED Relays2 Office
V10:LED Relays Bed
V11-V18:Alarms
V19:LED Relays2 Living
V20:LED Relays2 Dining
V21:vacation LED
V22:Humidity Bedroom
V23:Garage door push button
V24:LED Relays2 Garage
V25:Thermo Heating
V26:Temp Living
V27:Humidity Living
V28:Temp Office
V29:Humidity Office
V30: Bridge to Base
V31: Up Base

//#define BLYNK_DEBUG
#include <SoftwareSerial.h>
SoftwareSerial MySerial(9,10); // RX, TX attached to a FDDI adapter
//#define BLYNK_PRINT MySerial
// Set ESP8266 Serial object
#include <ESP8266_HardSer.h>
#include <BlynkSimpleShieldEsp8266_HardSer.h>
#define EspSerial Serial
ESP8266 wifi(EspSerial);
WidgetBridge bridge1(V30);
WidgetLED led21(21);

#include <SimpleTimer.h>
#include "DHT.h"
#include <EEPROM.h>
#include "max6675.h"
//#include <IRremote.h>
//#include <IRremoteInt.h>
//#define SEND_SAMSUNG // TV

// System parameters
const byte max_nbr_sensors = 6; //max number of sensors attached per Arduino 
const byte max_nbr_dif_sensors = 11; //max number of different sensors in the network

struct MyObject {
  uint16_t this_node;
  char room[9];
  byte sensoren[max_nbr_sensors];
  char auth[33];
  char othauth [33];
};
MyObject configuration; //Variable to store custom object read from EEPROM.

const int PirPin = 2;         // choose the input pin (for PIR sensor)
const int RelayPin1 = 4; //the "s" of relay module attach to
const int thermoDO = 5;
const int thermoCLK = 6;
const int thermoCS = 7;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
const int RelayPin2 = 8; //  the "s" of relay module attach to 
const int VacationPin = 9;
const int DoorPin = 13;  
const int LightSensor = A0;
#define DHTPIN 18     // what pin we're connected to
#define DHTTYPE DHT11 
DHT dht(DHTPIN, DHTTYPE);
const int WaterSensor = A5; 
const int Co2Sensor = A6; //analog Pin connected to "out" from sensor board
const int FlamePin = A7; // define the flame sensor interface
//IRsend irsend;

SimpleTimer timer;
int lighttimer = -1;
int checktimer;
long int didit = -72000000;
bool runn = 0;
bool alarm_movement = 0;
bool movement;
bool movement_did_it = 0;
bool alarm_door = 0;
bool door;
bool door_did_it = 0;
bool alarm_CO2 = 0;
bool CO2;
bool CO2_did_it = 0;
bool alarm_water = 0;
bool water;
bool water_did_it = 0;
bool alarm_flame = 0;
bool flame;
bool flame_did_it = 0;
int thermo = 0;
int vacation = 0;
int h = 0;
int t = 0;
int UP_LED = V1;
long int last_UP_change = millis();
int ALARM_LED = V11;
bool Alarm_last_reading = 0;
int Relay1_LED = V9;
int Relay2_LED = V9;
 
void setup_sensors (int node);
void switchofflight();
void checklight();
void checkvacation();
void sendData();
void is_it_vacation();

// setup reset
void(* resetFunc) (void) = 0;//declare reset function at address 0

void setup()
{
  MySerial.begin(9600);
  MySerial.println(F("setup start"));
  EEPROM.get(0, configuration); 
  pinMode(VacationPin, OUTPUT); //initialize relay as an output
  digitalWrite(VacationPin,LOW);
  pinMode(DoorPin, INPUT); 
  pinMode(PirPin, INPUT);     // declare PIR sensor as input
  pinMode(RelayPin1, OUTPUT); //initialize relay as an output
  digitalWrite(RelayPin1,LOW);
  pinMode(RelayPin2, OUTPUT); //initialize relay as an output
  digitalWrite(RelayPin2,HIGH);
  pinMode (FlamePin, INPUT);  // output interface defines the flame sensor

  

  // Set ESP8266 baud rate
  EspSerial.begin(115200);
  delay(10);
  Blynk.begin(configuration.auth, wifi, "wireless", "key");
  MySerial.println(F("while loop starting"));
  while (Blynk.connect() == false) {  // Wait until connected
  if ((millis() - last_UP_change) > 120000) {
    MySerial.println(F("resetting"));
    resetFunc();
    }
  }
  if (configuration.this_node != 0) bridge1.setAuthToken(configuration.othauth);
  vacation = led21.getValue();
  MySerial.print(F("led21: "));
  MySerial.println(vacation);
  checkvacation ();
  switch (configuration.this_node) {
     case 0: //Master
     UP_LED = V31;
     if (vacation) digitalWrite(VacationPin,HIGH);
     break;
     case 1: //Office 
     UP_LED = V1;
     ALARM_LED = V11;
     setup_sensors(1);
     break;           
     case 2: //Bed room
     UP_LED = V2;
     ALARM_LED = V12;
     setup_sensors(2);
     break;
     case 3: //Living room
     UP_LED = V3;
     ALARM_LED = V13;
     setup_sensors(3);
     break;
     case 4: //Dining room
     UP_LED = V4;
     ALARM_LED = V14;
     setup_sensors(4);
     break;    
     case 5: //Terasse
     UP_LED = V5;
     ALARM_LED = V15;
     setup_sensors(5);
     break;
     case 6: //Heating  
     UP_LED = V6;
     ALARM_LED = V16;
     setup_sensors(6);
     break;
     case 7: //Garage
     UP_LED = V7;
     ALARM_LED = V17;
     setup_sensors(7);
     break;
     case 8: //Laundry room
     UP_LED = V8;
     ALARM_LED = V18;
     setup_sensors(8);
     break;
     }
  
  Blynk.virtualWrite(UP_LED,0);    // turn Up off
  Blynk.virtualWrite(ALARM_LED,0); // turn Alarm off
  
  timer.setInterval(2000L, sendData);
  timer.setInterval(10000L, is_it_vacation);
 }

void loop()
{
  Blynk.run();
  if ((millis() - last_UP_change) > 120000) {
   resetFunc();
  }
  timer.run(); // Initiates SimpleTimer
}


void setup_sensors (int node) {
MySerial.println(F("Node: "));
MySerial.println(node);
MySerial.println(configuration.auth);
MySerial.println(F("Sensoren: "));
for(int i=0; i<max_nbr_sensors; i++){
  MySerial.println(configuration.sensoren[i]);
  switch (configuration.sensoren[i]) {  
     case 0: // no such sensor installed
     break;
     case 2: // 
     switch (node) {
       case 1:
       Relay2_LED = V9;
       break;
       case 2:
       Relay2_LED = V10;
       break;
       case 3:
       Relay2_LED = V19;
       break;
       case 4:
       Relay2_LED = V20;
       break;
       }    
     case 4: // DHT11 temp and humidity sensor
     dht.begin();
     break;    
     case 8: // Photoresistor
     checktimer = timer.setInterval(10000L, checklight);
     break;
   }
 } 
}

void sendData()
{
  // Please don't send more that 10 values per second.
  // Turn runn LED on/off
   Blynk.virtualWrite(UP_LED,runn);  // turn Up off
   runn = !runn;
      
   for(int i=0; i<max_nbr_sensors; i++){ // Read all sensors and take action
   switch (configuration.sensoren[i]) {  
     case 0: // no such sensor installed
     break;
     case 1: // Pir movement sensor      
     movement = digitalRead(PirPin);
     if (movement && !movement_did_it) {
       alarm_movement = 1;
       Blynk.notify("Movement in " + String(configuration.room));
       movement_did_it = 1;
      }
     else if (!movement && !vacation) {
       alarm_movement = 0;
       movement_did_it = 0;
      }  
     break;           
     case 2: // Light
     Blynk.virtualWrite(Relay2_LED, digitalRead(RelayPin2));
     break;
     case 3: // Door closed switch and vacation switch on Base
     door = digitalRead(DoorPin);
     if (door && !door_did_it) {
      alarm_door = 1;
      Blynk.notify("Door open in " + String(configuration.room));
      door_did_it = 1;
      }
     else if (!door && !vacation) {
      alarm_door = 0;
      door_did_it = 0;
      }
     break;
     case 5: // CO2 sensor
     CO2 = analogRead(Co2Sensor);
     if (CO2 > 150 && !CO2_did_it) {// Value to be verified
      alarm_CO2 = 1;
      Blynk.notify("CO2 in " + String(configuration.room));
      CO2_did_it = 1;
      }
     else if (!CO2 && !vacation) {
      alarm_CO2 = 0;
      CO2_did_it = 0;
      }
     break;
     case 7: // Water or Rain sensor
     water = analogRead(WaterSensor);
     if (water > 150 && !water_did_it) {// this value to be tested
      alarm_water = 1;
      Blynk.notify("Water in " + String(configuration.room));
      water_did_it = 1;
      }
     else if (!water && !vacation) {
      alarm_water = 0;
      water_did_it = 0;
      }
     break;
     case 10: // Flame sensor
     flame = analogRead(FlamePin);
     if (flame > 150 && !flame_did_it) {// this value to be tested
      alarm_flame = 1;
      Blynk.notify("Fire in " + String(configuration.room));
      flame_did_it = 1;
      }
     else if (!flame && !vacation) {
      alarm_flame = 0;
      flame_did_it = 0;
      }
     break;
         
   }
   if (!alarm_movement && !alarm_door && !alarm_CO2 && !alarm_water && !alarm_flame && Alarm_last_reading) {
    Blynk.virtualWrite(ALARM_LED, 0);
    Alarm_last_reading = 0;
  } 
   else {
    if (!Alarm_last_reading && (alarm_movement || alarm_door || alarm_CO2 || alarm_water || alarm_flame)) {
    Blynk.virtualWrite(ALARM_LED, 1);
    Alarm_last_reading = 1;
    }
   }
 }      
}

void is_it_vacation() {
   int temp_vacation;
   if (configuration.this_node == 0) {
   temp_vacation = digitalRead(VacationPin);
   }
   else {
   temp_vacation = led21.getValue();
   }
   if (vacation != temp_vacation) {
     vacation = temp_vacation;
     if (configuration.this_node == 0) {
      Blynk.virtualWrite(V21, vacation);
     }
     checkvacation();
   }
   
} 
  
void checkvacation() 
{
  MySerial.println(F("check vacation"));
  if(vacation && !timer.isEnabled(lighttimer))  {
    digitalWrite(RelayPin2, LOW); //Switch off everything on that pin
   }
  if (vacation) digitalWrite(RelayPin1, LOW); //Switch off everything on that pin
  else {
    digitalWrite(RelayPin2, HIGH); //Switch on everything on that pin
   }
  MySerial.print(F("Vacation: "));
  MySerial.println(vacation);
}

void checklight() {
    if (vacation) {
    int light = analogRead(LightSensor);
    MySerial.print(F("Light: "));
    MySerial.println(light);
    if ((millis() - didit) > 72000000 && light > 700 && !timer.isEnabled(lighttimer)) { //after 20 hours
      randomSeed(analogRead(A2));       // Zufallsgenerator initialisieren 
      digitalWrite(RelayPin2, HIGH);    // turn the LED on (HIGH is the voltage level)
      lighttimer = timer.setTimeout((random(120, 300) * 60000), switchofflight); // between 120 to 300 minutes
      didit=millis();
      } 
  }
}  
void switchofflight() {
    digitalWrite(RelayPin2, LOW);
    timer.deleteTimer(lighttimer);
}


BLYNK_READ(V0) {
     // Read temperature as Celsius
     t = dht.readTemperature();
     Blynk.virtualWrite(V26, t);
     last_UP_change = millis();
 }

BLYNK_READ(V22) {
     h = dht.readHumidity();
     Blynk.virtualWrite(V27, h);

}

BLYNK_READ(V23) {//Garage door open and close
   
}

BLYNK_READ(V25) {
     thermo = thermocouple.readCelsius();
     Blynk.virtualWrite(V25, thermo);
}

BLYNK_READ(V26) {
     // Read temperature as Celsius
     t = dht.readTemperature();
     Blynk.virtualWrite(V26, t);
     last_UP_change = millis();
}

BLYNK_READ(V27) {
     h = dht.readHumidity();
     Blynk.virtualWrite(V27, h);
}

BLYNK_READ(V28) {
     // Read temperature as Celsius
     t = dht.readTemperature();
     Blynk.virtualWrite(V28, t);
     last_UP_change = millis();
}

BLYNK_READ(V29) {
     h = dht.readHumidity();
     Blynk.virtualWrite(V29, h);
}

Program to put data to EEPROM

#include <EEPROM.h>
const byte max_nbr_sensors = 6;
struct MyObject {
  uint16_t this_node;
  char room[9];
  byte sensoren[max_nbr_sensors];
  char auth[33];
  char othauth [33];
};

void setup() {

  int eeAddress = 0;   //Location we want the data to be put.


  /** Put is designed for use with custom structures also. **/

  //Data to store: Node id (0 for base), 8 digits for room name, max. 6 sensors (referenced as 1-11),
  //32 digits for auth token, 32 digits for bridge (other token)
  // In this example node 1 in room office has sensors 1 (PIR sensor), 4 (DHT11 sensor), 2 (Relays) and 8 (Light sensor)

  MyObject configuration = {1,"Office. ",1,4,2,8,0,0,"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"};

  EEPROM.put(eeAddress, configuration);
 
}

void loop() {
  /* Empty loop */
}

7 Likes

Wow, this is a fantastic project! Could you post a video or photos of the working setup?

Have you used Android or iPhone?

I’m actually using an iPad, as this is the only device with iOS 9 I own.

hi - if i put the second bit in my loop will it help making sure the esp8266 stays ‘awake’ to respond to my button inputs on the app? it is every 2 minutes? is this the usual setting?

i have much more to learn from your code - i also want multiple ESP nodes around my house…

It will work, but why not use SimpleTimer? It may be more readable to use just one piece of code/library to handle all Timer things.

sorry, i thought that was a ‘soft reset’ code?

can you do that with simple timer?

Sure why not? It’s a function like any other :slight_smile:

@mrohner - This post, concept and code are brilliant. I’m blown away 2.6k people have viewed it with only a handful of replies and comments. This post should be a growing living topic with hundreds of replies. I only wish I could code and understand at your level and others on this forum. I can limp along, I love to create project and write code at 2am. I can’t write as well as this, create as well as this, but I understand the intent, this is great.

FANTASTIC !!! * * * * *

(think about the implications of this people!)

1 Like

@mrohner Fantastic Project. This one is epic. Can you please share all the details and code with us…I am really inspired by your work and want to make one for my house. Please do share this is invariably one of the best project in Blynk.

1 Like