Can't get sketch with PubSubClient working and I can't understand why?

In my void loop I am calling callback() expecting it to return a new value ti variable "dim1".
When I try to verify my sketch I get:

Arduino: 1.8.13 (Linux), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"











/home/eirik/Arduino/try_1000/try_1000/try_1000.ino: In function 'void loop()':
try_1000:80:12: error: too few arguments to function 'void callback(char*, byte*, unsigned int)'
   callback();
            ^
/home/eirik/Arduino/try_1000/try_1000/try_1000.ino:34:6: note: declared here
 void callback(char* topic, byte* payload, unsigned int length) {
      ^~~~~~~~
try_1000:81:28: error: expected ')' before '{' token
   if (dim1 != (dim_actual) {
                            ^
try_1000:85:1: error: expected primary-expression before '}' token
 }
 ^
/home/eirik/Arduino/try_1000/try_1000/try_1000.ino: In function 'void loop()':
try_1000:105:6: error: redefinition of 'void loop()'
 void loop() {
      ^~~~
/home/eirik/Arduino/try_1000/try_1000/try_1000.ino:78:6: note: 'void loop()' previously defined here
 void loop() {
      ^~~~
try_1000:106:3: error: 'client' was not declared in this scope
   client.loop();
   ^~~~~~
/home/eirik/Arduino/try_1000/try_1000/try_1000.ino:106:3: note: suggested alternative: 'Client'
   client.loop();
   ^~~~~~
   Client
try_1000:107:12: error: too few arguments to function 'void callback(char*, byte*, unsigned int)'
   callback();
            ^
/home/eirik/Arduino/try_1000/try_1000/try_1000.ino:34:6: note: declared here
 void callback(char* topic, byte* payload, unsigned int length) {
      ^~~~~~~~
try_1000:108:28: error: expected ')' before '{' token
   if (dim1 != (dim_actual) {
                            ^
try_1000:112:1: error: expected primary-expression before '}' token
 }
 ^
exit status 1
too few arguments to function 'void callback(char*, byte*, unsigned int)'


This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

This is my sketch code. Any pointers?

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <RBDdimmer.h>

#define CLIENT_ID       "Dimmer"
#define CLIENT_USER     "testuser"
#define CLIENT_PASS     "testpass"

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 68, 220);
IPAddress server(192, 168, 68, 115);

int dim1 = 0;// Dimming level (0-100)  0 = on, 100 = 0ff
int dim_actual = 0;
bool startsend = HIGH;

// Callback function header
void callback(char* topic, byte* payload, unsigned int length);

EthernetClient ethClient;
PubSubClient mqttClient(server, 1883, callback, ethClient);


void setup()
{
  Ethernet.begin(mac, ip);
  mqttClient.setCallback(callback);
}


//Callback function. Checks payload and update variable "dim1" with the value from mqtt.
void callback(char* topic, byte* payload, unsigned int length) {
  char msgBuffer[20];
  
   payload[length] = '\0';            // terminate string with '0'
  String strPayload = String((char*)payload);  // convert to string

dim1=strPayload.toInt();
}



// When I am done with this it will send data to mqtt broker.
void sendData() {
  char msgBuffer[20];
  if (mqttClient.connect(CLIENT_ID, CLIENT_USER, CLIENT_PASS)) {
    mqttClient.subscribe("homeassistant/lys/brightness_state_topic");
    if (startsend) {
     
      mqttClient.publish("homeassistant/lys/brightness_state_topic", dim1);
      startsend = LOW;
    }
  }
}




//brightness_command_topic string (optional)
//The MQTT topic to publish commands to change the light’s brightness.

//brightness_state_topic string (optional)
//The MQTT topic subscribed to receive brightness state updates.

//command_topic string REQUIRED
//The MQTT topic to publish commands to change the switch state.



// Void callback henter mqtt til dim1.
//Utfør endring av dimming
// Send tilbake kvittering på utført dimming

//Med jevne mellomrom sendt oppdatert status for å sørge for at dimming viser korrekt i home assistant dersom den skulle miste oversikten.

void loop() {
  mqttClient.loop();
  callback();
  if (dim1 != dim_actual) {
  dimmer.setPower(dim1);
  dim_actual = dim1;
  } 
}


//brightness_command_topic string (optional)
//The MQTT topic to publish commands to change the light’s brightness.

//brightness_state_topic string (optional)
//The MQTT topic subscribed to receive brightness state updates.

//command_topic string REQUIRED
//The MQTT topic to publish commands to change the switch state.



// Void callback henter mqtt til dim1.
//Utfør endring av dimming
// Send tilbake kvittering på utført dimming

//Med jevne mellomrom sendt oppdatert status for å sørge for at dimming viser korrekt i home assistant dersom den skulle miste oversikten.

You have 2 loop functions. Should you be calling callback from loop()? I assumed the mqtt client would be doing that; hence, why it is called a "callbacK".

Look at the examples that come with the PubSubClient library. They never directly call the callback() function since that is done when a subscribed messages is received by mqtt.

If you were going to call it for testing or something, you have to provide the 3 arguments that it is expecting.

Your sketch does not compile so you might be using a different PubSubClient library as well.

ToddL1962:
You have 2 loop functions. Should you be calling callback from loop()? I assumed the mqtt client would be doing that; hence, why it is called a "callbacK".

I only see one loop. Also, in the Arduino IDE you generally don't need to declare function prototypes.

You should not be calling callback(). when you call .setCallback, you are setting up an interrupt that gets executed when a subscribed topic is received.

Also, the data to publish has to be a const char.

mqttClient.publish("homeassistant/lys/brightness_state_topic", dim1);

won't compile.

You can convert the int into a char array (real string) with itoa() or sprintf().

int dim1= 123;
char cstr[4];
itoa(dim1, cstr, 10);

cstr-> "123"

or use sprintf()

sprintf(cstr, "%04d", dim1);

SteveMann:
I only see one loop. Also, in the Arduino IDE you generally don't need to declare function prototypes.

You are correct. I think I hit ctrl-V twice when I copied the code to my editor.

I'm stuck.

First of all. When my client connects to my broker it disconnects with this "error":

[color=#212121]Client Dimmer has exceeded timeout, disconnecting.
I don't understand why as mqttClient.loop(); is supposed to prevent that from happening.

Also my serial monitor gives me nothing. (Tried baud 9600 as well)
And because of all of this I am not sure if my code in general is working.

I have spent quite some time trying to figure this out. Googling everything I can think of. I now need help  :sweat_smile: [/color]
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <RBDdimmer.h>

#define CLIENT_ID       "Dimmer"
#define CLIENT_USER     "testuser"
#define CLIENT_PASS     "testpass"
#define PUBLISH_DELAY   10
#define outputPin1  12
// #define outputPin2 13
#define zerocross  2 // for boards with CHANGEBLE input pins

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 68, 220);
IPAddress server(192, 168, 68, 115);

int dim1 = 0;// Dimming level (0-100)  0 = on, 100 = 0ff
int dim_actual = 0;

dimmerLamp dimmer_1(outputPin1);
// dimmerLamp dimmer_2(outputPin2);

// Callback function header
void callback(char* topic, byte* payload, unsigned int length);

EthernetClient ethClient;
PubSubClient mqttClient(server, 1883, ethClient);


void setup()
{
  Serial.begin(115200);
  Ethernet.begin(mac, ip);
  delay(5000);
  mqttClient.setCallback(callback);
  dimmer_1.begin (NORMAL_MODE, ON);
  dimmer_1.setPower(50);
  if (mqttClient.connect(CLIENT_ID, CLIENT_USER, CLIENT_PASS)) {
      mqttClient.subscribe("homeassistant/dimmerlys/brightness_command_topic");
      mqttClient.publish("homeassistant/dimmerlys/brightness_state_topic","Dimmer1 connected");
  }
}



//Callback function. Checks payload and update variable "dim1" with the value from mqtt.
void callback(char* topic, byte* payload, unsigned int length) {
  char msgBuffer[20];
  
   payload[length] = '\0';            // terminate string with '0'
  String strPayload = String((char*)payload);  // convert to string
  Serial.print("strPayload =  ");
  Serial.println(strPayload); //can use this if using longer southbound topics
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");//MQTT_BROKER
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  Serial.println(payload[0]);

dim1=strPayload.toInt();
}




void loop() {
  mqttClient.loop();
  delay(500);
  if (!mqttClient.connected()) {
    reconnect();           
  }
  if (dim1 != dim_actual) {
  dimmer_1.setPower(dim1);
  dim_actual = dim1;
  char msgBuffer[20];
  itoa(dim1, msgBuffer, 10);
  mqttClient.publish("homeassistant/dimmerlys/brightness_state_topic", msgBuffer);
  } 
}





void reconnect() {      // This is for the MQTT connection
  // Loop until we're reconnected
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (mqttClient.connect(CLIENT_ID, CLIENT_USER, CLIENT_PASS)) {
      Serial.println("connected");
      mqttClient.subscribe("homeassistant/dimmerlys/brightness_command_topic"); 
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

In the future, please use Autoformat in the IDE. It makes the code more readable.

You can't get very far without the serial monitor working. Write a simple sketch that just sends a few lines of text to Serial.println("Hello World"); . Get this working first.

If the Serial monitor is not working, then where are you seeing this error?

Do you see the box labeled "Copy error message"? We need that.

The error is in the mqttbrokers log file.

I don't get any errors in Arduino so there is nothing to copy.
Serial works fine in a simple sketch...

Any Idea how I can keep the connection alive when I have mqttClient.loop(); in there as per the documentation?
Is there something wrong with my implementation?
If I could just manage to keep the connection alive I could do more experimentation on the rest of the program to get everything working.

P.s I have to mention I am new to this :smiley:

try this:

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <RBDdimmer.h>

#define CLIENT_ID       "Dimmer"
#define CLIENT_USER     "testuser"
#define CLIENT_PASS     "testpass"
#define PUBLISH_DELAY   10
#define outputPin1  12
// #define outputPin2 13
#define zerocross  2 // for boards with CHANGEBLE input pins

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 68, 220);
IPAddress server(192, 168, 68, 115);

int dim1 = 0;// Dimming level (0-100)  0 = on, 100 = 0ff
int dim_actual = 0;

dimmerLamp dimmer_1(outputPin1);
// dimmerLamp dimmer_2(outputPin2);


EthernetClient ethClient;
PubSubClient mqttClient(server, 1883, ethClient);


//Callback function. Checks payload and update variable "dim1" with the value from mqtt.
void callback(char* topic, byte* payload, unsigned int length) {
  char msgBuffer[20];
 
   payload[length] = '\0';            // terminate string with '0'
  String strPayload = String((char*)payload);  // convert to string
  Serial.print("strPayload =  ");
  Serial.println(strPayload); //can use this if using longer southbound topics
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");//MQTT_BROKER
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  Serial.println(payload[0]);

dim1=strPayload.toInt();

}


void setup()
{
  Serial.begin(115200);
  Ethernet.begin(mac, ip);
  delay(5000);



  dimmer_1.begin (NORMAL_MODE, ON);
  dimmer_1.setPower(50);
 
}







void loop() {
  
  //delay(500);
  if (!mqttClient.connected()) {
    reconnect();           
  }
  if (dim1 != dim_actual) {
  dimmer_1.setPower(dim1);
  dim_actual = dim1;
  char msgBuffer[20];
  itoa(dim1, msgBuffer, 10);
  mqttClient.publish("homeassistant/dimmerlys/brightness_state_topic", msgBuffer);
  }
mqttClient.loop();
}





void reconnect() {      // This is for the MQTT connection
  // Loop until we're reconnected
mqttClient.setKeepAlive( 90 );
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (mqttClient.connect(CLIENT_ID, CLIENT_USER, CLIENT_PASS)) {
      Serial.println("connected");
      mqttClient.subscribe("homeassistant/dimmerlys/brightness_command_topic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
 if (mqttClient.connect(CLIENT_ID, CLIENT_USER, CLIENT_PASS)) {
mqttClient.setCallback(callback); 
      mqttClient.subscribe("homeassistant/dimmerlys/brightness_command_topic");
      mqttClient.publish("homeassistant/dimmerlys/brightness_state_topic","Dimmer1 connected");
  }

  }
}

here is my mqtt connect function

void connectToMQTT()
{
  byte mac[5]; // create client ID from mac address
  WiFi.macAddress(mac); // get mac address
  String clientID = String(mac[0]) + String(mac[4]) ; // use mac address to create clientID
  while ( !MQTTclient.connected() )
  {
    MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password );
    log_i( "connecting to MQTT" );
    vTaskDelay( 250 );
  }
  MQTTclient.setCallback( mqttCallback );
  MQTTclient.subscribe( topicOK );
  MQTTclient.subscribe( topicRemainingMoisture_0 );
  log_i("MQTT Connected");
} //void connectToMQTT()

This is my function that does the client loop and connection management

void MQTTkeepalive( void *pvParameters )
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 250; //delay for ms
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status % s WiFi status % s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete ( NULL );
}

I have to read though this when my head is screwed on right. This is maybe a bit over my skill level.

It now keeps connected longer then before. But still disconnects.

Strange this is I get nothing in my serial monitor.
I even tried this to keep things more simple and see if it post to serial in my loop. It does not.

void loop() {
  Serial.print("Before loop");
  
  //delay(100);
 // if (!mqttClient.connected()) {
 //   reconnect();
//  }
  if (dim1 != dim_actual) {
    dimmer_1.setPower(dim1);
    dim_actual = dim1;
    char msgBuffer2[20];
    itoa(dim1, msgBuffer2, 10);
    mqttClient.publish("homeassistant/dimmerlys/brightness_state_topic", msgBuffer2);
  }
  mqttClient.loop();
}

That is not enough code to see where you might want code improvements.

You should uncomment the is connected if statement.

Also, are you checking that the network connection is being maintained? If the network connection failed no amount of logging into the MQTT broker will work.

Idahowalker:
That is not enough code to see where you might want code improvements.

You should uncomment the is connected if statement.

Also, are you checking that the network connection is being maintained? If the network connection failed no amount of logging into the MQTT broker will work.

Here is the code as is today. I am sure there are some mistakes that experienced programmers will spot easily :slight_smile:

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <RBDdimmer.h>

#define CLIENT_ID       "Dimmer"
#define CLIENT_USER     "testuser"
#define CLIENT_PASS     "testpass"
#define PUBLISH_DELAY   10
#define outputPin1  12
// #define outputPin2 13
#define zerocross  2 // for boards with CHANGEBLE input pins

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 68, 220);
IPAddress server(192, 168, 68, 115);

int dim1 = 0;// Dimming level (0-100)  0 = on, 100 = 0ff
int dim_actual = 0;

dimmerLamp dimmer_1(outputPin1);
// dimmerLamp dimmer_2(outputPin2);

// Callback function header
void callback(char* topic, byte* payload, unsigned int length);

EthernetClient ethClient;
PubSubClient mqttClient(server, 1883, ethClient);


void setup()
{
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  delay(5000);

  mqttClient.setKeepAlive( 90 );

  mqttClient.setCallback(callback);
  dimmer_1.begin (NORMAL_MODE, ON);
  dimmer_1.setPower(50);
  if (mqttClient.connect(CLIENT_ID, CLIENT_USER, CLIENT_PASS)) {
    mqttClient.subscribe("homeassistant/dimmerlys/brightness_command_topic");
    mqttClient.publish("homeassistant/dimmerlys/brightness_state_topic", "Dimmer1 connected");
  }
}



//Callback function. Checks payload and update variable "dim1" with the value from mqtt.
void callback(char* topic, byte* payload, unsigned int length) {
  char msgBuffer[20];

  payload[length] = '\0';            // terminate string with '0'
  String strPayload = String((char*)payload);  // convert to string
  Serial.print("strPayload =  ");
  Serial.println(strPayload); //can use this if using longer southbound topics
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");//MQTT_BROKER
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  Serial.println(payload[0]);

  dim1 = strPayload.toInt();
}




void loop() {
  Serial.print("Before loop");
  if (!mqttClient.connected()) {
    reconnect();
  }
  if (dim1 != dim_actual) {
    dimmer_1.setPower(dim1);
    dim_actual = dim1;
    char msgBuffer2[20];
    itoa(dim1, msgBuffer2, 10);
    if (mqttClient.connected()) {
      mqttClient.publish("homeassistant/dimmerlys/brightness_state_topic", msgBuffer2);
    }
  }
  mqttClient.loop();
}





void reconnect() {      // This is for the MQTT connection
  // Loop until we're reconnected
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (mqttClient.connect(CLIENT_ID, CLIENT_USER, CLIENT_PASS)) {
      Serial.println("connected");
      mqttClient.subscribe("homeassistant/dimmerlys/brightness_command_topic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

Add a network event to see if the network is being disconnected. If the network is disconnecting then the MQTT will disconnect. Time to prove network or MQTT.

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