Browse Source

mqtt: once again, do not quote numbers in MQTT JSON payload

Restore behaviour from dd12251e43
7ba1283024 unintentionally removed it
Instead of reverting to the 'atof' code, just use the provided string
as-is via RawJson (aka `serialized()` in the v6)

Note that the old approach may have caused some silent data loss b/c the
data could have been stored in 'double' or 'u64', where the ArduinoJson
only stores 'u32' and 'float' in it's internal buffer and does not (really)
warn us about any type incompatibilities.
(at least by default. but, the alternative is to store all floating point
numbers as 'double' internally, see ArduinoJson/Configuration.hpp)

resolves #2503
pull/2508/head
Maxim Prokhorov 2 years ago
parent
commit
ce7de7d812
3 changed files with 42 additions and 33 deletions
  1. +11
    -1
      code/espurna/mqtt.cpp
  2. +30
    -32
      code/espurna/utils.cpp
  3. +1
    -0
      code/espurna/utils.h

+ 11
- 1
code/espurna/mqtt.cpp View File

@ -1424,8 +1424,18 @@ void mqttFlush() {
root[MQTT_TOPIC_MESSAGE_ID] = (Rtcmem->mqtt)++;
#endif
// ref. https://github.com/xoseperez/espurna/issues/2503
// pretend that the message is already a valid json value
// when the string looks like a number
// ([0-9] with an optional decimal separator [.])
for (auto& payload : _mqtt_json_payload) {
root[payload.topic().c_str()] = payload.message().c_str();
const char* const topic { payload.topic().c_str() };
const char* const message { payload.message().c_str() };
if (isNumber(payload.message())) {
root[topic] = RawJson(message);
} else {
root[topic] = message;
}
}
String output;


+ 30
- 32
code/espurna/utils.cpp View File

@ -229,43 +229,41 @@ double roundTo(double num, unsigned char positions) {
return round(num * multiplier) / multiplier;
}
bool isNumber(const String& value) {
if (value.length()) {
const char* begin { value.c_str() };
const char* end { value.c_str() + value.length() };
bool dot { false };
bool digit { false };
const char* ptr { begin };
bool isNumber(const char* begin, const char* end) {
bool dot { false };
bool digit { false };
while (ptr != end) {
switch (*ptr) {
case '\0':
break;
case '-':
case '+':
if (ptr != begin) {
return false;
}
break;
case '.':
if (dot) {
return false;
}
dot = true;
break;
case '0' ... '9':
digit = true;
break;
case 'a' ... 'z':
case 'A' ... 'Z':
for (auto ptr = begin; ptr != end; ++ptr) {
switch (*ptr) {
case '\0':
break;
case '-':
case '+':
if (ptr != begin) {
return false;
}
++ptr;
break;
case '.':
if (dot) {
return false;
}
dot = true;
break;
case '0' ... '9':
digit = true;
break;
case 'a' ... 'z':
case 'A' ... 'Z':
return false;
}
}
return digit;
return digit;
}
bool isNumber(const String& value) {
if (value.length()) {
return isNumber(value.begin(), value.end());
}
return false;


+ 1
- 0
code/espurna/utils.h View File

@ -41,6 +41,7 @@ bool sslFingerPrintArray(const char * fingerprint, unsigned char * bytearray);
bool sslFingerPrintChar(const char * fingerprint, char * destination);
char* strnstr(const char* buffer, const char* token, size_t n);
bool isNumber(const char* begin, const char* end);
bool isNumber(const String&);
uint32_t randomNumber();


Loading…
Cancel
Save