diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..bdc7166f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,13 @@ +{ + "name": "SolaxModbusGateway", + "image": "mcr.microsoft.com/devcontainers/python:3.11", + "onCreateCommand": "pip3 install -U platformio", + "postStartCommand": "platformio run && platformio run --target buildfs", + "customizations": { + "vscode": { + "extensions": [ + "platformio.platformio-ide" + ] + } + } +} \ No newline at end of file diff --git a/.github/scripts/createManifest.py b/.github/scripts/createManifest.py index 9d79caf5..d83f067c 100644 --- a/.github/scripts/createManifest.py +++ b/.github/scripts/createManifest.py @@ -10,6 +10,7 @@ parser.add_argument('-s', '--build', type=str, help='Buildnummer der GithubAction (Unique ID)') parser.add_argument('-t', '--stage', type=str, help='Stage (Branch name)') parser.add_argument('-bp', '--binarypath', type=str, help='Path of binary files') +parser.add_argument('-fn', '--firmwarename', type=str, help='Name of the firmware') parser.add_argument('-rp', '--releasepath', type=str, default="release", help='Path of destination, BIN and JSON files') parser.add_argument('-rf', '--releasefile', type=str, help='Path of release file, contains version number') parser.add_argument('-a', '--arch', type=str, help='Architecture (ESP8266|ESP32|ESP32-S2|ESP32-C3|...)') @@ -26,6 +27,7 @@ logging.info(f"BUILDNUMMER={args.build}") logging.info(f"STAGE={args.stage}") logging.info(f"BINARYPATH={args.binarypath}") + logging.info(f"FIRMWARENAME={args.firmwarename}") logging.info(f"RELEASEPATH={args.releasepath}") logging.info(f"RELEASEFILE={args.releasefile}") logging.info(f"ARCHITECTURE={args.arch}") @@ -57,9 +59,7 @@ for file in files: if file == 'firmware.bin': FILENAME = os.path.splitext(file)[0] - FILEEXT = os.path.splitext(file)[1][1:] - FIRMWARENAME = args.binarypath.split(os.sep)[-2] # get the name of the firmware folder - + FILEEXT = os.path.splitext(file)[1][1:] DOWNLOADURL = f"https://tobiasfaust.github.io/{args.repository}/firmware/{FILENAME}.{FileExtension}.{FILEEXT}" ################ Create custom json ################## @@ -98,40 +98,40 @@ if os.path.isfile(os.path.join(args.binarypath, "merged-firmware.bin")): manifest_data["parts"].append({ - "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{FIRMWARENAME}/merged-firmware.{FileExtension}.bin", + "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{args.firmwarename}/merged-firmware.{FileExtension}.bin", "offset": 0 }) else: # fuer ESP8266 manifest_data["parts"].append({ - "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{FIRMWARENAME}/{FILENAME}.{FileExtension}.{FILEEXT}", + "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{args.firmwarename}/{FILENAME}.{FileExtension}.{FILEEXT}", "offset": 0 }) # process files.json if os.path.isfile(os.path.join(args.binarypath, "bootloader.bin")): files_data["parts"].append({ - "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{FIRMWARENAME}/bootloader.{FileExtension}.bin", + "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{args.firmwarename}/bootloader.{FileExtension}.bin", "offset": 4096, "filetype": "bootloader" }) if os.path.isfile(os.path.join(args.binarypath, "partitions.bin")): files_data["parts"].append({ - "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{FIRMWARENAME}/partitions.{FileExtension}.bin", + "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{args.firmwarename}/partitions.{FileExtension}.bin", "offset": 32768, "filetype": "partitions" }) if os.path.isfile(os.path.join(args.binarypath, "littlefs.bin")): files_data["parts"].append({ - "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{FIRMWARENAME}/littlefs.{FileExtension}.bin", - "offset": int(readOffsetFromPartitionCSV("partitions.csv", "spiffs"), 16), + "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{args.firmwarename}/littlefs.{FileExtension}.bin", + "offset": int(readOffsetFromPartitionCSV("partitions.csv", "webdata"), 16), "filetype": "filesystem" }) OFFSET = 0 if "ESP8266" in args.arch else int(readOffsetFromPartitionCSV("partitions.csv", "app0"), 16) files_data["parts"].append({ - "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{FIRMWARENAME}/{FILENAME}.{FileExtension}.{FILEEXT}", + "path": f"https://tobiasfaust.github.io/{args.repository}/firmware/{SubDir}/{args.firmwarename}/{FILENAME}.{FileExtension}.{FILEEXT}", "offset": OFFSET, "filetype": "firmware" }) diff --git a/.github/scripts/createMergedFirmware.py b/.github/scripts/createMergedFirmware.py index 301c66eb..d34f4c18 100644 --- a/.github/scripts/createMergedFirmware.py +++ b/.github/scripts/createMergedFirmware.py @@ -9,7 +9,7 @@ -b, --BuildDir (str): The build directory containing the built firmware binaries. Required. -p, --PathOfPartitionsCSV (str): The path to the partitions.csv file. Default is 'partitions.csv'. Required. Functions: - readOffsetFromPartitionCSV(path: str, name: str) -> int: + readOffsetFromPartitionCSV(path: str, partitionLabel: str) -> int: Args: Returns: Example: @@ -31,31 +31,46 @@ 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: - result = f'esptool.py --chip {args.ChipFamily} merge_bin \ + bootloader_offset = bootloader_offsets[args.ChipFamily] + + result = f'esptool --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 \ + --flash-mode dout \ + --flash-freq 80m \ + --flash-size 4MB \ + {bootloader_offset} {args.BuildDir}/bootloader.bin \ 0x8000 {args.BuildDir}/partitions.bin \ {readOffsetFromPartitionCSV("partitions.csv", "app0")} {args.BuildDir}/firmware.bin' if os.path.isfile(f'{args.BuildDir}/littlefs.bin'): - result += f' {readOffsetFromPartitionCSV("partitions.csv", "spiffs")} {args.BuildDir}/littlefs.bin' + result += f' {readOffsetFromPartitionCSV("partitions.csv", "webdata")} {args.BuildDir}/littlefs.bin' elif 'ESP8266' in args.ChipFamily and os.path.isfile(f'{args.BuildDir}/littlefs.bin'): - result = f'esptool.py --chip {args.ChipFamily} merge_bin \ + result = f'esptool --chip {args.ChipFamily} merge-bin \ --output {args.BuildDir}/merged-firmware.bin \ - --flash_mode dout \ - --flash_freq 40m \ - --flash_size 4MB \ + --flash-mode dout \ + --flash-freq 40m \ + --flash-size 4MB \ 0x0000 {args.BuildDir}/firmware.bin \ - {readOffsetFromPartitionCSV("partitions.csv", "spiffs")} {args.BuildDir}/littlefs.bin' + {readOffsetFromPartitionCSV("partitions.csv", "webdata")} {args.BuildDir}/littlefs.bin' print(f'command={result}') \ No newline at end of file diff --git a/.github/scripts/myUtils.py b/.github/scripts/myUtils.py index 5f80746a..c2d4b957 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 @@ -358,18 +358,18 @@ def changeURL(root: str, url: str) -> None: except Exception as e: logging.error(f"Fehler beim Verarbeiten der Datei {manifest_path}: {e}") -def readOffsetFromPartitionCSV(path: str, name: str) -> int: +def readOffsetFromPartitionCSV(path: str, partitionLabel: str) -> int: """ - Reads a CSV file and calculates the offset for a given name. + Reads a CSV file and calculates the offset for a given partition label. This function reads the specified CSV file with a delimiter of ','. It fills in the Offset column if it is empty by adding the previous offset and the value from the Size column of the previous row. It returns the calculated - offset from the row where the value in the first column matches the given name as a hexadecimal number. + offset from the row where the value in the first column matches the given partition label as a hexadecimal number. If the file does not exist or cannot be read, it returns None. Args: path (str): The path to the CSV file. - name (str): The name to search for in the first column. + partitionLabel (str): The partition label to search for in the first column. Returns: int: The calculated offset as a hexadecimal number, or None if the file cannot be read. @@ -379,7 +379,7 @@ def readOffsetFromPartitionCSV(path: str, name: str) -> int: with open(path, 'r') as file: lines = file.readlines() headers = lines[0].strip().split(',') - name_index = 0 + partition_label_index = 0 offset_index = 3 size_index = 4 @@ -391,7 +391,7 @@ def readOffsetFromPartitionCSV(path: str, name: str) -> int: columns[offset_index] = str(previous_offset + previous_size) previous_size = int(columns[size_index], 0) previous_offset = int(columns[offset_index], 0) - if columns[name_index] == name: + if columns[partition_label_index] == partitionLabel: return hex(previous_offset) except (FileNotFoundError, IndexError, ValueError): return None \ No newline at end of file diff --git a/.github/workflows/BuildAndDeploy.yml b/.github/workflows/BuildAndDeploy.yml index aa6cdc1c..0562661d 100644 --- a/.github/workflows/BuildAndDeploy.yml +++ b/.github/workflows/BuildAndDeploy.yml @@ -17,6 +17,11 @@ on: - '**.yml' - '**.sh' - '**.py' + - '**.json' + - '**.js' + - '**.css' + - '**.html' + - '**.ini' jobs: build: @@ -46,9 +51,6 @@ jobs: - firmware: firmware_ESP32-C3 architecture: ESP32-C3 subvariant: standard - - firmware: firmware_ESP32-WebSerial - architecture: ESP32 - subvariant: webSerial steps: - name: checkout repository @@ -68,13 +70,18 @@ jobs: - name: Run PlatformIO id: buildFw run: | + mkdir -p firmware/ platformio run -e ${{ matrix.variant.firmware }} + cp .pio/build/${{ matrix.variant.firmware }}/firmware.bin firmware/ + cp .pio/build/${{ matrix.variant.firmware }}/partitions.bin firmware/ + cp .pio/build/${{ matrix.variant.firmware }}/bootloader.bin firmware/ if [ -d "data" ]; then platformio run --target buildfs -e ${{ matrix.variant.firmware }} + cp .pio/build/${{ matrix.variant.firmware }}/littlefs.bin firmware/ fi python .github/scripts/createMergedFirmware.py \ --ChipFamily ${{ matrix.variant.architecture }} \ - --BuildDir .pio/build/${{ matrix.variant.firmware }} \ + --BuildDir firmware \ --PathOfPartitionsCSV partitions.csv \ >> "$GITHUB_OUTPUT" @@ -85,7 +92,7 @@ jobs: - name: Display generated files run: | - ls -R .pio/build/${{ matrix.variant.firmware }}/ + ls -R firmware/ - name: Schreibe Json/Manifest File id: json_params @@ -96,7 +103,8 @@ jobs: --variant ${{ matrix.variant.subvariant }} \ --stage ${{ env.BRANCH_NAME }} \ --repository ${{ env.REPOSITORY }} \ - --binarypath .pio/build/${{ matrix.variant.firmware }}/ \ + --binarypath firmware/ \ + --firmwarename ${{ matrix.variant.firmware }} \ --releasepath release \ --artifactpath artifacts \ --build ${{ github.run_number }} \ @@ -108,19 +116,6 @@ jobs: with: name: ${{ matrix.variant.firmware }} path: artifacts/* - -# - name: Upload to AWS S3 -# uses: jakejarvis/s3-sync-action@master -# with: -# args: '--acl public-read --follow-symlinks' -# env: -# AWS_S3_BUCKET: 'tfa-releases' -# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} -# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} -# AWS_REGION: 'eu-central-1' # optional: defaults to us-east-1 -# SOURCE_DIR: 'release' # optional: defaults to entire repository -# DEST_DIR: ${{ env.REPOSITORY }} - web-installer: needs: [build] @@ -250,7 +245,7 @@ jobs: continue fi echo "Uploading $file" - gh release upload -R tobiasfaust/${{ env.GITHUB_REPOSITORY }} ${{ steps.set_env_var.outputs.tagname }} "$file" --clobber + gh release upload -R ${{env.GITHUB_OWNER}}/${{ env.GITHUB_REPOSITORY }} ${{ steps.set_env_var.outputs.tagname }} "$file" --clobber fi done done @@ -263,18 +258,18 @@ jobs: GH_TOKEN: ${{ github.token }} run: | mkdir -p manifests - tagNames=$(gh release ls -R tobiasfaust/${{ env.GITHUB_REPOSITORY }} --json tagName) + tagNames=$(gh release ls -R ${{env.GITHUB_OWNER}}/${{ env.GITHUB_REPOSITORY }} --json tagName) for tag in $(echo "$tagNames" | jq -r '.[].tagName'); do - for asset in $(gh release view $tag -R tobiasfaust/${{ env.GITHUB_REPOSITORY }} --json assets --jq '.assets[].name' | grep -E 'manifestAll|filesAll'); do - echo "Downloading file: gh release download $tag -R tobiasfaust/${{ env.GITHUB_REPOSITORY }} --pattern '$asset' --dir 'manifests/${tag}/'" + for asset in $(gh release view $tag -R ${{env.GITHUB_OWNER}}/${{ env.GITHUB_REPOSITORY }} --json assets --jq '.assets[].name' | grep -E 'manifestAll|filesAll'); do + echo "Downloading file: gh release download $tag -R ${{env.GITHUB_OWNER}}/${{ env.GITHUB_REPOSITORY }} --pattern '$asset' --dir 'manifests/${tag}/'" gh release download $tag \ - -R tobiasfaust/${{ env.GITHUB_REPOSITORY }} \ + -R ${{env.GITHUB_OWNER}}/${{ env.GITHUB_REPOSITORY }} \ --pattern "$asset" \ --dir "manifests/${tag}/" || true done mkdir -p manifests/${tag}/ - gh release view $tag -R tobiasfaust/${{ env.GITHUB_REPOSITORY }} --json assets > "manifests/${tag}/assets.json" + gh release view $tag -R ${{env.GITHUB_OWNER}}/${{ env.GITHUB_REPOSITORY }} --json assets > "manifests/${tag}/assets.json" done python app/.github/scripts/createReleaseVersions.py \ --ManifestDir manifests \ diff --git a/.gitignore b/.gitignore index 84b3952b..2d5045c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .pio/ .vscode/ .git/ +data/web/handlefiles.* +data/web/webserial.* +include/board.h +data/web/gpio.js diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 72a03cf1..00000000 --- a/.gitpod.yml +++ /dev/null @@ -1,3 +0,0 @@ -tasks: - - command: pip3 install -U platformio && platformio run && platformio run --target buildfs - \ No newline at end of file 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..719b4cc1 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,9 +1,49 @@ +Release 3.4.3: + - ... + +Release 3.4.2: + - feature: specific board settings via board.h, important for ESP32-C3 + - feature: add new Deye SG05LP3 (thanks to @MagicSven81) (#171) + - feature: add new openWB topics up from version 2.1.8 (thanks to @AndreasNewbie) (#169) + +Release 3.4.1: + - fix BatVoltage in Growatt-SPH.json, thanks @Motl1 (#164) + - feature: add options "+unit" for modbus websocket streaming to show unit in output (#164) + - Fix: change gitpod to github codespace + +Release 3.4.0: + +++++++ This version is not OTA compatible with older versions +++++++ + +++++++ Please do a fresh installation by web-installer +++++++ + - add python.env file with HTML_DIR variable + - splitting LittleFS partitions: Separating system files (web UI, static assets) and user configuration/data (settings, user uploads) into distinct partitions (sysFS/configFS) improves reliability, allows safe firmware updates without overwriting user data, and enables easier backup/restore of user settings independently from system files. + - feature: add new webserial log monitor page for all variants + - fix broken ethernet connection handling by adding global gpio handling + - openwb: add more topics to Growatt-SPH (thanks to @AndreasNewbie) (#160) + +Release 3.3.4: + - Change default pins for ESP32-C3 (#149), thanks to @NHellFire + - remove deprecated backup functionality from Elegant-OTA + +Release 3.3.3: + - improve logging functionality methods + - fixing some bugs + - updated Solax-X3 json (thanks to @Lazgar) + +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/README.md b/README.md index ed163182..d003afd0 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Currently the following Inverters are with thier special registers integrated: * Growatt SPH * Sofar-KTL Solarmax-SGA * Deye Sun SG04LP3 +* Deye Sun SG05LP3 * QVolt-HYP-G3-3P If your Solar Inverter is not listed, feel free to add the special register simply, please check th [wiki page](configuration-register) or contact me by opening a [new issue](https://github.com/tobiasfaust/SolaxModbusGateway/issues) in github. diff --git a/data/misc/openwb.json b/data/misc/openwb.json index bece0478..bf982262 100644 --- a/data/misc/openwb.json +++ b/data/misc/openwb.json @@ -3,23 +3,57 @@ "version": "1.9", "topics": [ { "setpvw": "openWB/set/pv/#InverterID#/W" }, + { "setpvwh": "openWB/set/pv/#InverterID#/WhCounter"}, + { "setcoexp": "openWB/set/houseMeter/WhExported" }, + { "setcocur": "openWB/set/houseMeter/Currents" }, + { "setcofre": "openWB/set/houseMeter/Frequency" }, + { "setcovol": "openWB/set/houseMeter/Voltages" }, + { "setcopow": "openWB/set/houseMeter/Powers" }, + { "setcopowf": "openWB/set/houseMeter/PowerFactors" }, + { "setcoimp": "openWB/set/houseMeter/WhImported" }, + { "setcow": "openWB/set/houseMeter/W" }, { "setbatw": "openWB/set/houseBattery/W"}, { "setbatsoc": "openWB/set/houseBattery/%Soc"}, { "setbatexpwh": "openWB/set/houseBattery/WhExported"}, - { "setbatimpwh": "openWB/set/houseBattery/WhImported"}, - { "setcounterwh": "openWB/set/pv/#InverterID#/WhCounter"} + { "setbatimpwh": "openWB/set/houseBattery/WhImported"} ] }, { "version": "2.0", "topics": [ { "setpvw": "openWB/set/pv/#InverterID#/get/power" }, - { "setbatw": "openWB/set/bat/#BatteryID#/get/power"}, - { "setbatsoc": "openWB/set/bat/#BatteryID#/get/soc"}, - { "setbatexpwh": "openWB/set/bat/#BatteryID#/get/exported"}, - { "setbatimpwh": "openWB/set/bat/#BatteryID#/get/imported"}, - { "setcounterwh": " openWB/set/pv/#InverterID#/get/exported"} - + { "setpvwh": "openWB/set/pv/#InverterID#/get/exported" }, + { "setbatw": "openWB/set/bat/#BatteryID#/get/power" }, + { "setbatsoc": "openWB/set/bat/#BatteryID#/get/soc" }, + { "setbatexpwh": "openWB/set/bat/#BatteryID#/get/exported" }, + { "setbatimpwh": "openWB/set/bat/#BatteryID#/get/imported" }, + { "setcoexp": "openWB/set/counter/#SmartMeterID#/get/exported" }, + { "setcocur": "openWB/set/counter/#SmartMeterID#/get/currents" }, + { "setcofre": "openWB/set/counter/#SmartMeterID#/get/frequency" }, + { "setcovol": "openWB/set/counter/#SmartMeterID#/get/voltages" }, + { "setcopow": "openWB/set/counter/#SmartMeterID#/get/power" }, + { "setcopowf": "openWB/set/counter/#SmartMeterID#/get/power_factors" }, + { "setcoimp": "openWB/set/counter/#SmartMeterID#/get/imported" }, + { "setcow": "openWB/set/counter/#SmartMeterID#/get/power" } ] - } + }, + { + "version": "2.1.8", + "topics": [ + { "setpvw": "openWB/set/mqtt/pv/#InverterID#/get/power" }, + { "setpvwh": "openWB/set/mqtt/pv/#InverterID#/get/exported" }, + { "setbatw": "openWB/set/mqtt/bat/#BatteryID#/get/power" }, + { "setbatsoc": "openWB/set/mqtt/bat/#BatteryID#/get/soc" }, + { "setbatexpwh": "openWB/set/mqtt/bat/#BatteryID#/get/exported" }, + { "setbatimpwh": "openWB/set/mqtt/bat/#BatteryID#/get/imported" }, + { "setcoexp": "openWB/set/mqtt/counter/#SmartMeterID#/get/exported" }, + { "setcocur": "openWB/set/mqtt/counter/#SmartMeterID#/get/currents" }, + { "setcofre": "openWB/set/mqtt/counter/#SmartMeterID#/get/frequency" }, + { "setcovol": "openWB/set/mqtt/counter/#SmartMeterID#/get/voltages" }, + { "setcopow": "openWB/set/mqtt/counter/#SmartMeterID#/get/power" }, + { "setcopowf": "openWB/set/mqtt/counter/#SmartMeterID#/get/power_factors" }, + { "setcoimp": "openWB/set/mqtt/counter/#SmartMeterID#/get/imported" }, + { "setcow": "openWB/set/mqtt/counter/#SmartMeterID#/get/power" } + ] + } ] \ No newline at end of file diff --git a/data/regs/Deye-SUN-SG05LP3.json b/data/regs/Deye-SUN-SG05LP3.json new file mode 100644 index 00000000..34a67e40 --- /dev/null +++ b/data/regs/Deye-SUN-SG05LP3.json @@ -0,0 +1,201 @@ +{ + "Deye-SUN-xxK-SG05LP3-EU-SM2": { + "config": { + "author": "MagicSven81", + "RequestLiveData": [ + [ + "#ClientID", + "0x03", + "0x02", + "0x44", + "0x00", + "0x66" + ] + ], + "ClientIdPos": 0, + "LiveDataFunctionCodePos": 1, + "LiveDataFunctionCode": "0x03", + "LiveDataStartsAtPos": 3, + "LiveDataSuccessCode": "0x03" + }, + "data": { + "livedata": [ + + { + "position": [17, 18], + "name": "BatV", + "realname": "Batterie Spannung", + "datatype": "float", + "factor": 0.01, + "unit": "V" + }, + { + "position": [19, 20], + "name": "BatSOC", + "realname": "Batterie SOC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [21, 22], + "name": "BatCurrent", + "realname": "Batterie Strom", + "datatype": "float", + "factor": 0.01, + "unit": "A" + }, + { + "position": [23, 24], + "name": "BatP", + "realname": "Batterie Leistung", + "datatype": "integer", + "unit": "W" + }, + { + "position": [25, 26], + "name": "BatTemp", + "realname": "Batterie Temperatur", + "datatype": "float", + "factor": 0.1, + "valueAdd": -100, + "unit": "°C" + }, + { + "position": [69, 70], + "name": "GridV_L1", + "realname": "Netzspannung L1", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [71, 72], + "name": "GridV_L2", + "realname": "Netzspannung L2", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [73, 74], + "name": "GridV_L3", + "realname": "Netzspannung L3", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [75, 76], + "name": "GridP_L1", + "realname": "Netz L1 Leistung", + "datatype": "integer", + "unit": "W" + }, + { + "position": [77, 78], + "name": "GridP_L2", + "realname": "Netz L2 Leistung", + "datatype": "integer", + "unit": "W" + }, + { + "position": [79, 80], + "name": "GridP_L3", + "realname": "Netz L3 Leistung", + "datatype": "integer", + "unit": "W" + }, + { + "position": [81, 82], + "name": "Grid_Total", + "realname": "Netz Gesamtleistung", + "datatype": "integer", + "unit": "W" + }, + { + "position": [83, 84], + "name": "GridFreq", + "realname": "Netzfrequenz", + "datatype": "float", + "factor": 0.01, + "unit": "Hz" + }, + { + "position": [145, 146], + "name": "Load_L1", + "realname": "Hausverbrauch L1", + "datatype": "integer", + "unit": "W" + }, + { + "position": [147, 148], + "name": "Load_L2", + "realname": "Hausverbrauch L2", + "datatype": "integer", + "unit": "W" + }, + { + "position": [149, 150], + "name": "Load_Total", + "realname": "Hausverbrauch Gesamt", + "datatype": "integer", + "unit": "W" + }, + { + "position": [151, 152], + "name": "Load_L3", + "realname": "Hausverbrauch L3", + "datatype": "integer", + "unit": "W" + }, + { + "position": [187, 188], + "name": "PV1_P", + "realname": "PV1 Leistung", + "datatype": "integer", + "unit": "W" + }, + { + "position": [189, 190], + "name": "PV2_P", + "realname": "PV2 Leistung", + "datatype": "integer", + "unit": "W" + }, + { + "position": [193, 194], + "name": "PV1_V", + "realname": "PV1 Spannung", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [195, 196], + "name": "PV1_I", + "realname": "PV1 Strom", + "datatype": "float", + "factor": 0.1, + "unit": "A" + }, + { + "position": [197, 198], + "name": "PV2_V", + "realname": "PV2 Spannung", + "datatype": "float", + "factor": 0.1, + "unit": "V" + }, + { + "position": [199, 200], + "name": "PV2_I", + "realname": "PV2 Strom", + "datatype": "float", + "factor": 0.1, + "unit": "A" + } + + ] + } + } +} diff --git a/data/regs/Deye_SUN_SG04LP3.json b/data/regs/Deye_SUN_SG04LP3.json index d291499b..cf5d3358 100644 --- a/data/regs/Deye_SUN_SG04LP3.json +++ b/data/regs/Deye_SUN_SG04LP3.json @@ -336,7 +336,7 @@ "realname": "Total PV Power in Wh", "datatype": "float", "factor": 100, - "openwbtopic": "setcounterwh", + "openwbtopic": "setpvwh", "unit": "KWh" }, { diff --git a/data/regs/Growatt-MOD.json b/data/regs/Growatt-MOD.json index e4e858a9..74d74715 100644 --- a/data/regs/Growatt-MOD.json +++ b/data/regs/Growatt-MOD.json @@ -331,7 +331,7 @@ "name": "TotalEnergyGeneratedWh", "realname": "Erzeugte Energie Gesamt in Wh", "datatype": "integer", - "openwbtopic": "setcounterwh", + "openwbtopic": "setpvwh", "factor": 100, "unit": "KWh" }, diff --git a/data/regs/Growatt-SPH-V124.json b/data/regs/Growatt-SPH-V124.json new file mode 100644 index 00000000..922dbb5d --- /dev/null +++ b/data/regs/Growatt-SPH-V124.json @@ -0,0 +1,691 @@ +{ + "Growatt-SPH-V124": { + "config": { + "author": [ + "StefanNouza", + "AndreasNewbie" + ], + "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", + "openwbtopic": "setpvw", + "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", + "openwbtopic": "setcofre", + "datatype": "float", + "factor": 0.01, + "unit": "Hz" + }, + { + "position": [109, 110, 111, 112], + "name": "Energy_Generated_today_kWh", + "realname": "generated Energy today", + "openwbtopic": "setpvwh", + "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": "float", + "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", + "openwbtopic": "setbatexpwh", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [250, 251, 252, 253], + "name": "Power_Battery_Charge_W", + "realname": "Charge Power", + "openwbtopic": "setbatimpwh", + "datatype": "float", + "factor": 0.1, + "unit": "W" + }, + { + "position": [246, 247, 248, 249], + "position2": [250, 251, 252, 253], + "name": "BatChargingPower", + "realname": "Battery Charging Power", + "openwbtopic": "setbatw", + "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", + "openwbtopic": "setbatsoc", + "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": [270, 271, 272, 273], + "position2": [286, 287, 288, 289], + "name": "Power_AC_W", + "realname": "SmartMeter: Power", + "openwbtopic": "setcopow", + "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", + "openwbtopic": "setcoimp", + "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", + "openwbtopic": "setcoexp", + "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/Growatt-SPH.json b/data/regs/Growatt-SPH.json index a4c4aa56..6850ec43 100644 --- a/data/regs/Growatt-SPH.json +++ b/data/regs/Growatt-SPH.json @@ -76,7 +76,7 @@ ], "name": "TotalEnergyPV", "realname": "Erzeugte Energie PV", - "openwbtopic": "setcounterwh", + "openwbtopic": "setpvwh", "datatype": "integer", "factor": 100, "unit": "Wh" @@ -114,7 +114,7 @@ "unit": "KWh" }, { - "position": [183, 284], + "position": [272, 273], "name": "BatVoltage", "realname": "Battery Voltage", "datatype": "float", diff --git a/data/regs/QVolt.json b/data/regs/QVolt.json index 74fe1065..c67fd503 100644 --- a/data/regs/QVolt.json +++ b/data/regs/QVolt.json @@ -447,7 +447,7 @@ "name": "EnergyTotalToGridWh", "realname": "Total Energy to Grid in Wh", "datatype": "integer", - "openwbtopic": "setcounterwh", + "openwbtopic": "setpvwh", "factor": 100, "unit": "Wh" }, diff --git a/data/regs/Solax-MIC-Pro.json b/data/regs/Solax-MIC-Pro.json index e4820ecf..6eb9f89a 100644 --- a/data/regs/Solax-MIC-Pro.json +++ b/data/regs/Solax-MIC-Pro.json @@ -303,7 +303,7 @@ ], "name": "EnergyTotalToGridWh", "realname": "Total Energy to Grid in Wh", - "openwbtopic": "setcounterwh", + "openwbtopic": "setpvwh", "datatype": "integer", "factor": 100, "unit": "Wh" diff --git a/data/regs/Solax-MIC.json b/data/regs/Solax-MIC.json index b7b1db3f..dee86b9f 100644 --- a/data/regs/Solax-MIC.json +++ b/data/regs/Solax-MIC.json @@ -197,7 +197,7 @@ "position": [75, 76, 73, 74], "name": "EnergyTotalToGridWh", "realname": "Total Energy to Grid in Wh", - "openwbtopic": "setcounterwh", + "openwbtopic": "setpvwh", "datatype": "integer", "factor": 100, "unit": "Wh" diff --git a/data/regs/Solax-X1.json b/data/regs/Solax-X1.json index 65a8f3fc..22c7b6d2 100644 --- a/data/regs/Solax-X1.json +++ b/data/regs/Solax-X1.json @@ -405,7 +405,7 @@ ], "name": "EnergyTotalToGridWh", "realname": "Total Energy to Grid in Wh", - "openwbtopic": "setcounterwh", + "openwbtopic": "setpvwh", "datatype": "integer", "factor": 100, "unit": "Wh" @@ -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..13f30ee4 100644 --- a/data/regs/Solax-X3.json +++ b/data/regs/Solax-X3.json @@ -1,874 +1,1967 @@ { - "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", + "mapping": [ + [ + 0, + "Locked" + ], + [ + 1, + "Unlocked" + ] + ] + }, + { + "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": [ + 575, + 576, + 573, + 574 + ], + "name": "BatDischargeableEnergy", + "realname": "Battery Dischargeable Energy", + "datatype": "integer", + "unit": "Wh" + }, + { + "position": [ + 571, + 572, + 569, + 570 + ], + "name": "BatChargeableEnergy", + "realname": "Battery Chargeable Energy", + "datatype": "integer", + "unit": "Wh" + }, + { + "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": [ + 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": "setpvwh", + "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, + 305 + ], + "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" + }, + { + "position": [ + 525, + 526 + ], + "name": "VPPControlMode", + "realname": "VPP Control Mode", + "datatype": "integer", + "mapping": [ + [ + 0, + "Disabled" + ], + [ + 1, + "PowerControl" + ], + [ + 2, + "ElectricQuantityControl" + ], + [ + 3, + "SoCTargetControl" + ] + ] + }, + { + "position": [ + 527, + 528 + ], + "name": "VPPControlStatus", + "realname": "VPP Control Status", + "datatype": "integer", + "mapping": [ + [ + 0, + "Unfinished" + ], + [ + 1, + "Finished" + ] + ] + }, + { + "position": [ + 531, + 532, + 529, + 530 + ], + "name": "VPPActivePowerTarget", + "realname": "VPP Active Power Target", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 535, + 536, + 533, + 534 + ], + "name": "VPPReactivePowerTarget", + "realname": "VPP Reactive Power Target", + "datatype": "integer", + "unit": "VA" + }, + { + "position": [ + 563, + 564, + 561, + 562 + ], + "name": "VPPTargetEnergy", + "realname": "VPP Target Energy", + "datatype": "integer", + "unit": "Wh" + }, + { + "position": [ + 579, + 580 + ], + "name": "VPPTargetSoC", + "realname": "VPP Target SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 567, + 568, + 565, + 566 + ], + "name": "VPPChargeDischargePower", + "realname": "VPP Charge Discharge Power", + "datatype": "integer", + "unit": "W" + }, + { + "position": [ + 577, + 578 + ], + "name": "VPPDuration", + "realname": "VPP Duration", + "datatype": "integer", + "unit": "s" + }, + { + "position": [ + 585, + 586 + ], + "name": "VPPCtrlTimeout", + "realname": "VPP Ctrl Timeout", + "datatype": "integer", + "unit": "s" + } + ], + "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, + "ManualMode" + ], + [ + 4, + "PeakShaving" + ], + [ + 5, + "TOUMode" + ] + ] + }, + { + "position": [ + 288, + 289 + ], + "name": "ManualMode", + "realname": "Manual 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": "PhaseUnbalancedPowerFeed", + "realname": "Phase Unbalanced Power Feed", + "datatype": "integer", + "mapping": [ + [ + 0, + "Disabled" + ], + [ + 1, + "Enabled" + ] + ] + }, + { + "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": [ + 303 + ], + "name": "SelfUseChargeEnable", + "realname": "Self-Use Charge from Grid Enable", + "datatype": "integer", + "mapping": [ + [ + 0, + "Disabled" + ], + [ + 1, + "Enabled" + ] + ] + }, + { + "position": [ + 304, + 305 + ], + "name": "SelfUseMaxGridSoC", + "realname": "Self-Use Maximum Grid SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 306 + ], + "name": "FeedInNightChargeSoC", + "realname": "FeedIn NightCharge SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 307 + ], + "name": "FeedInMinSoC", + "realname": "FeedIn Minimum SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 308 + ], + "name": "BackupNightChargeSoC", + "realname": "Backup NightCharge SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 309 + ], + "name": "BackupMinSoC", + "realname": "Backup Minimum SoC", + "datatype": "integer", + "unit": "%" + }, + { + "position": [ + 311, + 310 + ], + "name": "ChargePeriod1_StartTime", + "realname": "Forced Charge Period Start Time", + "datatype": "integer", + "unit": "h:m" + }, + { + "position": [ + 313, + 312 + ], + "name": "ChargePeriod1_EndTime", + "realname": "Forced Charge Period End Time", + "datatype": "integer", + "unit": "h:m" + }, + { + "position": [ + 315, + 314 + ], + "name": "DischargePeriod1_StartTime", + "realname": "Allowed Disc Period Start Time", + "datatype": "integer", + "unit": "h:m" + }, + { + "position": [ + 317, + 316 + ], + "name": "DischargePeriod1_EndTime", + "realname": "Allowed Disc Period End Time", + "datatype": "integer", + "unit": "h:m" } - } + ] + }, + "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 + ], + [ + "ManualMode", + 3 + ], + [ + "PeakShaving", + 4 + ], + [ + "TOUMode", + 5 + ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x1f" + ] + }, + { + "name": "setManualMode", + "realname": "Manual 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": "setPhaseUnbalancedPowerFeed", + "realname": "Phase Unbalanced Power Feed", + "info": "Allow unbalanced power feed to the grid", + "mapping": [ + [ + "Disable", + 0 + ], + [ + "Enable", + 1 + ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x9e" + ] + }, + { + "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": "setSelfUseChargeEnable", + "realname": "Self-Use Charge from Grid", + "info": "enable/disable charging from grid", + "mapping": [ + [ + "Disable", + 0 + ], + [ + "Enable", + 1 + ] + ], + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x62" + ] + }, + { + "name": "setSelfUseMaxGridSoC", + "realname": "Self-Use Maximum Grid SoC", + "info": "can be set between 10 - 100 percent", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x63" + ] + }, + { + "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" + ] + }, + { + "name": "setVPPControl", + "realname": "VPP Control", + "info": "VPP Control Function, a comma separated List of Values. Check Solax Documentation for Details.", + "intsize": [ + "int16", + "int16", + "int32", + "int32", + "int16", + "int16", + "int32", + "int32", + "int16", + "int32" + ], + "request": [ + "#ClientID", + "0x10", + "0x00", + "0x7C", + "0x00", + "0x0F" + ] + }, + { + "name": "setChargePeriod1_StartTime", + "realname": "Forced Charge Period Start Time", + "info": "Forced Charge Period Start Time", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x68" + ] + }, + { + "name": "setChargePeriod1_EndTime", + "realname": "Forced Charge Period End Time", + "info": "Forced Charge Period End Time", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x69" + ] + }, + { + "name": "setDischargePeriod1_StartTime", + "realname": "Allowed Disc Period Start Time", + "info": "Allowed Discharge Period Start Time", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x6A" + ] + }, + { + "name": "setDischargePeriod1_EndTime", + "realname": "Allowed Disc Period End Time", + "info": "Allowed Discharge Period End Time", + "request": [ + "#ClientID", + "0x06", + "0x00", + "0x6B" + ] + } + ] + } } diff --git a/data/web/Javascript.js b/data/web/Javascript.js index 5474846d..fef10600 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) { @@ -94,33 +175,57 @@ function handleRadioSelections() { for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].onclick) { var onclickStr = checkboxes[i].getAttribute('onclick'); - var match = onclickStr.match(/onCheckboxSelection\((.*)\)/); + var match = onclickStr.match(/onCheckboxSelection\((.*)\)/); if (match) { - eval("onCheckboxSelection(" + match[1] + ")"); + // Entferne den ersten Parameter (->this) aus match[1] + // Beispiel: "this, ['EnableRelays_1','EnableRelays_2'],[]" + // Ergebnis: "['EnableRelays_1','EnableRelays_2'],[]" + let params = match[1].replace(/^\s*[^,]+,\s*/, ''); + // eval mit dem aktuellen Checkbox-Element als ersten Parameter + eval("onCheckboxSelection(checkboxes[i], " + params + ")"); } } } } /***************************************************************************************** - * 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 +245,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 +257,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 +366,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 +404,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 +419,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 +437,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 +452,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; @@ -334,7 +474,7 @@ function CreateSelectionListFromInputField(querySelector, jsonLists, blacklist) ****************************************************************************************/ function isVisible(_obj) { var ret = true; - if (_obj && _obj.style.display == "none") { ret = false;} + if (_obj && (_obj.style.display == "none" || _obj.classList.contains("hide"))) { ret = false; } else if (_obj && _obj.parentNode && _obj.tagName != "HTML") ret = isVisible(_obj.parentNode); return ret; } @@ -345,7 +485,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 +551,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 +580,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 +595,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 +609,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 +637,62 @@ 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'); + } +} + +/**************************************************************************************** + * Show or hide an object + * @returns {*} void + * ****************************************************************************************/ +export function toggleView() { + const logView = document.getElementById('logView'); + if (logView.style.display === 'none') { + logView.style.display = 'block'; + } else { + logView.style.display = 'none'; + } +} + +/**************************************************************************************** +****************************************************************************************/ 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..1c6443f8 100644 --- a/data/web/baseconfig.html +++ b/data/web/baseconfig.html @@ -3,13 +3,34 @@
- - - + + + + + + +