From 67d8ba99914614b85efbd55f069b1881eb63a9a7 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Mon, 26 Jan 2026 22:02:26 +0000 Subject: [PATCH 1/2] feat: migrate register definitions from YAML to CSV format - Add register_loader.py module to load CSV register definitions - Create migration scripts to convert YAML to CSV format - Update sungather.py with backward compatibility for both CSV and YAML - Generate registers-sungrow.csv with 210 read and 37 hold registers - Create scan-ranges.yaml for Modbus scan configuration - Add test script to verify CSV loader functionality - Maintain backward compatibility with deprecation warning for YAML files This migration simplifies register maintenance and enables easier editing in spreadsheet applications while preserving all existing functionality. --- SunGather/register_loader.py | 188 ++++++++++++++++ SunGather/registers-sungrow.csv | 248 +++++++++++++++++++++ SunGather/scan-ranges.yaml | 49 ++++ SunGather/sungather.py | 24 +- scripts/migrate_yaml_to_csv.py | 182 +++++++++++++++ scripts/migrate_yaml_to_csv_simple.py | 307 ++++++++++++++++++++++++++ scripts/test_loader.py | 150 +++++++++++++ 7 files changed, 1143 insertions(+), 5 deletions(-) create mode 100644 SunGather/register_loader.py create mode 100644 SunGather/registers-sungrow.csv create mode 100644 SunGather/scan-ranges.yaml create mode 100644 scripts/migrate_yaml_to_csv.py create mode 100644 scripts/migrate_yaml_to_csv_simple.py create mode 100644 scripts/test_loader.py diff --git a/SunGather/register_loader.py b/SunGather/register_loader.py new file mode 100644 index 0000000..89dd993 --- /dev/null +++ b/SunGather/register_loader.py @@ -0,0 +1,188 @@ +#!/usr/bin/python3 + +""" +Register Loader Module + +Loads register definitions from CSV format and scan ranges from YAML, +combining them into the structure expected by SungrowClient. +""" + +import csv +import json +import logging +import os + +try: + import yaml + YAML_AVAILABLE = True +except ImportError: + YAML_AVAILABLE = False + + +def simple_yaml_parse_scan_ranges(yaml_content): + """ + Simple YAML parser for scan-ranges.yaml file. + Only used when PyYAML is not available. + """ + lines = yaml_content.split('\n') + data = { + 'version': None, + 'vendor': None, + 'scan': [] + } + + current_scan_type = None + current_scan_block = None + + for line in lines: + stripped = line.strip() + + # Skip empty lines and comments + if not stripped or stripped.startswith('#'): + continue + + if stripped.startswith('version:'): + data['version'] = stripped.split(':', 1)[1].strip() + elif stripped.startswith('vendor:'): + data['vendor'] = stripped.split(':', 1)[1].strip() + elif stripped == 'scan:': + continue + elif stripped.startswith('- read:'): + current_scan_type = 'read' + current_scan_block = [] + data['scan'].append({'read': current_scan_block}) + elif stripped.startswith('- hold:'): + current_scan_type = 'hold' + current_scan_block = [] + data['scan'].append({'hold': current_scan_block}) + elif stripped.startswith('- start:'): + start_val = int(stripped.split(':', 1)[1].strip()) + if current_scan_block is not None: + current_scan_block.append({'start': start_val}) + elif stripped.startswith('range:') and current_scan_block is not None: + range_val = int(stripped.split(':', 1)[1].strip()) + if current_scan_block: + current_scan_block[-1]['range'] = range_val + + return data + + +def load_registers(csv_path, scan_yaml_path): + """ + Load registers from CSV and scan ranges from YAML. + + Args: + csv_path: Path to the CSV file containing register definitions + scan_yaml_path: Path to the YAML file containing scan ranges + + Returns: + dict: Combined structure matching original YAML format + """ + logging.info(f"Loading registers from CSV: {csv_path}") + + registers = {"read": [], "hold": []} + + # Read CSV file + try: + with open(csv_path, encoding="utf-8") as f: + reader = csv.DictReader(f) + for row in reader: + register = parse_register_row(row) + reg_type = row["type"] + if reg_type in registers: + registers[reg_type].append(register) + else: + logging.warning(f"Unknown register type: {reg_type} for register {row.get('name')}") + except Exception as err: + raise Exception(f"Failed to load CSV file {csv_path}: {err}") + + # Load scan ranges from YAML + try: + with open(scan_yaml_path, encoding="utf-8") as f: + if YAML_AVAILABLE: + scan_data = yaml.safe_load(f) + else: + # Use simple parser when PyYAML is not available + scan_data = simple_yaml_parse_scan_ranges(f.read()) + except Exception as err: + raise Exception(f"Failed to load scan ranges YAML {scan_yaml_path}: {err}") + + # Build final structure matching original YAML format + result = { + "version": scan_data.get("version"), + "vendor": scan_data.get("vendor"), + "registers": [ + {"read": registers["read"]}, + {"hold": registers["hold"]} + ], + "scan": scan_data.get("scan") + } + + logging.info(f"Loaded {len(registers['read'])} read registers and {len(registers['hold'])} hold registers") + + return result + + +def parse_register_row(row): + """ + Convert CSV row to register dictionary. + + Args: + row: Dictionary representing one CSV row + + Returns: + dict: Register definition + """ + # Required fields + register = { + "name": row["name"], + "level": int(row["level"]), + "address": int(row["address"]), + "datatype": row["datatype"] + } + + # Optional fields - only add if present and not empty + if row.get("accuracy") and row["accuracy"].strip(): + register["accuracy"] = float(row["accuracy"]) + + if row.get("unit") and row["unit"].strip(): + register["unit"] = row["unit"] + + if row.get("models") and row["models"].strip(): + # Models are pipe-delimited in CSV + register["models"] = [m.strip() for m in row["models"].split("|") if m.strip()] + + if row.get("datarange") and row["datarange"].strip(): + # Datarange is stored as JSON string in CSV + try: + register["datarange"] = json.loads(row["datarange"]) + except json.JSONDecodeError as err: + logging.warning(f"Failed to parse datarange JSON for {row['name']}: {err}") + + if row.get("mask") and row["mask"].strip(): + register["mask"] = int(row["mask"]) + + if row.get("default") and row["default"].strip(): + register["default"] = row["default"] + + if row.get("smart_meter") and row["smart_meter"].strip(): + # Only set if explicitly true + if row["smart_meter"].lower() == "true": + register["smart_meter"] = True + + return register + + +def get_scan_ranges_path(csv_path): + """ + Get the corresponding scan-ranges.yaml path for a given CSV path. + + Args: + csv_path: Path to the CSV file + + Returns: + str: Path to the scan-ranges.yaml file + """ + # Replace filename with scan-ranges.yaml, keep directory + directory = os.path.dirname(csv_path) + return os.path.join(directory, "scan-ranges.yaml") diff --git a/SunGather/registers-sungrow.csv b/SunGather/registers-sungrow.csv new file mode 100644 index 0000000..cca5ae3 --- /dev/null +++ b/SunGather/registers-sungrow.csv @@ -0,0 +1,248 @@ +type,name,level,address,datatype,accuracy,unit,models,datarange,mask,default,smart_meter +read,protocol_number,2,4950,U32,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,protocol_version,2,4952,U32,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,arm_software_version,2,4954,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,dsp_software_version,2,4969,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,serial_number,3,4990,UTF-8,,,,,,, +read,device_type_code,3,5000,U16,,,,"[{""response"": 39, ""value"": ""SG30KTL""}, {""response"": 38, ""value"": ""SG10KTL""}, {""response"": 41, ""value"": ""SG12KTL""}, {""response"": 40, ""value"": ""SG15KTL""}, {""response"": 42, ""value"": ""SG20KTL""}, {""response"": 44, ""value"": ""SG30KU""}, {""response"": 45, ""value"": ""SG36KTL""}, {""response"": 46, ""value"": ""SG36KU""}, {""response"": 47, ""value"": ""SG40KTL""}, {""response"": 309, ""value"": ""SG40KTL-M""}, {""response"": 283, ""value"": ""SG50KTL-M""}, {""response"": 305, ""value"": ""SG60KTL-M""}, {""response"": 310, ""value"": ""SG60KU""}, {""response"": 321, ""value"": ""SG30KTL-M""}, {""response"": 112, ""value"": ""SG30KTL-M-V31""}, {""response"": 308, ""value"": ""SG33KTL-M""}, {""response"": 116, ""value"": ""SG36KTL-M""}, {""response"": 317, ""value"": ""SG33K3J""}, {""response"": 311, ""value"": ""SG49K5J""}, {""response"": 114, ""value"": ""SG34KJ""}, {""response"": 115, ""value"": ""LP_P34KSG""}, {""response"": 283, ""value"": ""SG50KTL-M-20""}, {""response"": 271, ""value"": ""SG60KTL""}, {""response"": 312, ""value"": ""SG80KTL""}, {""response"": 312, ""value"": ""SG80KTL-20""}, {""response"": 306, ""value"": ""SG60KU-M""}, {""response"": 327, ""value"": ""SG5KTL-MT""}, {""response"": 328, ""value"": ""SG6KTL-MT""}, {""response"": 319, ""value"": ""SG8KTL-M""}, {""response"": 318, ""value"": ""SG10KTL-M""}, {""response"": 11279, ""value"": ""SG10KTL-MT""}, {""response"": 316, ""value"": ""SG12KTL-M""}, {""response"": 322, ""value"": ""SG15KTL-M""}, {""response"": 329, ""value"": ""SG17KTL-M""}, {""response"": 323, ""value"": ""SG20KTL-M""}, {""response"": 313, ""value"": ""SG80KTL-M""}, {""response"": 332, ""value"": ""SG111HV""}, {""response"": 315, ""value"": ""SG125HV""}, {""response"": 11267, ""value"": ""SG125HV-20""}, {""response"": 11280, ""value"": ""SG30CX""}, {""response"": 11264, ""value"": ""SG33CX""}, {""response"": 11274, ""value"": ""SG36CX-US""}, {""response"": 11265, ""value"": ""SG40CX""}, {""response"": 11266, ""value"": ""SG50CX""}, {""response"": 11275, ""value"": ""SG60CX-US""}, {""response"": 11270, ""value"": ""SG110CX""}, {""response"": 11276, ""value"": ""SG250HX""}, {""response"": 11281, ""value"": ""SG250HX-US""}, {""response"": 11282, ""value"": ""SG100CX""}, {""response"": 11282, ""value"": ""SG100CX-JP""}, {""response"": 11283, ""value"": ""SG250HX-IN""}, {""response"": 11285, ""value"": ""SG25CX-SA""}, {""response"": 11298, ""value"": ""SG75CX""}, {""response"": 9277, ""value"": ""SG3.0RT""}, {""response"": 9278, ""value"": ""SG4.0RT""}, {""response"": 9264, ""value"": ""SG5.0RT""}, {""response"": 9265, ""value"": ""SG6.0RT""}, {""response"": 9276, ""value"": ""SG7.0RT""}, {""response"": 9266, ""value"": ""SG8.0RT""}, {""response"": 9267, ""value"": ""SG10RT""}, {""response"": 9268, ""value"": ""SG12RT""}, {""response"": 9269, ""value"": ""SG15RT""}, {""response"": 9270, ""value"": ""SG17RT""}, {""response"": 9271, ""value"": ""SG20RT""}, {""response"": 3337, ""value"": ""SH5K-20""}, {""response"": 3334, ""value"": ""SH3K6""}, {""response"": 3335, ""value"": ""SH4K6""}, {""response"": 3331, ""value"": ""SH5K-V13""}, {""response"": 3340, ""value"": ""SH5K-30""}, {""response"": 3338, ""value"": ""SH3K6-30""}, {""response"": 3339, ""value"": ""SH4K6-30""}, {""response"": 3343, ""value"": ""SH5.0RS""}, {""response"": 3341, ""value"": ""SH3.6RS""}, {""response"": 3342, ""value"": ""SH4.6RS""}, {""response"": 3344, ""value"": ""SH6.0RS""}, {""response"": 3587, ""value"": ""SH10RT""}, {""response"": 3599, ""value"": ""SH10RT-V112""}, {""response"": 3603, ""value"": ""SH10RT-20""}, {""response"": 3586, ""value"": ""SH8.0RT""}, {""response"": 3585, ""value"": ""SH6.0RT""}, {""response"": 3584, ""value"": ""SH5.0RT""}, {""response"": 3596, ""value"": ""SH5.0RT-V112""}, {""response"": 290, ""value"": ""SG3K-D""}, {""response"": 294, ""value"": ""SG5K-D""}, {""response"": 9219, ""value"": ""SG8K-D""}, {""response"": 9731, ""value"": ""SG3.0RS""}, {""response"": 9732, ""value"": ""SG3.6RS""}, {""response"": 9733, ""value"": ""SG4.0RS""}, {""response"": 9734, ""value"": ""SG5.0RS""}, {""response"": 9735, ""value"": ""SG6.0RS""}, {""response"": 9742, ""value"": ""SG9.0RS""}, {""response"": 9737, ""value"": ""SG10RS""}]",,, +read,nominal_active_power,2,5001,U16,0.1,kW,,,,, +read,output_type,2,5002,U16,,,,"[{""response"": 0, ""value"": ""2P""}, {""response"": 1, ""value"": ""3P4L""}, {""response"": 2, ""value"": ""3PSL""}]",,, +read,daily_power_yields,0,5003,U16,0.1,kWh,,,,, +read,total_power_yields,1,5004,U32,,kWh,,,,, +read,total_running_time,1,5006,U32,,h,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,internal_temperature,1,5008,S16,0.1,°C,,,,, +read,total_apparent_power,1,5009,U32,,VA,SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG33K3J|SG36KTL-M|SG40KTL-M|SG50KTL|SG50KTL-M|SG60KTL|SG60KTL-M|SG60KU-M|SG80KTL|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG33CX|SG40CX|SG50CX|SG110CX|SG250HX|SG30CX|SG36CX-US|SG60CX-US|SG250HX-US|SG250HX-IN|SG25CX-SA|SG100CX|SG75CX|SG225HX,,,, +read,mppt_1_voltage,2,5011,U16,0.1,V,,,,, +read,mppt_1_current,2,5012,U16,0.1,A,,,,, +read,mppt_2_voltage,2,5013,U16,0.1,V,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|SG50KTL-M-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,mppt_2_current,2,5014,U16,0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|SG50KTL-M-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,mppt_3_voltage,2,5015,U16,0.1,V,SG40KTL-M|SG50KTL-M|SG60KTL-M|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG50KTL-M-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX,,,, +read,mppt_3_current,2,5016,U16,0.1,A,SG40KTL-M|SG50KTL-M|SG60KTL-M|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG50KTL-M-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG8K-D,,,, +read,total_dc_power,2,5017,"U32"" # Documentation says Unsigned, but seems to be returning Signed 32bit",,W,,,,, +read,phase_a_voltage,1,5019,U16,0.1,V,,,,, +read,phase_b_voltage,2,5020,U16,0.1,V,,,,, +read,phase_c_voltage,2,5021,U16,0.1,V,,,,, +read,phase_a_current,2,5022,"S16"" # Documentation says Unsigned, but seems to be returning Signed 16bit",0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,phase_b_current,2,5023,"S16"" # Documentation says Unsigned, but seems to be returning Signed 16bit",0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,phase_c_current,2,5024,"S16"" # Documentation says Unsigned, but seems to be returning Signed 16bit",0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,total_active_power,0,5031,U32,,W,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,total_reactive_power,2,5033,S32,,Var,,,,, +read,"power_factor"" # >0 means leading, <0 means lagging",2,5035,S16,0.001,,,,,, +read,grid_frequency,2,5036,U16,0.1,Hz,,,,, +read,"work_state_1"" # See Appendix 1",1,5038,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,"[{""response"": 0, ""value"": ""Run""}, {""response"": 32768, ""value"": ""Stop""}, {""response"": 4864, ""value"": ""Key Stop""}, {""response"": 5376, ""value"": ""Emergency Stop""}, {""response"": 5120, ""value"": ""Standby""}, {""response"": 4608, ""value"": ""Initial Standby""}, {""response"": 5632, ""value"": ""Starting""}, {""response"": 37120, ""value"": ""Alarm Run""}, {""response"": 33024, ""value"": ""Derating Run""}, {""response"": 33280, ""value"": ""Dispatch Run""}, {""response"": 21760, ""value"": ""Fault""}, {""response"": 9472, ""value"": ""Communication Fault""}]",,, +read,alarm_time_year,3,5039,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,alarm_time_month,3,5040,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,alarm_time_day,3,5041,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,alarm_time_hour,3,5042,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,alarm_time_minute,3,5043,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,alarm_time_second,3,5045,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,"alarm_code_1"" # See Appendix 3",3,5045,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,nominal_reactive_power,2,5049,U16,0.1,kVar,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,array_insulation_resistance,2,5071,U16,,k-ohm,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,active_power_regulation_setpoint,2,5077,U32,,W,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,reactive_power_regulation_setpoint,2,5079,S32,,Var,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,"work_state_2"" # See Appendix 2",2,5081,U32,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,"[{""response"": 0, ""value"": ""Run""}, {""response"": 1, ""value"": ""Stop""}, {""response"": 3, ""value"": ""Key Stop""}, {""response"": 5, ""value"": ""Emergency Stop""}, {""response"": 4, ""value"": ""Standby""}, {""response"": 2, ""value"": ""Initial Standby""}, {""response"": 6, ""value"": ""Starting""}, {""response"": 10, ""value"": ""Alarm Run""}, {""response"": 11, ""value"": ""Derating Run""}, {""response"": 12, ""value"": ""Dispatch Run""}, {""response"": 9, ""value"": ""Fault""}, {""response"": 13, ""value"": ""Communication Fault""}, {""response"": 17, ""value"": ""Total Run Bit""}, {""response"": 18, ""value"": ""Total Fault Bit""}]",,, +read,meter_power,1,5083,S32,,W,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,,true +read,meter_a_phase_power,2,5085,S32,,W,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, +read,meter_b_phase_power,2,5087,S32,,W,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, +read,meter_c_phase_power,2,5089,S32,,W,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, +read,load_power,1,5091,S32,,W,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,,true +read,daily_export_energy,1,5093,U32,0.1,kWh,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3K-D|SG5K-D|SG8K-D,,,, +read,total_export_energy,1,5095,U32,0.1,kWh,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3K-D|SG5K-D|SG8K-D,,,, +read,daily_import_energy,1,5097,U32,0.1,kWh,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3K-D|SG5K-D|SG8K-D,,,, +read,total_import_energy,1,5099,U32,0.1,kWh,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3K-D|SG5K-D|SG8K-D,,,, +read,daily_direct_energy_consumption,1,5101,U32,0.1,kWh,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3K-D|SG5K-D|SG8K-D,,,, +read,total_direct_energy_consumption,1,5103,U32,0.1,kWh,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3K-D|SG5K-D|SG8K-D,,,, +read,daily_running_time,1,5113,U16,,min,,,,, +read,mppt_4_voltage,2,5115,U16,0.1,V,SG50KTL-M|SG60KTL-M|SG49K5J|SG50KTL-M-20|SG60KU-M|SG80KTL-M|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_4_current,2,5116,U16,0.1,A,SG50KTL-M|SG60KTL-M|SG49K5J|SG50KTL-M-20|SG60KU-M|SG80KTL-M|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_5_voltage,2,5117,U16,0.1,V,SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_5_current,2,5118,U16,0.1,A,SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_6_voltage,2,5119,U16,0.1,V,SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_6_current,2,5120,U16,0.1,A,SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_7_voltage,2,5121,U16,0.1,V,SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_7_current,2,5122,U16,0.1,A,SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_8_voltage,2,5123,U16,0.1,V,SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_8_current,2,5124,U16,0.1,A,SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,monthly_power_yields,1,5128,U32,0.1,kWh,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,mppt_9_voltage,2,5130,U16,0.1,V,SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_9_current,2,5131,U16,0.1,A,SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,mppt_10_voltage,2,5132,U16,0.1,V,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,mppt_10_current,2,5133,U16,0.1,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,mppt_11_voltage,2,5134,U16,0.1,V,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,mppt_11_current,2,5135,U16,0.1,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,mppt_12_voltage,2,5136,U16,0.1,V,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,mppt_12_current,2,5137,U16,0.1,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,total_power_yields,1,5144,U32,0.1,kWh,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG33CX|SG40CX|SG50CX|SG110CX|SG250HX|SG30CX|SG36CX-US|SG60CX-US|SG250HX-US|SG250HX-IN|SG25CX-SA|SG100CX|SG75CX|SG225HX|SG3K-D|SG5K-D|SG8K-D,,,, +read,negative_voltage_to_the_ground,2,5146,S16,0.1,V,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,bus_voltage,2,5147,U16,0.1,V,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,grid_frequency,2,5148,U16,0.01,Hz,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG33CX|SG40CX|SG50CX|SG110CX|SG250HX|SG30CX|SG36CX-US|SG60CX-US|SG250HX-US|SG250HX-IN|SG25CX-SA|SG100CX|SG75CX|SG225HX|SG3K-D|SG5K-D|SG8K-D,,,, +read,pid_work_state,2,5150,U16,,,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG33CX|SG40CX|SG50CX|SG110CX|SG250HX|SG30CX|SG36CX-US|SG60CX-US|SG250HX-US|SG250HX-IN|SG25CX-SA|SG100CX|SG75CX|SG225HX,"[{""response"": 2, ""value"": ""PID Recover Operation""}, {""response"": 4, ""value"": ""Anti-PID Operation""}, {""response"": 8, ""value"": ""PID Abnormity""}]",,, +read,pid_alarm_code,2,5151,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,"[{""response"": 432, ""value"": ""PID resistance abnormal""}, {""response"": 433, ""value"": ""PID function abnormal""}, {""response"": 434, ""value"": ""PID overvoltage/overcurrent protection""}]",,, +read,export_power,2,5216,S32,,W,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,power_meter,2,5218,S32,,W,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,meter_total_power,2,5601,S32,,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112|SG8.0RT,,,, +read,meter_phase_a_power,2,5603,S32,,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112|SG8.0RT,,,, +read,meter_phase_b_power,2,5605,S32,,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112|SG8.0RT,,,, +read,meter_phase_c_power,2,5607,S32,,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112|SG8.0RT,,,, +read,export_limit_min,2,5622,U16,10.0,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,export_limit_max,2,5623,U16,10.0,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bdc_rated_power,2,5628,U16,100.0,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bms_max_charging_current,2,5635,U16,,A,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bms_max_discharging_current,2,5636,U16,,A,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,backup_phase_a_power,2,5723,S16,,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,backup_phase_b_power,2,5724,S16,,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,backup_phase_c_power,2,5725,S16,,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_backup_power,2,5726,S16,,W,SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,pv_power_of_today,1,6100,U16,,W,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,daily_pv_energy_yields,1,6196,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,monthly_pv_energy_yields,2,6227,U16,,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,yearly_pv_energy_yields,2,6250,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,direct_power_consumption_today_pv,1,6290,U16,,W,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,direct_power_consumption_pv,1,6386,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,direct_power_consumption_monthly_pv,2,6417,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,direct_power_consumption_yearly_pv,2,6429,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,export_power_from_pv_today,1,6469,U16,,W,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,export_power_from_pv,1,6565,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,export_power_from_pv_monthly,2,6596,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,export_power_from_pv_yearly,2,6608,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_charge_power_from_pv_today,1,6648,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_charge_power_from_pv,1,6744,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_charge_power_from_pv_monthly,2,6775,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_charge_power_from_pv_yearly,2,6787,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,string_1_current,2,7013,U16,0.01,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,string_2_current,2,7014,U16,0.01,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,string_3_current,2,7015,U16,0.01,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT,,,, +read,string_4_current,2,7016,U16,0.01,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX,,,, +read,string_5_current,2,7017,U16,0.01,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX,,,, +read,string_6_current,2,7018,U16,0.01,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX,,,, +read,string_7_current,2,7019,U16,0.01,A,SG30KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_8_current,2,7020,U16,0.01,A,SG30KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_9_current,2,7021,U16,0.01,A,SG30KU|SG36KTL|SG36KU|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG33K3J|SG49K5J|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_10_current,2,7022,U16,0.01,A,SG30KU|SG36KTL|SG36KU|SG50KTL-M|SG60KTL-M|SG49K5J|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_11_current,2,7023,U16,0.01,A,SG50KTL-M|SG60KTL-M|SG49K5J|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_12_current,2,7024,U16,0.01,A,SG50KTL-M|SG60KTL-M|SG49K5J|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_13_current,2,7025,U16,0.01,A,SG60KTL-M|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_14_current,2,7026,U16,0.01,A,SG60KTL-M|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT,,,, +read,string_15_current,2,7027,U16,0.01,A,SG60KTL-M|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_16_current,2,7028,U16,0.01,A,SG60KTL-M|SG80KTL|SG80KTL-20|SG60KU-M|SG80KTL-M|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_17_current,2,7029,U16,0.01,A,SG80KTL|SG80KTL-20|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_18_current,2,7030,U16,0.01,A,SG80KTL|SG80KTL-20|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG75CX,,,, +read,string_19_current,2,7031,U16,0.01,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,string_20_current,2,7032,U16,0.01,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,string_21_current,2,7033,U16,0.01,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,string_22_current,2,7034,U16,0.01,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,string_23_current,2,7035,U16,0.01,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,string_24_current,2,7036,U16,0.01,A,SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN,,,, +read,system_state,2,13000,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,"[{""response"": 2, ""value"": ""Stop""}, {""response"": 8, ""value"": ""Standby""}, {""response"": 16, ""value"": ""Initial Standby""}, {""response"": 32, ""value"": ""Startup""}, {""response"": 64, ""value"": ""Run""}, {""response"": 256, ""value"": ""Fault""}, {""response"": 1024, ""value"": ""Maintain Run""}, {""response"": 2048, ""value"": ""Forced Run""}, {""response"": 4096, ""value"": ""Off-grid Run""}, {""response"": 9473, ""value"": ""Restarting""}, {""response"": 16384, ""value"": ""EMS Run""}]",,, +read,running_state,2,13001,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,state_power_generated_from_pv,2,13001,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,1,, +read,state_battery_charging,2,13001,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,2,, +read,state_battery_discharging,2,13001,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,4,, +read,state_load_active,2,13001,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,8,, +read,state_feed_into_grid,2,13001,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,16,, +read,state_import_from_grid,2,13001,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,32,, +read,state_power_generated_from_load,2,13001,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,128,, +read,daily_pv_generation,2,13002,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_pv_generation,1,13003,U32,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,daily_pv_export,1,13005,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_pv_export,1,13006,U32,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,load_power_hybrid,1,13008,S32,,W,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,export_power_hybrid,1,13010,S32,,W,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,daily_battery_charge_from_pv,1,13012,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_battery_charge_from_pv,1,13013,U32,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,co2_reduction,2,13015,U32,0.1,kg,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,daily_direct_energy_consumption,1,13017,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_direct_energy_consumption,1,13018,U32,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_voltage,2,13020,U16,0.1,V,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_current,2,13021,S16,0.1,A,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_power,1,13022,S16,,W,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_level,1,13023,U16,0.1,%,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_state_of_healthy,2,13024,U16,0.1,%,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_temperature,2,13025,S16,0.1,°C,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,daily_battery_discharge_energy,2,13026,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_battery_discharge_energy,2,13027,U32,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,self_consumption_of_day,1,13029,U16,0.1,%,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,grid_state,1,13030,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,"[{""response"": 170, ""value"": ""Off-grid""}, {""response"": 85, ""value"": ""On-grid""}]",,, +read,phase_a_current,2,13031,S16,0.1,A,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,phase_b_current,2,13032,S16,0.1,A,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,phase_c_current,2,13033,S16,0.1,A,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_active_power,0,13034,S32,,W,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,daily_import_energy,1,13036,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_import_energy,1,13037,U32,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_capacity,1,13039,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,daily_charge_energy,2,13040,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_charge_energy,2,13041,U32,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,drm_state,2,13043,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,daily_export_energy,1,13045,U16,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,total_export_energy,2,13046,U32,0.1,kWh,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,inverter_alarm,3,13050,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,grid-side_fault,3,13052,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,system_fault1,3,13054,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,system_fault2,3,13056,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,dc-side_fault,3,13058,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,permanent_fault,3,13060,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bdc-side_fault,3,13062,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bdc-side_permanent_fault,3,13064,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_fault,3,13066,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,battery_alarm,3,13068,U32,0.1,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bms_alarm,3,13070,U32,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bms_protection,3,13072,U32,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bms_fault1,3,13074,U32,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bms_fault2,3,13076,U32,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bms_alarm2,3,13078,U32,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH5.0RS|SH3.6RS|SH4.6RS|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +read,bms_status,3,13100,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,max_charging_current,3,13101,U16,,A,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,max_discharging_current,3,13102,U16,,A,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,warning,3,13103,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,protection,3,13104,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,fault1,3,13105,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,fault2,3,13106,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,soc,2,13107,U16,,%,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,soh,2,13108,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,battery_current,2,13109,U16,,A,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,battery_voltage,2,13110,U16,0.01,V,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,cycle_count,2,13111,U16,0.01,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,average_cell_voltage,2,13112,U16,,V,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,max_cell_voltage,2,13113,U16,,V,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,min_cell_voltage,2,13114,U16,,V,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,battery_pack_voltage,2,13115,U16,,V,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,average_cell_temp,2,13116,S16,,°C,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +read,max_cell_temp,2,13117,S16,,°C,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +hold,min_cell_temp,2,13118,S16,,°C,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30,,,, +hold,year,0,5000,U16,,YYYY,,,,, +hold,month,0,5001,U16,,MM,,,,, +hold,day,0,5002,U16,,DD,,,,, +hold,hour,0,5003,U16,,HH,,,,, +hold,minute,0,5004,U16,,MM,,,,, +hold,second,0,5005,U16,,SS,,,,, +hold,start_stop,1,5006,U16,,,,"[{""response"": 207, ""value"": ""Start""}, {""response"": 206, ""value"": ""Stop""}]",,, +hold,power_limitation_switch,2,5007,U16,,,,"[{""response"": 170, ""value"": ""Enable""}, {""response"": 85, ""value"": ""Disable""}]",,, +hold,power_limitation_setting,2,5008,U16,0.1,%,,,,, +hold,export_power_limitation,2,5010,U16,,,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,"[{""response"": 170, ""value"": ""Enable""}, {""response"": 85, ""value"": ""Disable""}]",,, +hold,export_power_limitation_value,2,5011,U16,,,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, +hold,current_transformer_output_current,2,5012,U16,,A,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, +hold,current_transformer_range,2,5013,U16,,A,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, +hold,current_transformer,2,5014,U16,,,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,"[{""response"": 0, ""value"": ""Internal""}, {""response"": 1, ""value"": ""External""}]",,, +hold,export_power_limitation_percentage,2,5015,U16,0.1,%,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, +hold,installed_pv_power,2,5016,U16,0.01,KW,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, +hold,power_factor_setting,2,5019,U16,0.001,,,,,, +hold,scheduling_achieve_active_overload,2,5020,U16,,,SG33CX|SG40CX|SG50CX|SG75CX|SG110CX|SG136TX|SG250HX|SG30CX|SG36CX-US|SG60CX-US|SG250HX-US|SG250HX-IN|SG225HX|SG250HX|SG25CX-SA|SG100CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,"[{""response"": 170, ""value"": ""Enable""}, {""response"": 85, ""value"": ""Disable""}]",,, +hold,night_svg_switch,2,5035,U16,,,SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG80KTL-M|SG125HV-20|SG33CX|SG40CX|SG50CX|SG110CX|SG136TX|SG250HX|SG30CX|SG36CX-US|SG60CX-US|SG250HX-US|SG250HX-IN|SG225HX|SG250HX|SG25CX-SA|SG100CX|SG75CX,"[{""response"": 170, ""value"": ""Enable""}, {""response"": 85, ""value"": ""Disable""}]",,, +hold,reactive_power_adjustment_mode,2,5036,U16,,,,"[{""response"": 85, ""value"": ""Off""}, {""response"": 161, ""value"": ""Power factor setting""}, {""response"": 162, ""value"": ""Reactive power percentage setting""}, {""response"": 163, ""value"": ""Enable Q(P)""}, {""response"": 164, ""value"": ""Enable Q(U)""}]",,, +hold,reactive_power_percentage_setting,2,5037,S16,0.1,%,,,,, +hold,power_limitation_adjustment,2,5039,U16,0.1,kW,,,,, +hold,reactive_power_adjustment,2,5040,S16,0.1,kVar,,,,, +hold,pid_recovery,2,5041,U16,,,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG80KTL-M|SG125HV|SG125HV-20|SG80KTL|SG33CX|SG40CX|SG50CX|SG100CX、SG75CX|SG110CX|SG136TX|SG250HX|SG30CX|SG36CX-US|SG60CX-US|SG250HX-US|SG250HX-IN|SG25CX-SA|SG225HX,"[{""response"": 170, ""value"": ""Enable""}, {""response"": 85, ""value"": ""Disable""}]",,, +hold,anti_pid,2,5042,U16,,,SG125HV|SG125HV-20|SG250HX|SG250HX-US|SG250HX-IN|SG136TX|SG100CX-JP|SG225HX,"[{""response"": 170, ""value"": ""Enable""}, {""response"": 85, ""value"": ""Disable""}]",,, +hold,fullday_pid_suppression,2,5043,U16,,,SG250HX|SG250HX-US|SG250HX-IN|SG225HX,"[{""response"": 170, ""value"": ""Enable""}, {""response"": 85, ""value"": ""Disable""}]",,, +hold,ems_mode_selection,2,13050,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH3.6RS|SH5.0RS|SH4.6RS|SH6.0RS|SH5.0RT|SH5.0RT-V112|SH6.0RT|SH8.0RT|SH10RT|SH10RT-V112,"[{""response"": 0, ""value"": ""Self-consumption mode""}, {""response"": 2, ""value"": ""Compulsory mode""}, {""response"": 3, ""value"": ""External EMS mode""}]",,, +hold,charge_discharge_command,2,13051,U16,,,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH3.6RS|SH5.0RS|SH4.6RS|SH6.0RS|SH5.0RT|SH5.0RT-V112|SH6.0RT|SH8.0RT|SH10RT|SH10RT-V112,"[{""response"": 170, ""value"": ""Charge""}, {""response"": 187, ""value"": ""Discharge""}, {""response"": 204, ""value"": ""Stop""}]",,, +hold,charge_discharge_power,2,13052,U16,1.0,W,SH5K-20|SH3K6|SH4K6|SH5K-V13|SH5K-30|SH3K6-30|SH4K6-30|SH3.6RS|SH5.0RS|SH4.6RS|SH6.0RS|SH5.0RT|SH5.0RT-V112|SH6.0RT|SH8.0RT|SH10RT|SH10RT-V112,,,, +hold,start_charging_power,2,13084,U16,10.0,W,SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +hold,start_discharging_power,2,13085,U16,10.0,W,SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +hold,energy_meter_comm,2,13086,U16,,,SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,"[{""response"": 170, ""value"": ""Enabled""}, {""response"": 85, ""value"": ""Disabled""}]",,, +hold,export_power_limitation,2,13087,U16,,,SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,"[{""response"": 170, ""value"": ""Enabled""}, {""response"": 85, ""value"": ""Disabled""}]",,, +hold,soc_reserve,2,13100,U16,,%,SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +hold,battery_max_charge_power,2,33047,U16,10.0,W,SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, +hold,battery_max_discharge_power,2,33048,U16,10.0,W,SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, diff --git a/SunGather/scan-ranges.yaml b/SunGather/scan-ranges.yaml new file mode 100644 index 0000000..cb9f7b4 --- /dev/null +++ b/SunGather/scan-ranges.yaml @@ -0,0 +1,49 @@ +version: 0.2.4 +vendor: Sungrow +scan: + - read: + - start: 4949 + range: 50 + - start: 5000 + range: 38 + - start: 5039 + range: 61 + - start: 5100 + range: 100 + - start: 5200 + range: 100 + - start: 5600 + range: 100 + - start: 5720 + range: 10 + - start: 6099 + range: 100 + - start: 6199 + range: 100 + - start: 6299 + range: 100 + - start: 6399 + range: 100 + - start: 6499 + range: 100 + - start: 6599 + range: 100 + - start: 6699 + range: 100 + - start: 6799 + range: 100 + - start: 7012 + range: 25 + - start: 12999 + range: 125 + - hold: + - start: 4999 + range: 10 + - start: 5009 + range: 10 + - start: 5034 + range: 10 + - start: 13000 + range: 100 + - start: 33045 + range: 5 diff --git a/SunGather/sungather.py b/SunGather/sungather.py index e200810..697ac6e 100644 --- a/SunGather/sungather.py +++ b/SunGather/sungather.py @@ -2,6 +2,7 @@ from SungrowClient import SungrowClient from version import __version__ +from register_loader import load_registers, get_scan_ranges_path import importlib import logging @@ -11,10 +12,11 @@ import yaml import time import signal +import os def main(): configfilename = 'config.yaml' - registersfilename = 'registers-sungrow.yaml' + registersfilename = 'registers-sungrow.csv' logfolder = '' try: @@ -31,7 +33,7 @@ def main(): print(f'\nCommandling arguments override any config file settings') print(f'Options and arguments:') print(f'-c config.yaml : Specify config file.') - print(f'-r registers-file.yaml : Specify registers file.') + print(f'-r registers-file.csv : Specify registers file (CSV or YAML).') print(f'-l /logs/ : Specify folder to store logs.') print(f'-v 30 : Logging Level, 10 = Debug, 20 = Info, 30 = Warning (default), 40 = Error') print(f'--runonce : Run once then exit') @@ -73,9 +75,21 @@ def main(): sys.exit(f"Failed Loading config, missing Inverter settings") try: - registersfile = yaml.safe_load(open(registersfilename, encoding="utf-8")) - logging.info(f"Loaded registers: {registersfilename}") - logging.info(f"Registers file version: {registersfile.get('version','UNKNOWN')}") + # Detect file format and load accordingly + if registersfilename.endswith('.csv'): + # CSV format - new format + scan_yaml_path = get_scan_ranges_path(registersfilename) + registersfile = load_registers(registersfilename, scan_yaml_path) + logging.info(f"Loaded registers from CSV: {registersfilename}") + logging.info(f"Registers file version: {registersfile.get('version','UNKNOWN')}") + elif registersfilename.endswith('.yaml') or registersfilename.endswith('.yml'): + # YAML format - legacy format (backward compatibility) + logging.warning("YAML register files are deprecated. Please migrate to CSV format using scripts/migrate_yaml_to_csv.py") + registersfile = yaml.safe_load(open(registersfilename, encoding="utf-8")) + logging.info(f"Loaded registers from YAML: {registersfilename}") + logging.info(f"Registers file version: {registersfile.get('version','UNKNOWN')}") + else: + raise ValueError(f"Unsupported file format: {registersfilename}. Expected .csv, .yaml, or .yml") except Exception as err: logging.error(f"Failed: Loading registers: {registersfilename} {err}") sys.exit(f"Failed: Loading registers: {registersfilename} {err}") diff --git a/scripts/migrate_yaml_to_csv.py b/scripts/migrate_yaml_to_csv.py new file mode 100644 index 0000000..4da8f88 --- /dev/null +++ b/scripts/migrate_yaml_to_csv.py @@ -0,0 +1,182 @@ +#!/usr/bin/python3 + +""" +Migration Script: YAML to CSV + +Converts the existing registers-sungrow.yaml file to the new CSV format +and creates a separate scan-ranges.yaml file. +""" + +import yaml +import csv +import json +import sys +import os + + +def migrate(yaml_path, csv_path, scan_yaml_path): + """ + Migrate from YAML register file to CSV + scan-ranges YAML. + + Args: + yaml_path: Path to input YAML file + csv_path: Path to output CSV file + scan_yaml_path: Path to output scan-ranges YAML file + """ + print(f"Loading YAML from: {yaml_path}") + + # Load the YAML file + try: + with open(yaml_path, encoding="utf-8") as f: + data = yaml.safe_load(f) + except Exception as err: + print(f"Error loading YAML: {err}") + sys.exit(1) + + # Write CSV file + print(f"Writing CSV to: {csv_path}") + try: + with open(csv_path, "w", newline="", encoding="utf-8") as f: + fieldnames = [ + "type", "name", "level", "address", "datatype", + "accuracy", "unit", "models", "datarange", + "mask", "default", "smart_meter" + ] + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + + # Process all registers + read_count = 0 + hold_count = 0 + + for reg_block in data.get("registers", []): + for reg_type in ["read", "hold"]: + if reg_type in reg_block: + for reg in reg_block[reg_type]: + row = convert_register_to_row(reg_type, reg) + writer.writerow(row) + + if reg_type == "read": + read_count += 1 + else: + hold_count += 1 + + print(f" Wrote {read_count} read registers and {hold_count} hold registers") + except Exception as err: + print(f"Error writing CSV: {err}") + sys.exit(1) + + # Write scan ranges YAML + print(f"Writing scan ranges to: {scan_yaml_path}") + try: + scan_data = { + "version": data.get("version"), + "vendor": data.get("vendor"), + "scan": data.get("scan") + } + + with open(scan_yaml_path, "w", encoding="utf-8") as f: + yaml.dump(scan_data, f, default_flow_style=False, allow_unicode=True) + + print(f" Version: {scan_data.get('version')}") + print(f" Vendor: {scan_data.get('vendor')}") + except Exception as err: + print(f"Error writing scan ranges YAML: {err}") + sys.exit(1) + + print("\nMigration completed successfully!") + + +def convert_register_to_row(reg_type, reg): + """ + Convert a register dictionary to a CSV row. + + Args: + reg_type: "read" or "hold" + reg: Register dictionary from YAML + + Returns: + dict: CSV row dictionary + """ + row = { + "type": reg_type, + "name": reg.get("name", ""), + "level": reg.get("level", ""), + "address": reg.get("address", ""), + "datatype": reg.get("datatype", ""), + "accuracy": "", + "unit": "", + "models": "", + "datarange": "", + "mask": "", + "default": "", + "smart_meter": "" + } + + # Optional fields + if "accuracy" in reg: + row["accuracy"] = reg["accuracy"] + + if "unit" in reg: + row["unit"] = reg["unit"] + + if "models" in reg: + # Convert list to pipe-delimited string + row["models"] = "|".join(reg["models"]) + + if "datarange" in reg: + # Convert datarange to JSON string + # Need to ensure proper formatting for CSV + row["datarange"] = json.dumps(reg["datarange"], ensure_ascii=False) + + if "mask" in reg: + row["mask"] = reg["mask"] + + if "default" in reg: + row["default"] = reg["default"] + + if "smart_meter" in reg and reg["smart_meter"]: + row["smart_meter"] = "true" + + return row + + +def main(): + """Main entry point for the migration script.""" + + # Default paths + script_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(script_dir) + sungather_dir = os.path.join(project_root, "SunGather") + + yaml_path = os.path.join(sungather_dir, "registers-sungrow.yaml") + csv_path = os.path.join(sungather_dir, "registers-sungrow.csv") + scan_yaml_path = os.path.join(sungather_dir, "scan-ranges.yaml") + + # Allow command-line arguments to override + if len(sys.argv) > 1: + yaml_path = sys.argv[1] + if len(sys.argv) > 2: + csv_path = sys.argv[2] + if len(sys.argv) > 3: + scan_yaml_path = sys.argv[3] + + print("YAML to CSV Migration Script") + print("=" * 50) + print(f"Input: {yaml_path}") + print(f"Output: {csv_path}") + print(f"Output: {scan_yaml_path}") + print("=" * 50) + print() + + # Check if input file exists + if not os.path.exists(yaml_path): + print(f"Error: Input file not found: {yaml_path}") + sys.exit(1) + + # Run migration + migrate(yaml_path, csv_path, scan_yaml_path) + + +if __name__ == "__main__": + main() diff --git a/scripts/migrate_yaml_to_csv_simple.py b/scripts/migrate_yaml_to_csv_simple.py new file mode 100644 index 0000000..496d0a5 --- /dev/null +++ b/scripts/migrate_yaml_to_csv_simple.py @@ -0,0 +1,307 @@ +#!/usr/bin/python3 + +""" +Simplified Migration Script: YAML to CSV + +Converts registers-sungrow.yaml to CSV format without requiring PyYAML dependency. +Uses a simple parser for the specific YAML structure. +""" + +import csv +import json +import sys +import os +import re + + +def simple_yaml_parse(yaml_content): + """ + Simple YAML parser for the specific structure of registers-sungrow.yaml. + This is not a general-purpose YAML parser but works for this file format. + """ + lines = yaml_content.split('\n') + data = { + 'version': None, + 'vendor': None, + 'registers': [], + 'scan': [] + } + + current_reg_type = None + current_register = None + current_datarange = None + current_scan_type = None + current_scan_block = None + in_scan = False + in_registers = False + indent_stack = [] + + for line in lines: + stripped = line.strip() + + # Skip empty lines and comments + if not stripped or stripped.startswith('#'): + continue + + # Get indentation level + indent = len(line) - len(line.lstrip()) + + # Top-level metadata + if stripped.startswith('version:'): + data['version'] = stripped.split(':', 1)[1].strip() + elif stripped.startswith('vendor:'): + data['vendor'] = stripped.split(':', 1)[1].strip() + elif line.startswith('registers:') or stripped == 'registers:': + in_scan = False + in_registers = True + elif line.startswith('scan:') or stripped == 'scan:': + # Save last register before switching to scan mode + if current_register is not None and current_reg_type and in_registers: + data['registers'][-1][current_reg_type].append(current_register) + current_register = None + in_scan = True + in_registers = False + elif in_scan: + # Parse scan section + if stripped.startswith('- read:'): + current_scan_type = 'read' + current_scan_block = [] + data['scan'].append({'read': current_scan_block}) + elif stripped.startswith('- hold:'): + current_scan_type = 'hold' + current_scan_block = [] + data['scan'].append({'hold': current_scan_block}) + elif stripped.startswith('- start:'): + # Extract value and remove inline comments + val_str = stripped.split(':', 1)[1].strip() + # Remove inline comments + if '#' in val_str: + val_str = val_str.split('#')[0].strip() + start_val = int(val_str) + if current_scan_block is not None: + current_scan_block.append({'start': start_val}) + elif stripped.startswith('range:') and current_scan_block is not None: + # Extract value and remove inline comments + val_str = stripped.split(':', 1)[1].strip() + # Remove inline comments + if '#' in val_str: + val_str = val_str.split('#')[0].strip() + range_val = int(val_str) + if current_scan_block: + current_scan_block[-1]['range'] = range_val + elif in_registers: + # Parse registers section + if stripped.startswith('- read:'): + current_reg_type = 'read' + data['registers'].append({'read': []}) + elif stripped.startswith('- hold:'): + current_reg_type = 'hold' + data['registers'].append({'hold': []}) + elif stripped.startswith('- name:'): + # New register + if current_register is not None and current_reg_type: + data['registers'][-1][current_reg_type].append(current_register) + current_register = {} + current_datarange = None + name_val = stripped.split(':', 1)[1].strip().strip('"\'') + current_register['name'] = name_val + elif current_register is not None: + if stripped.startswith('level:'): + current_register['level'] = int(stripped.split(':', 1)[1].strip()) + elif stripped.startswith('address:'): + current_register['address'] = int(stripped.split(':', 1)[1].strip()) + elif stripped.startswith('datatype:'): + current_register['datatype'] = stripped.split(':', 1)[1].strip().strip('"\'') + elif stripped.startswith('accuracy:'): + val = stripped.split(':', 1)[1].strip() + current_register['accuracy'] = float(val) if val else None + elif stripped.startswith('unit:'): + current_register['unit'] = stripped.split(':', 1)[1].strip().strip('"\'') + elif stripped.startswith('models:'): + # Parse list format: ["model1","model2"] + models_str = stripped.split(':', 1)[1].strip() + if models_str.startswith('['): + # Remove brackets and split + models_str = models_str.strip('[]') + models = [m.strip().strip('"\',') for m in models_str.split(',') if m.strip()] + current_register['models'] = models + elif stripped.startswith('datarange:'): + current_datarange = [] + current_register['datarange'] = current_datarange + elif current_datarange is not None: + if stripped.startswith('- response:'): + # Parse response line + resp_val = stripped.split(':', 1)[1].strip() + # Convert hex values + if resp_val.startswith('0x'): + resp_val = int(resp_val, 16) + else: + resp_val = int(resp_val) + current_datarange.append({'response': resp_val}) + elif stripped.startswith('value:'): + val = stripped.split(':', 1)[1].strip().strip('"\'') + if current_datarange: + current_datarange[-1]['value'] = val + elif stripped.startswith('mask:'): + current_register['mask'] = int(stripped.split(':', 1)[1].strip()) + elif stripped.startswith('default:'): + current_register['default'] = stripped.split(':', 1)[1].strip().strip('"\'') + elif stripped.startswith('smart_meter:'): + val = stripped.split(':', 1)[1].strip().lower() + current_register['smart_meter'] = (val == 'true') + + # Add last register if still in registers mode + if current_register is not None and current_reg_type and in_registers: + data['registers'][-1][current_reg_type].append(current_register) + + return data + + +def migrate(yaml_path, csv_path, scan_yaml_path): + """Migrate from YAML register file to CSV + scan-ranges YAML.""" + print(f"Loading YAML from: {yaml_path}") + + try: + with open(yaml_path, encoding="utf-8") as f: + yaml_content = f.read() + except Exception as err: + print(f"Error loading YAML: {err}") + sys.exit(1) + + # Parse YAML + data = simple_yaml_parse(yaml_content) + + # Write CSV file + print(f"Writing CSV to: {csv_path}") + try: + with open(csv_path, "w", newline="", encoding="utf-8") as f: + fieldnames = [ + "type", "name", "level", "address", "datatype", + "accuracy", "unit", "models", "datarange", + "mask", "default", "smart_meter" + ] + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + + read_count = 0 + hold_count = 0 + + for reg_block in data.get("registers", []): + for reg_type in ["read", "hold"]: + if reg_type in reg_block: + for reg in reg_block[reg_type]: + row = convert_register_to_row(reg_type, reg) + writer.writerow(row) + + if reg_type == "read": + read_count += 1 + else: + hold_count += 1 + + print(f" Wrote {read_count} read registers and {hold_count} hold registers") + except Exception as err: + print(f"Error writing CSV: {err}") + import traceback + traceback.print_exc() + sys.exit(1) + + # Write scan ranges YAML + print(f"Writing scan ranges to: {scan_yaml_path}") + try: + with open(scan_yaml_path, "w", encoding="utf-8") as f: + f.write(f"version: {data.get('version')}\n") + f.write(f"vendor: {data.get('vendor')}\n") + f.write("scan:\n") + for scan_block in data.get('scan', []): + for scan_type in ['read', 'hold']: + if scan_type in scan_block: + f.write(f" - {scan_type}:\n") + for range_item in scan_block[scan_type]: + f.write(f" - start: {range_item['start']}\n") + f.write(f" range: {range_item['range']}\n") + + print(f" Version: {data.get('version')}") + print(f" Vendor: {data.get('vendor')}") + except Exception as err: + print(f"Error writing scan ranges YAML: {err}") + sys.exit(1) + + print("\nMigration completed successfully!") + + +def convert_register_to_row(reg_type, reg): + """Convert a register dictionary to a CSV row.""" + row = { + "type": reg_type, + "name": reg.get("name", ""), + "level": reg.get("level", ""), + "address": reg.get("address", ""), + "datatype": reg.get("datatype", ""), + "accuracy": "", + "unit": "", + "models": "", + "datarange": "", + "mask": "", + "default": "", + "smart_meter": "" + } + + if "accuracy" in reg and reg["accuracy"] is not None: + row["accuracy"] = reg["accuracy"] + + if "unit" in reg: + row["unit"] = reg["unit"] + + if "models" in reg: + row["models"] = "|".join(reg["models"]) + + if "datarange" in reg: + row["datarange"] = json.dumps(reg["datarange"], ensure_ascii=False) + + if "mask" in reg: + row["mask"] = reg["mask"] + + if "default" in reg: + row["default"] = reg["default"] + + if "smart_meter" in reg and reg["smart_meter"]: + row["smart_meter"] = "true" + + return row + + +def main(): + """Main entry point for the migration script.""" + + script_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(script_dir) + sungather_dir = os.path.join(project_root, "SunGather") + + yaml_path = os.path.join(sungather_dir, "registers-sungrow.yaml") + csv_path = os.path.join(sungather_dir, "registers-sungrow.csv") + scan_yaml_path = os.path.join(sungather_dir, "scan-ranges.yaml") + + if len(sys.argv) > 1: + yaml_path = sys.argv[1] + if len(sys.argv) > 2: + csv_path = sys.argv[2] + if len(sys.argv) > 3: + scan_yaml_path = sys.argv[3] + + print("YAML to CSV Migration Script") + print("=" * 50) + print(f"Input: {yaml_path}") + print(f"Output: {csv_path}") + print(f"Output: {scan_yaml_path}") + print("=" * 50) + print() + + if not os.path.exists(yaml_path): + print(f"Error: Input file not found: {yaml_path}") + sys.exit(1) + + migrate(yaml_path, csv_path, scan_yaml_path) + + +if __name__ == "__main__": + main() diff --git a/scripts/test_loader.py b/scripts/test_loader.py new file mode 100644 index 0000000..cc8f69e --- /dev/null +++ b/scripts/test_loader.py @@ -0,0 +1,150 @@ +#!/usr/bin/python3 + +""" +Test script to verify the register loader works correctly. +Compares CSV-loaded data with YAML-loaded data (if available). +""" + +import sys +import os + +# Add parent directory to path to import modules +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'SunGather')) + +from register_loader import load_registers, get_scan_ranges_path + + +def test_csv_loader(): + """Test loading registers from CSV format.""" + print("Testing CSV Register Loader") + print("=" * 60) + + csv_path = os.path.join(os.path.dirname(__file__), '..', 'SunGather', 'registers-sungrow.csv') + scan_yaml_path = os.path.join(os.path.dirname(__file__), '..', 'SunGather', 'scan-ranges.yaml') + + print(f"CSV Path: {csv_path}") + print(f"Scan YAML Path: {scan_yaml_path}") + print() + + # Test loading + try: + data = load_registers(csv_path, scan_yaml_path) + print("✓ CSV loaded successfully") + except Exception as err: + print(f"✗ Failed to load CSV: {err}") + import traceback + traceback.print_exc() + return False + + # Validate structure + print("\nValidating structure...") + + required_keys = ['version', 'vendor', 'registers', 'scan'] + for key in required_keys: + if key in data: + print(f"✓ Key '{key}' present") + else: + print(f"✗ Key '{key}' missing") + return False + + # Check registers + print(f"\nVersion: {data.get('version')}") + print(f"Vendor: {data.get('vendor')}") + + read_count = 0 + hold_count = 0 + + for reg_block in data.get('registers', []): + if 'read' in reg_block: + read_count = len(reg_block['read']) + if 'hold' in reg_block: + hold_count = len(reg_block['hold']) + + print(f"\nRegister counts:") + print(f" Read registers: {read_count}") + print(f" Hold registers: {hold_count}") + print(f" Total: {read_count + hold_count}") + + if read_count == 0 and hold_count == 0: + print("✗ No registers loaded") + return False + + # Validate a few sample registers + print("\nValidating sample registers...") + + sample_found = False + for reg_block in data.get('registers', []): + if 'read' in reg_block: + for reg in reg_block['read'][:3]: # Check first 3 + name = reg.get('name') + if name: + print(f" ✓ Register: {name}") + print(f" - Level: {reg.get('level')}") + print(f" - Address: {reg.get('address')}") + print(f" - Datatype: {reg.get('datatype')}") + if 'models' in reg: + print(f" - Models: {len(reg['models'])} models") + if 'datarange' in reg: + print(f" - Datarange: {len(reg['datarange'])} mappings") + sample_found = True + print() + + if not sample_found: + print("✗ No valid registers found") + return False + + # Check scan ranges + scan_ranges = data.get('scan', []) + print(f"Scan ranges: {len(scan_ranges)} blocks") + + for scan_block in scan_ranges: + for scan_type in ['read', 'hold']: + if scan_type in scan_block: + print(f" {scan_type}: {len(scan_block[scan_type])} ranges") + + print("\n" + "=" * 60) + print("✓ All tests passed!") + return True + + +def test_get_scan_ranges_path(): + """Test the helper function to get scan ranges path.""" + print("\nTesting get_scan_ranges_path helper") + print("=" * 60) + + test_cases = [ + ("SunGather/registers-sungrow.csv", "SunGather/scan-ranges.yaml"), + ("/path/to/registers.csv", "/path/to/scan-ranges.yaml"), + ("registers.csv", "scan-ranges.yaml"), + ] + + for csv_path, expected in test_cases: + result = get_scan_ranges_path(csv_path) + if result == expected: + print(f"✓ {csv_path} → {result}") + else: + print(f"✗ {csv_path} → {result} (expected: {expected})") + return False + + print("✓ All path tests passed!") + return True + + +if __name__ == "__main__": + success = True + + # Run tests + if not test_get_scan_ranges_path(): + success = False + + print() + + if not test_csv_loader(): + success = False + + if success: + print("\n✓✓✓ All tests passed! ✓✓✓") + sys.exit(0) + else: + print("\n✗✗✗ Some tests failed ✗✗✗") + sys.exit(1) From d339a8640d4e62ff05c738b598b3e32217d9673c Mon Sep 17 00:00:00 2001 From: Roo Code Date: Mon, 26 Jan 2026 23:35:33 +0000 Subject: [PATCH 2/2] fix: strip inline YAML comments from migration scripts and loader - Add strip_inline_comment() helper to migrate_yaml_to_csv_simple.py - Add strip_inline_comment() helper to migrate_yaml_to_csv.py - Add inline comment stripping to register_loader.py for robustness - Regenerate registers-sungrow.csv with clean data (no embedded comments) Fixes data corruption issue where YAML inline comments like: datatype: U32 # Documentation says... were being included in CSV output as: "U32"" # Documentation says..." --- SunGather/register_loader.py | 44 ++++++++++++++++++++------ SunGather/registers-sungrow.csv | 16 +++++----- scripts/migrate_yaml_to_csv.py | 43 +++++++++++++++++++------ scripts/migrate_yaml_to_csv_simple.py | 45 +++++++++++++++++++++------ 4 files changed, 111 insertions(+), 37 deletions(-) diff --git a/SunGather/register_loader.py b/SunGather/register_loader.py index 89dd993..6273576 100644 --- a/SunGather/register_loader.py +++ b/SunGather/register_loader.py @@ -19,6 +19,30 @@ YAML_AVAILABLE = False +def strip_inline_comment(value): + """ + Strip inline YAML comments from a value. + + YAML allows inline comments starting with '#'. This function removes + them from string values while preserving the actual content. This is + useful for robustness when loading data that may have residual comments. + + Args: + value: String value that may contain an inline comment + + Returns: + str: Value with inline comment removed, or original value if not a string + """ + if not isinstance(value, str): + return value + if not value: + return value + # Remove inline comment (text after #) + if '#' in value: + value = value.split('#')[0].strip() + return value + + def simple_yaml_parse_scan_ranges(yaml_content): """ Simple YAML parser for scan-ranges.yaml file. @@ -56,11 +80,13 @@ def simple_yaml_parse_scan_ranges(yaml_content): current_scan_block = [] data['scan'].append({'hold': current_scan_block}) elif stripped.startswith('- start:'): - start_val = int(stripped.split(':', 1)[1].strip()) + val_str = strip_inline_comment(stripped.split(':', 1)[1].strip()) + start_val = int(val_str) if current_scan_block is not None: current_scan_block.append({'start': start_val}) elif stripped.startswith('range:') and current_scan_block is not None: - range_val = int(stripped.split(':', 1)[1].strip()) + val_str = strip_inline_comment(stripped.split(':', 1)[1].strip()) + range_val = int(val_str) if current_scan_block: current_scan_block[-1]['range'] = range_val @@ -133,12 +159,12 @@ def parse_register_row(row): Returns: dict: Register definition """ - # Required fields + # Required fields - strip any residual inline comments for robustness register = { - "name": row["name"], - "level": int(row["level"]), - "address": int(row["address"]), - "datatype": row["datatype"] + "name": strip_inline_comment(row["name"]), + "level": int(strip_inline_comment(row["level"])), + "address": int(strip_inline_comment(row["address"])), + "datatype": strip_inline_comment(row["datatype"]) } # Optional fields - only add if present and not empty @@ -146,7 +172,7 @@ def parse_register_row(row): register["accuracy"] = float(row["accuracy"]) if row.get("unit") and row["unit"].strip(): - register["unit"] = row["unit"] + register["unit"] = strip_inline_comment(row["unit"]) if row.get("models") and row["models"].strip(): # Models are pipe-delimited in CSV @@ -163,7 +189,7 @@ def parse_register_row(row): register["mask"] = int(row["mask"]) if row.get("default") and row["default"].strip(): - register["default"] = row["default"] + register["default"] = strip_inline_comment(row["default"]) if row.get("smart_meter") and row["smart_meter"].strip(): # Only set if explicitly true diff --git a/SunGather/registers-sungrow.csv b/SunGather/registers-sungrow.csv index cca5ae3..288ed44 100644 --- a/SunGather/registers-sungrow.csv +++ b/SunGather/registers-sungrow.csv @@ -18,30 +18,30 @@ read,mppt_2_voltage,2,5013,U16,0.1,V,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG3 read,mppt_2_current,2,5014,U16,0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|SG50KTL-M-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D|SH6.0RS|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, read,mppt_3_voltage,2,5015,U16,0.1,V,SG40KTL-M|SG50KTL-M|SG60KTL-M|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG50KTL-M-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX,,,, read,mppt_3_current,2,5016,U16,0.1,A,SG40KTL-M|SG50KTL-M|SG60KTL-M|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG50KTL-M-20|SG60KU-M|SG80KTL-M|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG8K-D,,,, -read,total_dc_power,2,5017,"U32"" # Documentation says Unsigned, but seems to be returning Signed 32bit",,W,,,,, +read,total_dc_power,2,5017,U32,,W,,,,, read,phase_a_voltage,1,5019,U16,0.1,V,,,,, read,phase_b_voltage,2,5020,U16,0.1,V,,,,, read,phase_c_voltage,2,5021,U16,0.1,V,,,,, -read,phase_a_current,2,5022,"S16"" # Documentation says Unsigned, but seems to be returning Signed 16bit",0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, -read,phase_b_current,2,5023,"S16"" # Documentation says Unsigned, but seems to be returning Signed 16bit",0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, -read,phase_c_current,2,5024,"S16"" # Documentation says Unsigned, but seems to be returning Signed 16bit",0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,phase_a_current,2,5022,S16,0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,phase_b_current,2,5023,S16,0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, +read,phase_c_current,2,5024,S16,0.1,A,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, read,total_active_power,0,5031,U32,,W,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, read,total_reactive_power,2,5033,S32,,Var,,,,, -read,"power_factor"" # >0 means leading, <0 means lagging",2,5035,S16,0.001,,,,,, +read,power_factor,2,5035,S16,0.001,,,,,, read,grid_frequency,2,5036,U16,0.1,Hz,,,,, -read,"work_state_1"" # See Appendix 1",1,5038,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,"[{""response"": 0, ""value"": ""Run""}, {""response"": 32768, ""value"": ""Stop""}, {""response"": 4864, ""value"": ""Key Stop""}, {""response"": 5376, ""value"": ""Emergency Stop""}, {""response"": 5120, ""value"": ""Standby""}, {""response"": 4608, ""value"": ""Initial Standby""}, {""response"": 5632, ""value"": ""Starting""}, {""response"": 37120, ""value"": ""Alarm Run""}, {""response"": 33024, ""value"": ""Derating Run""}, {""response"": 33280, ""value"": ""Dispatch Run""}, {""response"": 21760, ""value"": ""Fault""}, {""response"": 9472, ""value"": ""Communication Fault""}]",,, +read,work_state_1,1,5038,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,"[{""response"": 0, ""value"": ""Run""}, {""response"": 32768, ""value"": ""Stop""}, {""response"": 4864, ""value"": ""Key Stop""}, {""response"": 5376, ""value"": ""Emergency Stop""}, {""response"": 5120, ""value"": ""Standby""}, {""response"": 4608, ""value"": ""Initial Standby""}, {""response"": 5632, ""value"": ""Starting""}, {""response"": 37120, ""value"": ""Alarm Run""}, {""response"": 33024, ""value"": ""Derating Run""}, {""response"": 33280, ""value"": ""Dispatch Run""}, {""response"": 21760, ""value"": ""Fault""}, {""response"": 9472, ""value"": ""Communication Fault""}]",,, read,alarm_time_year,3,5039,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, read,alarm_time_month,3,5040,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, read,alarm_time_day,3,5041,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, read,alarm_time_hour,3,5042,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, read,alarm_time_minute,3,5043,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, read,alarm_time_second,3,5045,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, -read,"alarm_code_1"" # See Appendix 3",3,5045,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, +read,alarm_code_1,3,5045,U16,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, read,nominal_reactive_power,2,5049,U16,0.1,kVar,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,,,, read,array_insulation_resistance,2,5071,U16,,k-ohm,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, read,active_power_regulation_setpoint,2,5077,U32,,W,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SH10RT|SH10RT-V112|SH10RT-20|SH8.0RT|SH6.0RT|SH5.0RT|SH5.0RT-V112,,,, read,reactive_power_regulation_setpoint,2,5079,S32,,Var,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT,,,, -read,"work_state_2"" # See Appendix 2",2,5081,U32,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,"[{""response"": 0, ""value"": ""Run""}, {""response"": 1, ""value"": ""Stop""}, {""response"": 3, ""value"": ""Key Stop""}, {""response"": 5, ""value"": ""Emergency Stop""}, {""response"": 4, ""value"": ""Standby""}, {""response"": 2, ""value"": ""Initial Standby""}, {""response"": 6, ""value"": ""Starting""}, {""response"": 10, ""value"": ""Alarm Run""}, {""response"": 11, ""value"": ""Derating Run""}, {""response"": 12, ""value"": ""Dispatch Run""}, {""response"": 9, ""value"": ""Fault""}, {""response"": 13, ""value"": ""Communication Fault""}, {""response"": 17, ""value"": ""Total Run Bit""}, {""response"": 18, ""value"": ""Total Fault Bit""}]",,, +read,work_state_2,2,5081,U32,,,SG30KTL|SG10KTL|SG12KTL|SG15KTL|SG20KTL|SG30KU|SG36KTL|SG36KU|SG40KTL|SG40KTL-M|SG50KTL-M|SG60KTL-M|SG60KU|SG30KTL-M|SG30KTL-M-V31|SG33KTL-M|SG36KTL-M|SG33K3J|SG49K5J|SG34KJ|LP_P34KSG|SG50KTL-M-20|SG60KTL|SG80KTL|SG80KTL-20|SG60KU-M|SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M|SG80KTL-M|SG111HV|SG125HV|SG125HV-20|SG30CX|SG33CX|SG36CX-US|SG40CX|SG50CX|SG60CX-US|SG110CX|SG250HX|SG250HX-US|SG100CX|SG100CX-JP|SG250HX-IN|SG25CX-SA|SG75CX|SG3.0RT|SG4.0RT|SG5.0RT|SG3.0RS|SG4.0RS|SG5.0RS|SG6.0RT|SG7.0RT|SG8.0RT|SG8.0RS|SG10RT|SG12RT|SG15RT|SG17RT|SG20RT|SG3K-D|SG5K-D|SG8K-D,"[{""response"": 0, ""value"": ""Run""}, {""response"": 1, ""value"": ""Stop""}, {""response"": 3, ""value"": ""Key Stop""}, {""response"": 5, ""value"": ""Emergency Stop""}, {""response"": 4, ""value"": ""Standby""}, {""response"": 2, ""value"": ""Initial Standby""}, {""response"": 6, ""value"": ""Starting""}, {""response"": 10, ""value"": ""Alarm Run""}, {""response"": 11, ""value"": ""Derating Run""}, {""response"": 12, ""value"": ""Dispatch Run""}, {""response"": 9, ""value"": ""Fault""}, {""response"": 13, ""value"": ""Communication Fault""}, {""response"": 17, ""value"": ""Total Run Bit""}, {""response"": 18, ""value"": ""Total Fault Bit""}]",,, read,meter_power,1,5083,S32,,W,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,,true read,meter_a_phase_power,2,5085,S32,,W,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, read,meter_b_phase_power,2,5087,S32,,W,SG5KTL-MT|SG6KTL-MT|SG8KTL-M|SG10KTL-M|SG10KTL-MT|SG12KTL-M|SG15KTL-M|SG17KTL-M|SG20KTL-M,,,, diff --git a/scripts/migrate_yaml_to_csv.py b/scripts/migrate_yaml_to_csv.py index 4da8f88..0b7771b 100644 --- a/scripts/migrate_yaml_to_csv.py +++ b/scripts/migrate_yaml_to_csv.py @@ -14,6 +14,29 @@ import os +def strip_inline_comment(value): + """ + Strip inline YAML comments from a value. + + YAML allows inline comments starting with '#'. This function removes + them from string values while preserving the actual content. + + Args: + value: String value that may contain an inline comment + + Returns: + str: Value with inline comment removed, or original value if not a string + """ + if not isinstance(value, str): + return value + if not value: + return value + # Remove inline comment (text after #) + if '#' in value: + value = value.split('#')[0].strip() + return value + + def migrate(yaml_path, csv_path, scan_yaml_path): """ Migrate from YAML register file to CSV + scan-ranges YAML. @@ -98,18 +121,24 @@ def convert_register_to_row(reg_type, reg): Returns: dict: CSV row dictionary """ + # Strip inline comments from string fields + name = strip_inline_comment(reg.get("name", "")) + datatype = strip_inline_comment(reg.get("datatype", "")) + unit = strip_inline_comment(reg.get("unit", "")) if "unit" in reg else "" + default = strip_inline_comment(reg.get("default", "")) if "default" in reg else "" + row = { "type": reg_type, - "name": reg.get("name", ""), + "name": name, "level": reg.get("level", ""), "address": reg.get("address", ""), - "datatype": reg.get("datatype", ""), + "datatype": datatype, "accuracy": "", - "unit": "", + "unit": unit, "models": "", "datarange": "", "mask": "", - "default": "", + "default": default, "smart_meter": "" } @@ -117,9 +146,6 @@ def convert_register_to_row(reg_type, reg): if "accuracy" in reg: row["accuracy"] = reg["accuracy"] - if "unit" in reg: - row["unit"] = reg["unit"] - if "models" in reg: # Convert list to pipe-delimited string row["models"] = "|".join(reg["models"]) @@ -132,9 +158,6 @@ def convert_register_to_row(reg_type, reg): if "mask" in reg: row["mask"] = reg["mask"] - if "default" in reg: - row["default"] = reg["default"] - if "smart_meter" in reg and reg["smart_meter"]: row["smart_meter"] = "true" diff --git a/scripts/migrate_yaml_to_csv_simple.py b/scripts/migrate_yaml_to_csv_simple.py index 496d0a5..6d5531e 100644 --- a/scripts/migrate_yaml_to_csv_simple.py +++ b/scripts/migrate_yaml_to_csv_simple.py @@ -14,6 +14,28 @@ import re +def strip_inline_comment(value): + """ + Strip inline YAML comments from a value. + + YAML allows inline comments starting with '#'. This function removes + them from string values while preserving the actual content. + + Args: + value: String value that may contain an inline comment + + Returns: + str: Value with inline comment removed + """ + if not value: + return value + # Remove inline comment (text after #) but be careful with quoted strings + # If the value has a # character, split and take only the part before it + if '#' in value: + value = value.split('#')[0].strip() + return value + + def simple_yaml_parse(yaml_content): """ Simple YAML parser for the specific structure of registers-sungrow.yaml. @@ -103,20 +125,22 @@ def simple_yaml_parse(yaml_content): data['registers'][-1][current_reg_type].append(current_register) current_register = {} current_datarange = None - name_val = stripped.split(':', 1)[1].strip().strip('"\'') + name_val = strip_inline_comment(stripped.split(':', 1)[1].strip()).strip('"\'') current_register['name'] = name_val elif current_register is not None: if stripped.startswith('level:'): - current_register['level'] = int(stripped.split(':', 1)[1].strip()) + val_str = strip_inline_comment(stripped.split(':', 1)[1].strip()) + current_register['level'] = int(val_str) elif stripped.startswith('address:'): - current_register['address'] = int(stripped.split(':', 1)[1].strip()) + val_str = strip_inline_comment(stripped.split(':', 1)[1].strip()) + current_register['address'] = int(val_str) elif stripped.startswith('datatype:'): - current_register['datatype'] = stripped.split(':', 1)[1].strip().strip('"\'') + current_register['datatype'] = strip_inline_comment(stripped.split(':', 1)[1].strip()).strip('"\'') elif stripped.startswith('accuracy:'): - val = stripped.split(':', 1)[1].strip() + val = strip_inline_comment(stripped.split(':', 1)[1].strip()) current_register['accuracy'] = float(val) if val else None elif stripped.startswith('unit:'): - current_register['unit'] = stripped.split(':', 1)[1].strip().strip('"\'') + current_register['unit'] = strip_inline_comment(stripped.split(':', 1)[1].strip()).strip('"\'') elif stripped.startswith('models:'): # Parse list format: ["model1","model2"] models_str = stripped.split(':', 1)[1].strip() @@ -139,15 +163,16 @@ def simple_yaml_parse(yaml_content): resp_val = int(resp_val) current_datarange.append({'response': resp_val}) elif stripped.startswith('value:'): - val = stripped.split(':', 1)[1].strip().strip('"\'') + val = strip_inline_comment(stripped.split(':', 1)[1].strip()).strip('"\'') if current_datarange: current_datarange[-1]['value'] = val elif stripped.startswith('mask:'): - current_register['mask'] = int(stripped.split(':', 1)[1].strip()) + val_str = strip_inline_comment(stripped.split(':', 1)[1].strip()) + current_register['mask'] = int(val_str) elif stripped.startswith('default:'): - current_register['default'] = stripped.split(':', 1)[1].strip().strip('"\'') + current_register['default'] = strip_inline_comment(stripped.split(':', 1)[1].strip()).strip('"\'') elif stripped.startswith('smart_meter:'): - val = stripped.split(':', 1)[1].strip().lower() + val = strip_inline_comment(stripped.split(':', 1)[1].strip()).lower() current_register['smart_meter'] = (val == 'true') # Add last register if still in registers mode