Skip to content

Commit

Permalink
bit_static_value decoder
Browse files Browse the repository at this point in the history
Initial Test with SwitchBot Bot, Xiaomi Scales and CGH1 decoder compression

Improved code reduction with @h2zero's suggestion

• condensed getBinaryData to its own function, it being called twice
• commented out the UPPER case condition, as all presented data should only be lower case
• commented out the static_value bool cast, as this doesn't seem to be necessary any longer
  • Loading branch information
DigiH committed May 25, 2022
1 parent 9fa7b5c commit 4c32888
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 80 deletions.
21 changes: 18 additions & 3 deletions docs/participate/adding-decoders.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,31 @@ The NOT comparison is case sensitive! Therefor any NOT comparisons should be def
The first parameter is the name of the function to call, The available functions are:
- "value_from_hex_data" - converts the hex string value into an `integer` or `double` type.
- "bf_value_from_hex_data" - converts the (binary fraction) hex string value into a `double` type. This should be used when the hex data is represented in the format of `XX.XX`. For example: when `0x1a1e` should output 26.30.
- "static_value" - sets the value to the static value specified if the condition is met.
- "string_from_hex_data" - converts the hex value to a string type.
- "static_value" - sets the value to the static value specified if the condition is met.
- "bit_static_value" - sets the value to either one of two given values, depending on the evaluated binary bit.

The other parameters are:
The other parameters for the first three functions are:
- "servicedata" or "manufacturerdata" Extract the value from the specified data.
- 30, The index of the data source where the value exists.
- 24, The index of the data source where the value exists.
- 4, The length of the data in bytes (characters in the string).
- true/false, If the value in the data source should have it's endianness reversed before converting.
- (optional)true/false, Sets if the resulting value can be a negative number.

```
"properties":{
"unit":{
"decoder":["bit_static_value", "servicedata", 1, 0, "kg", "lb"]
},
```

The parameters for the "bit_static_value" function are:
- "servicedata" or "manufacturerdata" Extract the value from the specified data.
- 1, the index of the data source where the value exists.
- 0, the bit position from 0-3.
- The return value for bit state 0.
- The return value for bit state 1.

`post_proc` This specifies any post processing of the resulting decoded value. This is a JSON array that should be written in the order that the operation order is desired. In the simple example the first parameter is the "/" divide operation and the second parameter (10) is the value to divide the result by. Multiple operations can be chained together in this array to perform more complex calculations.

Valid operations are:
Expand Down
48 changes: 35 additions & 13 deletions src/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ typedef double (TheengsDecoder::*decoder_function)(const char* data_str,
int offset, int data_length,
bool reverse, bool canBeNegative);

typedef double (TheengsDecoder::*staticbitdecoder_function)(const char* data_str,
const char* source_str, int offset, int bitindex,
const char* falseresult, const char* trueresult);

/*
* @brief Revert the string data 2 by 2 to get the correct endianness
*/
Expand Down Expand Up @@ -149,6 +153,16 @@ int TheengsDecoder::data_length_is_valid(size_t data_len, size_t default_min,
return -1;
}

uint8_t TheengsDecoder::getBinaryData(char ch) {
uint8_t data = 0;
if (ch >= '0' && ch <= '9')
data = ch - '0';
else if (ch >= 'a' && ch <= 'f')
data = 10 + (ch - 'a');

return data;
}

bool TheengsDecoder::checkDeviceMatch(const JsonArray& condition,
const char* svc_data,
const char* mfg_data,
Expand Down Expand Up @@ -325,15 +339,7 @@ bool TheengsDecoder::checkPropCondition(const JsonArray& prop_condition,
size_t cond_len = strlen(prop_condition[i + 2 + inverse].as<const char*>());
if (strstr((const char*)prop_condition[i + 2], "bit") != nullptr) {
char ch = *(data_src + prop_condition[i + 1].as<int>());
uint8_t data = 0;
if (ch >= '0' && ch <= '9')
data = ch - '0';
else if (ch >= 'a' && ch <= 'f')
data = 10 + (ch - 'a');
else if (ch >= 'A' && ch <= 'F')
data = 10 + (ch - 'F');
else
return false;
uint8_t data = getBinaryData(ch);

uint8_t shift = prop_condition[i + 3].as<uint8_t>();
uint8_t val = prop_condition[i + 4].as<uint8_t>();
Expand Down Expand Up @@ -542,11 +548,27 @@ int TheengsDecoder::decodeBLEJson(JsonObject& jsondata) {
success = i_main;
DEBUG_PRINT("found value = %s : %.2f\n", _key.c_str(), jsondata[_key].as<double>());
} else if (strstr((const char*)decoder[0], "static_value") != nullptr) {
if (prop.containsKey("is_bool") && !decoder[1].is<std::string>()) {
decoder[1] = (bool)decoder[1];
if (strstr((const char*)decoder[0], "bit") != nullptr) {
JsonArray staticbitdecoder = prop["decoder"];
const char* data_src = nullptr;

if (svc_data && strstr((const char*)staticbitdecoder[1], SVC_DATA) != nullptr) {
data_src = svc_data;
} else if (mfg_data && strstr((const char*)staticbitdecoder[1], MFG_DATA) != nullptr) {
data_src = mfg_data;
}

char ch = *(data_src + staticbitdecoder[2].as<int>());
uint8_t data = getBinaryData(ch);
uint8_t shift = staticbitdecoder[3].as<uint8_t>();
int x = 4 + ((data >> shift) & 0x01);

jsondata[sanitizeJsonKey(kv.key().c_str())] = staticbitdecoder[x];
success = i_main;
} else {
jsondata[sanitizeJsonKey(kv.key().c_str())] = decoder[1];
success = i_main;
}
jsondata[sanitizeJsonKey(kv.key().c_str())] = decoder[1];
success = i_main;
} else if (strstr((const char*)decoder[0], "string_from_hex_data") != nullptr) {
const char* src = svc_data;
if (strstr((const char*)decoder[1], MFG_DATA)) {
Expand Down
1 change: 1 addition & 0 deletions src/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class TheengsDecoder {
double bf_value_from_hex_string(const char* data_str, int offset, int data_length, bool reverse, bool canBeNegative = true);
bool data_index_is_valid(const char* str, size_t index, size_t len);
int data_length_is_valid(size_t data_len, size_t default_min, const JsonArray& condition, int idx);
uint8_t getBinaryData(char ch);
bool checkPropCondition(const JsonArray& prop, const char* svc_data, const char* mfg_data);
bool checkDeviceMatch(const JsonArray& condition, const char* svc_data, const char* mfg_data,
const char* dev_name, const char* svc_uuid);
Expand Down
28 changes: 6 additions & 22 deletions src/devices/CGH1_json.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const char* _CGH1_json = "{\"brand\":\"Qingping\",\"model\":\"Door sensor\",\"model_id\":\"CGH1\",\"condition\":[\"servicedata\",\"index\",0,\"c804\",\"|\",\"servicedata\",\"index\",0,\"4804\",\"|\",\"servicedata\",\"index\",0,\"0804\",\"|\",\"servicedata\",\"index\",0,\"8804\"],\"properties\":{\"open\":{\"condition\":[\"servicedata\",0,\"c804\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",21,1,false],\"is_bool\":1,\"post_proc\":[\"!\"]},\"_open\":{\"condition\":[\"servicedata\",0,\"4804\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",21,1,false],\"is_bool\":1,\"post_proc\":[\"!\"]},\"__open\":{\"condition\":[\"servicedata\",0,\"0804\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",33,1,false],\"is_bool\":1,\"post_proc\":[\"!\"]},\"___open\":{\"condition\":[\"servicedata\",0,\"8804\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",33,1,false],\"is_bool\":1,\"post_proc\":[\"!\"]}}}";
const char* _CGH1_json = "{\"brand\":\"Qingping\",\"model\":\"Door sensor\",\"model_id\":\"CGH1\",\"condition\":[\"servicedata\",\"index\",0,\"c804\",\"|\",\"servicedata\",\"index\",0,\"4804\",\"|\",\"servicedata\",\"index\",0,\"0804\",\"|\",\"servicedata\",\"index\",0,\"8804\"],\"properties\":{\"open\":{\"condition\":[\"servicedata\",0,\"c804\",\"|\",\"servicedata\",0,\"4804\"],\"decoder\":[\"bit_static_value\",\"servicedata\",21,0,true,false]},\"_open\":{\"condition\":[\"servicedata\",0,\"0804\",\"|\",\"servicedata\",0,\"8804\"],\"decoder\":[\"bit_static_value\",\"servicedata\",33,0,true,false]}}}";
/*R""""(
{
"brand":"Qingping",
Expand All @@ -7,28 +7,12 @@ const char* _CGH1_json = "{\"brand\":\"Qingping\",\"model\":\"Door sensor\",\"mo
"condition":["servicedata", "index", 0, "c804", "|", "servicedata", "index", 0, "4804", "|", "servicedata", "index", 0, "0804", "|", "servicedata", "index", 0, "8804"],
"properties":{
"open":{
"condition":["servicedata", 0, "c804"],
"decoder":["value_from_hex_data", "servicedata", 21, 1, false],
"is_bool":1,
"post_proc":["!"]
"condition":["servicedata", 0, "c804", "|", "servicedata", 0, "4804"],
"decoder":["bit_static_value", "servicedata", 21, 0, true, false]
},
"_open":{
"condition":["servicedata", 0, "4804"],
"decoder":["value_from_hex_data", "servicedata", 21, 1, false],
"is_bool":1,
"post_proc":["!"]
},
"__open":{
"condition":["servicedata", 0, "0804"],
"decoder":["value_from_hex_data", "servicedata", 33, 1, false],
"is_bool":1,
"post_proc":["!"]
},
"___open":{
"condition":["servicedata", 0, "8804"],
"decoder":["value_from_hex_data", "servicedata", 33, 1, false],
"is_bool":1,
"post_proc":["!"]
"_open":{
"condition":["servicedata", 0, "0804", "|", "servicedata", 0, "8804"],
"decoder":["bit_static_value", "servicedata", 33, 0, true, false]
}
}
})"""";*/
Expand Down
2 changes: 1 addition & 1 deletion src/devices/SBMT_json.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const char* _SBMT_json = "{\"brand\":\"SwitchBot\",\"model\":\"Meter (Plus)\",\"
"post_proc":["+", ".cal", "*", -1]
},
"_tempc":{
"condition":["servicedata", 8, "bit", 3, 1],
"condition":["servicedata", 8, "bit", 3, 1],
"decoder":["value_from_hex_data", "servicedata", 8, 2, true, false],
"post_proc":["+", ".cal", "-", 128]
},
Expand Down
16 changes: 3 additions & 13 deletions src/devices/SBS1_json.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const char* _SBS1_json = "{\"brand\":\"SwitchBot\",\"model\":\"Bot\",\"model_id\":\"X1\",\"condition\":[\"uuid\",\"index\",0,\"0d00\",\"&\",\"servicedata\",\"=\",6,\"index\",0,\"48\"],\"properties\":{\"mode\":{\"condition\":[\"servicedata\",2,\"bit\",3,1],\"decoder\":[\"static_value\",\"on/off\"]},\"_mode\":{\"condition\":[\"servicedata\",2,\"bit\",3,0],\"decoder\":[\"static_value\",\"onestate\"]},\"state\":{\"condition\":[\"servicedata\",2,\"bit\",2,0],\"decoder\":[\"static_value\",\"on\"]},\"_state\":{\"condition\":[\"servicedata\",2,\"bit\",2,1],\"decoder\":[\"static_value\",\"off\"]},\"batt\":{\"condition\":[\"servicedata\",4,\"bit\",3,0],\"decoder\":[\"value_from_hex_data\",\"servicedata\",4,2,false,false]},\"_batt\":{\"condition\":[\"servicedata\",4,\"bit\",3,1],\"decoder\":[\"value_from_hex_data\",\"servicedata\",4,2,false,false],\"post_proc\":[\"-\",128]}}}";
const char* _SBS1_json = "{\"brand\":\"SwitchBot\",\"model\":\"Bot\",\"model_id\":\"X1\",\"condition\":[\"uuid\",\"index\",0,\"0d00\",\"&\",\"servicedata\",\"=\",6,\"index\",0,\"48\"],\"properties\":{\"mode\":{\"decoder\":[\"bit_static_value\",\"servicedata\",2,3,\"onestate\",\"on/off\"]},\"state\":{\"decoder\":[\"bit_static_value\",\"servicedata\",2,2,\"on\",\"off\"]},\"batt\":{\"condition\":[\"servicedata\",4,\"bit\",3,0],\"decoder\":[\"value_from_hex_data\",\"servicedata\",4,2,false,false]},\"_batt\":{\"condition\":[\"servicedata\",4,\"bit\",3,1],\"decoder\":[\"value_from_hex_data\",\"servicedata\",4,2,false,false],\"post_proc\":[\"-\",128]}}}";
/*R""""(
{
"brand":"SwitchBot",
Expand All @@ -7,20 +7,10 @@ const char* _SBS1_json = "{\"brand\":\"SwitchBot\",\"model\":\"Bot\",\"model_id\
"condition":["uuid", "index",0, "0d00","&", "servicedata", "=", 6, "index", 0, "48"],
"properties":{
"mode":{
"condition":["servicedata", 2, "bit", 3, 1],
"decoder":["static_value", "on/off"]
},
"_mode":{
"condition":["servicedata", 2, "bit", 3, 0],
"decoder":["static_value", "onestate"]
"decoder":["bit_static_value", "servicedata", 2, 3, "onestate", "on/off"]
},
"state":{
"condition":["servicedata", 2, "bit", 2, 0],
"decoder":["static_value", "on"]
},
"_state":{
"condition":["servicedata", 2, "bit", 2, 1],
"decoder":["static_value", "off"]
"decoder":["bit_static_value", "servicedata", 2, 2, "on", "off"]
},
"batt":{
"condition":["servicedata", 4, "bit", 3, 0],
Expand Down
16 changes: 3 additions & 13 deletions src/devices/XMTZC04HM_json.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const char* _XMTZC04HM_json = "{\"brand\":\"Xiaomi\",\"model\":\"Mi_Smart_Scale\",\"model_id\":\"XMTZC01HM/XMTZC04HM\",\"condition\":[\"servicedata\",\"index\",0,\"2\",\"|\",\"servicedata\",\"index\",0,\"a\",\"|\",\"servicedata\",\"index\",0,\"6\",\"|\",\"servicedata\",\"index\",0,\"e\",\"&\",\"uuid\",\"contain\",\"181d\"],\"properties\":{\"weighing_mode\":{\"condition\":[\"servicedata\",0,\"2\",\"|\",\"servicedata\",0,\"a\"],\"decoder\":[\"static_value\",\"person\"]},\"_weighing_mode\":{\"condition\":[\"servicedata\",0,\"6\",\"|\",\"servicedata\",0,\"e\"],\"decoder\":[\"static_value\",\"object\"]},\"unit\":{\"condition\":[\"servicedata\",1,\"2\"],\"decoder\":[\"static_value\",\"kg\"]},\"_unit\":{\"condition\":[\"servicedata\",1,\"3\"],\"decoder\":[\"static_value\",\"lb\"]},\"weight\":{\"condition\":[\"servicedata\",1,\"2\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",2,4,true,false],\"post_proc\":[\"/\",200]},\"_weight\":{\"condition\":[\"servicedata\",1,\"3\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",2,4,true,false],\"post_proc\":[\"/\",100]}}}";
const char* _XMTZC04HM_json = "{\"brand\":\"Xiaomi\",\"model\":\"Mi_Smart_Scale\",\"model_id\":\"XMTZC01HM/XMTZC04HM\",\"condition\":[\"servicedata\",\"index\",0,\"2\",\"|\",\"servicedata\",\"index\",0,\"a\",\"|\",\"servicedata\",\"index\",0,\"6\",\"|\",\"servicedata\",\"index\",0,\"e\",\"&\",\"uuid\",\"contain\",\"181d\"],\"properties\":{\"weighing_mode\":{\"decoder\":[\"bit_static_value\",\"servicedata\",0,2,\"person\",\"object\"]},\"unit\":{\"decoder\":[\"bit_static_value\",\"servicedata\",1,0,\"kg\",\"lb\"]},\"weight\":{\"condition\":[\"servicedata\",1,\"2\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",2,4,true,false],\"post_proc\":[\"/\",200]},\"_weight\":{\"condition\":[\"servicedata\",1,\"3\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",2,4,true,false],\"post_proc\":[\"/\",100]}}}";
/*R""""(
{
"brand":"Xiaomi",
Expand All @@ -7,20 +7,10 @@ const char* _XMTZC04HM_json = "{\"brand\":\"Xiaomi\",\"model\":\"Mi_Smart_Scale\
"condition":["servicedata", "index", 0, "2", "|", "servicedata", "index", 0, "a", "|", "servicedata", "index", 0, "6", "|", "servicedata", "index", 0, "e", "&", "uuid", "contain", "181d"],
"properties":{
"weighing_mode":{
"condition":["servicedata", 0, "2", "|", "servicedata", 0, "a"],
"decoder":["static_value", "person"]
},
"_weighing_mode":{
"condition":["servicedata", 0, "6", "|", "servicedata", 0, "e"],
"decoder":["static_value", "object"]
"decoder":["bit_static_value", "servicedata", 0, 2, "person", "object"]
},
"unit":{
"condition":["servicedata", 1, "2"],
"decoder":["static_value", "kg"]
},
"_unit":{
"condition":["servicedata", 1, "3"],
"decoder":["static_value", "lb"]
"decoder":["bit_static_value", "servicedata", 1, 0, "kg", "lb"]
},
"weight":{
"condition":["servicedata", 1, "2"],
Expand Down
20 changes: 5 additions & 15 deletions src/devices/XMTZC05HM_json.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const char* _XMTZC05HM_json = "{\"brand\":\"Xiaomi\",\"model\":\"Mi_Body_Composition_Scale\",\"model_id\":\"XMTZC02HM/XMTZC05HM\",\"condition\":[\"servicedata\",\"index\",2,\"2\",\"|\",\"servicedata\",\"index\",2,\"a\",\"&\",\"uuid\",\"contain\",\"181b\"],\"properties\":{\"weighing_mode\":{\"condition\":[\"servicedata\",1,\"2\",\"|\",\"servicedata\",1,\"3\"],\"decoder\":[\"static_value\",\"person\"]},\"_weighing_mode\":{\"condition\":[\"servicedata\",1,\"6\",\"|\",\"servicedata\",1,\"7\"],\"decoder\":[\"static_value\",\"object\"]},\"unit\":{\"condition\":[\"servicedata\",1,\"2\",\"|\",\"servicedata\",1,\"6\"],\"decoder\":[\"static_value\",\"kg\"]},\"_unit\":{\"condition\":[\"servicedata\",1,\"3\",\"|\",\"servicedata\",1,\"7\"],\"decoder\":[\"static_value\",\"lb\"]},\"weight\":{\"condition\":[\"servicedata\",1,\"2\",\"|\",\"servicedata\",1,\"6\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",22,4,true,false],\"post_proc\":[\"/\",200]},\"_weight\":{\"condition\":[\"servicedata\",1,\"3\",\"|\",\"servicedata\",1,\"7\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",22,4,true,false],\"post_proc\":[\"/\",100]},\"impedance\":{\"condition\":[\"servicedata\",3,\"6\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",18,4,true,false]}}}";
const char* _XMTZC05HM_json = "{\"brand\":\"Xiaomi\",\"model\":\"Mi_Body_Composition_Scale\",\"model_id\":\"XMTZC02HM/XMTZC05HM\",\"condition\":[\"servicedata\",\"index\",2,\"2\",\"|\",\"servicedata\",\"index\",2,\"a\",\"&\",\"uuid\",\"contain\",\"181b\"],\"properties\":{\"weighing_mode\":{\"decoder\":[\"bit_static_value\",\"servicedata\",1,2,\"person\",\"object\"]},\"unit\":{\"decoder\":[\"bit_static_value\",\"servicedata\",1,0,\"kg\",\"lb\"]},\"weight\":{\"condition\":[\"servicedata\",1,\"bit\",0,0],\"decoder\":[\"value_from_hex_data\",\"servicedata\",22,4,true,false],\"post_proc\":[\"/\",200]},\"_weight\":{\"condition\":[\"servicedata\",1,\"bit\",0,1],\"decoder\":[\"value_from_hex_data\",\"servicedata\",22,4,true,false],\"post_proc\":[\"/\",100]},\"impedance\":{\"condition\":[\"servicedata\",3,\"6\"],\"decoder\":[\"value_from_hex_data\",\"servicedata\",18,4,true,false]}}}";
/*R""""(
{
"brand":"Xiaomi",
Expand All @@ -7,28 +7,18 @@ const char* _XMTZC05HM_json = "{\"brand\":\"Xiaomi\",\"model\":\"Mi_Body_Composi
"condition":["servicedata", "index", 2, "2", "|", "servicedata", "index", 2, "a", "&", "uuid", "contain", "181b"],
"properties":{
"weighing_mode":{
"condition":["servicedata", 1, "2", "|", "servicedata", 1, "3"],
"decoder":["static_value", "person"]
},
"_weighing_mode":{
"condition":["servicedata", 1, "6", "|", "servicedata", 1, "7"],
"decoder":["static_value", "object"]
"decoder":["bit_static_value", "servicedata", 1, 2, "person", "object"]
},
"unit":{
"condition":["servicedata", 1, "2", "|", "servicedata", 1, "6"],
"decoder":["static_value", "kg"]
},
"_unit":{
"condition":["servicedata", 1, "3", "|", "servicedata", 1, "7"],
"decoder":["static_value", "lb"]
"decoder":["bit_static_value", "servicedata", 1, 0, "kg", "lb"]
},
"weight":{
"condition":["servicedata", 1, "2", "|", "servicedata", 1, "6"],
"condition":["servicedata", 1, "bit", 0, 0],
"decoder":["value_from_hex_data", "servicedata", 22, 4, true, false],
"post_proc":["/", 200]
},
"_weight":{
"condition":["servicedata", 1, "3", "|", "servicedata", 1, "7"],
"condition":["servicedata", 1, "bit", 0, 1],
"decoder":["value_from_hex_data", "servicedata", 22, 4, true, false],
"post_proc":["/", 100]
},
Expand Down

0 comments on commit 4c32888

Please sign in to comment.