Comparison of the string received from MQTT/cloud/website

Hi,

I am trying to compare the string of data which I am receiving from the MQTT broker. If I receive the keyword faster I want to print "increase motor speed" and when I get slower keyword or any other keyword, I want to print "decrease motor speed". I am not sure how to store the data I receive from mqttClient.read()and then store it in string to then compare it
Below is the snippet of the code where I have added it and it seems not to work correctly in my case. can you look at it and let me know what is the mistake?

while (mqttClient.available()) {
Serial.print((char)mqttClient.read());
String ipstring= String("(char)mqttClient.read()");
String fast ="faster";
if((char)mqttClient.read()==fast)
{
Serial.println("increase motor speed");}
else
{
Serial.println("decrease motor speed");
}*
}

I have also attached the code for reference.
Thank you!

/*
  Azure IoT Hub NB

  This sketch securely connects to an Azure IoT Hub using MQTT over NB IoT/LTE Cat M1.
  It uses a private key stored in the ATECC508A and a self signed public
  certificate for SSL/TLS authetication.

  It publishes a message every 5 seconds to "devices/{deviceId}/messages/events/" topic
  and subscribes to messages on the "devices/{deviceId}/messages/devicebound/#"
  topic.

  The circuit:
  - MKR NB 1500 board
  - Antenna
  - SIM card with a data plan
  - LiPo battery

  The following tutorial on Arduino Project Hub can be used
  to setup your Azure account and the MKR board:

  https://create.arduino.cc/projecthub/Arduino_Genuino/securely-connecting-an-arduino-nb-1500-to-azure-iot-hub-af6470

  This example code is in the public domain.
*/

#include <ArduinoBearSSL.h>
#include <ArduinoECCX08.h>
#include <utility/ECCX08SelfSignedCert.h>
#include <ArduinoMqttClient.h>
#include <MKRNB.h>

#include "arduino_secrets.h"
int sensorValue;

/////// Enter your sensitive data in arduino_secrets.h
const char pinnumber[]   = SECRET_PINNUMBER;
const char broker[]      = SECRET_BROKER;
String     deviceId      = SECRET_DEVICE_ID;

NB nbAccess;
GPRS gprs;

NBClient      nbClient;            // Used for the TCP socket connection
BearSSLClient sslClient(nbClient); // Used for SSL/TLS connection, integrates with ECC508
MqttClient    mqttClient(sslClient);

unsigned long lastMillis = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!ECCX08.begin()) {
    Serial.println("No ECCX08 present!");
    while (1);
  }

  // reconstruct the self signed cert
  ECCX08SelfSignedCert.beginReconstruction(0, 8);
  ECCX08SelfSignedCert.setCommonName(ECCX08.serialNumber());
  ECCX08SelfSignedCert.endReconstruction();

  // Set a callback to get the current time
  // used to validate the servers certificate
  ArduinoBearSSL.onGetTime(getTime);

  // Set the ECCX08 slot to use for the private key
  // and the accompanying public certificate for it
  sslClient.setEccSlot(0, ECCX08SelfSignedCert.bytes(), ECCX08SelfSignedCert.length());

  // Set the client id used for MQTT as the device id
  mqttClient.setId(deviceId);

  // Set the username to "<broker>/<device id>/api-version=2018-06-30" and empty password
  String username;

  username += broker;
  username += "/";
  username += deviceId;
  username += "/api-version=2018-06-30";

  mqttClient.setUsernamePassword(username, "");

  // Set the message callback, this function is
  // called when the MQTTClient receives a message
  mqttClient.onMessage(onMessageReceived);
}

void loop() {
  if (nbAccess.status() != NB_READY || gprs.status() != GPRS_READY) {
    connectNB();
  }

  if (!mqttClient.connected()) {
    // MQTT client is disconnected, connect
    connectMQTT();
  }

  // poll for new MQTT messages and send keep alives
  mqttClient.poll();

  // publish a message roughly every 5 seconds.
  if (millis() - lastMillis > 5000) {
    lastMillis = millis();

    publishMessage();
  }
}

unsigned long getTime() {
  // get the current time from the cellular module
  return nbAccess.getTime();
}

void connectNB() {
  Serial.println("Attempting to connect to the cellular network");

  while ((nbAccess.begin(pinnumber) != NB_READY) ||
         (gprs.attachGPRS() != GPRS_READY)) {
    // failed, retry
    Serial.print(".");
    delay(1000);
  }

  Serial.println("You're connected to the cellular network");
  Serial.println();
}

void connectMQTT() {
  Serial.print("Attempting to MQTT broker: ");
  Serial.print(broker);
  Serial.println(" ");

  while (!mqttClient.connect(broker, 8883)) {
    // failed, retry
    Serial.print(".");
    Serial.println(mqttClient.connectError());
    delay(5000);
  }
  Serial.println();

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

  // subscribe to a topic
  mqttClient.subscribe("devices/" + deviceId + "/messages/devicebound/#");
}

void publishMessage() {
  Serial.println("Publishing message");

  // send message, the Print interface can be used to set the message contents
  mqttClient.beginMessage("devices/" + deviceId + "/messages/events/");
  mqttClient.print("hello ");
  sensorValue = analogRead(A0);
  mqttClient.println(sensorValue);
  //mqttClient.print(millis());
  
  mqttClient.endMessage();
}

void onMessageReceived(int messageSize) {
  // we received a message, print out the topic and contents
  Serial.print("Received a message with topic '");
  Serial.print(mqttClient.messageTopic());
  Serial.print("', length ");
  Serial.print(messageSize);
  Serial.println(" bytes:");

  // use the Stream interface to print the contents
  while (mqttClient.available()) {
    Serial.print((char)mqttClient.read());
    String ipstring= String("(char)mqttClient.read()");
    String fast ="faster";
    if((char)mqttClient.read()==fast)
    {
      Serial.println("increase motor speed");}
      else
      {
        Serial.println("decrease motor speed");
        }
  }
  Serial.println();

  Serial.println();
}

You don't seem to know whether you want to work with Strings or arrays of chars

String ipstring= String("(char)mqttClient.read()");

Why not turn the MQTT payload into a C style string like this

  char messageBuffer[30];
  memcpy(messageBuffer, payload, length);  //copy the payload to a buffer
  messageBuffer[length] = '\0';  //terminate with a zero to convert to a C style string

Then compare the resulting string with the string constant that you are looking for ?

if (strcmp(messageBuffer, "faster") == 0)
{
  //do something if there is a match
}
1 Like

Hi @UKHeliBob : Thank you for the suggestion! In my case how do I have all the data that comes from the MQTT broker assigned to payload?

mqttClient.read() returns a value of type int.

this means a single call to print( (char) mqttClient.read() ) prints a single character

the construction

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

prints consecutively single characters.

You have to store these values inside a string.
I recommend to use the SafeString-library for that.
the standard array of chars require very carefoul boundary checking
and variable type String is dangerous to use if they are global defined.

thit is not a complete answer to your question
IMHO find a MQTT-library that offers this functionality out of the box or learn hwo to compose a SafeString from single characters

best regards Stefan

In setup() you set a function to be called on receipt of a message.

 client.setCallback(callback);  //name of function in brackets

The previous code that I posted is from such a function like this

void callback(char* topic, byte* payload, unsigned int length)  //3 data items passed in by MQTT
{
  char messageBuffer[30];  //somewhere to put the message
  memcpy(messageBuffer, payload, length);  //copy in the payload
  messageBuffer[length] = '\0';  //convert copied payload to a C style string
  Serial.println(messageBuffer);  //print the buffer if you want to
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));  //toggle the state of an LED
} 

Once you have converted the payload into a C style string you can do what you like with it such as print it or use/test its contents

Hi Bob,

I have looked into the library-files and found there

void MqttClient::onMessage(void(*callback)(int))

I'm not so deep into c++-programming that I fully understand this.
I would assume from the definition above the callback-procedure would only accept one single parameter like it is in dkandays code

How should this work to suddenly hand over three parameters instead of one parameter as you suggested?

best regards Stefan

It doesn't. It appears (as usual) that there are multiple MQTT libraries available. The one I've seen before works as UKHeliBob explained. This one requires a bit more work to get hold of the payload.

I did not say anything about what the MQTT message contained, just that it could be converted into a C style string. It is up to the programmer to decide the format and contents of the message.

For instance, suppose that the message contained 3 values delimited in some way, then once you have converted to a C style string it is easy to parse it and extract the values

In order to make it simple, I tried the following:
I modified the code to use the built in string function. now I am using int value 0 to turn off, 1 to turn on, 2 to decrease speed and 3 to increase speed. The issue I am having is when I send any value I am receiving increase. here is the modified code:

void onMessageReceived(int messageSize) {
  // we received a message, print out the topic and contents
  String string1= "";

  // use the Stream interface to print the contents
  while (mqttClient.available()) {
  string1=  Serial.println((char)mqttClient.read());

}

    if(string1.indexOf("1")>=0)
    {
      Serial.println("On");
    }
    else if (string1.indexOf("0")>=0)
      {
        Serial.println("off");
       }
        else if (string1.indexOf("2")>=0)
      {
        Serial.println("decrease");
       }
        else if (string1.indexOf("3")>=0)
      {
        Serial.println("increase");
       }
       else
       {
       }
    
     Serial.println();
  Serial.println();
}

Snapshot of the output:

string1=  Serial.println((char)mqttClient.read());

What do you imagine this line of code does ?

Serial.println() returns the number of characters printed. Why are you interested in that, let alone trying to put it in a String ? Have you by any chance tried printing string1 after executing that line of code ?

string1 outputs 3 no matter what. could there a be a reason why? I am not very much acquainted with C coding

Yes. As I said, Serial.println() returns the number of characters printed, so when you print a single character, which is what you are doing, then that single character is followed by a linefeed and carriage return which makes a total of 3 characters

Try this (untested)

void onMessageReceived(int messageSize)
{
  char inChar;
  while (mqttClient.available())
  {
    inChar = (char)mqttClient.read());  //get next character
    switch (inChar)
  {
    case '0': //if it is a 0
      Serial.println("Off");
        break;
      case '1': //if it is a 1
        Serial.println("On");
        break;
      case '2': //if it is a 2
        Serial.println("decrease");
        break;
      case '3': //if it is a 3
        Serial.println("increase");
        break;
      default:  //otherwise
        Serial.println("got something else");
    }
    Serial.println();
    Serial.println();
  }
}
1 Like

Serial.print() does what its name says.

To translate it back into an everyday example

imagine a person that uses a spaycan to spray letters on a wall.
You can give this person commands like "spray ("Hello");

What the person does is spraying the letters onto the wall and if finished taking a small card out of his pocket with a number on it. The number is the number of letters that he spayed on the wall
In the example "spay("Hello"); this number is 5

If you code myVar = spray("Hello");
this means spray Hello onto the wall and after finishing that put the card with the number of sprayed letters into a box called "myVar"

command spay() sprays and command Serial.print() prints to the serial monitor
it prints that content that you give between the brackets ()
Serial.print("Hello World!") prints to the serial monitor Hello World!
nothing else

Serial.print(myStr) prints the content of variable myStr to the serial monitor

  • nothing else

Just print it and that's it.
If you want the mqt-message to be stored in a variable you need completely different commands/functions

I recommend
Take a look into this tutorial:

Arduino Programming Course

It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.

best regards Stefan

1 Like

Hi,

I am trying another code and I am stuck on how to get this message into a string to compare it:
below is the snippet:

case 3: {
                auto notification = (PublishNotification*) packet;
                info("publish notification");
                info(notification->getPayload());
                
                if (notification->getPacketId() != 0) {
                    info("before publish acknowledgement");
                    //
                    if (mqttSocket.sendPublishAcknowledgement(notification->getPacketId())) {
                        info("sent publish acknowledgement");
                    } else {
                        warning("cannot send publish acknowledgement");
                    }
                }

How do I get the payload into a string.
When I searched for the function in the code the only other reference was:

class PublishNotification : public Packet {
    private:
        const char* topic;
        const uint16_t packetid;
        const char* payload;

    public:
        PublishNotification(uint8_t f, uint8_t t, char* tc, uint16_t pi, char* pl) : Packet(f, t), topic(tc), packetid(pi), payload(pl) { }
        virtual ~PublishNotification() { delete topic; delete payload; }
        const char* getTopic() { return topic; }
        uint16_t getPacketId() { return packetid; }
        const char* getPayload() { return payload; }

};

I have attached the code for reference.sketch_aug06a_mosquitto.zip (8.3 KB)

See reply #5 for one way to do it

1 Like

I'm sorry such a code-snippet is worthless.

post your entire code as a code-section. An attached zip-file is a potential virus-danger.

Everything will become much easier if you post an example-code that is provided with the library.

If this MQTT-library has no examples delete the non-example-providing-library and take a different one.

This example-code is close to what you want to do

it uses a library called

PubSubClient.h

The website provides the link

This MQTT-libary's calback-function provides the common three parameters topic, payload, length (of payload = numbers of bytes the payload has)

The example-code for ESP32
Though it checks the payload directly and does not transfer the data into a string or array of char. I think it is a good starting point.

as a very short (and therefore still somehow hard to understand) description of how it works

The value inside the parameter "payload" is a pointer to a memory-adress.
Such a memory-adress is called a pointer.

At this memory-adress the real data is stored. At the end of the databytes is a zero indicating "end-of-data" This is called a zero terminated string.

The function serial.print(payoad) does a lot of things in the backround:

  • taking the pointer to find that location in memeory where to start reading the databytes
  • continue reading databytes until print-function comes across a zero to terminate printing (= zero-terminating string)

In the course I recommended pointers are chapter 18. This indicates it is somehow advanced programming.

https://startingelectronics.org/software/arduino/learn-to-program-course/18-strings/

There are C-functions that allow for copying databytes that represent a sequence of databytes or characters

memcpy, strcpy etc.

memcpy is what Bob is using in post #5.

MQTT is a medium complex datatransferprotocol. So programming is not a thing of 15 minutes. It is more about 15 hours to learn how to work with it.

altertatively you can take a look into the example-codes in the pubsuhclient-GiPo
I already mentioned above

If you start from such a working code and ask specific questions it will be much easier for others to give help

best regards Stefan

1 Like

Thanks Stefan. I leant C coding around 12 years back and havent been in touch since then. I know basic stuff.. Need to brush it up again. Thanks for the help!

I tried this and it worked for me:
char *expected = "on";

int compare = strcmp(expected, notification->getPayload());
Serial.println("compare is: ");
Serial.println(compare)

Thanks Bob for all the help!