MQTT is working fine on multiple devices in my home network. Now I'm trying to get the below sensorValue (using modified code from AReResearch for an MQ-7 CO sensor connected to an ESP32) to be published over MQTT. Serial output works fine.
I presume that I'm using "snprintf" wrong.. help would be much appreciated! Thanks!
#include <Arduino.h>
#include <analogWrite.h>
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "****";
const char* password = "****";
const char* mqttServer = "****";
const int mqttPort = 1883;
const char* mqttUser = "****";
const char* mqttPassword = "****";
char msg[50];
WiFiClient espClient;
PubSubClient client(espClient);
int step = 1;
int brightness = 0;
int sensorPin = A0; // select the input pin for the CO sensor
int sensorValue = 0; // variable to store the value coming from the sensor
// Initial setup
void setup() {
// initialize digital pin LED_BUILTIN as an output
pinMode(LED_BUILTIN, OUTPUT);
// initialize the serial port
Serial.begin(9600);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi...");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
long rssi = WiFi.RSSI();
Serial.print("RSSI: ");
Serial.println(rssi);
client.setServer(mqttServer, mqttPort);
while (!client.connected()) {
Serial.println("Connecting to MQTT...");
if (client.connect("ESP32Client", mqttUser, mqttPassword )) {
Serial.println("Broker connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
}
void loop() {
analogWrite(LED_BUILTIN, 255); // turn the heater fully on
delay(60000); // heat for 60 second
// now reduce the heating power
analogWrite(LED_BUILTIN, 72); // turn the heater to approx 1,4V
delay(90000); // wait for 90 seconds
// we need to read the sensor at 5V, but must not let it heat up. So hurry!
digitalWrite(LED_BUILTIN, HIGH);
delay (50); //don't know how long to wait without heating up too much. Getting an analog read apparently takes 100uSec
// read the value from the sensor:
int sensorValue = analogRead(sensorPin);
sensorValue;
Serial.println(sensorValue);
// MQTT publish
snprintf (msg, sizeof(msg), "%ld", sensorValue);
client.publish("toaster/co/", msg);
Serial.println(msg); // debug
}
sizeof(msg) will always return 50 in your code because msg is a char array. If you want the number of elements in the array, use: sizeof(msg) / sizeof(msg[0])
For simple conversions, like an integer to string array, sprintf() is safe.
Both options result in printing the sensorValue, which ist great! But the MQTT message still does not get published... after some more debugging I found that the long delays (60+90 seconds) in the loop don't seem to work for MQTT. Reducing delays to 6+9 seconds everything works as expected, the message gets published.
Is this a known issue with MQTT? Am I missing something? Different post..? Thanks again
Sort of. client.loop() must be called in loop() periodically or the broker link is dropped. I do not know how long.
The delay(eternity) statements in your code threw up a red flag for me. In general any delay() of more than a few ms is strongly discouraged in the loop() function. I suspect that you are losing connection to the MQTT broker.
It's not an issue per se, that's how MQTT works. There is a keep alive that checks whether you're still listening and closes your session if you don't respond. The timeout for it is often 60 seconds.
Seems like a backward step for code that works as is
snprintf is a safer option see C static code analysis
All that needs to be added is a check on the return value
if (snprintf (msg, sizeof(msg), "%ld", sensorValue) > sizeof(msg)) {
Serial.println(F("msg buffer too small"));
}
Well not really if you don't get the buffer size correct.
itoa has similar safety issues (possible buffer overflow)
snprintf() is the save option.
Thanks for claryfing that 'snprintf' is good/better practice and how to implement it properly! So it seems the inital code was not all bad but for the long delay periods.
Interestingly the sensor readings don't seem to differ much with the much shorter heating periods. Anyways the MQ-7 is prone to influence from all kinds of exterior factors (room temperature, window open/closed) which makes it hard to figure out a baseline to build upon. Just a side note