Merge pull request #11201 from s-hadinger/zigbee_str_as_num

Zigbee allow numbers as string
This commit is contained in:
s-hadinger 2021-03-02 21:41:13 +01:00 committed by GitHub
commit 2e7cf79111
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 11 deletions

View File

@ -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++;
}
}

View File

@ -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;

View File

@ -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:

View File

@ -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