Basic Idea about the Project:
The Esp32 Nodes will be used in this project amongst which Blynk Node connects with the internet and sends data to Blynk App. Gateway node is connected serially to this Blynk node. These both performs Serial2 communication to send and receive data in JSON format. The Child Nodes forms a Mesh Network. This Mesh Network interacts with the Gateway node to send data to Blynk App. Each Child node is collects the data of Temperature.
Details :
- ESP 32 Nodes (Blynk Node, Gateway Node and Child Nodes)
- PainlesssMesh Library for Mesh
Issue:
Whenever Gateway node gets/interacts with the Mesh Network formed by Child Nodes, the Gateway Node/Blynk Node looses its Serial2 communication i.e. the Serial2 Communication stops and thus, I am not able to see the updated Temperature in the Blynk App.
Due to this, I put delay in Gateway Node after mesh.update()
. Now due to this delay, the Gateway reconnects to Blynk Node and thus temperature is updated but yess with Delay. Now, I am facing new issue that includes the Temperature reading of Multiple Child Nodes. Now only 1 Child Node interacts with Gateway Node (Mesh Network) at a time. This particular Child Node's reading is updated on Blynk Console for some 2 to 3 minutes. But after this, the Child Node 1 disconnects with Mesh with Temperature setting to default value 0 and Child Node 2 gets connected and thus transmit its Temperature reading to Blynk. So due to this, only one Child Node's temperature is visible on BLynk Console at a time.
Here is the Screenshot of the Blynk Console:
Here are the Codes:
Blynk Node
#define BLYNK_PRINT Serial
// Credentials
#define BLYNK_TEMPLATE_ID "ID here"
#define BLYNK_TEMPLATE_NAME "Farm"
#define BLYNK_AUTH_TOKEN "token here"
// Necesaary Libraries
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <ArduinoJson.h>
// Serial2 pins of ESP32
#define RXD2 16
#define TXD2 17
char auth[] = BLYNK_AUTH_TOKEN;
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "iot";
char pass[] = "123456789";
// Variables
int board;
int pin;
bool pin_status;
String message = "";
bool messageReady = false;
//double child1_temperature;
//double child2_temperature;
#define LED_PIN 2 // LED is usually connected to D2 pin. Change if needed.
BLYNK_WRITE(V0)
{
board = 0;
pin = LED_PIN;
pin_status = param.asInt(); // Pin Status 1/0
Serial.println("V0 On");
}
// Data Coming from Blynk App
BLYNK_WRITE(V1)
{
board = 1;
pin = LED_PIN;
pin_status = param.asInt(); // Pin Status 1/0
//Serial.println(pin_status);
Serial.println("V1 On");
}
BLYNK_WRITE(V2)
{
board = 2;
pin = LED_PIN;
pin_status = param.asInt();
Serial.println("V2 On");
}
void setup()
{
// Debug console
Serial.begin(115200); // For Debugging purpose
Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2); // For sending data to another ESP32
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass); // Establishing Communication with Blynk Server
}
void loop()
{
if(Serial2.available()) //
{
message = Serial2.readString();
//Serial.println(message);
//Serial.println("");
Serial.println("Serial2 available in blynk node:");
Serial.println(message);
messageReady = true;
//break;
}
// Only process message if there's one
if (messageReady)
{
Serial.println("Received from Serial2: " + message);
// The only messages we'll parse will be formatted in JSON
DynamicJsonDocument doc(1024); // ArduinoJson version 6+
// Attempt to deserialize the message
DeserializationError error = deserializeJson(doc, message);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
messageReady = false;
return;
}
if (doc["type"] == "Data")
{
Serial.println("Received Type = Data in Blynk Node");
double child1_temperature = doc["child1_temperature"].as<double>();
double child2_temperature = doc["child2_temperature"].as<double>();
doc["type"] = "response";
// Get data from virtual pin
doc["board_number"] = board;
doc["led"] = pin;
doc["status"] = pin_status;
//doc["child1_temperature"] = child1_temperature;
//doc["child2_temperature"] = child2_temperature;
Serial.println("Temperature Child 1: " + String(child1_temperature));
Serial.println("Temperature Child 2: " + String(child2_temperature));
serializeJson(doc, Serial2); // Sending data to another ESP32
//Serial.println("");
Serial.println("Sending Data - ");
serializeJson(doc, Serial); //{"type":"response","board_number":1/2,"led": pin_number, "status": 1/0}
// Update Blynk virtual pin
Blynk.virtualWrite(V5, child1_temperature);
Blynk.virtualWrite(V6, child2_temperature);
}
messageReady = false;
}
Blynk.run(); // Handling Blynk Services
}
Gateway Node
// Necessary Libraries
#include "painlessMesh.h"
#include <ArduinoJson.h>
#include <SPI.h>
#include <Wire.h>
#include <WiFi.h>
#include <WiFiClient.h>
// Serial2 pins of ESP32
#define RXD2 16
#define TXD2 17
// WiFi Credentials for Mesh Networking
#define MESH_PREFIX "meshnetwork"
#define MESH_PASSWORD "123456789"
#define MESH_PORT 5555
// Gateway Node ID:
// Variables
int led;
int led_status;
int board_number;
int board;
int pin;
int pin_status;
bool message_ready = true;
String message = "";
String msg1 = "";
int temp;
double child1_temperature;
double child2_temperature;
String DO,pH,Temp,Tds;
Scheduler userScheduler; // to control your personal task
painlessMesh mesh;
// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain/ Used to Broadcast Message to all Child Nodes
void send_request() ; // Sends data serially to Blynk Node
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );
Task taskSendRequest( TASK_SECOND * 1 , TASK_FOREVER, &send_request );
void sendMessage()
{
uint32_t nodeId = mesh.getNodeId();
msg1 = "Hello from Gateway Node with Node ID: " + String(nodeId);
DynamicJsonDocument doc(1024);
doc["board"] = board_number;
doc["pin"] = led;
doc["status"] = led_status;
doc["child1_temperature"] = child1_temperature;
doc["child2_temperature"] = child2_temperature;
doc["msg1"] = msg1;
//doc["status_1"] = led_status_1;
String msg ;
serializeJson(doc, msg);
mesh.sendBroadcast( msg );
//Serial.println("Gateway to Mesh Broadcast - " + msg);
// taskSendMessage.setInterval((TASK_SECOND * 1));
}
void send_request()
{
DynamicJsonDocument doc_request(1024);
doc_request["type"] = "Data";
doc_request["child1_temperature"] = child1_temperature;
doc_request["child2_temperature"] = child2_temperature;
//doc_request["Temp"] = temp;
Serial.print("Sending Request - ");
//Serial.println("IS Serial 2 available: " + Serial2.available());
serializeJson(doc_request, Serial); //{"type":"request"}
Serial.println("");
serializeJson(doc_request, Serial2);
//Serial.println("");
//taskSendMessage.setInterval((TASK_SECOND * 1));
}
// Needed for painless library
void receivedCallback( uint32_t from, String &msg ) {
//Serial.println("Received Callback of Gateway");
//Deserializing
String json;
DynamicJsonDocument doc(1024);
json = msg.c_str();
DeserializationError error = deserializeJson(doc, json);
if (error)
{
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
}
msg1 = doc["msg1"].as<String>();
child1_temperature = doc["child1_temperature"];
child2_temperature = doc["child2_temperature"];
Serial.print("Child 1 Temp: ");
Serial.println(child1_temperature);
Serial.print("Child 2 Temp: ");
Serial.println(child2_temperature);
Serial.println("Received in Gateway: " + msg1);
serializeJson(doc, Serial); //{"type":"Data"}
serializeJson(doc, Serial2);
}
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); // For Debugging purpose
Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2); // For sending data to another ESP32
//mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION );
//mesh.setDebugMsgTypes( ERROR | STARTUP | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES );
mesh.setDebugMsgTypes(ERROR | STARTUP );
// Initialize the mesh network
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
// Get and print the Node ID
uint32_t nodeId = mesh.getNodeId();
Serial.printf("Node ID: %u\n", nodeId);
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
userScheduler.addTask( taskSendMessage );
userScheduler.addTask( taskSendRequest );
taskSendMessage.enable();
taskSendRequest.enable();
// timer.setInterval(1000L, send_request);
}
void loop()
{
if(Serial2.available())
{
Serial.println("Serial 2 available in Gateway Node");
message = Serial2.readString();
message_ready = true;
}
//Serial.println("");
if(message_ready){
Serial.println("Received from Serial2: " + message);
//delay(2000); // delay here
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, message);
board_number = doc["board_number"];
led = doc["led"];
led_status = doc["status"];
//temp = doc["Temp"];
//msg1 = doc["msg1"];
//int temp = doc["Temp"].as<int>(); // Assuming Temp is of type int
// reason behind getting last temperature even when child node 1 is down
double child1_temperature = doc["child1_temperature"].as<double>();
double child2_temperature = doc["child2_temperature"].as<double>();
String msg1 = doc["msg1"].as<String>();
// it will run the user scheduler as well
//timer.run();
message_ready = false;
}
mesh.update();
delay(1000); // This delay ensures the Serial2 Communication resumes
}
Child Node 1
// Necessary Libraries
#include "painlessMesh.h"
#include <ArduinoJson.h>
//#include <DHT.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
// WiFi Credentials
#define MESH_PREFIX "meshnetwork"
#define MESH_PASSWORD "123456789"
#define MESH_PORT 5555
#define LED_PIN 2
// Data wire is plugged into port 4
#define ONE_WIRE_BUS 5
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
int led;
int led_status = 0;
int board_number = 0;
String msg1 = "";
String nodeName = "child1";
Scheduler userScheduler; // to control your personal task
painlessMesh mesh;
double child1_temperature;
double child2_temperature;
// Needed for painless library
void receivedCallback( uint32_t from, String &msg)
{
//Serial.println("receivedCallback of Child Node");
//Serial.printf("Received from Gatewau msg=%s \n", from, msg.c_str());
//Deserializing
String json;
//String msg1 = "";
DynamicJsonDocument doc(1024);
json = msg.c_str();
DeserializationError error = deserializeJson(doc, json);
if (error)
{
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
}
board_number = doc["board"];
led = doc["pin"];
led_status = doc["status"];
msg1 = doc["msg1"].as<String>();
child1_temperature = doc["child1_temperature"].as<double>();
child2_temperature = doc["child2_temperature"].as<double>();
Serial.println("");
Serial.println("Received in Child Node 1: " + json);
if (board_number == 1 && led_status == 1){
digitalWrite(led, led_status);
Serial.println("Child Node 1 ON");
}
else{
digitalWrite(led, !led_status);
//Serial.println("Child Node 1 OFF");
}
}
Task taskSendMessage( TASK_SECOND * 1, TASK_FOREVER, &sendMessage );
void sendMessage()
{
msg1 = "Hello from Child Node 1";
//mesh.sendBroadcast(msg1);
DynamicJsonDocument doc(1024);
// Tempature
//json doc
doc["type"] = "Data";
sensors.requestTemperatures();
//Serial.print("Celsius temperature: ");
//Serial.print(sensors.getTempCByIndex(0));
double temp = sensors.getTempCByIndex(0);
doc["child1_temperature"] = temp;
doc["Node Name"] = nodeName;
doc["msg1"] = msg1;
doc["led_status"] = led_status;
String msg ;
serializeJson(doc, msg);
mesh.sendBroadcast( msg );
//Serial.println("");
//Serial.println("Mesh Broadcast Sensor Data from Child Node - " + 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);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN,LOW);
sensors.begin();
//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION ); // set before init() so that you can see startup messages
//mesh.setDebugMsgTypes( ERROR | STARTUP | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES ); // set before init() so that you can see startup messages
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
Serial.println("\n");
mesh.onReceive(&receivedCallback);
Serial.println("\n");
mesh.onNewConnection(&newConnectionCallback);
Serial.println("\n");
mesh.onChangedConnections(&changedConnectionCallback);
Serial.println("\n");
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
Serial.println("\n");
userScheduler.addTask( taskSendMessage );
Serial.println("\n");
taskSendMessage.enable();
}
void loop() {
// it will run the user scheduler as well
mesh.update();
}
Child Node 2
// Necessary Libraries
#include "painlessMesh.h"
#include <ArduinoJson.h>
//#include <DHT.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
// WiFi Credentials
#define MESH_PREFIX "meshnetwork"
#define MESH_PASSWORD "123456789"
#define MESH_PORT 5555
#define LED_PIN 2
// Data wire is plugged into port 4
#define ONE_WIRE_BUS 5
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
int led;
int led_status = 0;
int board_number = 0;
String msg1 = "";
String nodeName = "child2";
Scheduler userScheduler; // to control your personal task
painlessMesh mesh;
double child1_temperature;
double child2_temperature;
// Needed for painless library
void receivedCallback( uint32_t from, String &msg)
{
//Serial.println("receivedCallback of Child Node");
//Serial.printf("Received from Gatewau msg=%s \n", from, msg.c_str());
//Deserializing
String json;
//String msg1 = "";
DynamicJsonDocument doc(1024);
json = msg.c_str();
DeserializationError error = deserializeJson(doc, json);
if (error)
{
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
}
board_number = doc["board"];
led = doc["pin"];
led_status = doc["status"];
msg1 = doc["msg1"].as<String>();
child1_temperature = doc["child1_temperature"].as<double>();
child2_temperature = doc["child2_temperature"].as<double>();
Serial.println("");
Serial.println("Received in Child Node 2: " + json);
if (board_number == 2 && led_status == 1){
digitalWrite(led, led_status);
Serial.println("Child Node 2 ON");
}
else{
digitalWrite(led, !led_status);
//Serial.println("Child Node 2 OFF");
}
}
Task taskSendMessage( TASK_SECOND * 1, TASK_FOREVER, &sendMessage );
void sendMessage()
{
msg1 = "Hello from Child Node 2";
//mesh.sendBroadcast(msg1);
DynamicJsonDocument doc(1024);
// Tempature
//json doc
doc["type"] = "Data";
sensors.requestTemperatures();
//Serial.print("Celsius temperature: ");
//Serial.print(sensors.getTempCByIndex(0));
double temp = sensors.getTempCByIndex(0);
doc["child2_temperature"] = temp;
doc["Node Name"] = nodeName;
doc["msg1"] = msg1;
doc["led_status"] = led_status;
String msg ;
serializeJson(doc, msg);
mesh.sendBroadcast( msg );
//Serial.println("");
//Serial.println("Mesh Broadcast Sensor Data from Child Node - " + 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);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN,LOW);
sensors.begin();
//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION ); // set before init() so that you can see startup messages
//mesh.setDebugMsgTypes( ERROR | STARTUP | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES ); // set before init() so that you can see startup messages
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
Serial.println("\n");
mesh.onReceive(&receivedCallback);
Serial.println("\n");
mesh.onNewConnection(&newConnectionCallback);
Serial.println("\n");
mesh.onChangedConnections(&changedConnectionCallback);
Serial.println("\n");
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
Serial.println("\n");
userScheduler.addTask( taskSendMessage );
Serial.println("\n");
taskSendMessage.enable();
}
void loop() {
// it will run the user scheduler as well
mesh.update();
}
More Details:
- I have ensured that for the Serial2 communication, the RX and TX pins of Blynk Node are connected to TX and RX pins of Gateway Node.
- Every connection in the circuit is proper ensuring that these issues are not due to any connection fault.
Can Anyone help me with these issues:
- Serial2 communication should not be stopped without adding Delay in Gateway Node.
- Multiple Child Nodes Temperature Reading should be visible on the Blynk Console simultaneously.
Thanks :)