Sending sensor readings via MQTT/PubSubClient

Hi! I am trying to send sensorreadings via WEB MQTT and the PubSubClient from the Arduino but I don't seem to get any useful data out of it.

The Webserver displays the correct values and something is sent to my MQTT Instance (Mosquitto) on Ubuntu but it mostly just shows (null) instead of the actual sensor reading. I am quite sure it is some sort of data or format problem but I couldn't figure it out.

Any help is appreciated!

Code:

/*
  Web Server

 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)

 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 modified 02 Sept 2015
 by Arturo Guadalupi

 merged with https://www.digikey.at/en/maker/blogs/2018/how-to-use-basic-mqtt-on-arduino
 20210226cj
 */

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
String thisString = "TestStringGlobal" ;

// Function prototypes
void subscribeReceive(char* topic, byte* payload, unsigned int length);


// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB };
IPAddress ip(192, 168, 10, 5);
 
// mqtt server Make sure to leave out the http and slashes!
const char* mqttserver = "192.168.10.186";

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
// Ethernet and MQTT related objects
EthernetClient ethClient;
PubSubClient mqttClient(ethClient);

int sensorReading[6];

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  
  Serial.println("Ethernet WebServer/MQTT Example");

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // Set the MQTT server to the server stated above ^
  mqttClient.setServer(mqttserver, 1883); 

// Attempt to connect to the server with the ID "myClientID"
// We could also enter MQTT Username and password here as arguments for the Function connect()
  if (mqttClient.connect("myClientID")) 
  {
    Serial.println("Connection has been established, well done");
 
    //Establish the subscribe event
    mqttClient.setCallback(subscribeReceive);
  } 
  else 
  {
    Serial.println("Looks like the server connection failed...");
  }
  
  // start the web server
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void subscribeReceive(char* topic, byte* payload, unsigned int length) {
  // Print the topic
  Serial.print("Topic: ");
  Serial.println(topic);
 
  // Print the message
  Serial.print("Message: ");
  for(int i = 0; i < length; i ++)
  {
    Serial.print(char(payload[i]));
  }
 
  // Print a newline
  Serial.println("");
}


void loop() {
  // This is needed at the top of the loop!
  mqttClient.loop();
   
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // output the value of each analog input pin
          client.print("MQTT WEB Server <br />");
          
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            sensorReading[analogChannel] = analogRead(analogChannel);
            String thisString = String(analogRead(analogChannel), DEC);
            mqttClient.publish("webmqtt", "thisString");
            mqttClient.publish("webmqtt", analogRead(analogChannel)); //sends random (null) or other undefined jibberisch
            mqttClient.publish("webmqtt", thisString); //doesn't send the variable and needs to be commented out to compile...
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading[analogChannel]);
            client.println("<br />");
            Serial.println(sensorReading[analogChannel]);



            
            //mqttClient.publish("webmqtt", String thisString = String( client.println(sensorReading[analogChannel])));
          
          }
          client.println("</html>");

          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(100);
    // close the connection:
    // Ensure that we are subscribed to the topic 
    mqttClient.subscribe("webmqtt");
 
    // Attempt to publish a value to the topic 
    
 //mqttClient.publish("webmqtt", "Hello NEW World");
    
    client.stop();
    Serial.println("client disconnected");
    
  }
  delay(500);
}

What happens if you comment out the second of the publish() lines and only send the Strings ?

This Code gives me the following error.

mqttClient.publish("webmqtt", thisString); //doesn't send the variable and needs to be commented out

Error:

Arduino: 1.8.13 (Windows 10), Board: "Arduino Ethernet"

D:\Firefox Downloads\mqtt_WebServer_working_SendsData_is_null.ino\mqtt_WebServer_working_SendsData_is_null.ino.ino: In function 'void loop()':

mqtt_WebServer_working_SendsData_is_null.ino:144:53: error: no matching function for call to 'PubSubClient::publish(const char [8], String&)'

             mqttClient.publish("webmqtt", thisString); //doesn't send the variable

                                                     ^

In file included from D:\Firefox Downloads\mqtt_WebServer_working_SendsData_is_null.ino\mqtt_WebServer_working_SendsData_is_null.ino.ino:24:0:

C:\Users\User**\OneDrive\Dokumente\Arduino\libraries\PubSubClient\src/PubSubClient.h:151:12: note: candidate: boolean PubSubClient::publish(const char*, const char*)

    boolean publish(const char* topic, const char* payload);

            ^~~~~~~

C:\Users\User**\OneDrive\Dokumente\Arduino\libraries\PubSubClient\src/PubSubClient.h:151:12: note:   no known conversion for argument 2 from 'String' to 'const char*'

C:\Users\User**\OneDrive\Dokumente\Arduino\libraries\PubSubClient\src/PubSubClient.h:152:12: note: candidate: boolean PubSubClient::publish(const char*, const char*, boolean)

    boolean publish(const char* topic, const char* payload, boolean retained);

            ^~~~~~~

C:\Users\User**\OneDrive\Dokumente\Arduino\libraries\PubSubClient\src/PubSubClient.h:152:12: note:   candidate expects 3 arguments, 2 provided

C:\Users\User**\OneDrive\Dokumente\Arduino\libraries\PubSubClient\src/PubSubClient.h:153:12: note: candidate: boolean PubSubClient::publish(const char*, const uint8_t*, unsigned int)

    boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);

            ^~~~~~~

C:\Users\User**\OneDrive\Dokumente\Arduino\libraries\PubSubClient\src/PubSubClient.h:153:12: note:   candidate expects 3 arguments, 2 provided

C:\Users\User**\OneDrive\Dokumente\Arduino\libraries\PubSubClient\src/PubSubClient.h:154:12: note: candidate: boolean PubSubClient::publish(const char*, const uint8_t*, unsigned int, boolean)

    boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);

            ^~~~~~~

C:\Users\User**\OneDrive\Dokumente\Arduino\libraries\PubSubClient\src/PubSubClient.h:154:12: note:   candidate expects 4 arguments, 2 provided

exit status 1

no matching function for call to 'PubSubClient::publish(const char [8], String&)'



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

Now to your Question, this is the output in the Terminal:


Then it only sends the strings.

Try something simpler. Perhaps one sensor and no Strings.

Better still, don't use Strings

I personally don't need it as strings but it is weird to me that the terminal mostly shows (null) or some other random values that I can't interpret properly. I tried to get around that problem by using strings but it got me nowhere.

How would/could I check for what is actually being sent in Ubuntu if the terminal can't display it properly? Maybe the problem is in this area and not with the Arduino?

You could try verbose mode on the MQTT terminal. But standard debugging practice would be to reduce what you're doing until you get something working.

Try turning compilation error option to max on the Arduino, see there are any warnings.

Bob is a little bit correct, in that PubSubClient does not support Strings directly
The available publish methods are

   boolean publish(const char* topic, const char* payload);
   boolean publish(const char* topic, const char* payload, boolean retained);
   boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);
   boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
   boolean publish_P(const char* topic, const char* payload, boolean retained);
   boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);

So you need to fit your data into one of those.
For

mqttClient.publish("webmqtt", thisString);

instead use

mqttClient.publish("webmqtt", thisString.c_str()); // get the const char* of this String
mqttClient.publish("webmqtt", analogRead(analogChannel));

Will just not work, you need to use a text version of the number read in.
Using a String, like you have with 'thisString' is a simple way to do that.

The order of some of your code if off.

He the client.loop() is ran before the checking of a connection.

Next, as per the Eclipse document thingies, it is up to the user to handle NULL values being published or subscribed to. One way to handle NULL's is use the retain setting on as part of the publication being sent.