MQTT dimmer control with ESP8266 — message received but no action

Excuse my english, I hope my question is clear.

I try to control my rbdimmer module with MQTT from my Home Assistant via an ESP8266 (Wemos D1 Mini). The MQTT message arrive at the broker — I can see it in Mosquitto logs — but the dimmer do nothing.

Here is my code:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <RBDdimmer.h>

const char* ssid = "MyWiFi";
const char* password = "********";
const char* mqtt_server = "192.168.1.100";

RBDdimmer dimmer(D5, D6);  // output, zerocross
PubSubClient client;

void callback(char* topic, byte* payload, unsigned int length) {
  char msg[length + 1];
  memcpy(msg, payload, length);
  msg[length] = '\\0';
  int power = atoi(msg);
  dimmer.setPower(power);
}

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  dimmer.begin(NORMAL_MODE, ON);
}

void loop() {
  if (!client.connected()) {
    client.connect("esp-dimmer");
    client.subscribe("dimmer/set");
  }
  client.loop();
}

In Mosquitto log I see the client connect briefly then disconnect. I publish dimmer/set with payload 50 from Home Assistant but the lamp stay at whatever level it was.

I think maybe the callback function is never called? But the MQTT message arrive at the broker, I can confirm this.

Pretty sure this is a PubSubClient initialization issue.

Look at your declaration:

PubSubClient client;

You’re creating the MQTT client without passing a WiFiClient object. PubSubClient needs a network transport layer — without it, client.connect() fails silently every time.

The correct pattern is:

WiFiClient wifiClient;
PubSubClient client(wifiClient);

What’s happening: client.connect() returns false immediately because there’s no underlying TCP client to establish the connection. The brief connect you see in Mosquitto logs is probably the TCP handshake starting but never completing properly — or maybe you’re seeing a different client connecting.

IIRC PubSubClient doesn’t throw any error when the WiFiClient is missing, it just silently fails. That’s why your callback never fires — the MQTT session was never actually established.

Try adding the WiFiClient and see if that fixes it.

Oh! I think you are right Felix. I declare PubSubClient client; without the WiFiClient parameter.

I was confused because in the Mosquitto log I see a connection event and I think it was my ESP. But now I check more carefully — the client ID in the log is different. It was my Node-RED client that connect at the same time, not the ESP.

Let me fix this and test. I will change to:

WiFiClient wifiClient;
PubSubClient client(wifiClient);

I also add a Serial.print to check if client.connect() return true or false. I should have done this from the beginning — excuse me, this is a basic debugging step that I miss.

It work! After the fix the ESP connect properly to Mosquitto and the callback function is called.

Here is my corrected code for anyone who have the same problem:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <RBDdimmer.h>

const char* ssid = "MyWiFi";
const char* password = "********";
const char* mqtt_server = "192.168.1.100";

RBDdimmer dimmer(D5, D6);
WiFiClient wifiClient;                // <-- this was missing
PubSubClient client(wifiClient);       // <-- pass WiFiClient here

void callback(char* topic, byte* payload, unsigned int length) {
  char msg[length + 1];
  memcpy(msg, payload, length);
  msg[length] = '\\0';
  int power = atoi(msg);
  dimmer.setPower(power);
  Serial.printf("MQTT: set power to %d\
", power);
}

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  dimmer.begin(NORMAL_MODE, ON);
}

void loop() {
  if (!client.connected()) {
    if (client.connect("esp-dimmer")) {
      client.subscribe("dimmer/set");
      Serial.println("MQTT connected");
    }
  }
  client.loop();
}

Now I send dimmer/set with payload 75 from Home Assistant and the lamp go to 75% immediately. The problem was exactly what Felix say — without WiFiClient, the TCP connection never establish properly.

Thank you Felix, this save me many hours of debugging.

Nice one! Glad it was an easy fix.

For future reference — AFAIK every PubSubClient example in the Arduino library includes WiFiClient in the constructor. It’s easy to miss if you copy-paste from a partial example or write it from memory.

One small suggestion: add a reconnect delay to your loop so you’re not hammering the broker with connection attempts if it goes down:

void loop() {
  if (!client.connected()) {
    unsigned long now = millis();
    if (now - lastReconnect > 5000) {
      lastReconnect = now;
      if (client.connect("esp-dimmer")) {
        client.subscribe("dimmer/set");
      }
    }
  }
  client.loop();
}

This way you try reconnecting every 5 seconds instead of every loop iteration. YMMV but I’ve found this much more stable for long-running installs.

Good suggestion Felix, I add the reconnect delay.

For the complete guide on MQTT with rbdimmer modules, I found this page very helpful:
https://rbdimmer.com/faq/ac-dimmer-via-mqtt-with-esp32-and-esp8266-25

It cover both ESP8266 and ESP32 with PubSubClient and also explain the MQTT topic structure for multi-channel setup.

To resume my problem for anyone who search for this:

  • Symptom: MQTT message arrive at broker but dimmer do nothing
  • Cause: PubSubClient client; without WiFiClient — the TCP connection fail silently
  • Fix: Declare WiFiClient wifiClient; then pass it: PubSubClient client(wifiClient);
  • How to debug: Check client.connect() return value with Serial.print

[SOLVED]