From 0dc3b8d7e1d698b1079242d5b8948f93aaf6d0ca Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 23 Dec 2022 11:39:13 +0100 Subject: [PATCH] Add fieldpair "F" replacing "M" --- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 105 ++++++++++++------ 1 file changed, 74 insertions(+), 31 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index be66be989..0b06da4ca 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -36,7 +36,7 @@ * Voltage - Voltage register entered as decimal or hexadecimal for one phase (0x0000) or up to three phases ([0x0000,0x0002,0x0004]) or * Additional defined parameters * Value pair description: - * {"R":0,"T":0,"M":1} + * {"R":0,"T":0,"F":0} * R - Modbus register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) * T - Datatype - optional. default is 0 - float: * 0 - float @@ -48,7 +48,17 @@ * 6 = 4-byte signed with swapped words * 7 = not used * 8 = 4-byte unsigned with swapped words - * M - Multiply, if negative, or divide, if positive, the read register by 1 to 10000 - optional. default = 1 + * F - Register factor positive for multiplication or negative for division - optional. default is 0 - no action + * -4 - divide by 10000 + * -3 - divide by 1000 + * -2 - divide by 100 + * -1 - divide by 10 + * 0 - no action + * 1 - multiply by 10 + * 2 - multiply by 100 + * 3 - multiply by 1000 + * 4 - multiply by 10000 + * M - [LEGACY - replaced by "F"] Divide register by 1 to 10000 - optional. default = 0 (no action) * Current - Current register entered as decimal or hexadecimal for one phase (0x0006) or up to three phases ([0x0006,0x0008,0x000A]) or * See additional defines like voltage. * Power - Active power register entered as decimal or hexadecimal for one phase (0x000C) or up to three phases ([0x000C,0x000E,0x0010]) or @@ -68,7 +78,7 @@ * Optional user defined registers: * User - Additional user defined registers * Value pair description: - * "User":{"R":0x0024,"T":0,"M":1,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2} + * "User":{"R":0x0024,"T":0,"F":0,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2} * R - Modbus register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) * T - Datatype - optional. default is 0 - float: * 0 - float @@ -80,7 +90,17 @@ * 6 = 4-byte signed with swapped words * 7 = not used * 8 = 4-byte unsigned with swapped words - * M - Multiply, if negative, or divide, if positive, the read register by 1 to 10000 - optional. default = 1 + * F - Register factor positive for multiplication or negative for division - optional. default is 0 - no action + * -4 - divide by 10000 + * -3 - divide by 1000 + * -2 - divide by 100 + * -1 - divide by 10 + * 0 - no action + * 1 - multiply by 10 + * 2 - multiply by 100 + * 3 - multiply by 1000 + * 4 - multiply by 10000 + * M - [LEGACY - replaced by "F"] Divide register by 1 to 10000 - optional. default = 0 (no action) * J - JSON register name (preferrably without spaces like "PhaseAngle") * G - GUI register name * U - GUI unit name @@ -105,7 +125,7 @@ * rule3 on file#modbus do {"Name":"SDM120","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM230 with two user registers","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM630","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":[0,2,4],"Current":[6,8,10],"Power":[12,14,16],"ApparentPower":[18,20,22],"ReactivePower":[24,26,28],"Factor":[30,32,34],"Frequency":70,"Total":342,"ExportActive":[352,354,356],"User":{"R":[346,348,350],"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon - * rule3 on file#modbus do {"Name":"X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"M":10},"Power":{"R":0x040e,"T":3,"M":1},"Total":{"R":0x0423,"T":8,"M":1000}} endon + * rule3 on file#modbus do {"Name":"X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon * * Note: * - To enter long rules using the serial console and solve error "Serial buffer overrun" you might need to enlarge the serial input buffer with command serialbuffer 800 @@ -128,7 +148,7 @@ * rule3 on file#modbus do {"Name":"SDM120 test1","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"M":1},"Current":{"R":6,"T":0,"M":1},"Power":{"R":12,"T":0,"M":1},"Frequency":70,"Total":342} endon - * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"M":1},"Current":{"R":6,"T":0,"M":1},"Power":{"R":12,"T":0,"M":1},"Frequency":70,"Total":342,"User":{"R":0x0048,"T":0,"M":10,"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon + * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"F":0},"Current":{"R":6,"T":0,"F":0},"Power":{"R":12,"T":0,"F":0},"Frequency":70,"Total":342,"User":{"R":0x0048,"T":0,"F":-1,"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon \*********************************************************************************************/ #define XNRG_29 29 @@ -139,8 +159,6 @@ #define ENERGY_MODBUS_FUNC 0x04 // Default Modbus function code #define ENERGY_MODBUS_DATATYPE 0 // Default Modbus datatype is 4-byte float -#define ENERGY_MODBUS_DIVIDER 1 // Default Modbus data divider - #define ENERGY_MODBUS_DECIMALS 0 // Default user decimal resolution #define ENERGY_MODBUS_TICKER // Enable for ESP8266 when using softwareserial solving most modbus serial retries @@ -216,7 +234,7 @@ struct NRGMBSPARAM { typedef struct NRGMBSREGISTER { uint16_t address[ENERGY_MAX_PHASES]; - int16_t divider; + int16_t factor; uint32_t datatype; } NrgMbsRegister_t; NrgMbsRegister_t *NrgMbsReg = nullptr; @@ -342,10 +360,17 @@ void EnergyModbusLoop(void) { break; } } - if (NrgMbsReg[NrgMbsParam.state].divider < 1) { - value *= (NrgMbsReg[NrgMbsParam.state].divider * -1); + uint32_t factor = 1; + // 1 = 10, 2 = 100, 3 = 1000, 4 = 10000 + uint32_t scaler = abs(NrgMbsReg[NrgMbsParam.state].factor); + while (scaler) { + factor *= 10; + scaler--; + } + if (NrgMbsReg[NrgMbsParam.state].factor < 0) { + value /= factor; } else { - value /= NrgMbsReg[NrgMbsParam.state].divider; + value *= factor; } switch (NrgMbsParam.state) { @@ -417,7 +442,7 @@ void EnergyModbusLoop(void) { #ifdef USE_RULES bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add_index) { - // {"R":0x004E,"T":0,"M":1,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3} + // {"R":0x004E,"T":0,"F":0,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3} uint32_t reg_index = NRG_MBS_MAX_REGS + add_index; JsonParserToken val; val = user_add_value[PSTR("R")]; // Register address @@ -443,10 +468,21 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add // "T":0 NrgMbsReg[reg_index].datatype = val.getUInt(); } - val = user_add_value[PSTR("M")]; // Register divider + val = user_add_value[PSTR("F")]; // Register factor if (val) { - // "M":1 or "M":-10 - NrgMbsReg[reg_index].divider = val.getInt(); + // "F":1 or "F":-2 + NrgMbsReg[reg_index].factor = val.getInt(); + } + val = user_add_value[PSTR("M")]; // [LEGACY] Register divider + if (val) { + // "M":1 + int32_t divider = val.getUInt(); + int factor = 0; + while (divider > 1) { + divider /= 10; + factor--; + } + NrgMbsReg[reg_index].factor = factor; } val = user_add_value[PSTR("J")]; // JSON value name if (val) { @@ -472,13 +508,13 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add } #ifdef ENERGY_MODBUS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, M %d, J '%s', G '%s', U '%s', D %d"), + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, F %d, J '%s', G '%s', U '%s', D %d"), add_index, NrgMbsReg[reg_index].address[0], NrgMbsReg[reg_index].address[1], NrgMbsReg[reg_index].address[2], NrgMbsReg[reg_index].datatype, - NrgMbsReg[reg_index].divider, + NrgMbsReg[reg_index].factor, NrgMbsUser[add_index].json_name, NrgMbsUser[add_index].gui_name, NrgMbsUser[add_index].gui_unit, @@ -529,7 +565,6 @@ bool EnergyModbusReadRegisters(void) { // Init defaults for (uint32_t i = 0; i < NrgMbsParam.total_regs; i++) { NrgMbsReg[i].datatype = ENERGY_MODBUS_DATATYPE; - NrgMbsReg[i].divider = ENERGY_MODBUS_DIVIDER; for (uint32_t j = 0; j < ENERGY_MAX_PHASES; j++) { NrgMbsReg[i].address[j] = nrg_mbs_reg_not_used; } @@ -576,12 +611,12 @@ bool EnergyModbusReadRegisters(void) { if (val) { // "Voltage":0 // "Voltage":[0,0,0] - // "Voltage":{"R":0,"T":0,"M":1} - // "Voltage":{"R":[0,0,0],"T":0,"M":1} + // "Voltage":{"R":0,"T":0,"F":0} + // "Voltage":{"R":[0,0,0],"T":0,"F":0} uint32_t phase = 0; if (val.isObject()) { - // "Voltage":{"R":0,"T":0,"M":1} - // "Voltage":{"R":[0,0,0],"T":0,"M":1} + // "Voltage":{"R":0,"T":0,"F":0} + // "Voltage":{"R":[0,0,0],"T":0,"F":0} JsonParserObject register_add_values = val.getObject(); val = register_add_values[PSTR("R")]; // Register address if (val.isArray()) { @@ -602,10 +637,21 @@ bool EnergyModbusReadRegisters(void) { // "T":0 NrgMbsReg[names].datatype = val.getUInt(); } - val = register_add_values[PSTR("M")]; // Register divider + val = register_add_values[PSTR("F")]; // Register factor if (val) { - // "M":1 or "M":-10 - NrgMbsReg[names].divider = val.getInt(); + // "F":1 or "F":-2 + NrgMbsReg[names].factor = val.getInt(); + } + val = register_add_values[PSTR("M")]; // [LEGACY] Register divider + if (val) { + // "M":1 + int32_t divider = val.getUInt(); + int factor = 0; + while (divider > 1) { + divider /= 10; + factor--; + } + NrgMbsReg[names].factor = factor; } } else if (val.isArray()) { // "Voltage":[0,0,0] @@ -644,13 +690,13 @@ bool EnergyModbusReadRegisters(void) { } #ifdef ENERGY_MODBUS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, M %d"), + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, F %d"), names, NrgMbsReg[names].address[0], NrgMbsReg[names].address[1], NrgMbsReg[names].address[2], NrgMbsReg[names].datatype, - NrgMbsReg[names].divider); + NrgMbsReg[names].factor); #endif } @@ -687,9 +733,6 @@ bool EnergyModbusReadRegisters(void) { if (NrgMbsReg[i].datatype >= NRG_DT_MAX) { NrgMbsReg[i].datatype = ENERGY_MODBUS_DATATYPE; } - if (0 == NrgMbsReg[i].divider) { - NrgMbsReg[i].divider = ENERGY_MODBUS_DIVIDER; - } } #ifdef ENERGY_MODBUS_DEBUG