painlessMesh and Serial2 communication is not working simultaneously

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 :

  1. ESP 32 Nodes (Blynk Node, Gateway Node and Child Nodes)
  2. 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:

image

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:

  1. Serial2 communication should not be stopped without adding Delay in Gateway Node.
  2. Multiple Child Nodes Temperature Reading should be visible on the Blynk Console simultaneously.

Thanks :slight_smile:

I doubt very much if any forum members will be able to help with this, as it’s an architecture that you wouldn’t normally see in a Blynk project.

What’s the primary reason for choosing this architecture? Are you doing this to reduce the Blynk device count, to overcome WiFi signal strength issues, or for some other reason?

Pete.

1 Like

Well Thanks for the reply Sir, this is a part of my project to reduce manual work of getting parameters value from fields. So this Architecture of Mesh Network will be useful to get the parameter(temperature) values from each Child Nodes in Mesh Network then store it in Database for further analysis. If you could help me with this, then it would be of great help. Thanks

I can’t personally help you with this, as I have no experience of this architecture. And as I pointed-out, I think you’ll be extremely lucky to find any forum members who have adopted a similar architecture.

Your issues sound like something relating to the “painless” mesh system you’ve adopted. Is there a user forum for this system where you could obtain some help?

Pete.

1 Like

I have a set up similar to what you describe, I think, but to be clear I’ll outline what I have. I have an ESP32 I call ‘gateway’ this runs BlynkIOT and is connected by WiFi to my LAN. I have a Painless mesh root node running on another ESP32 calle ‘bridge’. I then have 6 other (child) Painlessmesh nodes running on ESP8266’s. The bridge and the gateway are linked by Txl / Rx1 on both devices, I use the SerialTranfer library for communication between the bridge and gateway. The bridge has bi-directional communication with both the child nodes and the gateway. Thus a child node sends its data to the briddge and the bridge sends it data to the gateway. The gateway sends / recieves the data to Blynk as appropriate. I use structures to transfer data in all cases, except the Blynk part, and the structures have to identical on both sender and receiver.
I suggest you Google Ralph McCleary who has done an excellent and extensive write up on using Painless mesh along with Blynk and that is where I got inspiration for my set up from. Ralph has a Github where all the information is located.
In the end I did not use the system as my need changed and that system added complexity = unreliability I didn’t need. It did work very well through the design evaluation process.

2 Likes

Okay Sir, np, Thanks though :raised_hands:

Okay I See, thanks man. I will read the Ralph’s write up you suggested. Btw we almost have a similar setup :raised_hands:

Hey, can you give me the write up linl by Ralph McCleary, I didn’t find it on Google :slightly_smiling_face:

GitHub - macca448/Blynk2MESH: Lifestyle Property Asset Monitoring & Control System. This link should get you to the Github, then drill down to get the extensive information provided. There is a lot to read but it is well worth the time and effort. Ralph has worked through a lot of the issues. FWIW fundamentally the Wifi shouldn’t interfere with the serial. However, as you will read Ralph DID experience a clash with Blynk.
https://github.com/macca448/Blynk2MESH/blob/main/current/node1/node1.ino. This link will take to one of Ralph’s nodes.

1 Like

Thanks Bob! I was a bit busy with other work.