From 4bfd22f9460a0cf02cb352f97a680366eef7d6a4 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Tue, 2 Mar 2021 21:18:08 +0100 Subject: [PATCH] Zigbee allow numbers as string --- .../jsmn-shadinger-1.0/src/JsonParser.cpp | 37 ++++++++++++++----- .../jsmn-shadinger-1.0/src/JsonParser.h | 3 ++ tasmota/xdrv_23_zigbee_1z_libs.ino | 14 +++++++ tasmota/xdrv_23_zigbee_A_impl.ino | 4 +- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/lib/default/jsmn-shadinger-1.0/src/JsonParser.cpp b/lib/default/jsmn-shadinger-1.0/src/JsonParser.cpp index 73703d6ed..41b79c868 100644 --- a/lib/default/jsmn-shadinger-1.0/src/JsonParser.cpp +++ b/lib/default/jsmn-shadinger-1.0/src/JsonParser.cpp @@ -26,18 +26,29 @@ const char * k_current_json_buffer = ""; +// returns nibble value or -1 if not an hex digit +static int32_t asc2byte(char chr) { + if (chr >= '0' && chr <= '9') { return chr - '0'; } + else if (chr >= 'A' && chr <= 'F') { return chr + 10 - 'A'; } + else if (chr >= 'a' && chr <= 'f') { return chr + 10 - 'a'; } + return -1; +} + /*********************************************************************************************\ * Lightweight String to Float, because atof() or strtof() takes 10KB * * To remove code, exponents are not parsed * (commented out below, just in case we need them after all) + * + * Moved to double to be able to parse 32 bits int as well without loss in accuracy \*********************************************************************************************/ // Inspired from https://searchcode.com/codesearch/view/22115068/ -float json_strtof(const char* s) { +double JsonParserToken::json_strtof(const char* s) { const char* p = s; - float value = 0.; + double value = 0.; int32_t sign = +1; - float factor; + double factor; + uint32_t base = 10; // support hex mode if start with Ox or OX // unsigned int expo; while (isspace(*p)){ // skip any leading white-spaces @@ -45,22 +56,30 @@ float json_strtof(const char* s) { } switch (*p) { - case '-': sign = -1; + case '-': sign = -1; // no break on purpose case '+': p++; default : break; } - while ((unsigned int)(*p - '0') < 10u) { - value = value*10 + (*p++ - '0'); + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { // detect hex mode + base = 16; + p += 2; + } + + int32_t v; // temp nibble value + while ((v = asc2byte(*p)) >= 0) { + value = value * base + v; + p++; } if (*p == '.' ) { factor = 1.0f; p++; - while ((unsigned int)(*p - '0') < 10u) { - factor *= 0.1f; - value += (*p++ - '0') * factor; + while ((v = asc2byte(*p)) >= 0) { + factor /= base; + value += v * factor; + p++; } } diff --git a/lib/default/jsmn-shadinger-1.0/src/JsonParser.h b/lib/default/jsmn-shadinger-1.0/src/JsonParser.h index a31f28c91..03a0aba65 100644 --- a/lib/default/jsmn-shadinger-1.0/src/JsonParser.h +++ b/lib/default/jsmn-shadinger-1.0/src/JsonParser.h @@ -114,6 +114,9 @@ public: JsonParserObject getObject(void) const; JsonParserArray getArray(void) const; + // general parser from string to int/hex/float + static double json_strtof(const char* s); + public: // the following should be 'protected' but then it can't be accessed by iterators const jsmntok_t * t; diff --git a/tasmota/xdrv_23_zigbee_1z_libs.ino b/tasmota/xdrv_23_zigbee_1z_libs.ino index c2510a01e..98a9f3a7d 100644 --- a/tasmota/xdrv_23_zigbee_1z_libs.ino +++ b/tasmota/xdrv_23_zigbee_1z_libs.ino @@ -191,6 +191,9 @@ public: int32_t getInt(void) const; uint32_t getUInt(void) const; bool getBool(void) const; + // optimistically try to get any value as literal or in string - double to not lose precision for 32 bits + double getOptimisticDouble(void) const; + // const SBuffer * getRaw(void) const; // always return a point to a string, if not defined then empty string. @@ -437,6 +440,17 @@ JsonGeneratorArray & Z_attribute::newJsonArray(void) { } // get num values +double Z_attribute::getOptimisticDouble(void) const { + switch (type) { + case Za_type::Za_bool: + case Za_type::Za_uint: return (double) val.uval32; + case Za_type::Za_int: return (double) val.ival32; + case Za_type::Za_float: return (double) val.fval; + case Za_type::Za_str: return JsonParserToken::json_strtof(val.sval); + default: return 0.0; + } +} + float Z_attribute::getFloat(void) const { switch (type) { case Za_type::Za_bool: diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index fc8bfdc3c..00309085b 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -235,7 +235,7 @@ void ZbApplyMultiplier(double &val_d, int8_t multiplier) { // Write Tuya-Moes attribute // bool ZbTuyaWrite(SBuffer & buf, const Z_attribute & attr) { - double val_d = attr.getFloat(); + double val_d = attr.getOptimisticDouble(); const char * val_str = attr.getStr(); if (attr.key_is_str) { return false; } // couldn't find attr if so skip @@ -294,7 +294,7 @@ bool ZbTuyaWrite(SBuffer & buf, const Z_attribute & attr) { // Send Attribute Write, apply mutlipliers before // bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_status_ok) { - double val_d = attr.getFloat(); + double val_d = attr.getOptimisticDouble(); const char * val_str = attr.getStr(); if (attr.key_is_str) { return false; } // couldn't find attr if so skip