MQTT no callback - PubSubClient - ESP32

@KennethLavrsen @AaronCake Thank you both for that, I believe it was a combination of a few things, and as it comes up on the forum 50 times without a solution I’m going to try and explain it so when I forget 3 weeks later I can do it again… :sweat_smile: :sweat_smile:

I had already established a connection which was confirmed via the MQTT mosquito broker log:

1598398605: New client connected from 192.168.0.34 as brainESP32 (p2, c1, k15, u'*****').

When I set up my switch as above I could confirm it was being published to the broker via configurations>intergrations>(MQTT)configure. when I typed a ‘#’ in the listen to a topic box and started listening I could see the message being published:

Message 15 received on office/light1/switch at 9:40:
ON
QoS: 0 - Retain: false

Based on @KennethLavrsen advise I had to include client.subscribe("office/light1/switch"); this was missed when following the mqtt_basic example. again thank you, I slotted this in the reconnect loop:

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(ID, HA_USER, HA_PASS)) {
      Serial.println("connected");
      //publish test connection
      client.publish("outTopic", "hello world");
      //subscribe to topics
      client.subscribe("office/light1/switch");
    }
    else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }

Additionally, as I had changed my configuration.yaml so much to get it to work I was using the original "/office/light1/switch/" i used to subscribe likewise. Again @KennethLavrsen pointed out it should as per the outgoing message to the broker so after rechecking the configuration.YAML I had to update the Arduino code accordingly by removing the ’ / ’ on either end:

("office/light1/switch") vs ("/office/light1/switch/") 

This resulted in the message passing successfully!!!:

10:20:25.075 -> Topic: office/light1/switch

So now we can read but the read is not executing as expected. therefor I added under Serial.println(topicStr) to check the payload message as per the comparison I was doing below:

Serial.print("payload: ");
Serial.println(payload[0]);

and when i ran it again received on the ardiuno serial monitor:

10:50:13.315 -> Topic: office/light1/switch
10:50:13.315 -> payload: 79

Still, it is not working but this is OK as I’m using a comparison of:
if (payload[0] == 'ON') /if (payload[0] == 'OFF')
and 79 is not ‘ON/OFF’ rather it is the first byte ‘O’ in ASCII. So some slight changes to look at the payload as a string will fix this:

payload[length] = '\0';
String payloadStr = String((char*)payload);

Then change if (payload[0] == 'ON') /if (payload[0] == 'OFF') to if (payloadStr == 'ON') /if (payloadStr == 'OFF')

So at this point, it works, BUT!!! The next step is to incorporate @AaronCake warning and removing the Publishing from the callback as per the PubSubClient and instead set a flag. sure it works, but this could lead to issues later on, so better safe than sorry

This leaves me with:

#include <ArduinoJson.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <WiFiManager.h>

unsigned long updateCurrentMillis;
unsigned long lastUpdateDelay;
unsigned long updateDelay = 1000;

// MQTT Network
const char* mqtt_server = "192.168.0.200";
//Node ID
const char *ID = "brainESP32";  // Name of our device, must be unique
//Topics
const char *TOPIC = "room/light";  // Topic to subcribe to
const char *STATE_TOPIC = "room/light/state";  // Topic to publish the light state to
int officeLight1Status;

// Home Assistant Credentials
const char *HA_USER = "****";
const char *HA_PASS = "****";

WiFiClient espClient;
PubSubClient client(espClient);

void callback(char* topic, byte* payload, unsigned int length) {
  String topicStr = topic;
  String payloadStr = String(( char *) payload);
  Serial.print("Topic: ");
  Serial.println(topicStr);
  payload[length] = '\0';
  String s = String((char*)payload);
  Serial.println(s);
  if (topicStr == "office/light1/switch") {
    //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
    if (s == "ON") {
      Serial.println("light on");
      officeLight1Status = 1;
    }

    //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
    else if (s == "OFF") {
      Serial.println("light off");
      officeLight1Status = 0;
    }
  }
}

// Reconnect to client
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(ID, HA_USER, HA_PASS)) {
      Serial.println("connected");
      //publish test connection
      client.publish("outTopic", "hello world");
      //subscribe to topics
      client.subscribe("office/light1/switch");
    }
    else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  
  setup_wifi(); // Connect to network
  delay(1500);
}

void setup_wifi() {
  Serial.print("\nConnecting to ");
  //WiFiManager
  WiFiManager wifiManager;
  Serial.println("started");
  //wifiManager.resetSettings(); // turn off after intital settings are done ****** turn on if needing to resetup wifi
  wifiManager.setCustomHeadElement("<style>html{filter: invert(40%); -webkit-filter: invert(40%);}</style>");
  WiFiManagerParameter custom_text("<p>This is just a text paragraph</p>");
  wifiManager.addParameter(&custom_text);
  wifiManager.setAPStaticIPConfig(IPAddress(100, 100, 100, 100), IPAddress(100, 100, 100, 100), IPAddress(255, 255, 255, 0));
  wifiManager.autoConnect();

  while (WiFi.status() != WL_CONNECTED) { // Wait for connection
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}


void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  delay(100);
  if (officeLight1Status != 3)  {
    if (officeLight1Status == 1) {
      client.publish("office/light1/status", "ON");
    }
    else client.publish("office/light1/status", "OFF");
    officeLight1Status = 3;
  }
  updateCurrentMillis = millis(); //send update every x seconds
  if (updateCurrentMillis - lastUpdateDelay >= updateDelay) {
    lastUpdateDelay = updateCurrentMillis;
    switchOut();  //dump data
  }
}

void switchOut() {
  const size_t capacity = JSON_OBJECT_SIZE(26);
  DynamicJsonDocument doc1(capacity);
  DynamicJsonDocument doc2(capacity);
  doc1["pbrAM"] = 0;
  doc1["pbrSS"] = 0;
  doc1["lightAM"] = 0;
  doc1["lp_1"] = 0;
  doc1["lp1_1"] = 0;
  doc1["lp1_2"] = 0;
  doc1["lp1_3"] = 1;
  doc1["lp1_4"] = 0;
  doc1["lp_2"] = 0;
  doc1["lp2_1"] = 1;
  doc1["lp2_2"] = 0;
  doc1["lp2_3"] = 0;
  doc1["lp2_4"] = 0;
  char buffer[256];
  size_t n = serializeJson(doc1, buffer);
  client.publish("brainOut1", buffer, n);
  doc2["tempAM"] = 0;
  doc2["tempSS"] = 1;
  doc2["airAM"] = 0;
  doc2["airSS"] = 0;
  doc2["doseAM"] = 0;
  doc2["doseSS"] = 1;
  doc2["dosephU"] = 0;
  doc2["dosepHD"] = 0;
  doc2["doseNut"] = 0;
  doc2["doseSam"] = 0;
  doc2["doseFill"] = 0;
  doc2["harvsetAM"] = 0;
  doc2["harvestSS"] = 0;
  n = serializeJson(doc2, buffer);
  client.publish("brainOut2", buffer, n);
}

Again thank you for the help guys!