Controll Relay with ESP32 via MQTT issues

Hi everyone,

i am running node red on a raspberry pi 4 and want to controll one or more relays on the dashboard.
Also i want send sensor values from my ESP32 to the dashboard.

Sending the sensor values works already fine, i can display them in a chart or gauge.

But i cannot controll the relay and i cant find the issue.
It seems like the broker is working, the message gets send out to the right topic.
I can see that in the debugger in node red.
But the ESP32 doesnt seem to correctly subscribe to the MQTT topic.

Here is the code, from randomnerdtutorials, just modified.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>




// Replace the next variables with your SSID/Password combination
const char* ssid = "**********";
const char* password = "********";

// Add your MQTT Broker IP address, example:
//const char* mqtt_server = "192.168.1.144";
const char* mqtt_server = "192.168.0.219";

WiFiClient espClient;
PubSubClient client(espClient);

long lastMsg = 0;
char msg[50];
int value = 0;

int Fuellstand = 26;
unsigned long lastMillis = 0;

int relais_one = 27; //Testrelay




void setup() {
  Serial.begin(115200);
  // default settings
  // (you can also pass in a Wire library object like &Wire2)
  
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

   pinMode(relais_eins,OUTPUT);
   pinMode(Fuellstand,INPUT);

   digitalWrite(relais_eins, HIGH);

    
}

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;
  
  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }
  Serial.println();

  // Feel free to add more if statements to control more GPIOs with MQTT

  if (String(topic) == "output") {
  Serial.print("changing output to");
  if (messageTemp == "on") {
    Serial.println("on");
    digitalWrite(relais_one, HIGH);
    delay(200);
  }
  else if (messageTemp == "off") {
    Serial.println("off");
    digitalWrite(relais_one, LOW);
     delay(200);
  }
}

  // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". 
  // Changes the output state according to the message

  }


void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("espClient")) {
      Serial.println("connected");
      // Subscribe
      client.subscribe("output");
      client.subscribe("hello");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
void loop() {
  if (!client.connected()) {
    reconnect();
  client.loop();
}



// publish a message roughly every second.
  if (millis() - lastMillis > 1000) {
    
    lastMillis = millis();
    Fuellstand = digitalRead(26);
    
    char fuellString[8];
dtostrf(Fuellstand, 1, 2, fuellString);
Serial.print("Fuellstand: ");
Serial.println(fuellString);
    
    client.publish("hello", fuellString);
   client.publish("chattest", "hi, this is a test message");
    client.publish("output", "topic output publish test ");

 
  }

 
}

the flow, only the relay part:

[
    {
        "id": "eb8f9c0d054be30c",
        "type": "tab",
        "label": "Flow 2",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "4ce6cd876fd5441f",
        "type": "mqtt out",
        "z": "eb8f9c0d054be30c",
        "name": "",
        "topic": "output",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "33a951cef9d47be6",
        "x": 330,
        "y": 120,
        "wires": []
    },
    {
        "id": "8f79b17bd2c2101c",
        "type": "inject",
        "z": "eb8f9c0d054be30c",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "output",
        "payload": "on",
        "payloadType": "str",
        "x": 120,
        "y": 120,
        "wires": [
            [
                "4ce6cd876fd5441f"
            ]
        ]
    },
    {
        "id": "974a7a8bb6db9bf9",
        "type": "mqtt in",
        "z": "eb8f9c0d054be30c",
        "name": "",
        "topic": "output",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "33a951cef9d47be6",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 90,
        "y": 280,
        "wires": [
            [
                "d0dc7378c7bfb03b"
            ]
        ]
    },
    {
        "id": "d0dc7378c7bfb03b",
        "type": "debug",
        "z": "eb8f9c0d054be30c",
        "name": "debug 4",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 300,
        "y": 280,
        "wires": []
    },
    {
        "id": "8dbcaf7b23fbb466",
        "type": "mqtt out",
        "z": "eb8f9c0d054be30c",
        "name": "",
        "topic": "output",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "33a951cef9d47be6",
        "x": 330,
        "y": 200,
        "wires": []
    },
    {
        "id": "1298d2bf330b5cb5",
        "type": "inject",
        "z": "eb8f9c0d054be30c",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "output",
        "payload": "off",
        "payloadType": "str",
        "x": 120,
        "y": 200,
        "wires": [
            [
                "8dbcaf7b23fbb466"
            ]
        ]
    },
    {
        "id": "33a951cef9d47be6",
        "type": "mqtt-broker",
        "name": "",
        "broker": "192.168.0.219",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "/hello",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]

Thanks for help.

I haven't loaded your flow so I won't comment on that but a few thoughts. Can you hook your esp to a computer and watch the serial output? If so make a flow that sends a relay off or on command using inject nodes to see if the topic is being received correctly on the esp. If it is then you might have a relay problem. You may not have an esp issue , it might be a relay problem, or a wiring/interface problem. I have several dozen esp's controlling relays and it was a long painful road to get everything running correctly. You don't give a specific esp model but be aware some pins may be reserved for a specific function or can't be used as outputs, maybe try different pins. You don't say what the relay is and it may not be compatible with esp. As I remember I went through several relays that claimed they would work but didn't. You have several print commands on the esp verify the esp is responding correctly to the commands via serial monitor and go from there. This is a node red forum so you may get better info on an esp forum but there are many here who have gone down your path.

If the esp needs to " listen" you have to subscribe to that topic. In this case the "output" topic.

Add to the void setup() at the end
client.subscribe("output");

I just noticed what @edje11 commented on. You don't subscribe except if you need to reconnect. So initially you never listen for a topic.

Some esp models have onboard led's so might try and see if you can turn that on or off as well.

One other thought, most check to see if mqtt is connected or not, and if wifi is connected. For a "production " system you may want to add that.

thank you for your answer

its the esp32, i already tried exactly what you mentioned and i can´t see the message off the topic in the serial monitor.
But the raspberry posts on the topic with the right message, i can see that in the debugger

i can publish on topics from the esp too, which i can also see in the node red debugger.
so the mqtt connection works.
the signal of the relay is connectet to pin 27,
i already looked for the right pins here : https://randomnerdtutorials.com/esp32-pinout-reference-gpios/

i noticed that there are declaration mistakes in the variables of the code i postet, i changed some off the variable. But thats not the issue, it still doesn´t work, even with right declaration.

it seems that the subscribe action doesnt work

thank you for your help, i subscribe to the topic in the void reconnect function already.
I also tried it in the void setup, but that didnt work also

So for some reason either you aren't subscribed or not seeing the correct topic. You can subscribe to all topics using
client.subscribe("#");
If you do that do you see any topics at all?

Also get a MQTT program that shows you MQTT traffic. Most use MQTT explorer and see what your MQTT traffic looks like.

that didnt work

i can see the right topics and the right messages with mqtt explorer, so sending messages from the esp works and sending messages from nodered via raspberry works also

When you say it didn't work... do you mean subscribing to # didn't show any topics?
Also, make sure you subscribe in the setup as well as reconnect, if you don't put it in setup then you really didn't subscribe unless for some reason the esp disconnects then reconnects.

You might want to put a delay of a second or so immediately after the print topic statement so you can easily see if it does print.

I just noticed one other thing. Your client.loop statement is inside an if statement. Move client.loop out of there . Put it below the } that is on the next line.

2 Likes

thank you so much, that was the mistake!!!
now everything works fine..

just made it back to the computer and I'm going to post my NodeMCU code for you. It may help a little to look, but I don't promise anything.

//192.168.1.41
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>

String LightName = "Light 1";
IPAddress local_IP(192, 168, 1, 41);  // set IP address here XXXXXXXXXXXXXXXX
IPAddress gateway(192, 168, 1, 254);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8);   //optional
IPAddress secondaryDNS(8, 8, 4, 4); //optional
/////////Timer ////////////
long interval1 = 5000;
long interval2 = 1000;
long previousMillis1 = 0; 
long previousMillis2 = 0;
unsigned long currentMillis1 = millis();
unsigned long currentMillis2 = millis();
//////////////////////////////////////////////////////

const char* ssid = 
const char* password = 
const char* mqtt_server = 

WiFiClient espClient;
PubSubClient MQTTclient(espClient);

WiFiServer server(80);    // Create a webserver object that listens for HTTP request on port 80
String MyIp;
String MySSID;
String MyMac;
String MyLight = "Undetermined";
int MyPin = 0;
int i;
int Cnt = 0;
String MyTopic = "";
int HeartCount = 0;
String MyCnt;
void setup() {  //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  Serial.begin(115200);
  // Wait for serial to initialize.
  while(!Serial) { }
  setup_wifi();
  
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }

    // NOTE: if updating FS this would be the place to unmount FS using FS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  pinMode(LED_BUILTIN, OUTPUT);  //set built in LED to output
  digitalWrite(LED_BUILTIN, HIGH);  //light the LED, low = on, high = off
  pinMode(D0,OUTPUT);

    ///////////////////////////////////////////////////////////////////

  server.begin();                           // Actually start the server
  Serial.println("HTTP server started");
  ///////////////////////////////////////////////////////////////////
}

void setup_wifi() { //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  // Configures static IP address
  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
    Serial.println("STA Failed to configure");
  }
  WiFi.hostname("random1");
  Serial.println("Booting");
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);
  WiFi.begin(ssid,password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Retry...");
    delay(500);
  Serial.println("");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  delay(500);
  }
  setup_mqtt();
}

void setup_mqtt() { //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 

boolean rc = MQTTclient.connect("random1"); 

MQTTclient.setServer(mqtt_server, 1883);
MQTTclient.setCallback(callback);
if  (!MQTTclient.connected()) {
    //Serial.println("Connecting to MQTT...");
  }
 
if (MQTTclient.connect("random1")) {
  //Serial.println("connected");  
    } else {
    //Serial.print("failed with state ");
    //Serial.print(MQTTclient.state());
    delay(2000);
  }
  MQTTclient.subscribe("random1_subscribe");
  MQTTclient.subscribe("Heart");
}

void callback(char* topic, byte* payload, unsigned int length) {
  //Serial.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
  //Serial.println("Message arrived ");
  //Serial.print("topic is ");
  String MyTopic = "";
    for (int i = 0; i < length; i++) {
    //Serial.print((char)topic[i]);
    MyTopic += (char)topic[i];
  }
  //Serial.println(topic);
  //Serial.print("payload is ");
  String MsgPayload = "";
  for (int i = 0; i < length; i++) {
    //Serial.print((char)payload[i]);
    MsgPayload += (char)payload[i];
  }
  //Serial.println(MsgPayload);
  //Serial.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
   if (String(topic) == "Heart"){
    HeartCount = 0;
  }
  
  if (String(topic) == "random1_subscribe" && MsgPayload == "reset") {
    EspReset();
  }

  if (String(topic) == "random1_subscribe" && MsgPayload == "on") {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on
    digitalWrite(D0, HIGH);
    MyLight = "Light is On";
    //Serial.println(MyLight);
    HeartCount = 0;
  }
  
  if (String(topic) == "random1_subscribe" && MsgPayload == "off") {  
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off
    digitalWrite(D0, LOW);
    MyLight = "Light is Off";
    //Serial.println(MyLight);
    HeartCount = 0;
  }  
}

void EspReset(){ //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    MQTTclient.publish("random1_count","reset"); 
//    MQTTclient.publish("random1", "reset"); 
    delay(3000);
    ESP.restart();
}

 void Webb(){    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  
//Serial.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
  //Serial.println(WiFi.hostname());
  //Serial.println(WiFi.localIP());
  //Serial.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");  
  MyMac = WiFi.macAddress();
  MySSID = WiFi.SSID();
   //Serial.println();
   //Serial.print("MAC: ");
   //Serial.println(WiFi.macAddress());

   WiFiClient client = server.available();   
  
  // Do nothing if server is not available
  if (!client) {
     return;
  }

  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); 
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.print(LightName + "   " + MyLight);
  client.println("<br>");
  client.println(MyCnt + " Count" + "<br>");
  client.println("</html>");
 
}


void loop() {  //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  if (millis() < 1000) {
    previousMillis1 = 1;
    previousMillis2 = 1;
  }
  currentMillis1 = millis();
  if(currentMillis1 - previousMillis1 > interval1) {   
    previousMillis1 = currentMillis1;   
  }
  currentMillis2 = millis();
  if(currentMillis2 - previousMillis2 > interval2) {
    Cnt = Cnt + 1;    
    MyCnt = String(Cnt);
    HeartCount = HeartCount + 1;
    MQTTclient.publish("random1_count", String(Cnt).c_str(), true); //
    previousMillis2 = currentMillis2;   
  }

  if (HeartCount > 20){
    EspReset();
  } 
    if (Cnt > 86400){
    Cnt = 0;
  } 
  MQTTclient.loop();
  ArduinoOTA.handle();
//WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
 
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print(" wifi has disconnected ");
    setup_wifi();
  }

if  (!MQTTclient.connected()) {
    Serial.println("Connecting to MQTT...");
    setup_mqtt;
  }  

   Webb();
}

there's a lot of stuff you probably don't need but it's at least an example of something close to what you are doing so you have something else to compare to

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