from flask import Flask, jsonify, render_template from pysolarmanv5 import PySolarmanV5 import config app = Flask(__name__) def get_inverter_data(): """ Connects to the inverter and reads voltage registers. Returns a dictionary with the data. """ try: inverter = PySolarmanV5( config.INVERTER_IP, config.INVERTER_SERIAL, port=config.INVERTER_PORT, mb_slave_id=config.INVERTER_SLAVE_ID, 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 block1 = inverter.read_holding_registers(register_addr=150, quantity=67) block2 = inverter.read_holding_registers(register_addr=600, quantity=28) def to_signed(val): return val if val < 32768 else val - 65536 data = {} # 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 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() data["status"] = "success" return data except Exception as e: return { "status": "error", "message": str(e) } @app.route('/') def index(): return render_template('index.html') @app.route('/api/data') def api_data(): data = get_inverter_data() return jsonify(data) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0')