Combine Topic & Payload from MQTT message to control multiple relays

Hi all,

Hope someone is able to help me.
I'm trying to control multiple relays trough MQTT. My idea is to combine the topic & payload into 1 string, and then with an if function; set the relay state.

I'm using the arduinoMQTTclient library. This is also sending DHT22 info back to home assistant.

For example;

  • topic = home/hok/relay1/set
  • payload = 0 (off from home assistant)
    then set relay 1 to LOW

I cannot manage to combine the topic + payload in 1 string so that i can check it against a single line of text, for example;
if MQTT_string = home/hok/relay1/set_0 then switch relay 1 OFF.

the relevant piece of code (in the loop) is this;

  //MQTT berichten uitlezen en relays sturen (continu)
   int messageSize = mqttClient.parseMessage();
  if (messageSize) { // we received a message, print out the topic and contents
    Serial.print("Received a message with topic '");
    Serial.println(mqttClient.messageTopic());
    Serial.println(String(mqttClient.messageTopic())); // test om te kijken of string hier werkt
    Serial.print("Payload: ");
    Serial.println((char)mqttClient.read());

    String MQTT_string = mqttClient.messageTopic() + "_" + ((char)mqttClient.read());
    Serial.print("String; ");
    Serial.println(MQTT_string); //geeft nog niet de topic + payload



    if (MQTT_string == "home/hok/relay1/set_0") {   digitalWrite(relay_1, LOW);} //werkt nog niet omdat string niet correct is
    if (MQTT_string == "home/hok/relay1/set_1") {   digitalWrite(relay_1, HIGH);}

the serial monitor shows the following;

Received a message with topic 'home/hok/relay1/set
home/hok/relay1/set
Payload: 0
String; _�

So separatly, the topic and payload are shown correctly in the serial monitor, but as soon as try to combine them in 1 string, the code behaves different then I expect it.
I think the string usage of me is incorrect, but I don't know how to fix this.

Any help is appreciated!

For reference; hereby the full code (still under construction);

#include <SPI.h>
#include <ArduinoMqttClient.h>
#include <WiFiNINA.h>
#include "arduino_secrets.h"
#include "DHT.h"
#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header lcd driver
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header lcd driver

//LCD
hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip
// LCD geometry
const int LCD_COLS = 20;
const int LCD_ROWS = 4;

///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;     // the WiFi radio's status

int ledState = LOW;                       //ledState used to set the LED
bool relayState1 = false;
bool relayState2 = false;
bool relayState3 = false;
bool relayState4 = false;
bool relayState5 = false;
bool relayState6 = false;
bool relayState7 = false;
bool relayState8 = false;

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

const char broker[] = "192.168.1.30";
int        port     = 1883;
const char temph_topic[]  = "home/hok/temperatuur_hok";
const char rvh_topic[]  = "home/hok/luchtvochtigheid_hok";
const char tempk_topic[]  = "home/hok/temperatuur_kas";
const char rvk_topic[]  = "home/hok/luchtvochtigheid_kas";
const char wifi_sterkte_topic[] = "home/hok/wifi_sterkte";
const char relay1_topic[] = "home/hok/relay1/set";
const char relay2_topic[] = "home/hok/relay2/set";
const char relay3_topic[] = "home/hok/relay3/set";
const char relay4_topic[] = "home/hok/relay4/set";
const char relay5_topic[] = "home/hok/relay5/set";
const char relay6_topic[] = "home/hok/relay6/set";
const char relay7_topic[] = "home/hok/relay7/set";
const char relay8_topic[] = "home/hok/relay8/set";


//set interval for sending messages (milliseconds)
const long interval = 8000;
unsigned long previousMillis = 0;
int count = 0;

//DHT22 setup
#define DHTPIN 10 // input pin 10 voor hok en 11 voor kas
#define DHTTYPE DHT22 // sensor type
DHT dht(DHTPIN, DHTTYPE);

//relay setup
int relay_1 = 2;
int relay_2 = 3;
int relay_3 = 4;
int relay_4 = 5;
int relay_5 = 6;
int relay_6 = 7;
int relay_7 = 8;
int relay_8 = 9;

//LCD icoontjes
byte hokchar[8] {B00000, B00100, B01110, B11111, B11001, B11001, B11111, B11111,}; //icoontje van een hok of huisje
byte kaschar[8] {B00000, B00000, B00100, B01010, B10001, B10001, B10001, B11111,}; //icoontje van een leeg huis of kas
byte wifi1char[8] {B00000, B00000, B00000, B00000, B00000, B00000, B00000, B00100,}; //WiFi icoontje met 1 streepje
byte wifi2char[8] {B00000, B00000, B00000, B00000, B00100, B01010, B00000, B00100,}; //WiFi icoontje met 2 streepjes
byte wifi3char[8] {B00000, B00000, B01110, B10001, B00100, B01010, B00000, B00100,}; //WiFi icoontje met 3 streepjes
byte wifi4char[8] {B01110, B10001, B01110, B10001, B00100, B01010, B00000, B00100,}; //Wifi icoontje met 4 streepjes



void setup() {
  pinMode(LED_BUILTIN, OUTPUT);// set the LED as output

  //relay setup en alle relays uitschakelen
  pinMode(relay_1, OUTPUT);
  pinMode(relay_2, OUTPUT);
  pinMode(relay_3, OUTPUT);
  pinMode(relay_4, OUTPUT);
  pinMode(relay_5, OUTPUT);
  pinMode(relay_6, OUTPUT);
  pinMode(relay_7, OUTPUT);
  pinMode(relay_8, OUTPUT);
  digitalWrite(relay_1, HIGH);
  digitalWrite(relay_2, HIGH);
  digitalWrite(relay_3, HIGH);
  digitalWrite(relay_4, LOW);
  digitalWrite(relay_5, LOW);
  digitalWrite(relay_6, LOW);
  digitalWrite(relay_7, LOW);
  digitalWrite(relay_8, LOW);

  //LCD
  int status;	// initialize LCD with number of columns and rows: 	status = lcd.begin(LCD_COLS, LCD_ROWS);
	if(status) // non zero status means it was unsuccesful
	{
		// hd44780 has a fatalError() routine that blinks an led if possible
		// begin() failed so blink error code using the onboard LED if possible
		hd44780::fatalError(status); // does not return
	}
	// initalization was successful, the backlight should be on now

	// Print a message to the LCD
	lcd.setCursor(0, 0);
  lcd.print("Hoi pap :-)");
  lcd.setCursor(0, 1);
  lcd.print("Computer start op");
  lcd.createChar(1,hokchar);

  //Initialize serial (and wait for port to open:)
  Serial.begin(9600);
  //while (!Serial) {  }  ; // wait for serial port to connect. Needed for native USB port only
  

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }
  
  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection: (aangepast naar 5 sec)
    delay(5000);
  }

  Serial.println("You're connected to the network");
  Serial.println();
  LED_Blink();
  LED_Blink();
  delay(100);
  lcd.setCursor(0, 2);
  lcd.print("WiFi verbonden");

  mqttClient.setUsernamePassword(SECRET_MQTT_User, SECRET_MQTT_PW);

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  if (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    while (1);
  }

//  mqttClient.subscribe(relays_topic); //verzamel topic om alle relay aansturing uit te lezen

  mqttClient.subscribe(relay1_topic);
  mqttClient.subscribe(relay2_topic);
  mqttClient.subscribe(relay3_topic);
  mqttClient.subscribe(relay4_topic);
  mqttClient.subscribe(relay5_topic);
  mqttClient.subscribe(relay6_topic);
  mqttClient.subscribe(relay7_topic);
  mqttClient.subscribe(relay8_topic);


  Serial.println("You're connected to the MQTT broker!");
  Serial.println();
  LED_Blink();
  LED_Blink();
  LED_Blink();

  dht.begin();

  lcd.setCursor(0, 3);
  lcd.print("Verbonden met server");

  //maak LCD scherm leeg
  delay(2000);
  lcd.clear();
  //LCD_clear(); // zelf geschreven code, backup als lcd.clear niet werkt.
}



void loop() {
  //MQTT berichten uitlezen en relays sturen (continu)
   int messageSize = mqttClient.parseMessage();
  if (messageSize) { // we received a message, print out the topic and contents
    Serial.print("Received a message with topic '");
    Serial.println(mqttClient.messageTopic());
    Serial.println(String(mqttClient.messageTopic())); // test om te kijken of string hier werkt
    Serial.print("Payload: ");
    Serial.println((char)mqttClient.read());

    String MQTT_string = mqttClient.messageTopic() + "_" + ((char)mqttClient.read());
    Serial.print("String; ");
    Serial.println(MQTT_string); //geeft nog niet de topic + payload



    if (MQTT_string == "home/hok/relay1/set_0") {   digitalWrite(relay_1, LOW);} //werkt nog niet omdat string niet correct is
    if (MQTT_string == "home/hok/relay1/set_1") {   digitalWrite(relay_1, HIGH);}

//      while (mqttClient.available()) {
//        Serial.print((char)mqttClient.read());
//    }
    Serial.println();
    }

// periodiek meetwaarden naar MQTT broker sturen;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;    // save the last time a message was sent
  digitalWrite(LED_BUILTIN, HIGH);
//temp en luchtvochtigheid meting
  float hh = dht.readHumidity(); //luchtvochtigheid hok
  float th = dht.readTemperature(); // temperatuur hok
  float hk = dht.readHumidity(); //luchtvochtigheid kas
  float tk = dht.readTemperature(); //temperatuur kas

/*
  // Check if any reads failed and exit early (to try again). //tijdelijk uitgeschakeld voor testen MQTT
  if (isnan(h) || isnan(t)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }
*/

/*
    printCurrentNet();

    Serial.print(F("Humidity: "));
    Serial.print(hh);
    Serial.print(F("%  Temperature: "));
    Serial.print(th);
    Serial.println(F("°C "));

    Serial.print("Sending message to temph.topic: ");
    Serial.println(temph_topic);
    Serial.println(th);

    Serial.print("Sending message to RVh.topic: ");
    Serial.println(rvh_topic);
    Serial.println(hh);

    Serial.print("Sending message to Wifi_sterkte.topic: ");
    Serial.println(wifi_sterkte_topic);
    Serial.println(WiFi.RSSI());
*/
    // send message, the Print interface can be used to set the message contents
    mqttClient.beginMessage(temph_topic);
    mqttClient.print(th);
    mqttClient.endMessage();

    mqttClient.beginMessage(rvh_topic);
    mqttClient.print(hh);
    mqttClient.endMessage();

    mqttClient.beginMessage(wifi_sterkte_topic);
    mqttClient.print(WiFi.RSSI());
    mqttClient.endMessage();

    //Serial.println();
  digitalWrite(LED_BUILTIN, LOW);
    

/*
  //LCD weergave
  lcd.clear();
  delay(10);
  lcd.setCursor(0,0);
  lcd.write(1);
  lcd.setCursor(1,0);
  lcd.print(th);
  lcd.setCursor(3,0);
  lcd.print("°C ");
  lcd.setCursor(6,0);
  lcd.print(hh);
  lcd.setCursor(7,0);
  lcd.print("% ");
*/
  }
}

void printCurrentNet() {
  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.println(rssi);
}

void LED_Blink() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(50);  
  digitalWrite(LED_BUILTIN, LOW);
  delay(50);
}


void LCD_clear() {
  lcd.setCursor(0, 0);
  lcd.print("                    ");
  lcd.setCursor(0, 1);
  lcd.print("                    ");
  lcd.setCursor(0, 2);
  lcd.print("                    ");
  lcd.setCursor(0, 3);
  lcd.print("                    ");
}


You are reading the topic and message twice. Does reading them the first time remove them from the receive buffer, I wonder ?

Try reading the topic and message and putting them in variables then using the variables in your sketch

Yes, with ArduinoMqttClient, once you read the payload, the messageTopic returns an empty String.

Also, as is commonly the case, every time you call read, you get the next character, or -1 if there is no more. That's why it returns int instead of char.

So create the String MQTT_string at the very top. Then you can pass it to Serial.println

Yes, that was it. Thanks alot for your quick reply!

For other people that are struggling with the same challange hereby the code i'm now using;

   int messageSize = mqttClient.parseMessage();
  if (messageSize) { // we received a message, print out the topic and contents
    String MQTT_Topic = String(mqttClient.messageTopic());
    String MQTT_Payload = String((char)mqttClient.read());
    String MQTT_string = MQTT_Topic + "_" + MQTT_Payload;    
    Serial.print("Received a message with topic ");
    Serial.println(MQTT_Topic);
    Serial.print("Payload: ");
    Serial.println(MQTT_Payload);
    Serial.print("String; ");
    Serial.println(MQTT_string); 

    if (MQTT_string == "home/hok/relay1/set_0") {
      digitalWrite(relay_1, LOW);
      Serial.println("Relay 1 UIT");
}
(etc)
}

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