NodeMCU wireless home security system


This project is an incredibly low cost Arduino home security system with ESP8266 wireless stations, infrared presence sensors and RFID identification system.

Introduction

The system described here is a wireless network of several devices. The platform chosen for the realization is a circuit compatible with NodeMCU 1.0, easy to program with Arduino IDE, very cheap and with several GPIOs. This involves that the project is easily scalable, allowing to add an high number of network nodes with sensing/computing capabilities on the dedicated Wifi network.

One of such boards is the access point, with the control logic over the entire wireless network, that is private for the purpose of such system. The access point board has also an identification system based on an RFID tag reader to switch on or off the alarm. Finally a presence sensor is connected to the access point.

Some other NodeMCU boards, connected with the same wireless network, are equipped with presence sensors to make the intrusion detection capability distributed on the monitored space.

Finally, a NodeMCU deployed out of the monitored space carries a second RFID reader card, to make possible activating and deactivating the alarm without entering the monitored area.

NodeMCU clone: Lolin platform

I chose the “Lolin” platform for the low cost and for the compatibility with NodeMCU 1.0 platform, that integrates the ESP8266 Wifi chip with a bunch of GPIOs and some voltage regulation items. The platform presents also an analog input. Following image describes the pinout of NodeMCU 1.0 platform, with the main serial line (TXD0 and RXD0) and SPI connections highlighted. Note that in Arduino IDE the GPIO pins can be referred with the original name (e.g. “D4”) or with the number (e.g. pin number 2). In this case the pin number 2 corresponds with pin named D4.

Lolin platform

Lolin platform pinout

RC522 board test and RFID reading

In order to read the ID of RFID tags in my hand and to test the RF522 sensing board, I started with a simple program able to read a tag and print the hex identitfier to the NodeMCU output serial port.

Following image is the wiring diagram to test RFID reader.

RFIT test schematic

Below the code for the testing board.

// filename: rfidtest.ino
#include <SPI.h>
#include <MFRC522.h>

//////////////////////////////////////////////////////////////////////////////
// Defines
#define SS_PIN 15 // SPI pin connected to local RFID reader
#define RST_PIN 5 // SPI RST pin connected to local RFID reader

// PINOUT:
// RC522 MODULE    NodeMCU 1.0
// SDA             15 (D8)
// SCK             14 (D5)
// MOSI            13 (D7)
// MISO            12 (D6)
// IRQ             N/A
// GND             GND
// RST             5  (D1)
// 3.3V            3.3V

//////////////////////////////////////////////////////////////////////////////
// Globals
MFRC522 mfrc522(SS_PIN, RST_PIN);

//////////////////////////////////////////////////////////////////////////////
// Setup routine
void setup()
{
  // Init  SPI bus
  SPI.begin();
  
  // Init MFRC522
  mfrc522.PCD_Init();   

  // To send rfid tag values via serial 
  Serial.begin(9600);

  // Setup completed
  Serial.println("Setup completed");
}

//////////////////////////////////////////////////////////////////////////////
// Main loop
void loop()
{
  CheckLocalRFIDReader();
}

//////////////////////////////////////////////////////////////////////////////
// Check local RFID tag reader
void CheckLocalRFIDReader()
{
  // Look for new cards
  if (!mfrc522.PICC_IsNewCardPresent()) 
  {
    return;
  }
  
  // Select one of the cards
  if (!mfrc522.PICC_ReadCardSerial()) 
  {
    return;
  }

  // Show UID on serial monitor
  Serial.print("UID tag :");

  String content = "";
  
  for (byte i = 0; i < mfrc522.uid.size; i++) 
  {
     content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
     content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  content.toUpperCase();

  Serial.print(content);
  Serial.println();
  Serial.println();
}

Access point

// filename: accesspoint.ino
// Select NodeMCU 1.0

// PINOUT:
// ---------------------------
// RC522 MODULE    NodeMCU 1.0
// SDA             15 (D8)
// SCK             14 (D5)
// MOSI            13 (D7)
// MISO            12 (D6)
// IRQ             N/A
// GND             GND
// RST             5  (D1)
// 3.3V            3.3V
// ---------------------------
// Peripherals     NodeMcu 1.0
// Buzzer          4 (D2)
// Pir             2 (D4)
// Status led         D3

// IP of this access point: 42.42.42.42
// SSID: "GuaglioWifi"
// Password: "testtesttest"
// Server port: 42501
//
// 

#include <SPI.h>
#include <MFRC522.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 

//////////////////////////////////////////////////////////////////////////////
// Defines
#define SS_PIN 15       // SPI pin connected to local RFID reader
#define RST_PIN 5       // SPI RST pin connected to local RFID reader
#define LOCALPIR_PIN D4 // PIR sensor input
#define ARMEDLED_PIN D3 // Led showing armed status

//////////////////////////////////////////////////////////////////////////////
// Globals
bool g_armed(false);
MFRC522 mfrc522(SS_PIN, RST_PIN);
bool rfidStationConnected;
WiFiServer httpServer(42501);
WiFiClient rfidStationClient;

//////////////////////////////////////////////////////////////////////////////
// Setup
void setup()
{
  Serial.begin(9600);

  // Local sensor input pin setup
  pinMode(LOCALPIR_PIN, INPUT);

  // Led showing armed status
  pinMode(ARMEDLED_PIN, OUTPUT);

  // Led is ON when system is not armed
  digitalWrite(ARMEDLED_PIN, g_armed ? LOW : HIGH);

  // Flag used to store if the station with secondary RFID reader is present and connected
  rfidStationConnected = false;
  
  // Initiate  SPI bus
  SPI.begin();
  
  // Init MFRC522 interface
  mfrc522.PCD_Init();

  // Start Wifi
  bool apCreation = WiFi.softAP(
    "GuaglioWifi",  // ssid
    "testtesttest", // password
    13,             // channel
    1);             // ssid_hidden

  if(!apCreation)
  {
    Serial.println("Error, WiFi.softAP() returned false.");
  }

   bool apConfig = WiFi.softAPConfig(
    IPAddress(42, 42, 42, 42),  // local_ip
    IPAddress(42, 42, 42, 42),  // gateway
    IPAddress(255, 255, 255, 0) // subnet
    );

  if(!apConfig)
  {
    Serial.println("Error, WiFi.softAPConfig() returned false.");
  }

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("IP address: ");
  Serial.println(myIP);

  // Start Webserver
  httpServer.begin();

  Serial.println("Server started.");

  Serial.println("Setup completed.");
}

//////////////////////////////////////////////////////////////////////////////
// Main loop
void loop()
{
  // Check presence of remote RFID reader. If present, no delay will be applied
  // to alarm
  ConnectRfidStation();
  
  // Read from local RFID reader 
  CheckLocalRFIDReader();
  
  // Check local sensor
  if(digitalRead(LOCALPIR_PIN) == HIGH)
  {
    PresenceDetected();
  }

  // Handle remote requests
  HandleRemoteRequests();

  // Delay on main loop
  delay(500);
}

//////////////////////////////////////////////////////////////////////////////
// Check presence of remote RFID reader
void ConnectRfidStation()
{
  if(!rfidStationClient.connected())
  {
    if (rfidStationClient.connect(IPAddress(42, 42, 42, 43), 15763))
    {
      rfidStationConnected = true;
      return;
    }
    rfidStationConnected = false;
  }
  else
  {
    rfidStationConnected = true;
  }

  String strstatus = "rfidstation:";
  if(rfidStationConnected) strstatus += "connected\n";
  else strstatus += "not connected\n";
  Serial.print(strstatus);
}

//////////////////////////////////////////////////////////////////////////////
// Decide if start alarm immediately or with a delay
void PresenceDetected()
{
  if(g_armed)
  {
    if(rfidStationConnected)
    {
      ImmediateIntrusion();
    }
    else
    {
      DelayedIntrusion();
    }
  }
}

//////////////////////////////////////////////////////////////////////////////
// Handle remote requests
void HandleRemoteRequests()
{
  // Check if a client has connected
  WiFiClient wifiClient = httpServer.available();
  if (!wifiClient)
  {
    return;
  }

  // Check if there's a pending request
  if(!wifiClient.available())
  {
    return;
  }

  // Read the first line of the request
  String req = wifiClient.readStringUntil('\n');
  Serial.println("Client request:" + req);

  // Match the request
  if (req.indexOf("/armed") != -1)
  {
    // rfid station requested to get current alarm state
    wifiClient.print(g_armed ? "1" : "0");
  }
  else if (req.indexOf("/pir") != -1)
  {
    // Some sensor station detected presence
    PresenceDetected();
  }
  else if (req.indexOf("TAG:") != -1)
  {
    // Tag ID received from remote RFID station
    rfidStationConnected = true;

    Serial.println(">>>>>" + req.substring(5));

    if(IsKnownTagId(req.substring(5)))
    {
      Serial.println("Known tag received!!!");
      ToggleAlarmStatus();
    }
  }
  else
  {
    Serial.println("invalid request");
    //wifiClient.stop();
    return;
  }
}

//////////////////////////////////////////////////////////////////////////////
// Check local RFID tag reader
void CheckLocalRFIDReader()
{
  // Look for new cards
  if(!mfrc522.PICC_IsNewCardPresent()) 
  {
    return;
  }
  
  // Select one of the cards
  if(!mfrc522.PICC_ReadCardSerial()) 
  {
    return;
  }

  String content= "";
  for (byte i = 0; i < mfrc522.uid.size; i++) 
  {
     content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
     content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }  
  content.toUpperCase();

  // Check if present tag is one of known tags
  if (IsKnownTagId(content.substring(1)))
  {
    ToggleAlarmStatus();
  }
}

//////////////////////////////////////////////////////////////////////////////
// Check if tag ID is known
bool IsKnownTagId(const String & id)
{
  if(id == "55 79 D7 2B" ||
    id == "3D 98 2C 62" ||
    id == "57 11 A1 59" ||
    id == "3D 3C 07 85")
  {
    return true;
  }
  else
  {
    return false;
  }
}

//////////////////////////////////////////////////////////////////////////////
// Check local RFID tag reader
void ToggleAlarmStatus()
{
  if(g_armed)
  {
    // Switch off alarm
    g_armed = false;

    // Blink
    digitalWrite(ARMEDLED_PIN, HIGH);
    delay(1000);
    digitalWrite(ARMEDLED_PIN, LOW);
    delay(1000);

    // Led is ON when system is not armed
    digitalWrite(ARMEDLED_PIN, g_armed ? LOW : HIGH);
  }
  else
  {
    // Turn on alarm
    digitalWrite(ARMEDLED_PIN, LOW);
    delay(500);
    digitalWrite(ARMEDLED_PIN, HIGH);
    delay(500);
    digitalWrite(ARMEDLED_PIN, LOW);
    delay(500);
    digitalWrite(ARMEDLED_PIN, HIGH);
    delay(500);
    digitalWrite(ARMEDLED_PIN, LOW);

    // System armed
    g_armed = true;
    
    // Led is ON when system is not armed
    digitalWrite(ARMEDLED_PIN, g_armed ? LOW : HIGH);
  }
}

//////////////////////////////////////////////////////////////////////////////
// Siren!
void ImmediateIntrusion()
{
  // TODO
}

//////////////////////////////////////////////////////////////////////////////
// 20 seconds to turn off, then siren!
void DelayedIntrusion()
{
  // OK, alarm is fired. But it can be the home owner
  // So, wait 20 seconds to possibly disable armed value
  for(int i=0; i<20; i++)
  {
    CheckLocalRFIDReader();
    String msg = "Wait for possible disarm by owner [";
    msg.concat(i);
    msg.concat("]");
    Serial.println(msg);
    delay(900);
  }

  // Now, if alarm is still armed, turn on siren
  if(g_armed)
  {
    ImmediateIntrusion();
  }
}

RFID Reader station

// filename: rfidstation.ino
// PINOUT:
// RC522 MODULE    NodeMCU 1.0
// SDA             15 (D8)
// SCK             14 (D5)
// MOSI            13 (D7)
// MISO            12 (D6)
// IRQ             N/A
// GND             GND
// RST             5  (D1)
// 3.3V            3.3V

//////////////////////////////////////////////////////////////////////////////
// Includes
#include <SPI.h>
#include <MFRC522.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 

//////////////////////////////////////////////////////////////////////////////
// Defines
#define SS_PIN 15       // SPI pin connected to local RFID reader
#define RST_PIN 5       // SPI RST pin connected to local RFID reader
#define REDLED_PIN D2   // D2
#define GREENLED_PIN D4 // D4

//////////////////////////////////////////////////////////////////////////////
// Globals
MFRC522 mfrc522(SS_PIN, RST_PIN);
IPAddress accesspoint_ip(42, 42, 42, 42);
int accesspoint_port(42501);
WiFiClient wifiClient;
WiFiServer httpServer(15763);
bool g_connected(false);
bool g_armed(false);

//////////////////////////////////////////////////////////////////////////////
// Setup
void setup()
{
  // Debug
  Serial.begin(9600);
  
  // Status leds
  pinMode(REDLED_PIN, OUTPUT);
  pinMode(GREENLED_PIN, OUTPUT);
  
  // Initiate  SPI bus
  SPI.begin();
  
  // Initiate MFRC522
  mfrc522.PCD_Init();

  // Configure wifi node
  bool stationConfigured = WiFi.config(
    IPAddress(42, 42, 42, 43),  // local_ip
    IPAddress(42, 42, 42, 42),  // gateway
    IPAddress(255, 255, 255, 0) // subnet
    );

  if(!stationConfigured)
  {
    Serial.println("Error, WiFi.config() returned false.");
  }

  // Connect to wifi
  bool stationConnected = WiFi.begin(
    "GuaglioWifi",
    "testtesttest");

  if(!stationConnected)
  {
    Serial.println("Error, WiFi.begin() returned false.");
  }

  // Set automatic reconnection
  bool autoreconnect = WiFi.setAutoReconnect(true);

  if(!autoreconnect)
  {
    Serial.println("Error, WiFi.setAutoReconnect() returned false.");
  }

  // Start http server
  httpServer.begin();

  Serial.println("Server started on port 15763");

  Serial.println("Setup completed.");
}

//////////////////////////////////////////////////////////////////////////////
// Loop
void loop()
{
  // Set green led according to connection
  CheckConnection();
  digitalWrite(GREENLED_PIN, g_connected ? HIGH : LOW);
  
  // If connected, check alarm state and read from local RFID reader 
  if(g_connected)
  {
    CheckAlarmState();
    
    // Set red led according to alarm state
    digitalWrite(REDLED_PIN, g_armed ? HIGH : LOW);

    // Read if tag present
    CheckLocalRFIDReader();
  }

  // Wait for a while 
  delay(1000);
}

//////////////////////////////////////////////////////////////////////////////
// Check connection
void CheckConnection()
{
  g_connected = WiFi.status() == WL_CONNECTED;
}

//////////////////////////////////////////////////////////////////////////////
// Check alarm state
void CheckAlarmState()
{
  if(!wifiClient.connected())
  {
    if (!wifiClient.connect(accesspoint_ip, accesspoint_port))
    {
      return;
    }
  }

  // This will send the request to the server
  wifiClient.print("/armed\n");

  // Wait response
  //String resp = wifiClient.readStringUntil('\r');
  String resp = wifiClient.readStringUntil('\n');

  if(resp.length() != 0)
  {
    //Serial.println("armed: " + resp + "_" + resp.length());
    if(resp.charAt(0) == '1')
    {
      g_armed = true;
    }
    else if(resp.charAt(0) == '0')
    {
      g_armed = false;
    }
    // else, does not change g_armed value
  }
  wifiClient.flush();
}

//////////////////////////////////////////////////////////////////////////////
// Check local RFID tag reader
void CheckLocalRFIDReader()
{  
  // Look for new cards
  if(!mfrc522.PICC_IsNewCardPresent()) 
  {
    return;
  }
  
  // Select one of the cards
  if(!mfrc522.PICC_ReadCardSerial()) 
  {
    return;
  }

  String content= "";
  for (byte i = 0; i < mfrc522.uid.size; i++) 
  {
     content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
     content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }  
  content.toUpperCase();

  // Send data to access point and blink green led
  if(!wifiClient.connected())
  {
    if (!wifiClient.connect(accesspoint_ip, accesspoint_port))
    {
      return;
    }
  }

  // This will send the request to the server
  wifiClient.print("TAG:" + content + "\n");
  Serial.println("TAG:" + content);

  // Assuming here if connection ok and green led ON.
  // Blink green led to inform user that card info was sent 
  digitalWrite(GREENLED_PIN, LOW);
  delay(200);
  digitalWrite(GREENLED_PIN, HIGH);
  delay(200);
  digitalWrite(GREENLED_PIN, LOW);
  delay(200);
  digitalWrite(GREENLED_PIN, HIGH);
  delay(200);
  digitalWrite(GREENLED_PIN, LOW);
  delay(200);
  digitalWrite(GREENLED_PIN, HIGH);
}

Presence sensing stations

// filename: pirstation.ino
//////////////////////////////////////////////////////////////////////////////
// Includes
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 

//////////////////////////////////////////////////////////////////////////////
// Defines
#define PIR_PIN D5      // Sensor
#define REDLED_PIN D2   // D2
#define GREENLED_PIN D4 // D4

//////////////////////////////////////////////////////////////////////////////
// Globals
IPAddress accesspoint_ip(42, 42, 42, 42);
int accesspoint_port(42501);
WiFiClient wifiClient;
bool g_connected(false);
bool g_armed(false);

//////////////////////////////////////////////////////////////////////////////
// Setup
void setup()
{
  // Debug
  Serial.begin(9600);
  
  // Status leds
  pinMode(REDLED_PIN, OUTPUT);
  pinMode(GREENLED_PIN, OUTPUT);
  
  // Setup sensor pin
  pinMode(PIR_PIN, INPUT);

  // Configure wifi node
  bool stationConfigured = WiFi.config(
    IPAddress(42, 42, 42, 44),  // local_ip
    IPAddress(42, 42, 42, 42),  // gateway
    IPAddress(255, 255, 255, 0) // subnet
    );

  if(!stationConfigured)
  {
    Serial.println("Error, WiFi.config() returned false.");
  }

  // Connect to wifi
  bool stationConnected = WiFi.begin(
    "GuaglioWifi",
    "testtesttest");

  if(!stationConnected)
  {
    Serial.println("Error, WiFi.begin() returned false.");
  }

  // Set automatic reconnection
  bool autoreconnect = WiFi.setAutoReconnect(true);

  if(!autoreconnect)
  {
    Serial.println("Error, WiFi.setAutoReconnect() returned false.");
  }

  Serial.println("Setup completed.");
}

//////////////////////////////////////////////////////////////////////////////
// Loop
void loop()
{
  // Loop every 1 second.
  // Check connetion only every 
  CheckConnection();
  digitalWrite(GREENLED_PIN, g_connected ? HIGH : LOW);
  
  // If connected, check alarm state and read from local RFID reader 
  if(g_connected)
  {
    CheckAlarmState();
    
    // Set red led according to alarm state
    digitalWrite(REDLED_PIN, g_armed ? HIGH : LOW);

    // If armed, loop fast on pir sensor
    CheckLocalPIR();
  }

  // Wait for a while 
  delay(1000);
}

//////////////////////////////////////////////////////////////////////////////
// Check connection
void CheckConnection()
{
  g_connected = WiFi.status() == WL_CONNECTED;
}

//////////////////////////////////////////////////////////////////////////////
// Check alarm state
void CheckAlarmState()
{
  if(!wifiClient.connected())
  {
    if (!wifiClient.connect(accesspoint_ip, accesspoint_port))
    {
      return;
    }
  }

  // This will send the request to the server
  wifiClient.print("/armed\n");

  // Wait response
  String resp = wifiClient.readStringUntil('\n');

  if(resp.length() != 0)
  {
    //Serial.println("armed: " + resp + "_" + resp.length());
    if(resp.charAt(0) == '1')
    {
      g_armed = true;
    }
    else if(resp.charAt(0) == '0')
    {
      g_armed = false;
    }
    // else, does not change g_armed value
  }
  wifiClient.flush();
}

//////////////////////////////////////////////////////////////////////////////
// Check local PIR sensor
void CheckLocalPIR()
{
  // If no signal on sensor, all ok, return
  if(digitalRead(PIR_PIN) == LOW)
  {
    return;
  }

  // Else, send alarm to access point
  if(!wifiClient.connected())
  {
    if (!wifiClient.connect(accesspoint_ip, accesspoint_port))
    {
      return;
    }
  }

  // This will send the request to the server
  wifiClient.print("ALARM44\n");
  Serial.println("ALARM44");
}

Comments