diff --git a/.github/scripts/createMergedFirmware.py b/.github/scripts/createMergedFirmware.py index 301c66eb..b89ac3ad 100644 --- a/.github/scripts/createMergedFirmware.py +++ b/.github/scripts/createMergedFirmware.py @@ -31,18 +31,33 @@ args = parser.parse_args() result = None +# Bootloader offsets vary by chip +bootloader_offsets = { + "ESP32": "0x1000", + "ESP32-S2": "0x1000", + "ESP32-S3": "0x0", + "ESP32-C2": "0x0", + "ESP32-C3": "0x0", + "ESP32-C5": "0x2000", + "ESP32-C6": "0x0", + "ESP32-H2": "0x0", + "ESP32-P4": "0x2000", +} + if(not os.path.isfile(args.PathOfPartitionsCSV)): logging.error(f'File {args.PathOfPartitionsCSV} does not exist') exit(1) if args.BuildDir and os.path.isdir(args.BuildDir): if 'ESP32' in args.ChipFamily: + bootloader_offset = bootloader_offsets[args.ChipFamily] + result = f'esptool.py --chip {args.ChipFamily} merge_bin \ --output {args.BuildDir}/merged-firmware.bin \ --flash_mode dout \ --flash_freq 80m \ --flash_size 4MB \ - 0x1000 {args.BuildDir}/bootloader.bin \ + {bootloader_offset} {args.BuildDir}/bootloader.bin \ 0x8000 {args.BuildDir}/partitions.bin \ {readOffsetFromPartitionCSV("partitions.csv", "app0")} {args.BuildDir}/firmware.bin' diff --git a/.github/scripts/myUtils.py b/.github/scripts/myUtils.py index 5f80746a..445eebc9 100644 --- a/.github/scripts/myUtils.py +++ b/.github/scripts/myUtils.py @@ -288,7 +288,7 @@ def deleteVersions(root: str, keepVersions: int, json: list = None) -> None: # Lade die 'versions.json' Datei versions_file = os.path.join(root, 'versions.json') json = read_json_file(versions_file) - if versions is None: + if json is None: logging.error(f"Fehler beim Verarbeiten der Datei {versions_file}") return diff --git a/.github/workflows/BuildAndDeploy.yml b/.github/workflows/BuildAndDeploy.yml index aa6cdc1c..74417466 100644 --- a/.github/workflows/BuildAndDeploy.yml +++ b/.github/workflows/BuildAndDeploy.yml @@ -17,6 +17,10 @@ on: - '**.yml' - '**.sh' - '**.py' + - '**.json' + - '**.js' + - '**.css' + - '**.html' jobs: build: diff --git a/CPPLINT.cfg b/CPPLINT.cfg new file mode 100644 index 00000000..3c255f5e --- /dev/null +++ b/CPPLINT.cfg @@ -0,0 +1,3 @@ +linelength=120 +root=src +filter=-build/include_what_you_use \ No newline at end of file diff --git a/ChangeLog.md b/ChangeLog.md index 1ce829e9..8c91a1e1 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,9 +1,18 @@ +Release 3.3.2: + - new feature: add confirmation dialog for ESP reset + - migrate from old ajax communication to standard websocket communication + - new feature: show set topics in WebUI (thanks to @laszgar) + - new feature: add "newUpdate available" info in WebUI header + - new feature: add toggle buttons at ModbusItems WebUI to change all items at once (#96) + - new Inverter: add Growatt-SPH-V124 register file (thanks to @StefanNouza) (#109) + Release 3.3.1: - new Feature: datatype "binary" now available for json register definitions (PR #115) - BugFix: fix null-terminationof string handling (#96) - new feature: support for OpenWB 2.0 Api (#100) - bugfix: fix esp crash for /getitems if using an huge register table (#76) - fix CORS Issue when download a stable release + - bugfix: fix register id definition (#113) Release 3.3.0: - new feature: WebSerial as remote serial output (#74) diff --git a/data/regs/Growatt-SPH-V124.json b/data/regs/Growatt-SPH-V124.json new file mode 100644 index 00000000..8fbe97fb --- /dev/null +++ b/data/regs/Growatt-SPH-V124.json @@ -0,0 +1,659 @@ +{ + "Growatt-SPH-V124": { + "config": { + "author": "StefanNouza", + "RequestLiveData": [ + ["#ClientID", "0x04", "0x00", "0x00", "0x00", "0x77"], + ["#ClientID", "0x04", "0x03", "0xF1", "0x00", "0x7D"] + ], + "RequestIdData": [ + ["#ClientID", "0x03", "0x00", "0x00", "0x00", "0x1E"] + ], + "ClientIdPos": 0, + "LiveDataFunctionCodePos": 1, + "LiveDataFunctionCode": "0x04", + "IdDataFunctionCodePos": 1, + "IdDataFunctionCode": "0x03", + "LiveDataStartsAtPos": 3, + "IdDataStartsAtPos": 3, + "LiveDataErrorPos": 1, + "LiveDataErrorCode": "0x84", + "IdDataErrorPos": 1, + "IdDataErrorCode": "0x83", + "LiveDataSuccessPos": 1, + "LiveDataSuccessCode": "0x04", + "IdDataSuccessPos": 1, + "IdDataSuccessCode": "0x03" + }, + "data": { + "livedata": [ + { + "position": [3, 4], + "name": "Inverter_Status", + "realname": "Inverter status (number)", + "datatype": "integer", + "unit": "" + }, + { + "position": [3, 4], + "name": "Inverter_StatusText", + "realname": "Inverter status (text)", + "datatype": "integer", + "mapping": [[0,"0: waiting"], + [1,"1: normal"], + [2,"2:"], + [3,"3: fault"], + [4,"4:"], + [5,"5:"], + [6,"6:"], + [7,"7:"], + [8,"8:"], + [9,"9:"]], + "unit": "" + }, + { + "position": [5, 6, 7, 8], + "name": "Power_PV_Input_W", + "realname": "Power of PV input", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [9, 10], + "name": "PV1_InputVoltage_V", + "realname": "PV1 input Voltage", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [11, 12], + "name": "PV1_InputCurrent_A", + "realname": "PV1 input Current", + "datatype": "float", + "factor": 1.0, + "unit": "A" + }, + { + "position": [13, 14, 15, 16], + "name": "Power_PV1_Input_W", + "realname": "Power of PV1 input", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [17, 18], + "name": "PV2_InputVoltage_V", + "realname": "PV2 input Voltage", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [19, 20], + "name": "PV2_InputCurrent_A", + "realname": "PV2 input Current", + "datatype": "float", + "factor": 1.0, + "unit": "A" + }, + { + "position": [21, 22, 23, 24], + "name": "Power_PV2_Input_W", + "realname": "Power of PV2 input", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [73, 74, 75, 76], + "name": "AC_OutputPower_W", + "realname": "AC output Power", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [77, 78], + "name": "AC_GridFrequency_Hz", + "realname": "Grid Frequency", + "datatype": "float", + "factor": 0.01, + "unit": "Hz" + }, + { + "position": [109, 110, 111, 112], + "name": "Energy_Generated_today_kWh", + "realname": "generated Energy today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [113, 114, 115, 116], + "name": "Energy_Generated_total_kWh", + "realname": "generated Energy total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [117, 118, 119, 120], + "name": "Inverter_WorkTime_total_s", + "realname": "Inverter work time total", + "datatype": "integer", + "factor": 0.5, + "unit": "s" + }, + { + "position": [121, 122, 123, 124], + "name": "Energy_Generated_PV1_today_kWh", + "realname": "generated Energy today PV1", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [125, 126, 127, 128], + "name": "Energy_Generated_PV1_total_kWh", + "realname": "generated Energy total PV1", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [129, 130, 131, 132], + "name": "Energy_Generated_PV2_today_kWh", + "realname": "generated Energy today PV2", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [133, 134, 135, 136], + "name": "Energy_Generated_PV2_total_kWh", + "realname": "generated Energy total PV2", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [185, 186, 187, 188], + "name": "Energy_Generated_PV_total_kWh", + "realname": "generated Energy total PV", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [211, 212], + "name": "Inverter_DeratingMode", + "realname": "Inverter derating mode", + "datatype": "integer", + "mapping": [[0,"no derate"], + [1,"PV derate"], + [2,"derate-2"], + [3,"Vac derate"], + [4,"Fac derate"], + [5,"Tboost derate"], + [6,"Tinv derate"], + [7,"Control derate"], + [8,"derate-8"], + [9,"OverBack By Time derate"]], + "unit": "" + }, + { + "position": [213, 214], + "name": "Inverter_FaultCode", + "realname": "Inverter fault code (number)", + "datatype": "integer", + "unit": "" + }, + { + "position": [215, 216, 217, 218], + "name": "Inverter_FaultCodeText", + "realname": "Inverter fault code bits (text)", + "datatype": "integer", + "mapping": [[ 1,"b00 "], + [ 2,"b01 communication error"], + [ 4,"b02 "], + [ 8,"b03 StrReverse or StrShort fault"], + [ 16,"b04 model init fault"], + [ 32,"b05 grid volt sample different"], + [ 64,"b06 ISO sample different"], + [ 128,"b07 GFCI sample different"], + [ 256,"b08 "], + [ 512,"b09 "], + [ 1024,"b10 "], + [ 2048,"b11 "], + [ 4096,"b12 AFCI fault"], + [ 8192,"b13 "], + [ 16384,"b14 AFCI module fault"], + [ 32768,"b15 "], + [ 65536,"b16 "], + [ 131072,"b17 relay check fault"], + [ 262144,"b18 "], + [ 524288,"b19 "], + [ 1048576,"b20 "], + [ 2097152,"b21 communication error"], + [ 4194304,"b22 bus voltage error"], + [ 8388608,"b23 auto-test fail"], + [ 16777216,"b24 no utility"], + [ 33554432,"b25 PV isolation low"], + [ 67108864,"b26 residual I high"], + [ 134217728,"b27 output high DCI"], + [ 268435456,"b28 PV voltage high"], + [ 536870912,"b29 AC V outrange"], + [ 1073741824,"b30 AC F outrange"], + [-2147483648,"b31 temperature high"]], + "unit": "" + }, + { + "position": [227, 228, 229, 230], + "name": "Energy_ChargeFromGrid_today_kWh", + "realname": "Charge Energy from Grid today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [231, 232, 233, 234], + "name": "Energy_ChargeFromGrid_total_kWh", + "realname": "Charge Energy from Grid total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [239, 240], + "name": "Inverter_Priority", + "realname": "Priority of power-distribution by inverter (number)", + "datatype": "integer", + "unit": "" + }, + { + "position": [239, 240], + "name": "Inverter_Priority_Text", + "realname": "Priority of power-distribution by inverter (text)", + "datatype": "integer", + "mapping": [[0,"0: Load first"], + [1,"1: Batt first"], + [2,"2: Grid first"]], + "unit": "" + }, + { + "position": [246, 247, 248, 249], + "name": "Power_Battery_Discharge_W", + "realname": "Discharge Power", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [250, 251, 252, 253], + "name": "Power_Battery_Charge_W", + "realname": "Charge Power", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [254, 255], + "name": "Battery_Voltage_V", + "realname": "Battery Voltage", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [256, 257], + "name": "Battery_SOC_Percent", + "realname": "Battery State Of Charge", + "datatype": "float", + "factor": 1.0, + "unit": "%" + }, + { + "position": [270, 271, 272, 273], + "name": "Power_AC_GridToUser_W", + "realname": "SmartMeter: AC Power Grid to User", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [286, 287, 288, 289], + "name": "Power_AC_UserToGrid_W", + "realname": "SmartMeter: AC Power User to Grid", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [302, 303, 304, 305], + "name": "Power_AC_toLocalLoad_W", + "realname": "Power to Local Load", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [308, 309], + "name": "Battery_Temperature_degC", + "realname": "Battery Temperature", + "datatype": "float", + "factor": 0.1, + "unit": "°C" + }, + { + "position": [316, 317, 318, 319], + "name": "Energy_toUser_today_kWh", + "realname": "Energy to User today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [320, 321, 322, 323], + "name": "Energy_toUser_total_kWh", + "realname": "Energy to User total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [324, 325, 326, 327], + "name": "Energy_toGrid_today_kWh", + "realname": "Energy to Grid today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [328, 329, 330, 331], + "name": "Energy_toGrid_total_kWh", + "realname": "Energy to Grid total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [332, 333, 334, 335], + "name": "Energy_Discharge_today_kWh", + "realname": "Discharge Energy today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [336, 337, 338, 339], + "name": "Energy_Discharge_total_kWh", + "realname": "Discharge Energy total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [340, 341, 342, 343], + "name": "Energy_Charge_today_kWh", + "realname": "Charge Energy today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [344, 345, 346, 347], + "name": "Energy_Charge_total_kWh", + "realname": "Charge Energy total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [348, 349, 350, 351], + "name": "Energy_LocalLoad_today_kWh", + "realname": "Energy Local Load today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [352, 353, 354, 355], + "name": "Energy_LocalLoad_total_kWh", + "realname": "Energy Local Load total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [362, 363], + "name": "UPS_Frequency_Hz", + "realname": "UPS Frequency", + "datatype": "float", + "factor": 0.01, + "unit": "Hz" + }, + { + "position": [364, 365], + "name": "UPS_VoltageL1_V", + "realname": "UPS Voltage L1", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [366, 367], + "name": "UPS_CurrentL1_A", + "realname": "UPS Current L1", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [368, 369, 370, 371], + "name": "UPS_PowerL1_VA", + "realname": "UPS Power L1", + "datatype": "float", + "factor": 0.1, + "unit": "VA" + }, + { + "position": [372, 373], + "name": "UPS_VoltageL2_V", + "realname": "UPS Voltage L2", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [374, 375], + "name": "UPS_CurrentL2_A", + "realname": "UPS Current L2", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [376, 377, 378, 379], + "name": "UPS_PowerL2_VA", + "realname": "UPS Power L2", + "datatype": "float", + "factor": 0.1, + "unit": "VA" + }, + { + "position": [380, 381], + "name": "UPS_VoltageL3_V", + "realname": "UPS Voltage L3", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [382, 383], + "name": "UPS_CurrentL3_A", + "realname": "UPS Current L3", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [384, 385, 386, 387], + "name": "UPS_PowerL3_VA", + "realname": "UPS Power L3", + "datatype": "float", + "factor": 0.1, + "unit": "VA" + }, + { + "position": [388, 389], + "name": "UPS_Load_Percent", + "realname": "UPS Load Percent", + "datatype": "float", + "factor": 1.0, + "unit": "%" + }, + { + "position": [400, 401], + "name": "Battery_SOC_BMS_Percent", + "realname": "Battery State Of Charge from BMS", + "datatype": "float", + "factor": 1.0, + "unit": "%" + }, + { + "position": [402, 403], + "name": "Battery_Voltage_BMS_V", + "realname": "Battery Voltage from BMS", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [404, 405], + "name": "Battery_Current_BMS_A", + "realname": "Battery Current from BMS", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [406, 407], + "name": "Battery_Temperature_BMS_degC", + "realname": "Battery Temperature from BMS", + "datatype": "float", + "factor": 0.1, + "unit": "°C" + }, + { + "position": [418, 419], + "name": "Battery_CycleCount_BMS", + "realname": "Cycle count from BMS", + "datatype": "integer", + "unit": "" + }, + { + "position": [420, 421], + "name": "Battery_SOH_BMS_Percent", + "realname": "Battery State Of Health from BMS", + "datatype": "float", + "factor": 1.0, + "unit": "%" + }, + { + "position": [444, 445], + "name": "BMS_MaxCellVoltage_V", + "realname": "Highest cell voltage", + "datatype": "float", + "factor": 0.001, + "unit": "V" + }, + { + "position": [446, 447], + "name": "BMS_MinCellVoltage_V", + "realname": "Lowest cell voltage", + "datatype": "float", + "factor": 0.001, + "unit": "V" + }, + { + "position": [452, 453], + "name": "BMS_MaxVoltageCellNr", + "realname": "Number of cell with highest voltage", + "datatype": "integer", + "unit": "" + }, + { + "position": [454, 455], + "name": "BMS_MinVoltageCellNr", + "realname": "Number of cell with lowest voltage", + "datatype": "integer", + "unit": "" + }, + { + "position": [456, 457], + "name": "BMS_MaxCellTemperature_degC", + "realname": "Highest cell temperature", + "datatype": "float", + "factor": 0.1, + "unit": "°C" + }, + { + "position": [458, 459], + "name": "BMS_MinCellTemperature_degC", + "realname": "Lowest cell temperature", + "datatype": "float", + "factor": 0.1, + "unit": "°C" + }, + { + "position": [460, 461], + "name": "BMS_MaxTemperatureCellNr", + "realname": "Number of cell with highest temp.", + "datatype": "integer", + "unit": "" + }, + { + "position": [462, 463], + "name": "BMS_MinTemperatureCellNr", + "realname": "Number of cell with lowest temp.", + "datatype": "integer", + "unit": "" + }, + { + "position": [476, 477, 478, 479], + "name": "AC_ChargeEnergy_today_kWh", + "realname": "AC charging energy today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [480, 481, 482, 483], + "name": "AC_ChargeEnergy_total_kWh", + "realname": "AC charging energy total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [484, 485, 486, 487], + "name": "AC_ChargePower_W", + "realname": "AC charging power", + "datatype": "float", + "factor": 1.0, + "unit": "W" + } + ], + "id": [ + { + "position": [49, 50, 51, 52, 53, 54, 55, 56, 57, 58], + "name": "InverterSN", + "realname": "Inverter SerialNumber", + "datatype": "string" + }] + } + } +} \ No newline at end of file diff --git a/data/regs/Solax-X1.json b/data/regs/Solax-X1.json index 65a8f3fc..70ae2b47 100644 --- a/data/regs/Solax-X1.json +++ b/data/regs/Solax-X1.json @@ -515,14 +515,46 @@ ] }, "set": [ + { + "name": "setUnlockSettings", + "realname": "Unlock Settings", + "info": "send the 4 digit advanced password", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x00" + ] + }, { - "name": "TargetBatSOC", - "request": [ - "#ClientID", - "0x06", - "0x00", - "0x83" + "name": "setTargetBatSOC", + "realname": "Target SoC", + "info": "set battery SOC: 0 - 100 in percent", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x83" ] + }, + { + "name": "setOperationMode", + "realname": "Operation Mode", + "info": "setting of 6 possible operation modes", + "mapping": [ + [ "SelfUse", 0 ], + [ "FeedInPriority", 1 ], + [ "BackupMode", 2 ], + [ "ManuelMode", 3 ], + [ "PeakShaving", 4 ], + [ "TUOMode", 5 ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x1f" + ] } ] } diff --git a/data/regs/Solax-X3.json b/data/regs/Solax-X3.json index 1ff20640..0a9cb884 100644 --- a/data/regs/Solax-X3.json +++ b/data/regs/Solax-X3.json @@ -1,874 +1,1751 @@ { - "Solax-X3": { - "config": { - "author": "Lazgar", - "RequestLiveData": [ - [ - "#ClientID", - "0x04", - "0x00", - "0x00", - "0x00", - "0x78" - ], - [ - "#ClientID", - "0x04", - "0x00", - "0x78", - "0x00", - "0x77" - ] - ], - "RequestIdData": [ - [ - "#ClientID", - "0x03", - "0x00", - "0x00", - "0x00", - "0x14" - ] - ], - "ClientIdPos": 0, - "LiveDataFunctionCodePos": 1, - "LiveDataFunctionCode": "0x04", - "IdDataFunctionCodePos": 1, - "IdDataFunctionCode": "0x03", - "LiveDataStartsAtPos": 3, - "IdDataStartsAtPos": 3, - "LiveDataErrorPos": 1, - "LiveDataErrorCode": "0x84", - "IdDataErrorPos": 1, - "IdDataErrorCode": "0x83", - "LiveDataSuccessPos": 1, - "LiveDataSuccessCode": "0x04", - "IdDataSuccessPos": 1, - "IdDataSuccessCode": "0x03" - }, - "data": { - "livedata": [ - { - "position": [ - 215, - 216 - ], - "name": "GridVoltage_R", - "realname": "Grid Voltage L1", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 217, - 218 - ], - "name": "GridCurrent_R", - "realname": "Grid Current L1", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 219, - 220 - ], - "name": "GridPower_R", - "realname": "Grid Power L1", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 221, - 222 - ], - "name": "GridFrequency_R", - "realname": "Grid Frequency L1", - "datatype": "float", - "factor": 0.01, - "unit": "Hz" - }, - { - "position": [ - 223, - 224 - ], - "name": "GridVoltage_S", - "realname": "Grid Voltage L2", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 225, - 226 - ], - "name": "GridCurrent_S", - "realname": "Grid Current L2", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 227, - 228 - ], - "name": "GridPower_S", - "realname": "Grid Power L2", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 229, - 230 - ], - "name": "GridFrequency_S", - "realname": "Grid Frequency L2", - "datatype": "float", - "factor": 0.01, - "unit": "Hz" - }, - { - "position": [ - 231, - 232 - ], - "name": "GridVoltage_T", - "realname": "Grid Voltage L3", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 233, - 234 - ], - "name": "GridCurrent_T", - "realname": "Grid Current L3", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 235, - 236 - ], - "name": "GridPower_T", - "realname": "Grid Power L3", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 237, - 238 - ], - "name": "GridFrequency_T", - "realname": "Grid Frequency L3", - "datatype": "float", - "factor": 0.01, - "unit": "Hz" - }, - { - "position": [ - 9, - 10 - ], - "name": "PvVoltage1", - "realname": "Pv Voltage 1", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 11, - 12 - ], - "name": "PvVoltage2", - "realname": "Pv Voltage 2", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 13, - 14 - ], - "name": "PvCurrent1", - "realname": "Pv Current 1", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 15, - 16 - ], - "name": "PvCurrent2", - "realname": "Pv Current 2", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 19, - 20 - ], - "name": "Temperature", - "realname": "Temperature", - "datatype": "integer", - "unit": "°C" - }, - { - "position": [ - 21, - 22 - ], - "name": "InverterStatus", - "realname": "Inverter Status", - "datatype": "integer", - "mapping": [ - [ - 0, - "WaitMode" - ], - [ - 1, - "CheckMode" - ], - [ - 2, - "NormalMode" - ], - [ - 3, - "FaultMode" - ], - [ - 4, - "PermanentFaultMode" - ], - [ - 5, - "UpdateMode" - ], - [ - 6, - "EPSCheckMode" - ], - [ - 7, - "EPSMode" - ], - [ - 8, - "SelfTest" - ], - [ - 9, - "IdleMode" - ] - ] - }, - { - "position": [ - 23, - 24 - ], - "name": "PowerPv1", - "realname": "Power PV 1", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 25, - 26 - ], - "name": "PowerPv2", - "realname": "Power PV 2", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 43, - 44 - ], - "name": "BatVoltage", - "realname": "Battery Voltage", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 45, - 46 - ], - "name": "BatCurrent", - "realname": "Battery Current", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 47, - 48 - ], - "name": "BatPower", - "realname": "Battery Power", - "datatype": "integer", - "openwbtopic": "setbatimpwh", - "unit": "W" - }, - { - "position": [ - 51, - 52 - ], - "name": "BatTemp", - "realname": "Battery Temperature", - "datatype": "integer", - "unit": "°C" - }, - { - "position": [ - 55, - 56 - ], - "name": "GridStatus", - "realname": "Grid Status", - "datatype": "integer", - "mapping": [ - [ - 0, - "OnGrid" - ], - [ - 1, - "OffGrid" - ] - ] - }, - { - "position": [ - 59, - 60 - ], - "name": "BatCapacity", - "realname": "Battery Capacity", - "datatype": "integer", - "openwbtopic": "setbatsoc", - "unit": "%" - }, - { - "position": [ - 63, - 64, - 61, - 62 - ], - "name": "OutputEnergyChargeWh", - "realname": "Output Energy Charge (Wh)", - "datatype": "integer", - "openwbtopic": "setbatexpwh", - "factor": 100, - "unit": "Wh" - }, - { - "position": [ - 63, - 64, - 61, - 62 - ], - "name": "OutputEnergyChargeKWh", - "realname": "Output Energy Charge (KWh)", - "datatype": "float", - "factor": 0.1, - "unit": "KWh" - }, - { - "position": [ - 67, - 68 - ], - "name": "OutputEnergyChargeToday", - "realname": "Output Energy Charge Today", - "datatype": "float", - "factor": 0.1, - "unit": "KWh" - }, - { - "position": [ - 71, - 72, - 69, - 70 - ], - "name": "InputEnergyChargeWh", - "realname": "Input Energy Charge (Wh)", - "datatype": "integer", - "openwbtopic": "setbatimpwhhImported", - "factor": 100, - "unit": "Wh" - }, - { - "position": [ - 71, - 72, - 69, - 70 - ], - "name": "InputEnergyChargeKWh", - "realname": "Input Energy Charge (KWh)", - "datatype": "float", - "factor": 0.1, - "unit": "KWh" - }, - { - "position": [ - 73, - 74 - ], - "name": "InputEnergyChargeToday", - "realname": "Input Energy Charge Today", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 145, - 146, - 143, - 144 - ], - "name": "feedinPower", - "realname": "FeedIn Energy Power to Grid", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 149, - 150, - 147, - 148 - ], - "name": "feedinEnergyTotal", - "realname": "FeedIn Energy Total", - "datatype": "float", - "factor": 0.01, - "unit": "kWh" - }, - { - "position": [ - 153, - 154, - 151, - 152 - ], - "name": "consumedEnergyTotal", - "realname": "Consumed Energy Total", - "datatype": "float", - "factor": 0.01, - "unit": "kWh" - }, - { - "position": [ - 163, - 164 - ], - "name": "EnergyTodayToGrid", - "realname": "Today Energy to Grid", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 169, - 170, - 167, - 168 - ], - "name": "EnergyTotalToGridKwh", - "realname": "Total Energy to Grid in KWh", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 169, - 170, - 167, - 168 - ], - "name": "EnergyTotalToGridWh", - "realname": "Total Energy to Grid in Wh", - "datatype": "integer", - "openwbtopic": "setcounterwh", - "factor": 100, - "unit": "Wh" - }, - { - "position": [ - 282, - 283, - 280, - 281 - ], - "name": "OnGridRunTime", - "realname": "OnGrid RunTime", - "datatype": "float", - "factor": 0.1, - "unit": "h" - }, - { - "position": [ - 286, - 287, - 284, - 285 - ], - "name": "OffGridRunTime", - "realname": "OffGrid RunTime", - "datatype": "float", - "factor": 0.1, - "unit": "h" - }, - { - "position": [ - 239, - 240 - ], - "name": "OffGridVoltage_R", - "realname": "Off Grid Voltage L1", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 241, - 242 - ], - "name": "OffGridCurrent_R", - "realname": "Off Grid Current L1", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 250, - 251 - ], - "name": "OffGridPowerActive_R", - "realname": "Off Grid Power L1", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 254, - 255 - ], - "name": "OffGridVoltage_S", - "realname": "Off Grid Voltage L2", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 256, - 257 - ], - "name": "OffGridCurrent_S", - "realname": "Off Grid Current L2", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 258, - 259 - ], - "name": "OffGridPowerActive_S", - "realname": "Off Grid Power L2", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 262, - 263 - ], - "name": "OffGridVoltage_T", - "realname": "Off Grid Voltage L3", - "datatype": "float", - "factor": 0.1, - "unit": "V" - }, - { - "position": [ - 264, - 265 - ], - "name": "OffGridCurrent_T", - "realname": "Off Grid Current L3", - "datatype": "float", - "factor": 0.1, - "unit": "A" - }, - { - "position": [ - 266, - 267 - ], - "name": "OffGridPowerActive_T", - "realname": "Off Grid Power L3", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 270, - 271, - 268, - 269 - ], - "name": "FeedInPowerPhase_R", - "realname": "FeedIn Power Phase L1", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 274, - 275, - 272, - 273 - ], - "name": "FeedInPowerPhase_S", - "realname": "FeedIn Power Phase L2", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 278, - 279, - 276, - 277 - ], - "name": "FeedInPowerPhase_T", - "realname": "FeedIn Power Phase L3", - "datatype": "integer", - "unit": "W" - }, - { - "position": [ - 294, - 295, - 292, - 293 - ], - "name": "OffGridYieldTotal", - "realname": "OffGrid Yield Total", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 296, - 297 - ], - "name": "OffGridYieldToday", - "realname": "OffGrid Yield Today", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 298, - 299 - ], - "name": "EChargeToday", - "realname": "ECharge Today", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 302, - 303, - 300, - 301 - ], - "name": "EChargeTotal", - "realname": "ECharge Total", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 306, - 307, - 304, - 305 - ], - "name": "SolarEnergyTotal", - "realname": "SolarEnergy Total", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 308, - 309 - ], - "name": "SolarEnergyToday", - "realname": "SolarEnergy Today", - "datatype": "float", - "factor": 0.1, - "unit": "kWh" - }, - { - "position": [ - 314, - 315, - 312, - 313 - ], - "name": "EnergyFeedin", - "realname": "EnergyFeedin Today", - "datatype": "float", - "factor": 0.01, - "unit": "kWh" - }, - { - "position": [ - 318, - 319, - 316, - 317 - ], - "name": "EnergyConsum", - "realname": "EnergyConsum Today", - "datatype": "float", - "factor": 0.01, - "unit": "kWh" - }, - { - "position": [ - 384, - 385 - ], - "name": "CellVoltageHigh", - "realname": "Cell Voltage High", - "datatype": "float", - "factor": 0.001, - "unit": "V" - }, - { - "position": [ - 386, - 387 - ], - "name": "CellVoltageLow", - "realname": "Cell Voltage Low", - "datatype": "float", - "factor": 0.001, - "unit": "V" - } - ], - "id": [ - { - "position": [ - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16 - ], - "name": "InverterSN", - "realname": "Inverter SerialNumber", - "datatype": "string" - }, - { - "position": [ - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30 - ], - "name": "FactoryName", - "realname": "Factory Name", - "datatype": "string" - }, - { - "position": [ - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42 - ], - "name": "ModuleName", - "realname": "Module Name", - "datatype": "string" - } + "Solax-X3": { + "config": { + "author": "Lazgar", + "RequestLiveData": [ + [ + "#ClientID", + "0x04", + "0x00", + "0x00", + "0x00", + "0x79" + ], + [ + "#ClientID", + "0x04", + "0x00", + "0x79", + "0x00", + "0x79" + ], + [ + "#ClientID", + "0x04", + "0x00", + "0xf2", + "0x00", + "0x41" + ] + ], + "RequestIdData": [ + [ + "#ClientID", + "0x03", + "0x00", + "0x00", + "0x00", + "0x79" + ], + [ + "#ClientID", + "0x03", + "0x00", + "0x79", + "0x00", + "0x79" + ], + [ + "#ClientID", + "0x03", + "0x00", + "0xf2", + "0x00", + "0x79" + ], + [ + "#ClientID", + "0x03", + "0x01", + "0x6b", + "0x00", + "0x0c" + ] + ], + "ClientIdPos": 0, + "LiveDataFunctionCodePos": 1, + "LiveDataFunctionCode": "0x04", + "IdDataFunctionCodePos": 1, + "IdDataFunctionCode": "0x03", + "LiveDataStartsAtPos": 3, + "IdDataStartsAtPos": 3, + "LiveDataErrorPos": 1, + "LiveDataErrorCode": "0x84", + "IdDataErrorPos": 1, + "IdDataErrorCode": "0x83", + "LiveDataSuccessPos": 1, + "LiveDataSuccessCode": "0x04", + "IdDataSuccessPos": 1, + "IdDataSuccessCode": "0x03" + }, + "data": { + "livedata": [ + { + "position": [ + 9, + 10 + ], + "name": "PvVoltage1", + "realname": "Pv Voltage 1", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 11, + 12 + ], + "name": "PvVoltage2", + "realname": "Pv Voltage 2", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 13, + 14 + ], + "name": "PvCurrent1", + "realname": "Pv Current 1", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 15, + 16 + ], + "name": "PvCurrent2", + "realname": "Pv Current 2", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 23, + 24 + ], + "name": "PvPower1", + "realname": "Pv Power 1", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 25, + 26 + ], + "name": "PvPower2", + "realname": "Pv Power 2", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 19, + 20 + ], + "name": "Temperature", + "realname": "Temperature", + "datatype": "integer", + "unit": "°C" + }, + { + "position": [ + 21, + 22 + ], + "name": "InverterStatus", + "realname": "Inverter Status", + "datatype": "integer", + "mapping": [ + [ + 0, + "Waiting" + ], + [ + 1, + "Checking" + ], + [ + 2, + "Normal" + ], + [ + 3, + "Fault" + ], + [ + 4, + "Permanent Fault" + ], + [ + 5, + "Update" + ], + [ + 6, + "Off-Grid Waiting" + ], + [ + 7, + "Off-Grid" + ], + [ + 8, + "Self Testing" + ], + [ + 9, + "Idle" + ], + [ + 10, + "Standby" + ] + ] + }, + { + "position": [ + 133, + 134, + 131, + 132 + ], + "name": "InverterFaultMessage", + "realname": "Inverter Fault Message", + "datatype": "binary", + "mapping": [ + "TZ Protect Fault", + "Grid Lost Fault", + "Grid Volt Fault", + "Grid Freq Fault", + "PV Volt Fault", + "Bus Volt Fault", + "Bat Volt Fault", + "AC10mins Volt Fault", + "DCI OCP Fault", + "DCV OCP Fault", + "SW OCP Fault", + "RC OCP Fault", + "Isolation Fault", + "Temp Over Fault", + "BatConnDir Fault", + "Off-Grid Overload", + "Overload", + "Bat Power Low", + "BMS Lost", + "Fan Fault", + "Low Temp Fault", + "Parallel Fault", + "Hard Limit Fault", + "INV Volt Sample Fault", + "Inner Comm Fault", + "INV EEPROM Fault", + "RCD Fault", + "Grid Relay Fault", + "Off-grid Relay Fault", + "PV Conndir Fault", + "Charger Relay Fault", + "Earth Relay Fault", + "no Error" + ] + }, + { + "position": [ + 137, + 138 + ], + "name": "ManagerFaultMessage", + "realname": "Manager Fault Message", + "datatype": "binary", + "mapping": [ + "Power Type Fault", + "Port OC Warning", + "Mgr EEPROM Fault", + "Reserve3", + "NTC Sample Invalid", + "Bat Temp Low", + "Bat Temp High", + "Reserve7", + "Reserve8", + "Meter Fault", + "Bypass Relay Fault", + "Fan 2 Fault", + "Reserve12", + "Reserve13", + "Reserve14", + "Reserve15", + "no Error" + ] + }, + { + "position": [ + 141, + 142, + 139, + 140 + ], + "name": "BMSFaultMessage", + "realname": "BMS Fault Message", + "datatype": "binary", + "mapping": [ + "BMS_External_Err", + "BMS_Internal_Err", + "BMS_OverVoltage", + "BMS_LowerVoltage", + "BMS_ChargeOCP", + "BMS_DischargeOCP", + "BMS_TemHigh", + "BMS_TemLow", + "BMS_CellImbalance", + "BMS_Hardware_Protect", + "BMS_Circuit_Fault", + "BMS_ISO_Fault", + "BMS_VolSen_Fault", + "BMS_TempSen_Fault", + "BMS_CurSen_Fault", + "BMS_Relay_Fault", + "BMS_Type_Unmatch", + "BMS_Ver_Unmathch", + "BMS_MFR_Unmathch", + "BMS_SW_Unmathch", + "BMS_M&S_Unmatch", + "BMS_CR_NORespond", + "BMS_SW_Protect", + "BMS_536_Fault", + "BMS_SelfcheckErr", + "BMS_TempdiffErr", + "BMS_BreakFault", + "BMS_Flash_Fault", + "BMS_Precharge_Fault", + "BMS_AirSwitch_Break", + "Rev", + "Rev", + "no Error" + ] + }, + { + "position": [ + 171, + 172 + ], + "name": "InverterSettings", + "realname": "Inverter Settings", + "datatype": "integer", + "settopic": "UnlockSettings", + "mapping": [ + [ + 0, + "Locked" + ], + [ + 1, + "Unlocked" + ] + ] + }, + { + "position": [ + 525, + 526 + ], + "name": "ModbusPowerControl", + "realname": "Modbus Power Control", + "datatype": "integer", + "settopic": "ModbusPowerControl", + "mapping": [ + [ + 0, + "Off" + ], + [ + 1, + "PowerCtrl" + ], + [ + 2, + "ElectricQuantityCtrl" + ], + [ + 3, + "SoCTargetCtrl" + ] + ] + }, + { + "position": [ + 55, + 56 + ], + "name": "GridStatus", + "realname": "Grid Status", + "datatype": "integer", + "mapping": [ + [ + 0, + "OnGrid" + ], + [ + 1, + "OffGrid" + ] + ] + }, + { + "position": [ + 53, + 54 + ], + "name": "BatStatus", + "realname": "Battery Status", + "datatype": "integer", + "mapping": [ + [ + 0, + "Discharge" + ], + [ + 1, + "Charge" + ], + [ + 2, + "Stop" + ] + ] + }, + { + "position": [ + 43, + 44 + ], + "name": "BatVoltage", + "realname": "Battery Voltage", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 45, + 46 + ], + "name": "BatCurrent", + "realname": "Battery Current", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 47, + 48 + ], + "name": "BatPower", + "realname": "Battery Power", + "datatype": "integer", + "openwbtopic": "setbatimpwh", + "unit": "W" + }, + { + "position": [ + 51, + 52 + ], + "name": "BatTemp", + "realname": "Battery Temperature", + "datatype": "integer", + "unit": "°C" + }, + { + "position": [ + 59, + 60 + ], + "name": "BatCapacity", + "realname": "Battery Capacity", + "datatype": "integer", + "openwbtopic": "setbatsoc", + "unit": "%" + }, + { + "position": [ + 388, + 389 + ], + "name": "BatUserSoC", + "realname": "Battery User SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 390, + 391 + ], + "name": "BatUserSoH", + "realname": "Battery User SoH", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 579, + 580 + ], + "name": "BatTargetSoC", + "realname": "Battery Target SoC", + "datatype": "integer", + "settopic": "TargetSoC", + "unit": "%" + }, + { + "position": [ + 67, + 68 + ], + "name": "ChargeEnergyOutputToday", + "realname": "Charge Energy Output Today", + "datatype": "float", + "factor": 0.1, + "unit": "KWh" + }, + { + "position": [ + 63, + 64, + 61, + 62 + ], + "name": "ChargeEnergyOutputTotal", + "realname": "Charge Energy Output Total", + "datatype": "float", + "factor": 0.1, + "unit": "KWh" + }, + { + "position": [ + 63, + 64, + 61, + 62 + ], + "name": "ChargeEnergyOutputTotalWh", + "realname": "Charge Energy Output Total(Wh)", + "datatype": "integer", + "openwbtopic": "setbatexpwh", + "factor": 100, + "unit": "Wh" + }, + { + "position": [ + 73, + 74 + ], + "name": "ChargeEnergyInputToday", + "realname": "Charge Energy Input Today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 71, + 72, + 69, + 70 + ], + "name": "ChargeEnergyInputTotal", + "realname": "Charge Energy Input Total", + "datatype": "float", + "factor": 0.1, + "unit": "KWh" + }, + { + "position": [ + 71, + 72, + 69, + 70 + ], + "name": "ChargeEnergyInputTotalWh", + "realname": "Charge Energy Input Total (Wh)", + "datatype": "integer", + "openwbtopic": "setbatimpwh", + "factor": 100, + "unit": "Wh" + }, + { + "position": [ + 314, + 315, + 312, + 313 + ], + "name": "FeedInEnergyToday", + "realname": "FeedIn Energy Today", + "datatype": "float", + "factor": 0.01, + "unit": "kWh" + }, + { + "position": [ + 149, + 150, + 147, + 148 + ], + "name": "FeedInEnergyTotal", + "realname": "FeedIn Energy Total", + "datatype": "float", + "factor": 0.01, + "unit": "kWh" + }, + { + "position": [ + 318, + 319, + 316, + 317 + ], + "name": "ConsumedEnergyToday", + "realname": "Consumed Energy Today", + "datatype": "float", + "factor": 0.01, + "unit": "kWh" + }, + { + "position": [ + 153, + 154, + 151, + 152 + ], + "name": "ConsumedEnergyTotal", + "realname": "Consumed Energy Total", + "datatype": "float", + "factor": 0.01, + "unit": "kWh" + }, + { + "position": [ + 163, + 164 + ], + "name": "EnergyTodayToGrid", + "realname": "Today Energy to Grid", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 169, + 170, + 167, + 168 + ], + "name": "EnergyTotalToGrid", + "realname": "Total Energy to Grid in KWh", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 169, + 170, + 167, + 168 + ], + "name": "EnergyTotalToGridWh", + "realname": "Total Energy to Grid in Wh", + "datatype": "float", + "openwbtopic": "setcounterwh", + "factor": 100, + "unit": "Wh" + }, + { + "position": [ + 215, + 216 + ], + "name": "GridVoltage_L1", + "realname": "Grid Voltage L1", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 223, + 224 + ], + "name": "GridVoltage_L2", + "realname": "Grid Voltage L2", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 231, + 232 + ], + "name": "GridVoltage_L3", + "realname": "Grid Voltage L3", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 217, + 218 + ], + "name": "GridCurrent_L1", + "realname": "Grid Current L1", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 225, + 226 + ], + "name": "GridCurrent_L2", + "realname": "Grid Current L2", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 233, + 234 + ], + "name": "GridCurrent_L3", + "realname": "Grid Current L3", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 219, + 220 + ], + "name": "GridPower_L1", + "realname": "Grid Power L1", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 227, + 228 + ], + "name": "GridPower_L2", + "realname": "Grid Power L2", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 235, + 236 + ], + "name": "GridPower_L3", + "realname": "Grid Power L3", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 221, + 222 + ], + "name": "GridFrequency_L1", + "realname": "Grid Frequency L1", + "datatype": "float", + "factor": 0.01, + "unit": "Hz" + }, + { + "position": [ + 229, + 230 + ], + "name": "GridFrequency_L2", + "realname": "Grid Frequency L2", + "datatype": "float", + "factor": 0.01, + "unit": "Hz" + }, + { + "position": [ + 237, + 238 + ], + "name": "GridFrequency_L3", + "realname": "Grid Frequency L3", + "datatype": "float", + "factor": 0.01, + "unit": "Hz" + }, + { + "position": [ + 239, + 240 + ], + "name": "OffGridVoltage_L1", + "realname": "Off Grid Voltage L1", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 252, + 253 + ], + "name": "OffGridVoltage_L2", + "realname": "Off Grid Voltage L2", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 260, + 261 + ], + "name": "OffGridVoltage_L3", + "realname": "Off Grid Voltage L3", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [ + 241, + 242 + ], + "name": "OffGridCurrent_L1", + "realname": "Off Grid Current L1", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 254, + 255 + ], + "name": "OffGridCurrent_L2", + "realname": "Off Grid Current L2", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 262, + 263 + ], + "name": "OffGridCurrent_L3", + "realname": "Off Grid Current L3", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 243, + 244 + ], + "name": "OffGridPowerActive_L1", + "realname": "Off Grid Power L1", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 256, + 257 + ], + "name": "OffGridPowerActive_L2", + "realname": "Off Grid Power L2", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 264, + 265 + ], + "name": "OffGridPowerActive_L3", + "realname": "Off Grid Power L3", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 145, + 146, + 143, + 144 + ], + "name": "FeedInPower", + "realname": "FeedIn Power to Grid", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 270, + 271, + 268, + 269 + ], + "name": "FeedInPower_L1", + "realname": "FeedIn Power L1", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 274, + 275, + 272, + 273 + ], + "name": "FeedInPower_L2", + "realname": "FeedIn Power L2", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 278, + 279, + 276, + 277 + ], + "name": "FeedInPower_L3", + "realname": "FeedIn Power L3", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 282, + 283, + 280, + 281 + ], + "name": "OnGridRunTime", + "realname": "OnGrid RunTime", + "datatype": "float", + "factor": 0.1, + "unit": "h" + }, + { + "position": [ + 286, + 287, + 284, + 285 + ], + "name": "OffGridRunTime", + "realname": "OffGrid RunTime", + "datatype": "float", + "factor": 0.1, + "unit": "h" + }, + { + "position": [ + 296, + 297 + ], + "name": "OffGridYieldToday", + "realname": "OffGrid Yield Today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 294, + 295, + 292, + 293 + ], + "name": "OffGridYieldTotal", + "realname": "OffGrid Yield Total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 298, + 299 + ], + "name": "EChargeToday", + "realname": "ECharge Today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 302, + 303, + 300, + 301 + ], + "name": "EChargeTotal", + "realname": "ECharge Total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 308, + 309 + ], + "name": "SolarEnergyToday", + "realname": "SolarEnergy Today", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 306, + 307, + 304, + 306 + ], + "name": "SolarEnergyTotal", + "realname": "SolarEnergy Total", + "datatype": "float", + "factor": 0.1, + "unit": "kWh" + }, + { + "position": [ + 384, + 385 + ], + "name": "CellVoltageHigh", + "realname": "Cell Voltage High", + "datatype": "float", + "factor": 0.001, + "unit": "V" + }, + { + "position": [ + 386, + 387 + ], + "name": "CellVoltageLow", + "realname": "Cell Voltage Low", + "datatype": "float", + "factor": 0.001, + "unit": "V" + } + ], + "id": [ + { + "position": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "name": "InverterSN", + "realname": "Inverter SerialNumber", + "datatype": "string" + }, + { + "position": [ + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30 + ], + "name": "InverterManufacturer", + "realname": "Inverter Manufacturer", + "datatype": "string" + }, + { + "position": [ + 535, + 536 + ], + "name": "InverterMachineType", + "realname": "Inverter Machine Type", + "datatype": "integer", + "mapping": [ + [ + 1, + "X1" + ], + [ + 3, + "X3" + ] + ] + }, + { + "position": [ + 539, + 540 + ], + "name": "InverterMachineStyle", + "realname": "Inverter Machine Style", + "datatype": "integer", + "mapping": [ + [ + 0, + "Hybrid" + ], + [ + 1, + "FIT" + ] + ] + }, + { + "position": [ + 380, + 381 + ], + "name": "InverterPowerType", + "realname": "Inverter Power Type", + "datatype": "integer", + "mapping": [ + [ + 15000, + "15k" + ], + [ + 12000, + "12k" + ], + [ + 10000, + "10k" + ], + [ + 8000, + "8k" + ], + [ + 6000, + "6k" + ], + [ + 5000, + "5k" + ] + ] + }, + { + "position": [ + 456, + 457 + ], + "name": "InverterUserPassword", + "realname": "Inverter User Password", + "datatype": "integer" + }, + { + "position": [ + 458, + 459 + ], + "name": "InverterAdminPassword", + "realname": "Inverter Admin Password", + "datatype": "integer" + }, + { + "position": [ + 286, + 287 + ], + "name": "OperationMode", + "realname": "Operation Mode", + "datatype": "integer", + "mapping": [ + [ + 0, + "SelfUseMode" + ], + [ + 1, + "FeedInPriority" + ], + [ + 2, + "BackupMode" + ], + [ + 3, + "ManuelMode" + ], + [ + 4, + "PeakShaving" + ], + [ + 5, + "TOUMode" + ] + ] + }, + { + "position": [ + 288, + 289 + ], + "name": "ManuelMode", + "realname": "Manuel Mode", + "datatype": "integer", + "mapping": [ + [ + 0, + "StopCharge&Discharge" + ], + [ + 1, + "ForceCharge" + ], + [ + 2, + "ForceDischarge" + ] + ] + }, + { + "position": [ + 372, + 373 + ], + "name": "ExportLimit", + "realname": "Export Limit", + "datatype": "integer", + "factor": 10, + "unit": "W" + }, + { + "position": [ + 374, + 375 + ], + "name": "OffGridMute", + "realname": "Off-Grid Mute", + "datatype": "integer", + "mapping": [ + [ + 0, + "Off" + ], + [ + 1, + "On" + ] + ] + }, + { + "position": [ + 376, + 377 + ], + "name": "OffGridMinimumSoC", + "realname": "Off-Grid Minimum SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 384, + 385 + ], + "name": "MPPT", + "realname": "MPPT", + "datatype": "integer", + "mapping": [ + [ + 0, + "Off" + ], + [ + 1, + "On" + ] + ] + }, + { + "position": [ + 529, + 530 + ], + "name": "DRMFunction", + "realname": "DRM Function", + "datatype": "integer", + "mapping": [ + [ + 0, + "Off" + ], + [ + 1, + "On" + ] + ] + }, + { + "position": [ + 537, + 538 + ], + "name": "PhasePowerBalance", + "realname": "Phase Power Balance", + "datatype": "integer", + "mapping": [ + [ + 1, + "On" + ], + [ + 0, + "Off" + ] + ] + }, + { + "position": [ + 364, + 365 + ], + "name": "PgridBias", + "realname": "Pgrid Bias", + "datatype": "integer", + "mapping": [ + [ + 2, + "INV" + ], + [ + 1, + "Grid" + ], + [ + 0, + "Off" ] + ] + }, + { + "position": [ + 296, + 297 + ], + "name": "BatChargeMaxCurrent", + "realname": "Battery Charge Max Current", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 298, + 299 + ], + "name": "BatDischargeMaxCurrent", + "realname": "Battery Discharge Max Current", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [ + 302 + ], + "name": "SelfUseMinSoC", + "realname": "Self-Use Minimum SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 307 + ], + "name": "FeedInMinSoC", + "realname": "FeedIn Minimum SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 306 + ], + "name": "FeedInNightChargeSoC", + "realname": "FeedIn NightCharge SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 309 + ], + "name": "BackupMinSoC", + "realname": "Backup Minimum SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 309 + ], + "name": "BackupNightChargeSoC", + "realname": "Backup NightCharge SoC", + "datatype": "integer", + "unit": "%" } - } + ] + }, + "set": [ + { + "name": "setUnlockSettings", + "realname": "Unlock Settings", + "info": "send the 4 digit advanced password", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x00" + ] + }, + { + "name": "setOperationMode", + "realname": "Operation Mode", + "info": "accepted values:", + "mapping": [ + [ + "SelfUseMode", + 0 + ], + [ + "FeedInPriority", + 1 + ], + [ + "BackupMode", + 2 + ], + [ + "ManuelMode", + 3 + ], + [ + "PeakShaving", + 4 + ], + [ + "TUOMode", + 5 + ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x1f" + ] + }, + { + "name": "setManuelMode", + "realname": "Manuel Mode", + "info": "accepted values:", + "mapping": [ + [ + "StopCharge&Discharge", + 0 + ], + [ + "ForceCharge", + 1 + ], + [ + "ForceDischarge", + 2 + ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x20" + ] + }, + { + "name": "setExportLimit", + "realname": "Export Limit in Watt", + "info": "can be set in steps of 10, if you send 100 the limit is set to 1000 W", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x42" + ] + }, + { + "name": "setOffGridMute", + "realname": "Off-Grid Mute", + "info": "accepted values:", + "mapping": [ + [ + "Off", + 0 + ], + [ + "On", + 1 + ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x43" + ] + }, + { + "name": "setOffGridMinimumSoC", + "realname": "Off-Grid Minimum SoC", + "info": "can be set between 10 and 25 percent", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x44" + ] + }, + { + "name": "setPhasePowerBalance", + "realname": "Phase Power Balance", + "info": "has to be investigated", + "mapping": [ + [ + "Off", + 0 + ], + [ + "On", + 1 + ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x9e" + ] + }, + { + "name": "setModbusPowerControl", + "realname": "Modbus Power Control", + "info": "accepted values:", + "mapping": [ + [ + "Off", + 0 + ], + [ + "PowerCtrl", + 1 + ], + [ + "ElectricQuantityCtrl", + 2 + ], + [ + "SoCTargetCtrl", + 3 + ] + ], + "request": [ + "#ClientID", + "0x10", + "0x00", + "0x7c" + ] + }, + { + "name": "setTargetSetType", + "realname": "Target Set Type", + "info": "accepted values:", + "mapping": [ + [ + "Set", + 1 + ], + [ + "Update", + 2 + ] + ], + "request": [ + "#ClientID", + "0x10", + "0x00", + "0x7d" + ] + }, + { + "name": "setTargetSoC", + "realname": "Target SoC", + "info": "set 0 - 100 in percent", + "request": [ + "#ClientID", + "0x10", + "0x00", + "0x83" + ] + }, + { + "name": "setPgridBias", + "realname": "Pgrid Bias", + "info": "accepted values:", + "mapping": [ + [ + "Off", + 0 + ], + [ + "Grid", + 1 + ], + [ + "INV", + 2 + ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x8D" + ] + }, + { + "name": "setBatChargeMaxCurrent", + "realname": "Battery Charge Max Current", + "info": "can be set in steps of 0.1, if you send 300 the limit is set to 30A", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x24" + ] + }, + { + "name": "setBatDischargeMaxCurrent", + "realname": "Battery Charge Max Current", + "info": "can be set in steps of 0.1, if you send 300 the limit is set to 30A", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x25" + ] + }, + { + "name": "setSelfUseMinSoC", + "realname": "Self-Use Minimum SoC", + "info": "can be set between 10 - 100 percent", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x61" + ] + }, + { + "name": "setFeedInMinSoC", + "realname": "FeedIn Minimum SoC", + "info": "can be set between 10 - 100 percent", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x65" + ] + }, + { + "name": "setFeedInNightChargeSoC", + "realname": "FeedIn NightCharge SoC", + "info": "can be set between 10 - 100 percent", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x64" + ] + }, + { + "name": "setBackupMinSoC", + "realname": "Backup Minimum SoC", + "info": "can be set between 15 - 100 percent", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x67" + ] + }, + { + "name": "setBackupNightChargeSoC", + "realname": "Backup NightCharge SoC", + "info": "can be set between 30 - 100 percent", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x66" + ] + } + ] + } } diff --git a/data/web/Javascript.js b/data/web/Javascript.js index 5474846d..b5297ec8 100644 --- a/data/web/Javascript.js +++ b/data/web/Javascript.js @@ -17,9 +17,9 @@ * Definition of constants *****************************************************************************************/ -const gpio_disabled = []; +export const gpio_disabled = []; -const gpio = [ {port: 1, name:'D1/TX0'}, +export const gpio = [ {port: 1, name:'D1/TX0'}, {port: 2 , name:'D2'}, {port: 3, name:'D3/RX0'}, {port: 4 , name:'D4'}, @@ -51,7 +51,7 @@ const gpio = [ {port: 1, name:'D1/TX0'}, {port: 39, name:'D39'} ]; -const gpioanalog = [ {port: 36, name:'ADC1_CH0 - GPIO36'}, +export const gpioanalog = [ {port: 36, name:'ADC1_CH0 - GPIO36'}, {port: 37, name:'ADC1_CH1 - GPIO37'}, {port: 38, name:'ADC1_CH2 - GPIO38'}, {port: 39, name:'ADC1_CH3 - GPIO39'}, @@ -71,14 +71,95 @@ const gpioanalog = [ {port: 36, name:'ADC1_CH0 - GPIO36'}, {port: 26, name:'ADC2_CH9 - GPIO26'} ]; +import { functionMap as statusFunctionMap } from './status.js'; +import { functionMap as baseconfigFunctionMap } from './baseconfig.js'; +import { functionMap as mbconfigFunctionMap } from './modbusconfig.js'; +import { functionMap as mbitemconfigFunctionMap } from './modbusitemconfig.js'; +import { functionMap as rawdataFunctionMap } from './rawdata.js'; +import { functionMap as filesFunctionMap } from './handlefiles.js'; + +const combinedFunctionMap = { + ...statusFunctionMap, + ...baseconfigFunctionMap, + ...mbconfigFunctionMap, + ...mbitemconfigFunctionMap, + ...rawdataFunctionMap, + ...filesFunctionMap +}; + +export let ws; // websocket handle +var datavalues; // form data values as string to check, if "needToSave" Dialog should be shown + var timer; // ID of setTimout Timer -> setResponse +let reconnectInterval = 5000; // 5 seconds interval to reconnect websocket connection + +/****************************************************************************************** + * Connect to WebSocket server + * *****************************************************************************************/ +export function connectWebSocket() { + window.addEventListener('beforeunload', function() { + if (ws) { + ws.close(); + } + }, false); + + document.addEventListener('visibilitychange', function() { + if (document.visibilityState === 'visible') { + if (!ws || ws.readyState === WebSocket.CLOSED) { + console.log('Reconnecting WebSocket due to visibility change'); + connectWebSocket(); + } + } else { + if (ws) { + console.log('Closing WebSocket due to visibility change'); + ws.close(); + } + } + }); + + if (document.visibilityState != 'visible') { + console.log('Not connecting WebSocket due to visibility state:', document.visibilityState); + return; + } + + ws = new WebSocket(location.origin.replace(/^http/, 'ws') + '/ajaxws'); + //ws = new WebSocket('ws://10.0.2.150/ajaxws'); + var wsStatus = document.getElementById('ws-status'); + + ws.onopen = function() { + console.log('WebSocket connection opened'); + if (wsStatus) wsStatus.style.backgroundColor = 'green'; + }; + + ws.onmessage = function(event) { + //try { + const json = JSON.parse(event.data); + console.log('Received JSON:', json); + handleJsonItems(json); + //} catch (e) { + // console.error('Invalid JSON received:', event.data); + //} + }; + + ws.onclose = function() { + console.log('WebSocket connection closed, attempting to reconnect in ' + reconnectInterval / 1000 + ' seconds'); + if (wsStatus) wsStatus.style.backgroundColor = 'yellow'; + setTimeout(connectWebSocket, reconnectInterval); + }; + + ws.onerror = function(error) { + console.error('WebSocket error:', error); + if (wsStatus) wsStatus.style.backgroundColor = 'red'; + ws.close(); + }; +} /****************************************************************************************** * activate all radioselections after pageload to hide unnecessary elements * Works for all checkbox and radio elements with onclick="radioselection(show, hide)" * ******************************************************************************************/ -function handleRadioSelections() { +export function handleRadioSelections() { var radios = document.querySelectorAll('input[type=radio][onclick*=radioselection]:checked'); for (var i = 0; i < radios.length; i++) { if (radios[i].onclick) { @@ -103,24 +184,43 @@ function handleRadioSelections() { } /***************************************************************************************** - * central function to initiate data fetch + * central function to send data to server * @param {*} json -> json object to send * @param {*} highlight -> highlight on/off * @param {*} callbackFn -> callback function to call after data is fetched * @returns {*} void ******************************************************************************************/ +export function requestData(json) { + if (typeof ws !== 'undefined' && ws.readyState === WebSocket.OPEN) { + console.log('WebSocket is open, sending data:', json); + ws.send(JSON.stringify(json)); + } else { + console.log('WebSocket not open'); + setResponse(false, 'WebSocket not open, could not send data'); + } +} -function requestData(json, highlight, callbackFn) { - const data = new URLSearchParams(); - data.append('json', json); - - fetch('/ajax', { - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: data - }) - .then (response => response.json()) - .then (json => { handleJsonItems(json, highlight, callbackFn)}); +/***************************************************************************************** + * @description This function updated values according their data-id in DOM elements. + * @param {*} json: JSON object containing the data-id values to update + * @param {*} highlight: boolean value to highlight the updated elements + * @returns {*} void + * @example updateDataID({"data-id":{"InverterSN.value":"123456789"}}, true) + * *****************************************************************************************/ +function updateDataID(json, highlight) { + if (json["data-id"]) { + for (const key in json["data-id"]) { + const elements = document.querySelectorAll(`[data-id="${key}"]`); + elements.forEach(element => { + element.innerHTML = json["data-id"][key]; + if (highlight && element.classList.contains('ajaxchange')) { + element.classList.add('highlightOn'); + setTimeout(function() {document.getElementById(element.id).classList.remove('highlightOn')}, 1000); + } + + }); + } + } } /***************************************************************************************** @@ -140,13 +240,10 @@ function applyKey (_obj, _key, _val, counter, tplHierarchie, highlight) { if (['SPAN', 'DIV', 'TD', 'DFN'].includes(_obj.tagName)) { if (highlight && _obj.classList.contains('ajaxchange')) { _obj.classList.add('highlightOn'); - _obj.innerHTML = _val; - } if (!highlight && _obj.classList.contains('ajaxchange')) { - _obj.classList.remove('highlightOn'); - _obj.innerHTML = _val; - } else { - _obj.innerHTML = _val; - } + setTimeout(function() {document.getElementById(_obj.id).classList.remove('highlightOn')}, 1000); + } + _obj.innerHTML = _val; + } else if (_obj.tagName == 'INPUT' && ['checkbox','radio'].includes(_obj.type)) { if (_val == true) _obj.checked = true; } else if (_obj.tagName == 'OPTION') { @@ -155,8 +252,17 @@ function applyKey (_obj, _key, _val, counter, tplHierarchie, highlight) { _obj.value = _val; } } else { - // using parenet object - _obj[_key] = _val; + // using parent object + if (_key in _obj) { + if (highlight && _obj.classList.contains('ajaxchange')) { + _obj.classList.add('highlightOn'); + setTimeout(function() {document.getElementById(_obj.id).classList.remove('highlightOn')}, 1000); + } + + _obj[_key] = _val; + } else { + _obj.setAttribute(_key, _val); + } } } @@ -255,11 +361,37 @@ function applyTemplate(TemplateJson, templateID, doc, tplHierarchie, highlight) } } -function handleJsonItems(json, highlight, callbackFn) { +/***************************************************************************************** + * apply Javascript variables to the window object from a JSON object + * @param {*} json: JSON object containing the variables to apply + * @returns {*} void + * @example applyJS({"myVar": "myValue"}) + * *****************************************************************************************/ +function applyJS(json) { + for (var key in json) { + window[key] = json[key]; + } +} + +/***************************************************************************************** + * Main function to handle JSON response + * @param {*} json: JSON object containing the response data + * @returns {*} void + * @example handleJsonItems({"data-id": {"InverterSN": "123456789"}, "cmd": {"action": "GetInitData", "subaction": "status", "callbackFn": "MyCallback"}, " + * "response": {"status": 1, "text": "OK"}}) + * *****************************************************************************************/ +export function handleJsonItems(json) { + const callbackFn = (typeof json['cmd'] !== 'undefined' && typeof json['cmd']['callbackFn'] !== 'undefined') ? json['cmd']['callbackFn'] : undefined; + const highlight = (typeof json['cmd'] !== 'undefined' && typeof json['cmd']['highlight'] !== 'undefined') ? json['cmd']['highlight'] : false; + if ("data" in json) { applyKeys(json.data, document, undefined, undefined, '', highlight); } + if ('js' in json) { + applyJS(json.js); + } + if ('response' in json) { try { if (json.response.status == 1) {setResponse(true, json.response.text);} @@ -267,8 +399,14 @@ function handleJsonItems(json, highlight, callbackFn) { } catch(e) {setResponse(false, 'unknow error');} } + if ("data-id" in json) { + updateDataID(json, highlight); + } + // DOM objects now ready - if (callbackFn) {callbackFn();} + if (callbackFn && typeof combinedFunctionMap[callbackFn] === 'function') { + combinedFunctionMap[callbackFn](json); + } } /***************************************************************************************** @@ -276,7 +414,7 @@ function handleJsonItems(json, highlight, callbackFn) { * @param {*} b (bool): true = OK; false = Error * @param {*} s (String): text to show *****************************************************************************************/ -function setResponse(b, s) { +export function setResponse(b, s) { try { // clear if previous timer still run clearTimeout(timer); @@ -294,17 +432,14 @@ function setResponse(b, s) { } /****************************************************************************************** -# -# definition of creating selectionlists from input fields -# querySelector -> select input fields to convert -# jsonLists -> define multiple predefined lists to set as option as array -# blacklist -> simple list of ports (numbers) to set as disabled option -# -# example: -# CreateSelectionListFromInputField('input[type=number][id^=AllePorts], input[type=number][id^=GpioPin]', -# [gpio, gpio_analog], gpio_disabled); + * definition of creating selectionlists from input fields + * @param {*} querySelector -> select input fields to convert + * @param {*} jsonLists -> define multiple predefined lists to set as option as array + * @param {*}blacklist -> simple list of ports (numbers) to set as disabled option + * @example + * CreateSelectionListFromInputField('input[type=number][id^=AllePorts], input[type=number][id^=GpioPin]', [gpio, gpio_analog], gpio_disabled); ******************************************************************************************/ -function CreateSelectionListFromInputField(querySelector, jsonLists, blacklist) { +export function CreateSelectionListFromInputField(querySelector, jsonLists, blacklist) { var _parent, _select, _option, i, j, k; var objects = document.querySelectorAll(querySelector); for( j=0; j< objects.length; j++) { @@ -312,8 +447,8 @@ function CreateSelectionListFromInputField(querySelector, jsonLists, blacklist) _select = document.createElement('select'); _select.id = objects[j].id; _select.name = objects[j].name; - for ( k = 0; k < jsonLists.length; k += 1 ) { - for ( i = 0; i < jsonLists[k].length; i += 1 ) { + for ( k = 0; k < jsonLists.length; k++ ) { + for ( i = 0; i < jsonLists[k].length; i++ ) { _option = document.createElement( 'option' ); _option.value = jsonLists[k][i].port; _option.text = jsonLists[k][i].name; @@ -345,7 +480,7 @@ regex of item ID to identify first element in row - if set, returned json is an array, all elements per row, example: "^myonoffswitch.*" - if emty, all elements at one level together, ONLY for small json´s (->memory issue) ****************************************************************************************/ -function onSubmit(DataForm, separator='') { +export function onSubmit(DataForm, separator='') { // init json Objects var JsonData, tempData; @@ -411,19 +546,20 @@ function onSubmit(DataForm, separator='') { }) .then (() => { var data = {}; - data['action'] = "ReloadConfig"; - data['subaction'] = filename; - requestData(JSON.stringify(data), false); + data['cmd'] = {}; + data['cmd']['action'] = "ReloadConfig"; + data['cmd']['subaction'] = filename; + requestData(data); }); } - /**************************************************************************************** -blendet Zeilen der Tabelle aus - show: Array of shown IDs return true; - hide: Array of hidden IDs + * blendet Zeilen der Tabelle aus + * @param {*} show: Array of shown IDs return true; + * @param {*} hide: Array of hidden IDs + * @example radioselection(["row1", "row2"], ["row3", "row4"]) ****************************************************************************************/ -function radioselection(show, hide) { +export function radioselection(show, hide) { for(var i = 0; i < show.length; i++){ if (document.getElementById(show[i])) {document.getElementById(show[i]).style.display = 'table-row';} } @@ -439,7 +575,7 @@ function radioselection(show, hide) { * @param {*} hide Array of hidden IDs if checkbox is checked * @returns {*} void ****************************************************************************************/ -function onCheckboxSelection(checkbox, show, hide) { +export function onCheckboxSelection(checkbox, show, hide) { if (checkbox.checked) { radioselection(show, hide); } else { @@ -454,7 +590,7 @@ function onCheckboxSelection(checkbox, show, hide) { * For each of these checkboxes, it creates a new div element with the class "onoffswitch", clones the checkbox into this div, * and adds a label with the necessary span elements for styling. Finally, it replaces the original checkbox with the new div element. ****************************************************************************************/ -function transformCheckboxes() { +export function transformCheckboxes() { // Alle Checkboxen im Dokument suchen deren elternelement kein div mit der Style class "onoffswitch" ist const checkboxes = document.querySelectorAll("input[type='checkbox']:not(.onoffswitch-checkbox)"); @@ -468,6 +604,7 @@ function transformCheckboxes() { // Checkbox in das neue Div-Element kopieren const newCheckbox = checkboxes[i].cloneNode(true) + newCheckbox.className = 'onoffswitch-checkbox'; div.appendChild(newCheckbox); @@ -495,3 +632,48 @@ function transformCheckboxes() { } } + +/**************************************************************************************** + * Get all form data values as a string + * @param {*} formElement: id of the form element + * + * @returns {*} string containing all form data values + * ****************************************************************************************/ +export function getFormData(formElement) { + const form = document.getElementById(formElement); + if (form) { + const formData = new FormData(form); + let dataString = ''; + formData.forEach((value, key) => { + dataString += `${key}=${value}|`; + }); + // Remove the last '|' character + dataString = dataString.slice(0, -1); + return dataString; + } +} + +/**************************************************************************************** + * Show a dialog if the values of items in formdata has been changed + * ****************************************************************************************/ +export function showMustSaveDialog() { + if (document.getElementById('needToSave') && datavalues !== getFormData("DataForm")) { + document.getElementById('needToSave').classList.remove('hide'); + } else { + document.getElementById('needToSave').classList.add('hide'); + } +} + +/**************************************************************************************** + * Save the current form data values in the variable "datavalues" to check on every change + * if the form data has been changed. If the form data has been changed, show a dialog. + * ****************************************************************************************/ +export function initDataValues() { + datavalues = getFormData("DataForm"); + + if (document.getElementById('needToSave')) { + document.getElementById('needToSave').classList.add('hide'); + } +} +/**************************************************************************************** +****************************************************************************************/ diff --git a/data/web/Style.css b/data/web/Style.css index 7fdbc505..dc43fbcb 100644 --- a/data/web/Style.css +++ b/data/web/Style.css @@ -18,7 +18,7 @@ body { display: none; } - input[type="submit"] { + input[type="submit"], button { padding: 4px 16px; margin: 4px; background-color: #07D; @@ -27,7 +27,10 @@ body { border-radius: 4px; border: none; } - input[type="submit"]:hover { background: #336699; } + + input[type="submit"]:hover, button:hover { + background: #336699; + } input, select, textarea { margin: 4px; @@ -233,4 +236,30 @@ body { to { transform: rotate(360deg); } +} + +@keyframes pulse { + 0% { + opacity: 1; + } + 50% { + opacity: 0.3; + } + 100% { + opacity: 1; + } +} + +.pulse { + animation: pulse 1.5s infinite; +} + +.needToSave { + width: 300px; + margin: 0 auto; + border: 1px solid red; + border-radius: 25px; + text-align: center; + margin-bottom: 5px; + padding-bottom: 3px; } \ No newline at end of file diff --git a/data/web/baseconfig.html b/data/web/baseconfig.html index cb204305..7bb5b7cc 100644 --- a/data/web/baseconfig.html +++ b/data/web/baseconfig.html @@ -4,12 +4,33 @@ - - + + + + + +