Help with MQTT + Mesh integration

I have both mesh network and MQTT-hivemq working separately I just would like to combine them together where the esp32's will relay their information to the root esp32 and relay to hivemq. I'm also using a sensor dashboard called virtuino to display the data in real time as well to control the onboard led. Currently I'm having issues implementing the mesh network which causes my real time data to stop. Can I get some advice on how to properly implement.

#include <WiFi.h>  
#include <painlessMesh.h>
#include <PubSubClient.h>
#include <WiFiClientSecure.h>
 
#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555
 
void receivedCallback( const uint32_t &from, const String &msg );
void mqttCallback(char* topic, byte* payload, unsigned int length);
 
painlessMesh  mesh;
 
//---- WiFi settings
const char* ssid = "";
const char* password = "";
 
#define HOSTNAME "MQTT_Bridge"
 
//---- MQTT Broker settings
const char* mqtt_server = ""; 
const char* mqtt_username = "";
const char* mqtt_password = "";
const int mqtt_port =8883;
 
WiFiClientSecure espClient;   
PubSubClient client(espClient);
unsigned long lastMsg = 0;
 
#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];
 
int sensor1 = 0;
float sensor2 = 0;
int command1 =0;
 
const char* sensor1_topic= "sensor1";
const char*  sensor2_topic="sensor2";
//const char*  sensor2_topic="sensor3";
 
const char* command1_topic="command1";
//const char* command1_topic="command2";
 
 
static const char *root_ca PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
)EOF";
 
 
//==========================================
void setup_wifi() {
  delay(10);
  Serial.print("\nConnecting to ");
  Serial.println(ssid);
 
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("\nWiFi connected\nIP address: ");
  Serial.println(WiFi.localIP());
}
 
 
//=====================================
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    String clientId = "ESP8266Client-";   // Create a random client ID
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {
      Serial.println("connected");
 
      client.subscribe(command1_topic);   // subscribe the topics here
      //client.subscribe(command2_topic);   // subscribe the topics here
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");   // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
 
//================================================ setup
//================================================
void setup() {
  Serial.begin(9600);
  while (!Serial) delay(1);
  setup_wifi();
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
 
  mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION );  // set before init() so that you can see startup messages
 
  mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT, WIFI_AP_STA, 6 );
  mesh.onReceive(&receivedCallback);
  mesh.stationManual(STATION_SSID, STATION_PASSWORD);  
  mesh.setHostname(HOSTNAME);
  mesh.setRoot(true);
  mesh.setContainsRoot(true);
 
  #ifdef ESP8266
    espClient.setInsecure();
  #else   // for the ESP32
    espClient.setCACert(root_ca);      
  #endif
 
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
}
 
 
void loop() {
  mesh.update()
  if (!client.connected()) reconnect();
  client.loop();
 
  //---- example: how to publish sensor values every 5 sec
  unsigned long now = millis();
  if (now - lastMsg > 5000) {
    lastMsg = now;
    sensor1= random(50);       
    sensor2= 20+random(80);    
    publishMessage(sensor1_topic,String(sensor1),true);    
    publishMessage(sensor2_topic,String(sensor2),true);
 
  }
}
 
void callback(char* topic, byte* payload, unsigned int length) {
  String incommingMessage = "";
  for (int i = 0; i < length; i++) incommingMessage+=(char)payload[i];
 
  Serial.println("Message arrived ["+String(topic)+"]"+incommingMessage);
 
  //--- check the incomming message
    if( strcmp(topic,command1_topic) == 0){
     if (incommingMessage.equals("1")) digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on 
     else digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off 
  }
 
   //  check for other commands
 /*  else  if( strcmp(topic,command2_topic) == 0){
     if (incommingMessage.equals("1")) {  } // do something else
  }
  */
}
 
void publishMessage(const char* topic, String payload , boolean retained){
  client.publish(topic, (byte*) payload.c_str(), 10, true);
  Serial.println("Message publised ["+String(topic)+"]: "+payload);
}
 
void receivedCallback( const uint32_t &from, const String &msg ) {
  Serial.printf("bridge: Received from %u msg=%s\n", from, msg.c_str());
  String topic = "painlessMesh/from/" + String(from);
  client.publish(topic.c_str(), msg.c_str());
}
void mqttCallback(char* topic, uint8_t* payload, unsigned int length) {
  char* cleanPayload = (char*)malloc(length+1);
  payload[length] = '\0';
  memcpy(cleanPayload, payload, length+1);
  String msg = String(cleanPayload);
  free(cleanPayload);
 
  String targetStr = String(topic).substring(16);
 
  if(targetStr == "gateway")
  {
    if(msg == "getNodes")
    {
      auto nodes = mesh.getNodeList(true);
      String str;
      for (auto &&id : nodes)
        str += String(id) + String(" ");
      client.publish("painlessMesh/from/gateway", str.c_str());
    }
  }
  else if(targetStr == "broadcast") 
  {
    mesh.sendBroadcast(msg);
  }
  else
  {
    uint32_t target = strtoul(targetStr.c_str(), NULL, 10);
    if(mesh.isConnected(target))
    {
      mesh.sendSingle(target, msg);
    }
    else
    {
      client.publish("painlessMesh/from/gateway", "Client not connected!");
    }
  }
}

Hi @xgr1mx
I have been facing the same issues with painlessMesh connecting to Arduino IOT Cloud.

When I can I’ll compare my code with yours. Maybe together we can resolve!

I’ll be following this thread.

Good luck

Post code to the forum and not to any external (temporary) site!

Alright, done.

Yes, that would be great!

My understanding of the painlessMesh network is that it uses the WiFi hardware of the ESP to build it's own network but the ESP cannot be in a router based WiFi network at the same time.

painlessMesh is not IP networking

painlessMesh does not create a TCP/IP network of nodes. Rather each of the nodes is uniquely identified by its 32bit chipId which is retrieved from the esp8266/esp32 using the system_get_chip_id() call in the SDK. Every node will have a unique number. Messages can either be broadcast to all of the nodes on the mesh, or sent specifically to an individual node which is identified by its `nodeId.

is there any work around? I know you can communicate via serial with a raspberry pi via the root node communicating with the other nodes but just seems a little overboard.

I have the same concerns/confusion but the mqqt bridge example implies otherwise. Could it be switching between mesh and external server?

I have actually had this running from time to time but after refactoring it is failing to maintain all the connections - so it is work in progress :blush:

No, the basic concept of that mesh network doesn't allow what you want.

That's a solution. You don't need a Raspberry Pi, another ESP32 connected serially to the root node may do the same job, you just need another WiFi hardware not being part of the mesh network to connect to your router's WiFi network.

Theoretically it can but you might miss an important message on the mesh network while connected to the router's WiFi network. I would expect such a system to never run reliably.

Check out https://www.hackster.io/davidefa/esp32-wireless-mesh-made-easy-with-painlessmesh-part-3-982af1

I did see that and I got my SD card module in today. Has this worked for you?

I won’t be able to sit down with this until next week. I am currently travelling. I posted it to show that bridge mode does connect painlessMesh to MQTT

Got you. Yes it seems like it's possible.

Hi @xgr1mx
Some good news - I have reverted to an older version of my code and I can confirm, again, that we can bridge from a painlessMesh to MQTT using a singe device as the bridge.

Currently, I have

  • 4 ESP8266 with temperature sensors feeding temp values to the mesh root every 10 seconds
  • 1 ESP32 WROOM on devkit 01 with the 5th temperature sensor and acting as the bridge to Arduino IoT Cloud (AIoTC) and sending push notifications using espProwl to my mobile.
  • With the AIoTC dashboard I can track all the values
    It is working fine without crashing or dropping mesh connections

Next steps:

  1. Load your code and compare it with the MQTT bridge example in the painlessMesh code
  2. Compare my working code with both in code sets
  3. Refactor my newer project to work!

I'll keep you updated with progress :smile:

.

Hi @xgr1mx

Some differences which maybe significant?
In your code your are missing ; on mesh.update(); so it shouldn't compile?

In the mqttBridge.ino example from painlessMesh.h, you don't have the setClient(wifiClient) function

  mqttClient.setServer(mqttBroker, MQTTPORT);
  mqttClient.setCallback(mqttCallback);  
  mqttClient.setClient(wifiClient);

Otherwise your code matches well with both the example and the code in

Let me know if this helps

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.