diff --git a/app.py b/app.py index 29e1180..62be46a 100644 --- a/app.py +++ b/app.py @@ -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 { diff --git a/templates/index.html b/templates/index.html index 0dcbe2c..115fc6f 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,5 +1,6 @@ +
@@ -20,34 +21,6 @@ font-family: var(--font-family); margin: 0; padding: 20px; - display: flex; - flex-direction: column; - align-items: center; - min-height: 100vh; - } - - h1 { - margin-bottom: 40px; - font-weight: 300; - letter-spacing: 2px; - text-transform: uppercase; - background: linear-gradient(45deg, var(--accent-color), var(--secondary-accent)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - } - - .dashboard { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 20px; - width: 100%; - max-width: 1000px; - } - - .card { - background-color: var(--card-bg); - border-radius: 15px; - padding: 25px; text-align: center; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); transition: transform 0.3s ease, box-shadow 0.3s ease; @@ -118,17 +91,34 @@ } @keyframes pulse { - 0% { opacity: 1; } - 50% { opacity: 0.5; } - 100% { opacity: 1; } + 0% { + opacity: 1; + } + + 50% { + opacity: 0.5; + } + + 100% { + opacity: 1; + } } .loading .value { animation: pulse 1.5s infinite; color: #666; } + + .dashboard { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 20px; + width: 100%; + max-width: 1000px; + } +