feat: Enhance Deye inverter data extraction with a new web dashboard and Modbus register mapping tools.

This commit is contained in:
Vladyslav Doloman
2025-11-22 17:35:18 +02:00
parent a6b1010650
commit e75f7222a0
2 changed files with 467 additions and 87 deletions

77
app.py
View File

@@ -18,34 +18,69 @@ def get_inverter_data():
verbose=False
)
# Registers to read:
# 150: Grid Voltage (Input Voltage) - 0.1V
# 154: Output Voltage - 0.1V
# 157: Load Voltage - 0.1V
# 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 individually for simplicity, though block read is more efficient if contiguous
# But these are slightly apart (150, 154, 157).
# We can read a block from 150 to 157 (8 registers) and parse.
block1 = inverter.read_holding_registers(register_addr=150, quantity=67)
block2 = inverter.read_holding_registers(register_addr=600, quantity=28)
# Let's read block starting at 150, length 8.
# 150 -> Index 0
# 154 -> Index 4
# 157 -> Index 7
def to_signed(val):
return val if val < 32768 else val - 65536
data = {}
raw_data = inverter.read_holding_registers(register_addr=150, quantity=8)
# Block 1 Parsing
# Offsets relative to 150
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
input_voltage = raw_data[0] * 0.1
output_voltage = raw_data[4] * 0.1
load_voltage = raw_data[7] * 0.1
data["grid_current"] = round(to_signed(block1[10]) * 0.01, 2) # 160
data["grid_clamp_current"] = round(to_signed(block1[12]) * 0.01, 2) # 162
data["output_current"] = round(to_signed(block1[14]) * 0.01, 2) # 164
data["load_current"] = round(to_signed(block1[29]) * 0.01, 2) # 179
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["pv1_power"] = block1[36] # 186
data["pv2_power"] = block1[37] # 187
data["batt_power"] = to_signed(block1[40]) # 190
data["batt_current"] = round(to_signed(block1[41]) * 0.01, 2) # 191
data["grid_relay_status"] = block1[44] # 194
data["gen_relay_status"] = block1[45] # 195
data["max_charge_current"] = block1[60] # 210
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)
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
inverter.disconnect()
return {
"input_voltage": round(input_voltage, 1),
"output_voltage": round(output_voltage, 1),
"load_voltage": round(load_voltage, 1),
"status": "success"
}
data["status"] = "success"
return data
except Exception as e:
return {