Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/devices/VICTRON_ORIONTR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Victron Energy Orion TR

|Model Id|[VICTORIONXS](https://github.com/theengs/decoder/blob/development/src/devices/VICTRON_ORIONTR_json.h)|
|-|-|
|Brand|Victron Energy|
|Model|Orion TR|
|Short Description|Various DC-DC Battery Charger models|
|Communication|BLE broadcast|
|Frequency|2.4Ghz|
|Power Source|From connected battery/alternator|
|Exchanged Data|device state, voltage out, voltage in, error code|
|Encrypted|Yes|
|Device Tracker|✅|
4 changes: 2 additions & 2 deletions docs/devices/VICTRON_SBS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
|Model Id|[VICTSBS](https://github.com/theengs/decoder/blob/development/src/devices/VICTRON_SBS_json.h)|
|-|-|
|Brand|Victron Energy|
|Model|Smart Battery Sense|
|Model|Smart Battery Sense, BMV-712 Smart and other battery monitoring devices|
|Short Description|Wireless battery voltage and temperature sensor|
|Communication|BLE broadcast|
|Frequency|2.4Ghz|
|Power Source|From connected battery|
|Exchanged Data|voltage, temperature|
|Exchanged Data|time to go, voltage, current, temperature, consumed Ah, state of charge, alarm|
|Encrypted|Yes|
|Device Tracker|✅|
83 changes: 81 additions & 2 deletions src/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,48 @@ double TheengsDecoder::value_from_hex_string(const char* data_str,
return value;
}

/*
* @brief Extracts bit-aligned values from a hex string.
* Bit 0 is the least significant bit of the first byte.
*/
double TheengsDecoder::value_from_bit_string(const char* data_str,
int bit_offset, int bit_length,
bool canBeNegative) {
if (bit_offset < 0 || bit_length <= 0 || bit_length > 63) {
return 0;
}

size_t data_chars = strlen(data_str);
size_t required_chars = ((size_t)(bit_offset + bit_length + 7) / 8) * 2;
if (data_chars < required_chars) {
return 0;
}

unsigned long long value = 0;
for (int i = 0; i < bit_length; ++i) {
int abs_bit = bit_offset + i;
size_t byte_idx = (size_t)abs_bit / 8;
uint8_t bit_idx = (uint8_t)(abs_bit % 8);
size_t hex_idx = byte_idx * 2;

uint8_t byte = (uint8_t)((getBinaryData(data_str[hex_idx]) << 4) |
getBinaryData(data_str[hex_idx + 1]));
if ((byte >> bit_idx) & 0x01) {
value |= (1ULL << i);
}
}

long long signed_value = (long long)value;
if (canBeNegative) {
unsigned long long sign_bit = (1ULL << (bit_length - 1));
if (value & sign_bit) {
signed_value -= (long long)(1ULL << bit_length);
}
}

return (double)signed_value;
}

/*
* @brief Removes the underscores at the beginning of key strings
* when duplicate properties exist in a device.
Expand Down Expand Up @@ -695,7 +737,8 @@ int TheengsDecoder::decodeBLEJson(JsonObject& jsondata) {

if (checkPropCondition(prop["condition"], svc_data, mfg_data, dev_name)) {
JsonArray decoder = prop["decoder"];
if (strstr((const char*)decoder[0], "value_from_hex_data") != nullptr) {
if (strstr((const char*)decoder[0], "value_from_hex_data") != nullptr ||
strstr((const char*)decoder[0], "value_from_bit_data") != nullptr) {
const char* src = svc_data;
if (strstr((const char*)decoder[1], MFG_DATA)) {
src = mfg_data;
Expand All @@ -706,7 +749,21 @@ int TheengsDecoder::decodeBLEJson(JsonObject& jsondata) {
static double cal_val = 0;
std::string proc_str = "";

if (data_index_is_valid(src, decoder[2].as<int>(), decoder[3].as<int>())) {
if (strstr((const char*)decoder[0], "value_from_bit_data") != nullptr) {
int bit_offset = decoder[2].as<int>();
int bit_length = decoder[3].as<int>();
size_t required_chars = ((size_t)(bit_offset + bit_length + 7) / 8) * 2;

if (data_index_is_valid(src, 0, required_chars)) {
temp_val = value_from_bit_string(
src,
bit_offset,
bit_length,
decoder[4].isNull() ? true : decoder[4].as<bool>());
} else {
break;
}
} else if (data_index_is_valid(src, decoder[2].as<int>(), decoder[3].as<int>())) {
decoder_function dec_fun = &TheengsDecoder::value_from_hex_string;

if (strstr((const char*)decoder[0], "bf") != nullptr) {
Expand Down Expand Up @@ -819,6 +876,28 @@ int TheengsDecoder::decodeBLEJson(JsonObject& jsondata) {
}
}

/* Optional enum-style lookup for numeric decoders. */
if (prop.containsKey("lookup")) {
JsonArray lookup = prop["lookup"];
for (unsigned int i = 0; i + 1 < lookup.size(); i += 2) {
long long lookup_key = LLONG_MIN;

if (lookup[i].is<const char*>()) {
const char* key_str = lookup[i].as<const char*>();
if (key_str != nullptr) {
lookup_key = strtoll(key_str, NULL, 16);
}
}

if (lookup_key != LLONG_MIN &&
(long long)temp_val == lookup_key &&
lookup[i + 1].is<const char*>()) {
proc_str = lookup[i + 1].as<const char*>();
break;
}
}
}

/* If there is any underscores at the beginning of the property name, there is multiple
* properties of this type, we need remove the underscores for creating the key.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ class TheengsDecoder {
UT363BT,
VICTRON_ENCR,
VICTBSC,
VICTORIONTR,
VICTORIONXS,
VICTSBP,
VICTSBS,
Expand All @@ -202,6 +203,7 @@ class TheengsDecoder {
private:
void reverse_hex_data(const char* in, char* out, int l);
double value_from_hex_string(const char* data_str, int offset, int data_length, bool reverse, bool canBeNegative = true, bool isFloat = false);
double value_from_bit_string(const char* data_str, int bit_offset, int bit_length, bool canBeNegative = true);
double bf_value_from_hex_string(const char* data_str, int offset, int data_length, bool reverse, bool canBeNegative = true, bool isFloat = false);
bool data_index_is_valid(const char* str, size_t index, size_t len);
bool data_length_is_valid(size_t data_len, size_t default_min, const JsonArray& condition, int *idx);
Expand Down
2 changes: 2 additions & 0 deletions src/devices.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
#include "devices/UT363BT_json.h"
#include "devices/VICTRON__ENCR_json.h"
#include "devices/VICTRON_BSC_json.h"
#include "devices/VICTRON_ORIONTR_json.h"
#include "devices/VICTRON_ORIONXS_json.h"
#include "devices/VICTRON_SBP_json.h"
#include "devices/VICTRON_SBS_json.h"
Expand Down Expand Up @@ -276,6 +277,7 @@ const char* _devices[][2] = {
{_UT363BT_json, _UT363BT_json_props},
{_VICTRON_ENCR_json, _VICTRON_ENCR_json_props},
{_VICTBSC_json, _VICTBSC_json_props},
{_VICTORIONTR_json, _VICTORIONTR_json_props},
{_VICTORIONXS_json, _VICTORIONXS_json_props},
{_VICTSBP_json, _VICTSBP_json_props},
{_VICTSBS_json, _VICTSBS_json_props},
Expand Down
86 changes: 86 additions & 0 deletions src/devices/VICTRON_ORIONTR_json.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const char* _VICTORIONTR_json = "{\"brand\":\"Victron Energy\",\"model\":\"Orion TR\",\"model_id\":\"VICTORIONTR\",\"tag\":\"0c48\",\"condition\":[\"manufacturerdata\",\"=\",40,\"index\",0,\"e10211\",\"&\",\"manufacturerdata\",\"index\",8,\"d0a3\",\"&\",\"manufacturerdata\",\"index\",12,\"04ffff\"],\"properties\":{\"device_state\":{\"decoder\":[\"string_from_hex_data\",\"manufacturerdata\",20,2],\"lookup\":[\"00\",\"off\",\"01\",\"low power\",\"02\",\"fault\",\"03\",\"bulk\",\"04\",\"absorption\",\"05\",\"float\",\"06\",\"storage\",\"07\",\"equalize manual\",\"09\",\"inverting\",\"0b\",\"power_supply\",\"f5\",\"starting up\",\"f6\",\"repeated absorption\",\"f7\",\"recondition\",\"f8\",\"battery safe\",\"f9\",\"active\",\"fc\",\"external control\",\"ff\",\"N/A\"]},\"volt_in\":{\"condition\":[\"manufacturerdata\",24,\"!\",\"ff7f\"],\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",24,4,true,true],\"post_proc\":[\"/\",100]},\"current_out\":{\"condition\":[\"manufacturerdata\",28,\"!\",\"ff7f\"],\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",28,4,true,true],\"post_proc\":[\"/\",10]},\"volt_out\":{\"condition\":[\"manufacturerdata\",32,\"!\",\"ffff\"],\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",32,4,true,false],\"post_proc\":[\"/\",100]},\"current_in\":{\"condition\":[\"manufacturerdata\",36,\"!\",\"ffff\"],\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",36,4,true,false],\"post_proc\":[\"/\",10]},\"error_code\":{\"condition\":[\"manufacturerdata\",22,\"!\",\"ff\"],\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",22,2]}}}";
/*R""""(
{
"brand":"Victron Energy",
"model":"Orion TR",
"model_id":"VICTORIONTR",
"tag":"0c48",
"condition":["manufacturerdata", "=", 40, "index", 0, "e10211", "&", "manufacturerdata", "index", 8, "d0a3", "&", "manufacturerdata", "index", 12, "04ffff"],
"properties":{
"device_state":{
"decoder":["string_from_hex_data", "manufacturerdata", 20, 2],
"lookup":["00", "off",
"01", "low power",
"02", "fault",
"03", "bulk",
"04", "absorption",
"05", "float",
"06", "storage",
"07", "equalize manual",
"09", "inverting",
"0b", "power_supply",
"f5", "starting up",
"f6", "repeated absorption",
"f7", "recondition",
"f8", "battery safe",
"f9", "active",
"fc", "external control",
"ff", "N/A"]
},
"volt_in":{
"condition":["manufacturerdata", 24, "!", "ff7f"],
"decoder":["value_from_hex_data", "manufacturerdata", 24, 4, true, true],
"post_proc":["/", 100]
},
"current_out":{
"condition":["manufacturerdata", 28, "!", "ff7f"],
"decoder":["value_from_hex_data", "manufacturerdata", 28, 4, true, true],
"post_proc":["/", 10]
},
"volt_out":{
"condition":["manufacturerdata", 32, "!", "ffff"],
"decoder":["value_from_hex_data", "manufacturerdata", 32, 4, true, false],
"post_proc":["/", 100]
},
"current_in":{
"condition":["manufacturerdata", 36, "!", "ffff"],
"decoder":["value_from_hex_data", "manufacturerdata", 36, 4, true, false],
"post_proc":["/", 10]
},
"error_code":{
"condition":["manufacturerdata", 22, "!", "ff"],
"decoder":["value_from_hex_data", "manufacturerdata", 22, 2]
}
}
})"""";*/

const char* _VICTORIONTR_json_props = "{\"properties\":{\"device_state\":{\"unit\":\"string\",\"name\":\"device state\"},\"volt_out\":{\"unit\":\"V\",\"name\":\"voltage\"},\"current_out\":{\"unit\":\"A\",\"name\":\"current\"},\"volt_in\":{\"unit\":\"V\",\"name\":\"voltage\"},\"current_in\":{\"unit\":\"A\",\"name\":\"current\"},\"error_code\":{\"unit\":\"int\",\"name\":\"error code\"}}}";
/*R""""(
{
"properties":{
"device_state":{
"unit":"string",
"name":"device state"
},
"volt_out": {
"unit": "V",
"name": "voltage"
},
"current_out": {
"unit": "A",
"name": "current"
},
"volt_in": {
"unit": "V",
"name": "voltage"
},
"current_in": {
"unit": "A",
"name": "current"
},
"error_code":{
"unit":"int",
"name":"error code"
}
}
})"""";*/
72 changes: 62 additions & 10 deletions src/devices/VICTRON_SBS_json.h
Original file line number Diff line number Diff line change
@@ -1,40 +1,92 @@
const char* _VICTSBS_json = "{\"brand\":\"Victron Energy\",\"model\":\"Smart Battery Sense\",\"model_id\":\"VICTSBS\",\"tag\":\"0c48\",\"condition\":[\"manufacturerdata\",\"index\",8,\"a5a3\",\"|\",\"manufacturerdata\",\"index\",8,\"a4a3\",\"&\",\"manufacturerdata\",\"=\",50,\"index\",0,\"e10211\",\"&\",\"manufacturerdata\",\"index\",12,\"02ffff\"],\"properties\":{\"volt\":{\"condition\":[\"manufacturerdata\",24,\"!\",\"ffff\"],\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",24,4,true,false],\"post_proc\":[\"/\",100]},\"tempc\":{\"condition\":[\"manufacturerdata\",37,\"bit\",0,0,\"&\",\"manufacturerdata\",37,\"bit\",1,1],\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",32,4,true,false],\"post_proc\":[\"-\",27315,\"/\",100]},\"alarm_reason\":{\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",28,4]}}}";
const char* _VICTSBS_json = "{\"brand\":\"Victron Energy\",\"model\":\"Battery Monitor/Smart Battery Sense/SmartShunt\",\"model_id\":\"VICTSBS\",\"tag\":\"0c48\",\"condition\":[\"manufacturerdata\",\"=\",50,\"index\",0,\"e10211\",\"&\",\"manufacturerdata\",\"index\",12,\"02ffff\"],\"properties\":{\"ttg\":{\"condition\":[\"manufacturerdata\",20,\"!\",\"ffff\"],\"decoder\":[\"value_from_bit_data\",\"manufacturerdata\",80,16,false]},\"volt\":{\"decoder\":[\"value_from_bit_data\",\"manufacturerdata\",96,16,true],\"post_proc\":[\"/\",100]},\"volt_aux\":{\"condition\":[\"manufacturerdata\",37,\"bit\",0,0,\"&\",\"manufacturerdata\",37,\"bit\",1,0],\"decoder\":[\"value_from_bit_data\",\"manufacturerdata\",128,16,true],\"post_proc\":[\"/\",100]},\"volt_mid\":{\"condition\":[\"manufacturerdata\",37,\"bit\",0,1,\"&\",\"manufacturerdata\",37,\"bit\",1,0],\"decoder\":[\"value_from_bit_data\",\"manufacturerdata\",128,16,true],\"post_proc\":[\"/\",100]},\"tempc\":{\"condition\":[\"manufacturerdata\",37,\"bit\",0,0,\"&\",\"manufacturerdata\",37,\"bit\",1,1],\"decoder\":[\"value_from_bit_data\",\"manufacturerdata\",128,16,true],\"post_proc\":[\"-\",27315,\"/\",100]},\"current\":{\"condition\":[\"manufacturerdata\",38,\"!\",\"ff\"],\"decoder\":[\"value_from_bit_data\",\"manufacturerdata\",146,22,true],\"post_proc\":[\"/\",1000]},\"consumed_ah\":{\"condition\":[\"manufacturerdata\",41,\"!\",\"fffff\"],\"decoder\":[\"value_from_bit_data\",\"manufacturerdata\",168,20,true],\"post_proc\":[\"/\",-10]},\"soc\":{\"condition\":[\"manufacturerdata\",46,\"!\",\"fff\"],\"decoder\":[\"value_from_bit_data\",\"manufacturerdata\",188,10,false],\"post_proc\":[\"/\",10]},\"alarm_reason\":{\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",28,4]}}}";
/*R""""(
{
"brand":"Victron Energy",
"model":"Smart Battery Sense",
"model":"Battery Monitor/Smart Battery Sense/SmartShunt",
"model_id":"VICTSBS",
"tag":"0c48",
"condition":["manufacturerdata", "index", 8, "a5a3", "|", "manufacturerdata", "index", 8, "a4a3", "&", "manufacturerdata", "=", 50, "index", 0, "e10211", "&", "manufacturerdata", "index", 12, "02ffff"],
"condition":["manufacturerdata", "=", 50, "index", 0, "e10211", "&", "manufacturerdata", "index", 12, "02ffff"],
"properties":{
"ttg":{
"condition":["manufacturerdata", 20, "!", "ffff"],
"decoder":["value_from_bit_data", "manufacturerdata", 80, 16, false]
},
"volt":{
"condition":["manufacturerdata", 24, "!", "ffff"],
"decoder":["value_from_hex_data", "manufacturerdata", 24, 4, true, false],
"post_proc":["/", 100]
"decoder":["value_from_bit_data", "manufacturerdata", 96, 16, true],
"post_proc":["/", 100]
},
"volt_aux":{
"condition":["manufacturerdata", 37, "bit", 0, 0, "&", "manufacturerdata", 37, "bit", 1, 0],
"decoder":["value_from_bit_data", "manufacturerdata", 128, 16, true],
"post_proc":["/", 100]
},
"volt_mid":{
"condition":["manufacturerdata", 37, "bit", 0, 1, "&", "manufacturerdata", 37, "bit", 1, 0],
"decoder":["value_from_bit_data", "manufacturerdata", 128, 16, true],
"post_proc":["/", 100]
},
"tempc":{
"condition":["manufacturerdata", 37, "bit", 0, 0, "&", "manufacturerdata", 37, "bit", 1, 1],
"decoder":["value_from_hex_data", "manufacturerdata", 32, 4, true, false],
"post_proc":["-", 27315, "/", 100]
"condition":["manufacturerdata", 37, "bit", 0, 0, "&", "manufacturerdata", 37, "bit", 1, 1],
"decoder":["value_from_bit_data", "manufacturerdata", 128, 16, true],
"post_proc":["-", 27315, "/", 100]
},
"current":{
"condition":["manufacturerdata", 38, "!", "ff"],
"decoder":["value_from_bit_data", "manufacturerdata", 146, 22, true],
"post_proc":["/", 1000]
},
"consumed_ah":{
"condition":["manufacturerdata", 41, "!", "fffff"],
"decoder":["value_from_bit_data", "manufacturerdata", 168, 20, true],
"post_proc":["/", -10]
},
"soc":{
"condition":["manufacturerdata", 46, "!", "fff"],
"decoder":["value_from_bit_data", "manufacturerdata", 188, 10, false],
"post_proc":["/", 10]
},
"alarm_reason":{
"decoder":["value_from_hex_data", "manufacturerdata", 28, 4]
}
}
})"""";*/

const char* _VICTSBS_json_props = "{\"properties\":{\"volt\":{\"unit\":\"V\",\"name\":\"voltage\"},\"tempc\":{\"unit\":\"°C\",\"name\":\"temperature\"},\"alarm_reason\":{\"unit\":\"int\",\"name\":\"alarm reason\"}}}";
const char* _VICTSBS_json_props = "{\"properties\":{\"ttg\":{\"unit\":\"min\",\"name\":\"duration\"},\"volt\":{\"unit\":\"V\",\"name\":\"voltage\"},\"volt_aux\":{\"unit\":\"V\",\"name\":\"voltage\"},\"volt_mid\":{\"unit\":\"V\",\"name\":\"voltage\"},\"tempc\":{\"unit\":\"°C\",\"name\":\"temperature\"},\"current\":{\"unit\":\"A\",\"name\":\"current\"},\"consumed_ah\":{\"unit\":\"Ah\",\"name\":\"consumed ampere hours\"},\"soc\":{\"unit\":\"%\",\"name\":\"state of charge\"},\"alarm_reason\":{\"unit\":\"int\",\"name\":\"alarm reason\"}}}";
/*R""""(
{
"properties":{
"ttg":{
"unit":"min",
"name":"duration"
},
"volt": {
"unit": "V",
"name": "voltage"
},
"volt_aux":{
"unit":"V",
"name":"voltage"
},
"volt_mid":{
"unit":"V",
"name":"voltage"
},
"tempc":{
"unit":"°C",
"name":"temperature"
},
"current":{
"unit":"A",
"name":"current"
},
"consumed_ah":{
"unit":"Ah",
"name":"consumed ampere hours"
},
"soc":{
"unit":"%",
"name":"state of charge"
},
"alarm_reason":{
"unit":"int",
"name":"alarm reason"
Expand Down
Loading
Loading