feat: Introduce a web interface for Deye inverter monitoring, expand Modbus data collection with new register blocks, and add supporting documentation.

This commit is contained in:
Vladyslav Doloman
2025-11-22 23:27:38 +02:00
parent e75f7222a0
commit 0b377db6c2
2 changed files with 313 additions and 271 deletions

47
app.py
View File

@@ -18,20 +18,25 @@ def get_inverter_data():
verbose=False
)
# Reading two main blocks:
# Block 1: 150 - 216 (67 registers) - Covers Voltages, Currents, Battery, PV, Control
# Block 2: 600 - 627 (28 registers) - Covers BMS Data
# Reading blocks:
# Block 1: 150 - 216 (67 registers) - Voltages, Currents, Battery, PV, Control
# Block 2: 600 - 627 (28 registers) - BMS Data
# Block 3: 245 (1 register) - Max Grid Output
# Block 4: 292 - 293 (2 registers) - Peak Shaving
# Block 5: 314 - 325 (12 registers) - Advanced Limits
block1 = inverter.read_holding_registers(register_addr=150, quantity=67)
block2 = inverter.read_holding_registers(register_addr=600, quantity=28)
block3 = inverter.read_holding_registers(register_addr=245, quantity=1)
block4 = inverter.read_holding_registers(register_addr=292, quantity=2)
block5 = inverter.read_holding_registers(register_addr=314, quantity=12)
def to_signed(val):
return val if val < 32768 else val - 65536
data = {}
# Block 1 Parsing
# Offsets relative to 150
# Block 1 Parsing (150-216)
data["input_voltage"] = round(block1[0] * 0.1, 1) # 150
data["output_voltage"] = round(block1[4] * 0.1, 1) # 154
data["load_voltage"] = round(block1[7] * 0.1, 1) # 157
@@ -45,7 +50,7 @@ def get_inverter_data():
data["batt_temp"] = round(to_signed(block1[32]) * 0.1, 1) # 182
data["batt_voltage"] = round(block1[33] * 0.01, 2) # 183
data["batt_soc"] = block1[34] # 184
data["batt_charge_status"] = block1[35] # 185 (Raw for now)
data["batt_charge_status"] = block1[35] # 185
data["pv1_power"] = block1[36] # 186
data["pv2_power"] = block1[37] # 187
@@ -59,24 +64,34 @@ def get_inverter_data():
data["max_discharge_current"] = block1[61] # 211
data["batt_charge_efficiency"] = block1[66] # 216
# Block 2 Parsing (BMS)
# Offsets relative to 600
# BMS 1 (600-613)
# Block 2 Parsing (BMS 600-627)
data["bms1_soc"] = block2[3] # 603
data["bms1_voltage"] = round(block2[6] * 0.01, 2) # 606 (Charge Voltage?) - Wait, PDF says 606 Charge Voltage.
# Let's stick to the PDF labels from extraction if possible, or generic BMS fields.
# Extracted: 606 Charge Voltage 0.01V.
# Actually commonly 600+ are BMS specific.
# Let's just map them raw or with simple scaling as per PDF.
data["bms1_charge_voltage"] = round(block2[6] * 0.01, 2) # 606
data["bms1_charge_current"] = round(block2[7] * 0.1, 1) # 607
# BMS 2 (614-627)
data["bms2_soc"] = block2[17] # 617
data["bms2_charge_voltage"] = round(block2[20] * 0.01, 2) # 620
data["bms2_charge_current"] = round(block2[21] * 0.1, 1) # 621
# Block 3 Parsing (245)
data["max_grid_output_power"] = block3[0] # 245
# Block 4 Parsing (292-293)
data["gen_peak_shaving_power"] = block4[0] # 292
data["grid_peak_shaving_power"] = block4[1] # 293
# Block 5 Parsing (314-325)
data["discharge_voltage"] = round(block5[0] * 0.01, 2) # 314
data["charge_current_limit"] = block5[1] # 315
data["discharge_current_limit"] = block5[2] # 316
data["real_time_capacity"] = block5[3] # 317
data["real_time_voltage"] = round(block5[4] * 0.01, 2) # 318
# 319 skipped
data["max_charge_current_limit"] = block5[6] # 320
data["max_discharge_current_limit"] = block5[7] # 321
# 322-324 skipped
data["lithium_battery_type"] = block5[11] # 325
inverter.disconnect()
data["status"] = "success"