Need simple piece of code, byte* to int (SOLVED!)

Hi all,

I really, really tried. I looked at many examples for hours :worried:. They either are calling objects/libraries I do not want to get into (or I feel I'll waste another couple of hours down a rabbit hole), or the examples simply do not apply to my use case.

To add insult to injury, I have a COM port issue which fails to open to let me access the serial monitor. I have spent another couple of hours trying to fix this. I've read some post about a driver rollback but the website it refers is 404... Plus, the only way I can upload a sketch to my chip is using esp8266 v2.4.2. Old version! Anything over that and I have errors and cannot upload anything. These are not what I need help with, but I want to provide context.

Clearly I'm fighting an uphill battle to get something very simple working. I can see the day where I'll get tired of this hobby as too many times I just feel like this is a boxing match in the dark, with limited debugging tools. I need to step back from the fight and reachout for help.

I have a Lolin NodeMCU v3 (ESP8266). I can write to it using v.2.4.2 of the esp8266 board.

I am receiving a MQTT message which contains a payload that I want to read into an integer. This integer would be the number of minutes my alarm would ring (I trigger a relay), so the value will never be more than 0-15. Naturally I also check the topic value.

>mosquitto_pub -t 'home/alarm/cmd' -m '4'

Would ask the module to trigger an alarm for 4 minutes.

I am using this callback function which works. I can successfully get the message and validate the topic using strcmp( ).

However I am always getting a "0" or "loglogloglog" when I ty to convert the value.

I am using this function constructor for the callBack( )

void callback(char* topic, byte* payload, unsigned int length)

I just want that byte* into an int variable

Any help is greatly appreciated

edit: fixed to list esp8266 instead of esp32

So which is it? ESP32 or ESP8266?

Is the payload data sent to the MQTT broker as binary or ASCII?

Post your complete code.
Use Code Tags.

1 Like

Maybe something like this would work, if the payload is ascii.

void callback(char* topic, byte* payload, unsigned int length)
{
  int alarmTime  = atoi ((const char*)payload);
  Serial.println (alarmTime);
}

ETA: that will probably not work.

Typo, it is ESP8266 all the way. I will edit the post.

Honestly the code is irrelevant. Any sample code propose that gets the byte* and prints the int to Serial would make me very happy!

Honestly, post your code.

1 Like

Is the payload data sent to the MQTT broker as binary or ASCII? If the latter, is it NULL-terminated?

Here you go : )


#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Update these with values suitable for your network.
const char* ssid = "xxxxxxx";
const char* password = "xxxxxx"; // 

// Update these with the name of the sensor
const char* sensorname = "AS1";
const char* sensorlog = "Alarm triggered";


const char* mqtt_server = "xxxxxxxxxxx"; /* "broker.mqtt-dashboard.com"  test.mosquitto.org  broker.hivemq.com */

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];

#define alarmRead 0  // Pin to check if the alarm was manually triggey via a mechanical switch
#define alarmWrite 2 // Pin to trigger the alarm by activating the connected relay

bool bCurrentAlarm = false; // if the alarm is currently on

int iPinAlarmState = HIGH;        // since the relay is low-triggered, we default to HIGH

int timerInterval = 0;
int alarmTimerInterval = 5;
int keepaliveTimerInterval = 5; 

void setup_wifi() {

  delay(10);


  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

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

  randomSeed(micros());

}


void reconnect() {

  // Loop until we're reconnected
  while (!client.connected()) {
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);


    byte willQoS = 0;
    const char* willTopic = "lastwill";  
    const char* willMessage = sensorname;
    boolean willRetain = false;

    // Attempt to connect
    if (client.connect(clientId.c_str(),"username", "password", willTopic, willQoS, willRetain, willMessage)) {
      // Wait 2 seconds before retrying
      delay(2000);
    } else {
      // Wait 2 seconds before retrying
      delay(2000);
    }

    // make sure we are subscribed to the alarm watcher
    client.subscribe("home/alarm/cmd");

  }
}


void setup() {
  pinMode(alarmRead, INPUT);    // initialize the ability to monitor alarm state
  pinMode(alarmWrite, OUTPUT);    // initialize the ability to write an alarm state
  digitalWrite(alarmWrite, HIGH); // Turning the relay off as precaution

  delay(1000); 
  Serial.begin(9600);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {
  
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  //for dev purposes, we send evey second
  snprintf (msg, MSG_BUFFER_SIZE, "alarm sensor is connected"); 
  client.publish("home/alarm/log", msg);   // publish the sensorname to the keep-alive topic 
  delay(1000); // make sure the message is sent

  if (timerInterval % keepaliveTimerInterval == 0) { // we send the keep alive ping
    snprintf (msg, MSG_BUFFER_SIZE, sensorname); 
    client.publish("keep-alive", msg);   // publish the sensorname to the keep-alive topic   
  }


  if (timerInterval % alarmTimerInterval == 0) { // we 

      iPinAlarmState = digitalRead(alarmRead);   // read if the alarm is running (LOW)
      
      if (iPinAlarmState==LOW) { // the alarm is manually triggered
        if (!bCurrentAlarm) { // the system is idle (meaning is is not already triggered)

          // at this point the relay was manually activated and cannot be turned off by the ESP.
          // the only way to turn it off is manually.
          
          bCurrentAlarm = true; // declare an alarm is running

          // confirm the alarm is triggered by sending a message
          snprintf (msg, MSG_BUFFER_SIZE, "1"); // send the message
          client.publish("home/alarm/state", msg);  
          delay(200); // make sure the message is sent
          
          snprintf (msg, MSG_BUFFER_SIZE, "Garage alarm triggered in the workshop by a user input"); // send the message like a remote sensor would
          client.publish("home/alarm/log",msg);
          delay(200); // make sure the message is sent
        }
      } else {
        bCurrentAlarm = false;
      }
  }

  // increasing the internal timer by 1 or resetting
  if  (timerInterval == 30000) {
    timerInterval = 0;
  } else {
    timerInterval++;
  }
  delay(1000); // timer increments by 1 second 
}


void triggerAlarm(int iAlarmDuration) { // triggers the alarm, sends the messages, waits, and turns it off
  
  if (!bCurrentAlarm) { // this only will run if the alarm is not already triggered (manually)
    
    if (iAlarmDuration >0) { // start the alarm
      bCurrentAlarm = true; // declare the emergency, set the global state
      
      digitalWrite(alarmWrite,LOW); // start the alarm

      // confirm the alarm is triggered by sending a message
      snprintf (msg, MSG_BUFFER_SIZE, "1"); // send the message
      client.publish("home/alarm/state", msg);  
      delay(200); // make sure the message is sent

      // wait for the duration ... could test here if this is blocking, or if the callBack would be called...
      delay(iAlarmDuration*1000);
    }

    // else the duration was <=0 or the delay
    // turn the alarm off
    digitalWrite(alarmWrite,HIGH); // stop the alarm
    delay(3000); // to protect the relay switching as it sometimes take 1-2 sec to turn off

    // confirm the alarm is stopped by sending a message
    snprintf (msg, MSG_BUFFER_SIZE, "0"); // send the message
    client.publish("home/alarm/state", msg);  
    delay(200); // make sure the message is sent

    bCurrentAlarm = false; // end the emergency, set the global state
    
  }
}

void callback(char* topic, byte* payload, unsigned int length)
{
  if (strcmp(topic, "home/alarm/cmd") == 0)
  { 
  
   // need help here

  }
}


As you have not posted a complete sketch it is difficult to be be certain what your sketch is actually doing and how

It looks like the payload is an array

Try this untested callback() function

void callback(char* topic, byte* payload, unsigned int length)
{
    char payloadBuffer[30];                  //somewhere to save the payload as a C string
    int payloadInt = 0;                      //the int value will be save in this variable
    memcpy(payloadBuffer, payload, length);  //copy the payload to the buffer
    payloadBuffer[length] = '\0';            //add the terminating null to create a string
    Serial.println(payloadBuffer);           //print the string for debugging
    payloadInt = atoi(payloadBuffer);  //convert ASCII the string to an int
    Serial.println(payloadInt); //print the int for debugging
}
1 Like

ascii

like I would do on a linux terminal
>mosquitto_pub -t 'home/alarm/cmd' -m '4'

you could always construct it "manually"

void callback(char* topic, byte* payload, unsigned int length) {
    long value = 0;
    bool negative = false;
    unsigned int i = 0;
    
    if (length > 0 && payload[0] == '-') {
        negative = true;
        i = 1;
    }
    
    for (; i < length; i++) {
        if (payload[i] < '0' || payload[i] > '9') break;
        value = value * 10 + (payload[i] - '0');
    }
    
    if (negative)  value = -value;
    
    Serial.print("Received on topic: ");
    Serial.print(topic);
    Serial.print(" -> Value: ");
    Serial.println(value);
}

Thanks! I've just made a itoa( ) conversion. Maybe this is the issue?

I am still getting 0
See screenshot :slight_smile:

Please post your code in code tags rather than a screenshot

the full code was posted above. The screenshot is because I wanted to show the output of MQTT when I send it numbers.

this is the callBack function as suggested by J-M-L

void callback(char* topic, byte* payload, unsigned int length)
{
   int value = 0;
   bool negative = false;
   unsigned int i = 0;

  if (strcmp(topic, "home/alarm/cmd") == 0) { 

    snprintf (msg, MSG_BUFFER_SIZE, "length is"); // send the message
    client.publish("home/alarm/log", msg);  
    delay(200); // make sure the message is sent

    if (length > 0 && payload[0] == '-') {
        negative = true;
        i = 1;
    }

    for (; i < length; i++) {
        if (payload[i] < '0' || payload[i] > '9') break;
        value = value * 10 + (payload[i] - '0');
    }

    if (negative)  value = -value;

    itoa(value, msg, 10); // converting to string for display
    client.publish("home/alarm/log", msg);
    delay(200); // make sure the message is sent
  }
}

I have a feeling the function work, but it is my itoa( ) and when I publish again to "home/alarm/log" that does not work

As I said in my original post, my Serial monitor does not work. Hence I troubleshoot by sending to MQTT ( :roll_eyes:).

Sorry, I missed the Serial port not working

Start by trying my method of turning the message into a C style string and sending that via MQTT

Success?
I simply output the payloadBuffer using snprintf( ) into MQTT, so I did not use atoi ( )

Seems like it is working! I will run some more test (and backup the code!!!)

CODE TAGS !

Do you mean when I past the code or when I mention functions in regular text?

I use code tags when posting code.

I am posting the screenshot to simply show the output of mosquitto, not to show the code (in fact it is the same as in the code tags above)

It makes things easier if you use code tags when posting any text from a screen

posting images of text is nonsense. Please stop.

Copy and paste the code with code tags
Copy and paste the Terminal data with code tags too.

Ok, I will try to also use code tags when writing text as well.

I think I understand the code.
You create a buffer, then copy the entirety of the payload into it. Then you null terminate the buffer.
Pretty simple, after you get it working! :sweat_smile:
How can I repay you back?