Mesh Networking Home Automation

Mesh Networking Home Automation

Overview

ESP-MESH is a networking protocol built atop the Wi-Fi protocol. ESP-MESH allows numerous devices (henceforth referred to as nodes) spread over a large physical area (both indoors and outdoors) to be interconnected under a single WLAN (Wireless Local-Area Network). ESP-MESH is self-organizing and self-healing meaning the network can be built and maintained autonomously.

Diagram of Traditional Network Architecture

Traditional Wi-Fi Network Architecture

A traditional infrastructure Wi-Fi network is a point-to-multipoint network where a single central node known as the access point (AP) is directly connected to all other nodes known as stations. The AP is responsible for arbitrating and forwarding transmissions between the stations. Some APs also relay transmissions to/from an external IP network via a router. Traditional infrastructure Wi-Fi networks suffer the disadvantage of limited coverage area due to the requirement that every station must be in range to directly connect with the AP. Furthermore, traditional Wi-Fi networks are susceptible to overloading as the maximum number of stations permitted in the network is limited by the capacity of the AP.Diagram of ESP-MESH Network Architecture

ESP-MESH Network Architecture

ESP-MESH differs from traditional infrastructure Wi-Fi networks in that nodes are not required to connect to a central node. Instead, nodes are permitted to connect with neighboring nodes. Nodes are mutually responsible for relaying each others transmissions. This allows an ESP-MESH network to have much greater coverage area as nodes can still achieve interconnectivity without needing to be in range of the central node. Likewise, ESP-MESH is also less susceptible to overloading as the number of nodes permitted on the network is no longer limited by a single central node.

ESP-MESH Concepts

Till now you have seen many different kind of Home automation using Smart phone, Blynk, Google Assistant, Alexa, Google Firebase or even local MQTT server based as well. But what if I tell you that there is one more method of controlling appliances which don’t require Internet or not even a router. Here I present you my Home Automation project made using Mesh Networking

Code for ESP32

//************************************************************
// this is a simple example that uses the painlessMesh library
//
// this code is designed by RoboCircuits
//
//
//************************************************************
#include "painlessMesh.h"

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

Scheduler userScheduler; // to control your personal task
painlessMesh  mesh;

// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain

Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );

void sendMessage() {
  String msg = "Hello from node ";
  msg += mesh.getNodeId();

  taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 ));
}

// Needed for painless library
void receivedCallback( uint32_t from, String &msg ) {
  Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
    mesh.sendBroadcast( msg );
}

void newConnectionCallback(uint32_t nodeId) {
    Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}

void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}

void nodeTimeAdjustedCallback(int32_t offset) {
    Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}

void setup() {
  Serial.begin(115200);

//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
  mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages

  mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
  mesh.onReceive(&receivedCallback);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);

  userScheduler.addTask( taskSendMessage );
  taskSendMessage.enable();
}

void loop() {
  if(Serial.available()>1)
  {
    String msg1 = Serial.readString();
    mesh.sendBroadcast( msg1 );
  }
  // it will run the user scheduler as well
  mesh.update();
}

Code for ESP8266

//************************************************************
// this is a simple example that uses the painlessMesh library
//
// 1. sends a silly message to every node on the mesh when intrupt happens
// this code is designed by RoboCircuits
//
//
//************************************************************
#include "painlessMesh.h"

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555


void ICACHE_RAM_ATTR button1();
void ICACHE_RAM_ATTR button2();
void ICACHE_RAM_ATTR button3();
void ICACHE_RAM_ATTR button4();

painlessMesh  mesh;

int out1 = 12;
int out2 = 13;
int out3 = 14;
int out4 = 16;
int in1 = 4;
int in2 = 5;
int in3 = 10;
int in4 = 9;

String json;

boolean buttonState1, buttonState2, buttonState3, buttonState4;
// Needed for painless library
void receivedCallback( uint32_t from, String &msg ) {
  Serial.println(msg);
  String json = ""; 
  DynamicJsonDocument doc(1024);
  json = msg.c_str();
  DeserializationError error = deserializeJson(doc,json);
  if(error)
  {
    Serial.println(" deserialization failed");
  }

  if(doc["on1"] == true)
  {
    digitalWrite(out1,HIGH);
  }
  else if(doc["on2"] == true)
  {
    digitalWrite(out2,HIGH);
  }
  else if(doc["on3"] == true)
  {
    digitalWrite(out3,HIGH);
  }
  else if(doc["on4"] == true)
  {
    digitalWrite(out4,HIGH);
  }
  else if(doc["on1"] == false)
  {
    digitalWrite(out1,LOW);
  }
  else if(doc["on2"] == false)
  {
    digitalWrite(out2,LOW);
  }
  else if(doc["on3"] == false)
  {
    digitalWrite(out3,LOW);
  }
  else if(doc["on4"] == false)
  {
    digitalWrite(out4,LOW);
  } 
}

void newConnectionCallback(uint32_t nodeId) {
    Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}

void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}

void nodeTimeAdjustedCallback(int32_t offset) {
    Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}

void button1()
{
  delayMicroseconds(100000);
  if(digitalRead(in1)==HIGH)                                     
  {
    buttonState1 =! buttonState1;
    digitalWrite(out1,buttonState1);
    delayMicroseconds(200000);
    json.clear();
    DynamicJsonDocument doc1(1024);
    doc1["on1"] = buttonState1;
    serializeJson(doc1,json);
    mesh.sendBroadcast( json );
  }
}

void button2()
{
  delayMicroseconds(100000);
  if(digitalRead(in2)==HIGH)                                 
  {
    buttonState2 =! buttonState2;
    digitalWrite(out2,buttonState2);
    delayMicroseconds(200000);
    json.clear();
    DynamicJsonDocument doc1(1024);
    doc1["on2"] = buttonState2;
    serializeJson(doc1,json);
    mesh.sendBroadcast( json );
  }
}

void button3()
{
  delayMicroseconds(100000);
  if(digitalRead(in3)==HIGH)                                     
  {
    buttonState3 =! buttonState3;
    digitalWrite(out3,buttonState3);
    delayMicroseconds(200000);
    json.clear();
    DynamicJsonDocument doc1(1024);
    doc1["on3"] = buttonState4;
    serializeJson(doc1,json);
    mesh.sendBroadcast( json );
  }
}

void button4()
{
  delayMicroseconds(100000);
  if(digitalRead(in4)==HIGH)                                 
  {
    buttonState4 =! buttonState4;
    digitalWrite(out4,buttonState4);
    delayMicroseconds(200000);
    json.clear();
    DynamicJsonDocument doc1(1024);
    doc1["on4"] = buttonState4;
    serializeJson(doc1,json);
    mesh.sendBroadcast( json );
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(out1,OUTPUT);
  pinMode(out2,OUTPUT);
  pinMode(out3,OUTPUT);
  pinMode(out4,OUTPUT);
  pinMode(in1,INPUT);
  pinMode(in2,INPUT);
  pinMode(in3,INPUT);
  pinMode(in4,INPUT);

  attachInterrupt(digitalPinToInterrupt(in1), button1, RISING);
  attachInterrupt(digitalPinToInterrupt(in2), button2, RISING);
  attachInterrupt(digitalPinToInterrupt(in3), button3, RISING);
  attachInterrupt(digitalPinToInterrupt(in4), button4, RISING);
  delay(100);
  
  mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages

  mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT );
  mesh.onReceive(&receivedCallback);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
}

void loop() {
  mesh.update();
}

Leave a Reply