MQTT does not connect properly (ESP8266)

Sorry for posting this here, but I have been looking for a while and I just can’t find the problem. I have some sensors on a NodeMCU that should send data to my Raspberry Pi using MQTT. The NodeMCU connects to wifi and MQTT successfully, but no message is being sent. I tried using a premade script, which had the same problem. This is the script:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
 
const char* ssid = "wifi-ssid";                   // wifi ssid
const char* password =  "wifipassword";         // wifi password
const char* mqttServer = "ipn.umb.e.rrr";    // IP adress Raspberry Pi
const int mqttPort = 1883;
const char* mqttUser = "mqtt-user";      // if you don't have MQTT Username, no need input
const char* mqttPassword = "mqttpassword";  // if you don't have MQTT Password, no need input

WiFiClient espClient;
PubSubClient client(espClient);
 
void setup() {
 
  Serial.begin(115200);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connected to the WiFi network");
 
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);
 
  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");
 
    if (client.connect("ESP8266Client", mqttUser, mqttPassword )) {
 
      Serial.println("connected");  
 
    } else {
 
      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);
 
    }
  }
 
  client.publish("esp/test", "Hello from ESP8266");
  client.subscribe("esp/test");
 
}
 
void callback(char* topic, byte* payload, unsigned int length) {
 
  Serial.print("Message arrived in topic: ");
  Serial.println(topic);
 
  Serial.print("Message:");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
 
  Serial.println();
  Serial.println("-----------------------");
 
}

This is my serial:

Connecting to WiFi..
Connected to the WiFi network
Connecting to MQTT...
connected

After this, no message is sent.

Further info:

Mosquitto broker options:

logins: []
anonymous: true
customize:
  active: false
  folder: mosquitto
certfile: fullchain.pem
keyfile: privkey.pem
require_certificate: false

configuration.yaml snippet

mqtt:
  broker: ipn.umb.e.rrr
  username: mqtt-user
  password: mqttpassword

sensor:
- platform: mqtt
  name: "Test"
  state_topic: "esp/test"
  unit_of_measurement: "ºC"

The NodeMCU seems to connect to the broker, which confuses me even more:

1620242545: New client connected from 192.168.1.19 as ESP8266Client (p2, c1, k15).

I don’t use the broker on Home Assistant, mostly because I started my home IOT on Node Red and many of my nodes are inside walls or electrical boxes and I don’t want to open them u to reprogram to a new broker.

What you need is https://mqtt-explorer.com/ to monitor what’s going on. Subscribe to esp/test and see if your MQTT publish is working.

I have tried sending a test message to the broker with mqtt-explorer, and this arrived at my home assistant. However, even though my NodeMCU connects to it, the messages aren’t being sent through.

Hi
did you try to add a loop()-Function in you code?

void loop()
{
  client.loop();
}

Most of the examples for PubSubClient I have seen ( and as I have it in my code), have a “reconnect” function and call that ( and client.loop) from loop().

Armin

I did this, and it worked for a bit. However, upon restarting home assistant the sensor readings stopped coming through again, despite connecting to the broker

Hi

This is, a bit simplified, what I have (only publishing, no subscription), the part reading temperature, humidity and such from a BME680 is missing, also headers, declarations and setup
the loop sleeps for one second to check for OTA and requests for the debug server, but publishing to mqtt is done only every 60 seconds
Might also be important, I’m running HA core in a python venv, no docker containers, mqtt is also manually installed and configured

in comparison to the code you posted earlier, the call to “publish” is in the loop(), otherwise it is done only once during setup. Reconnect is used in most examples because the NodeMCU might have lost the connection

void reconnect()
{
  while (!client.connected())
  {
    debugI("Reconnecting");
    if (!client.connect(HOST_NAME, MQTT_USER, MQTT_PW))
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" retrying in 5 seconds");
      debugV("failed, rc=%d retrying in 5 seconds",client.state());
      delay(5000);
    }
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  StaticJsonDocument<200> doc;
  ArduinoOTA.handle();
  Debug.handle();

  if (!client.connected())
  {
    reconnect();
  }
  client.loop();
  sleepcount+=1;
  if(sleepcount >= 60)
  {
	// code to build pubMsg removed  
    client.publish("sensors/bme680", pubMsg);
    digitalWrite(LED, LOW);  //Led port ausschalten
    delay(500);             //500ms Pause
    digitalWrite(LED, HIGH); //Led port einschalten
    sleepcount=0;
  }	
  delay(sleeptime);
}

will check later again, have to go back to work… which in these days means to switch the input for my monitor back to the company laptop

Armin

Checking that the client is connected in loop() is important.

Thank you for the quick responses! I have migrated from MQTT to ESPHome, as I was not able to get a reliable connection. Sometimes it would send data, but more often it would completely stop.

That’s why I don’t think my code is wrong (I have added a reconnect in the loop so that is alright) but the data was not being sent reliably anyway.

Using ESPHome I am at least getting some data in (a lot is still lost somehow, but that’s a problem for another day)