Hi all, I'm hoping you can help me clarify a point on MQTT and topic subscription.
I am working on an ESP32 Dev board for a project that both publishes to MQTT topics, and subscribes to control variables, using the PubSubClient library. I have a Digital Ocean machine running Mosquitto server, and Node Red to handle the published data from the ESP32 onto a dashboard along with controls that the ESP32 is subscribed to.
The publishing of the topics from the MCU is working just fine. The subscription however doesn't seem to work - the first step I have in Void Callback() is a Serial.print line which I use to debug and check that the message is arriving from the MQTT server.
To check where I am going wrong I have stripped back the code for my project and put just the essentials into the PubSubClient example file mqtt_basic. I have also installed MQTT Explorer on my PC, and using that I can see both the messages published by the MCU, and the messages published by the Mosquitto server via Node Red. As such I definitely know that the messages are being sent out from the server just fine.
This is the code that I am using to test the MQTT usage. It's the PubSubClient example with as little changed as possible:
#include <SPI.h>
#include <Ethernet.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <NTPClient.h>
#define ssid "**********"
#define password "**********"
#define mqttServer "***.***.***.***"
#define mqttUser "**********"
#define mqttPass "**********"
#define mqttTime "BrewKettle/time"
//NTP Client for time retrieval
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
long now;
String formattedTime;
char strTime [9];
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i=0;i<length;i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
WiFiClient ethClient;
PubSubClient client(ethClient);
void reconnect() {
// Loop until we're reconnected
delay(1500);
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("arduinoClient", mqttUser, mqttPass)) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("BrewKettle/inTemp","hello world");
// ... and resubscribe
client.subscribe("BrewKettle/*");
//client.subscribe("BrewKettle/heat1");
//client.subscribe("BrewKettle/heat2");
//client.subscribe("BrewKettle/pump");
//client.subscribe("BrewKettle/state");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup()
{
Serial.begin(115200);
client.setServer(mqttServer, 1883);
client.setCallback(callback);
// Initialise Serial output, connect to Wifi
Serial.begin(115200);
Serial.println("Setting up Wifi");
WiFi.begin(ssid, password);
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Failed to connect to Wifi");
}else{
Serial.println("Wifi Connected");
}
// Allow the hardware to sort itself out
delay(1500);
Serial.println("Setting Up");
//Initialise NTPClient for time retrieval
timeClient.begin();
}
void loop()
{
if (!client.connected()) {
reconnect();
}
client.loop();
if((millis()-now)>3000) {
timeClient.forceUpdate();
formattedTime = timeClient.getFormattedTime();
strcpy(strTime, formattedTime.c_str());
Serial.print("Last update: ");
Serial.println(strTime);
client.publish(mqttTime, strTime);
now = millis();
}
}
I might be wrong, but even with the actual functionality of my full project stripped out, from this I should be seeing a message printed out on the Serial Monitor any time a message under one of the subscribed topics is sent. As it is all I see over the Serial Monitor in the Arduino IDE are the time updates, even though I see the subscribed values change on MQTT Explorer running on my PC. Could you help me figure out why my code isn't subscribing correctly?
To be honest, I don't have a great understanding on how this library works, even after trying to read up on it. I especially don't understand how the Callback() function works, how it is called, and how that makes the subscription work.
I wondered if there is a problem with timing and conflicts, but that seems unlikely.
Many thanks for any help!