diff --git a/lib/TWCManager/Control/HTTPControl.py b/lib/TWCManager/Control/HTTPControl.py index b38b84f3..2031ec82 100644 --- a/lib/TWCManager/Control/HTTPControl.py +++ b/lib/TWCManager/Control/HTTPControl.py @@ -270,6 +270,7 @@ def do_API_GET(self): elif self.url.path == "/api/getSlaveTWCs": data = {} totals = { + "carsCharging": 0, "lastAmpsOffered": 0, "lifetimekWh": 0, "maxAmps": 0, @@ -278,15 +279,15 @@ def do_API_GET(self): for slaveTWC in master.getSlaveTWCs(): TWCID = "%02X%02X" % (slaveTWC.TWCID[0], slaveTWC.TWCID[1]) data[TWCID] = { + "carsCharging": slaveTWC.isCharging, + "chargerLoadInW": round(slaveTWC.getCurrentChargerLoad()), "currentVIN": slaveTWC.currentVIN, "lastAmpsOffered": round(slaveTWC.lastAmpsOffered, 2), "lastHeartbeat": round(time.time() - slaveTWC.timeLastRx, 2), - "carsCharging": slaveTWC.isCharging, "lastVIN": slaveTWC.lastVIN, "lifetimekWh": slaveTWC.lifetimekWh, "maxAmps": float(slaveTWC.maxAmps), "reportedAmpsActual": float(slaveTWC.reportedAmpsActual), - "chargerLoadInW": round(slaveTWC.getCurrentChargerLoad()), "state": slaveTWC.reportedState, "version": slaveTWC.protocolVersion, "voltsPhaseA": slaveTWC.voltsPhaseA, @@ -307,21 +308,23 @@ def do_API_GET(self): # Adding some vehicle data vehicle = slaveTWC.getLastVehicle() if vehicle != None: + data[TWCID]["lastAtHome"] = vehicle.atHome data[TWCID]["lastBatterySOC"] = vehicle.batteryLevel data[TWCID]["lastChargeLimit"] = vehicle.chargeLimit - data[TWCID]["lastAtHome"] = vehicle.atHome data[TWCID]["lastTimeToFullCharge"] = vehicle.timeToFullCharge + totals["carsCharging"] += slaveTWC.isCharging totals["lastAmpsOffered"] += slaveTWC.lastAmpsOffered totals["lifetimekWh"] += slaveTWC.lifetimekWh - totals["maxAmps"] += slaveTWC.maxAmps + totals["maxAmps"] = slaveTWC.maxAmps if totals["maxAmps"] == 0 else min(totals["maxAmps"], slaveTWC.maxAmps) totals["reportedAmpsActual"] += slaveTWC.reportedAmpsActual data["total"] = { + "carsCharging": totals["carsCharging"], "lastAmpsOffered": round(totals["lastAmpsOffered"], 2), "lifetimekWh": totals["lifetimekWh"], "maxAmps": totals["maxAmps"], - "reportedAmpsActual": round(totals["reportedAmpsActual"], 2), + "reportedAmpsActual": totals["reportedAmpsActual"], "TWCID": "total", } diff --git a/lib/TWCManager/EMS/Victron.py b/lib/TWCManager/EMS/Victron.py new file mode 100644 index 00000000..ea4e313c --- /dev/null +++ b/lib/TWCManager/EMS/Victron.py @@ -0,0 +1,64 @@ +import logging +from pyModbusTCP.client import ModbusClient + +logger = logging.getLogger("Victron") + +class Victron: + def __init__(self, master): + self.master = master + self.config = master.config.get("sources", {}).get("CerboGX", {}) + self.enabled = self.config.get("enabled", False) + self.server_ip = self.config.get("serverIP", "192.168.30.101") + self.server_port = int(self.config.get("serverPort", 502)) + self.unit_id = int(self.config.get("unitID", 100)) + + self.client = ModbusClient(host=self.server_ip, port=self.server_port, unit_id=self.unit_id, auto_open=True) + + if not self.enabled: + logger.info("Victron EMS Module Disabled.") + + def getConsumption(self): + if not self.enabled: + return 0 + return self.update("consumption") + + def getGeneration(self): + if not self.enabled: + return 0 + return self.update("generation") + + def update(self, data_type): + try: + if not self.client.is_open: + self.client.open() + + if data_type == "consumption": + # Addresses for Output Power (per phase) + registers = [(817,100), (818,100), (819,100)] + scale_factor = 1 + elif data_type == "generation": + # Addresses for PV AC-coupled output (per phase) + registers = [(808,100), (809,100), (810,100)] + scale_factor = 1 + else: + return 0 + + total_power = 0 + for reg, unit_id in registers: + # Set the unit_id dynamically for each read operation + self.client.unit_id = unit_id + result = self.client.read_input_registers(reg, 1) + if result: + total_power += result[0] * scale_factor + else: + logger.warning(f"Failed to read register {reg} on unit {unit_id}") + + return total_power + + except Exception as e: + logger.error(f"Error communicating with Victron: {e}") + return 0 + + finally: + if self.client.is_open: + self.client.close() diff --git a/lib/TWCManager/TWCManager.py b/lib/TWCManager/TWCManager.py index 8b50d7dc..e6c93246 100755 --- a/lib/TWCManager/TWCManager.py +++ b/lib/TWCManager/TWCManager.py @@ -106,6 +106,7 @@ "EMS.SolarLog", "EMS.TeslaPowerwall2", "EMS.TED", + "EMS.Victron", "EMS.Volkszahler", "EMS.URL", "Status.HASSStatus",