New: the AI firewall watches the whole platform and explains each incident in plain words. See how it works

NodeMCU gets the command as byte* payload and atoi gives me 0

NodeMCU gets the command as byte* payload and atoi gives me 0

Solved 5 5

Hello, still learning. I have a NodeMCU (ESP8266) with PubSubClient controlling a LED strip through a MOSFET. On my Hermetry board there’s a slider that sends a command called light.set. I can see the message arrive in the serial monitor:

topic: v1/rpc/req/17
payload: {"method":"light.set","params":{"level":42}}

But in my callback I can’t get the 42 out. I tried:

void callback(char* topic, byte* payload, unsigned int length) {
int level = atoi((char*)payload);
analogWrite(D5, level);
}

level is always 0, sometimes a random big number. The strip doesn’t change. I also think the slider shows “Sent; waiting for the device” forever. What am I doing wrong?

Ask me about 4–20 mA.
♥ 0

Maybe cast it to a String first? String s = (char*)payload;

Still waiting for the gateway to reconnect.
♥ 0

The payload isn’t null-terminated, so reading it as a C string runs past the end. That’s the random number.

Measure twice, poll once.
♥ 2

Even with a null at the end, atoi on {“method”:… gives 0 because the first character is a brace. You need to parse the JSON.

If it isn't logged, it didn't happen.
♥ 0

Kevin A and Maria have both bits. I did nearly the same light controller for our office last year. Parse the JSON with ArduinoJson (it takes the buffer and length, so no null needed), pull the request id off the end of the topic, and answer on v1/rpc/res/ with that id. The “waiting for the device” stays because the board never gets an answer.

#include <ArduinoJson.h>
void callback(char* topic, byte* payload, unsigned int length) {
String t(topic);
String id = t.substring(t.lastIndexOf('/') + 1);   // "17"
StaticJsonDocument<256> doc;
if (deserializeJson(doc, payload, length)) return;
if (doc["method"] == "light.set") {
int level = doc["params"]["level"] | -1;          // -1 if missing
if (level >= 0 && level <= 100) {
analogWrite(D5, map(level, 0, 100, 0, 1023));
client.publish(("v1/rpc/res/" + id).c_str(), "{"ok":true}");
return;
}
}
client.publish(("v1/rpc/res/" + id).c_str(), "{"ok":false}");
}

ESP8266 analogWrite is 0-1023 by default, hence the map. And subscribe to v1/rpc/req/+ after every reconnect, not only in setup, or commands stop after the first Wi-Fi drop.

The topic list is on MQTT topics and payload reference.

Accepted solution♥ 1

It works!! The strip dims with the slider now and the board says Done. I had also been answering on v1/rpc/req/17 instead of res, so even when I got the number right nothing came back. Thank you Emily.

Ask me about 4–20 mA.
♥ 1
Viewing 6 posts – 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.

Join the conversation

Sign in to ask and answer, like helpful posts and mark the reply that solved your problem. Every contribution earns points and levels.

Share