import asyncio from Wattpilot import Wattpilot from dataclasses import dataclass import sys import logging import gatherModbusData import charger_goE import webSocketServer import time from mysql.connector import connect, Error import json import gatherOpenDTUData import gatherDTUBIData import gatherSkodaData import gatherWaterData import gatherHeaterData import gatherShellyEM3DataEG import gatherShellyEM3DataUG import datetime from dateutil import tz from suntime import Sun, SunTimeException from typing import List from dataclasses import dataclass from dataclasses import field from time import sleep import dataclasses import logging.config import mqttClient import konfig logging.config.fileConfig('./logging.ini') def is_summer_time(aware_dt): assert aware_dt.tzinfo is not None assert aware_dt.tzinfo.utcoffset(aware_dt) is not None return bool(aware_dt.dst()) #Log_Format = "%(levelname)s %(asctime)s - %(message)s" #logging.basicConfig(stream = sys.stdout, # filemode = "w", # format = Log_Format, # level = logging.INFO) #_LOGGER = logging.getLogger() #Log_Format = "%(levelname)s %(module)s:%(lineno)d %(asctime)s - %(message)s" #logging.basicConfig(stream=sys.stdout, format = Log_Format, level=logging.INFO) _LOGGER = logging.getLogger() #_LOGGER.setLevel(logging.INFO) #logging.getLogger("Wattpilot").setLevel(logging.WARNING) #handler = logging.StreamHandler(sys.stdout) #handler.setLevel(logging.WARNING) #formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #handler.setFormatter(formatter) #_LOGGER.addHandler(handler) class EnhancedJSONEncoder(json.JSONEncoder): def default(self, o): if dataclasses.is_dataclass(o): return dataclasses.asdict(o) return super().default(o) #"inverter1":"Symo Gen24 10.0", #"inverter1nPV":2, #"inverter2":"HM1500", #"inverter2nPV":4, #"inverter3":"HMT1800", #"inverter3nPV":6, #"inverter4":"HMs800w", #"inverter4nPV":2, @dataclass class InvData: p_PV:List[float] = field(default_factory=list) p_AC:float = 0.0 temp:float = 0.0 error:int = 0 name:str = "" rtData = {"P_Load":0.0, "SOC":0.0, "P_Akku":0.0, "crgMaxPct":0.0, "eff":0.0, "P_PVn":[0.0]*34, "P_PV":0.0, "P_PV_est":0.0, "invErr":0, "autarky":0.0, "P_Grid":0.0, "P_WR":0.0, "P_GridCons":0.0, "P_GridFeed":0.0, "ibatt":0.0, "ubatt":0.0, "tbatt":0.0, "p_l1evu":0.0, "p_l2evu":0.0, "p_l3evu":0.0, "p_l1og":0.0, "p_l2og":0.0, "p_l3og":0.0, "p_l1eg":0.0, "p_l2eg":0.0, "p_l3eg":0.0, "p_l1ug":0.0, "p_l2ug":0.0, "p_l3ug":0.0, "og":0.0, "eg":0.0, "ug":0.0, "i_l1evu":0.0, "i_l2evu":0.0, "i_l3evu":0.0, "i_l1og":0.0, "i_l2og":0.0, "i_l3og":0.0, "p_l1ev":0.0, "p_l2ev":0.0, "p_l3ev":0.0, "evPower":0.0, "evSOC":0.0, "evLock":False, "evFuel":0.0, "evMode":"man", "evRemChrgTime":0.0, "evRange":0.0, "evChgState":"", "wbWh":0, "wbogWh":0, "evModeOG":"man", "p_l1evOG":0.0, "p_l2evOG":0.0, "p_l3evOG":0.0, "evPowerOG":0.0, "evPlugOG":False, "shellyUG":False, "shellyOG":False, "evPlug":False, "t_buffT":0.0, "t_buffM":0.0, "t_buffB":0.0, "t_heatVL":0.0, "t_heatRL":0.0, "t_gasVLu":0.0, "t_gasVLo":0.0, "t_gasRL":0.0, "t_fbVL":0.0, "t_fbRL":0.0, "t_triac":0.0, "pHeat":0.0, "heatMode":"man", "waterHeight":0, "waterTemp": 0.0, "inverters":[InvData(),InvData(),InvData(),InvData(),InvData(),InvData(),InvData(),InvData()], "P_AC": 0.0 } avgData = dict(rtData) lock = asyncio.Lock() def wp_handle_events(event, *args): _LOGGER.debug(f"wp_handle_events(event={event},{args})") _LOGGER.debug(f"wp_handle_events(): MQTT client not yet initialized - status publishing skipped.") if event['type'] == 'fullStatus': _LOGGER.debug(f"wp_handle_events()") return def isfloat(num): try: float(num) return True except ValueError: return False async def repeat(interval): """Run func every interval seconds. If func has not finished before *interval*, will run again immediately when the previous iteration finished. *args and **kwargs are passed as the arguments to func. """ # Zugangsdaten stehen in config.ini und nicht mehr hier, siehe konfig.py. _zugang = konfig.datenbank() mysqlHost = _zugang["host"] mysqlPort = _zugang["port"] mysqlUser = _zugang["user"] mysqlPW = _zugang["password"] mysqlDB = _zugang["database"] gatherSkodaData.setDbPasswort(mysqlPW) avgCounter = 0 invErrAcc = 0 next_dbEntry = round(time.time()) + 300 _LOGGER.info("Manager started!") lat = 47.5779944 lon = 10.2623373 sun = Sun(lat, lon) lastDay = datetime.datetime.now() query = "SELECT date FROM daylight ORDER BY date DESC LIMIT 1;" lastSunriseDate = 0 try: with connect( host=mysqlHost, port=mysqlPort, user=mysqlUser, password=mysqlPW, database=mysqlDB, ) as connection: with connection.cursor() as cursor: cursor.execute(query) myresult = cursor.fetchone() connection.commit() if myresult: lastSunriseDate = myresult[0] if(lastSunriseDate): newDay = lastSunriseDate while newDay < datetime.datetime.now().date() + datetime.timedelta(days=2): sunrise = sun.get_sunrise_time(newDay,tz.gettz('Europe/Berlin')) #tz.gettz('Europe/Kaliningrad') tz.gettz('Europe/Berlin') sunset = sun.get_sunset_time(newDay,tz.gettz('Europe/Berlin')) if(is_summer_time(sunrise) == False): sunrise = sunrise + datetime.timedelta(hours=1) #_LOGGER.info("Wintertime!!") if(is_summer_time(sunset) == False): sunset = sunset + datetime.timedelta(hours=1) #_LOGGER.info(str(sunrise.strftime('%H:%M:%S'))) query = "REPLACE INTO daylight (date, sunrise, sunset) VALUES ('"+newDay.isoformat()+"', '"+str(sunrise.strftime('%H:%M:%S'))+"', '"+str(sunset.strftime('%H:%M:%S'))+"');" with connection.cursor() as cursor: cursor.execute(query) connection.commit() newDay = newDay + datetime.timedelta(days=1) except Error as e: print(e) sunrise = sun.get_sunrise_time(datetime.datetime.now(),tz.gettz('Europe/Berlin')) #tz.gettz('Europe/Kaliningrad') tz.gettz('Europe/Berlin') sunset = sun.get_sunset_time(datetime.datetime.now(),tz.gettz('Europe/Berlin')) if(is_summer_time(sunrise) == False): sunrise = sunrise + datetime.timedelta(hours=1) #_LOGGER.info("Wintertime!!") if(is_summer_time(sunset) == False): sunset = sunset + datetime.timedelta(hours=1) wp = Wattpilot.Wattpilot(konfig.wert("wattpilot", "host"), konfig.wert("wattpilot", "password")) wp._auto_reconnect = 1 wp._reconnect_interval = 60 wp.connect() wp.add_event_handler("ws_close", wp_handle_events) wp.add_event_handler("ws_open", wp_handle_events) wp.add_event_handler("wp_fullStatus_finished", wp_handle_events) i=0 estProduction = 0.0 while (wp.allPropsInitialized == 0 and i < 10): sleep(1); i = i + 1; water=await gatherWaterData.getWaterData() rtData["waterHeight"] = water.waterHeight rtData["waterTemp"] = water.temp await gatherModbusData.connect() mqttClient.startMqttClient() rtData["inverters"][0].p_PV.append(0) rtData["inverters"][0].p_PV.append(0) while True: inv,dtubi,dtu,heat,chrg,pEG,pUG,skoda,slp = await asyncio.gather( gatherModbusData.get_runtime_data(estProduction, sunset), gatherDTUBIData.gatherData(), gatherOpenDTUData.gatherData(), gatherHeaterData.gatherData(), charger_goE.gatherNeededStatus(), gatherShellyEM3DataEG.gatherData(), gatherShellyEM3DataUG.gatherData(), gatherSkodaData.gatherData(rtData["evPower"], rtData["evPlug"], rtData["evPowerOG"], rtData["evPlugOG"], rtData["P_PV"]/1000.0, rtData["P_Grid"]/1000.0, rtData["wbWh"], rtData["wbogWh"]), asyncio.sleep(interval), ) rtData["evSOC"] = skoda.soc rtData["evRange"] = skoda.range_km rtData["evRemChrgTime"] = skoda.chgRemMin rtData["evChgState"] = skoda.chgState rtData["evFuel"] = skoda.fuelPct if skoda.locked is not None: rtData["evLock"] = skoda.locked pvIt = 0 if inv is None: _LOGGER.error("no inverter data available, skipping PV calculation fot Fronius!") else: for ppv in inv.p_PV: if ppv is not None: if ppv < 1: ppv = 0 rtData["P_PVn"][pvIt] = round(ppv,2) pvIt =pvIt+1 pvIt = 2 for ppv in dtubi.inverter[0].p_PV: #Veranda UG2 if ppv < 1: ppv = 0 rtData["P_PVn"][pvIt] = round(ppv,2) pvIt =pvIt+1 pvIt = 4 for ppv in dtu.inverter[0].p_PV: #Veranda UG/OG1 if ppv < 1: ppv = 0 rtData["P_PVn"][pvIt] = round(ppv,2) pvIt =pvIt+1 pvIt = 8 for ppv in dtu.inverter[3].p_PV: #was inverter 3 Veranda OG2-4 if ppv < 1: ppv = 0 rtData["P_PVn"][pvIt] = round(ppv,2) pvIt =pvIt+1 pvIt = 14 for ppv in dtu.inverter[2].p_PV: #carport 1 (HMS2250-6T) if ppv < 1: ppv = 0 rtData["P_PVn"][pvIt] = round(ppv,2) pvIt =pvIt+1 pvIt = 20 for ppv in dtu.inverter[1].p_PV: #carport 2 (HMS2250-6T) if ppv < 1: ppv = 0 rtData["P_PVn"][pvIt] = round(ppv,2) pvIt =pvIt+1 pvIt = 26 for ppv in dtu.inverter[4].p_PV: #carport 3 (HMS1800-4T) if ppv < 1: ppv = 0 rtData["P_PVn"][pvIt] = round(ppv,2) pvIt =pvIt+1 pvIt = 30 for ppv in dtu.inverter[5].p_PV: #carport 4 (HMS1600-4T) only take three plates if ppv < 1: ppv = 0 if pvIt < 34: rtData["P_PVn"][pvIt] = round(ppv,2) pvIt =pvIt+1 invNum = 0 if inv is None: pass else: rtData["inverters"][invNum].p_PV[0] = (inv.ppv) rtData["inverters"][invNum].p_PV[1] = (inv.ppv2) rtData["inverters"][invNum].p_AC = inv.p_AC rtData["inverters"][invNum].temp = inv.temp rtData["inverters"][invNum].name = "Gen24 "+str(inv.temp) invNum = invNum+1 rtData["inverters"][invNum] = dtubi.inverter[0] #Veranda UG2 invNum = invNum+1 rtData["inverters"][invNum] = dtu.inverter[0] #Veranda UG/OG1 invNum = invNum+1 rtData["inverters"][invNum] = dtu.inverter[3] #Veranda OG2-4 invNum = invNum+1 rtData["inverters"][invNum] = dtu.inverter[2] #carport 1-6 invNum = invNum+1 rtData["inverters"][invNum] = dtu.inverter[1] #carport 7-12 invNum = invNum+1 rtData["inverters"][invNum] = dtu.inverter[4] #carport 13-16 invNum = invNum+1 rtData["inverters"][invNum] = dtu.inverter[5] #carport 17-19 invNum = invNum+1 # Wer hat in diesem Durchlauf keine frischen Daten geliefert? Ein Bit je # Wechselrichter in der Reihenfolge oben, damit die Zeile spaeter selbst # sagt, ob pvP eine Messung ist. P_PV_est haelt fest, wieviel davon aus # den gesunden Nachbarn hochgerechnet wurde - pvP minus pvP_est ist # also weiterhin die reine Messung. if inv is None: rtData["inverters"][0].error += 1 else: rtData["inverters"][0].error = 0 rtData["invErr"] = 0 estSum = 0.0 for wrNum, wr in enumerate(rtData["inverters"]): if wr.error: rtData["invErr"] |= (1 << wrNum) estSum += getattr(wr, "p_PV_est", 0.0) rtData["P_PV_est"] = round(estSum,2) try: rtData["P_AC"] = 0#rtData["inverters"][0].p_AC#inv.p_AC for inverter in rtData["inverters"]: rtData["P_AC"] = rtData["P_AC"] + inverter.p_AC rtData["P_PV"] = round(sum(rtData["P_PVn"]),2) rtData["P_Grid"] = inv.pgrid if inv.pgrid > 0: rtData["P_GridCons"] = inv.pgrid rtData["P_GridFeed"] = 0 else: rtData["P_GridCons"] = 0 rtData["P_GridFeed"] = -inv.pgrid rtData["P_WR"] = inv.p_wr rtData["ibatt"] = inv.ibatt rtData["ubatt"] = inv.ubatt rtData["tbatt"] = 0 rtData["crgMaxPct"] = inv.crgMaxPct #rtData["pwrMaxPct"] = inv.pwrMaxPct if((rtData["P_PV"]+rtData["P_Akku"]) != 0): rtData["eff"] = ((100.0 / (rtData["P_PV"]+rtData["P_Akku"])) * rtData["P_AC"]) else: rtData["eff"] = 0 rtData["p_l1evu"] = inv.p_l1evu rtData["p_l2evu"] = inv.p_l2evu rtData["p_l3evu"] = inv.p_l3evu rtData["i_l1evu"] = inv.i_l1evu rtData["i_l2evu"] = inv.i_l2evu rtData["i_l3evu"] = inv.i_l3evu rtData["p_l1og"] = inv.p_l1og rtData["p_l2og"] = inv.p_l2og rtData["p_l3og"] = inv.p_l3og rtData["i_l1og"] = inv.i_l1og rtData["i_l2og"] = inv.i_l2og rtData["i_l3og"] = inv.i_l3og rtData["og"] = inv.p_l1og + inv.p_l2og + inv.p_l3og - (chrg.p_l1ev+chrg.p_l2ev+chrg.p_l3ev)*1000 rtData["p_l1eg"] = pEG.P_L1 rtData["p_l2eg"] = pEG.P_L2 rtData["p_l3eg"] = pEG.P_L3 rtData["eg"] = pEG.P_L1 + pEG.P_L2 + pEG.P_L3 + (wp.power1+wp.power2+wp.power3)*1000 rtData["p_l1ug"] = pUG.P_L1 rtData["p_l2ug"] = pUG.P_L2 rtData["p_l3ug"] = pUG.P_L3 rtData["ug"] = pUG.P_L1 + pUG.P_L2 + pUG.P_L3 rtData["P_Akku"] = inv.pbat rtData["SOC"] = inv.soc rtData["evMode"] = wp.mode rtData["p_l1ev"] = wp.power1 rtData["p_l2ev"] = wp.power2 rtData["p_l3ev"] = wp.power3 rtData["evPower"] = wp.power # carConnected ist ein Text ("no car", "charging", "ready", # "complete"), kein Wahrheitswert - und bool("no car") ist True. # So stand der Stecker der Wallbox im Carport dauerhaft auf # gesteckt: in der Tabelle skoda, im Abruftakt von # gatherSkodaData.py und als Steckersymbol im Realtime-SVG. # "ready" heisst: Auto dran, wartet noch - also gesteckt. # Als bool passt es zu evPlugOG und kommt per MQTT als 1/0 an. rtData["evPlug"] = wp.carConnected not in (None, "no car") # Gesamtzaehler beider Wallboxen in Wh. Die Differenz zweier # Staende trifft eine Ladung auf die Wattstunde genau - genauer # als jede Summe ueber die Fuenf-Minuten-Leistungswerte, deren # Fenstergrenzen nie auf Anfang und Ende der Ladung fallen. rtData["wbWh"] = int(wp.energyCounterTotal or 0) rtData["evModeOG"] = chrg.mode rtData["p_l1evOG"] = chrg.p_l1ev rtData["p_l2evOG"] = chrg.p_l2ev rtData["p_l3evOG"] = chrg.p_l3ev rtData["evPowerOG"] = chrg.p_l1ev + chrg.p_l2ev + chrg.p_l3ev rtData["evPlugOG"] = chrg.connected rtData["wbogWh"] = chrg.eto rtData["heatMode"] = heat.mode rtData["t_buffT"] = heat.t_buffT rtData["t_buffM"] = heat.t_buffM rtData["t_buffB"] = heat.t_buffB rtData["t_heatVL"] = heat.t_heatVL rtData["t_heatRL"] = heat.t_heatRL rtData["t_gasVLu"] = heat.t_gasVLu rtData["t_gasVLo"] = heat.t_gasVLo rtData["t_gasRL"] = heat.t_gasRL rtData["t_fbVL"] = heat.t_fbVL rtData["t_fbRL"] = heat.t_fbRL rtData["t_triac"] = heat.t_triac rtData["pHeat"] = heat.p_heat rtData["P_Load"] = -(rtData["P_AC"] + rtData["P_Grid"])# + rtData["P_Akku"]) if(-rtData["P_Load"] < -rtData["og"] + rtData["eg"] + rtData["ug"] + rtData["pHeat"] ): #if Pload is less than combined consumption, there is a measurement error-- assume Pload still a little more than consumption to leave some common consumption rtData["P_Load"] = -(-rtData["og"] + rtData["eg"] + rtData["ug"] + rtData["pHeat"])-50 if rtData["P_Grid"] > 0 and rtData["P_Load"] < 0: rtData["autarky"] = 100 + 100*(rtData["P_Grid"]/rtData["P_Load"]) #load is negative if rtData["autarky"] > 100: rtData["autarky"] = 100 if rtData["autarky"] < 0: rtData["autarky"] = 0 else: rtData["autarky"] = 100 try: for key in avgData: if isinstance(avgData[key],float): avgData[key] += rtData[key] invErrAcc |= rtData["invErr"] # Bits sammeln, nicht mitteln avgCounter = avgCounter+1 except: _LOGGER.error("data average failed!") except Exception as e: _LOGGER.error(e) _LOGGER.error("rtdata fill failed!") if round(time.time()) >= next_dbEntry: next_dbEntry = next_dbEntry + 300 water=await gatherWaterData.getWaterData() rtData["waterHeight"] = water.waterHeight rtData["waterTemp"] = water.temp if avgCounter: for key in avgData: if isinstance(avgData[key],float): avgData[key] /= avgCounter #_LOGGER.info("DB-OUTPUT!!") if(-avgData["P_Load"] < (-avgData["p_l1og"] - avgData["p_l2og"] - avgData["p_l3og"] + avgData["p_l1ev"] + avgData["p_l2ev"] + avgData["p_l3ev"] + avgData["p_l1evOG"] + avgData["p_l2evOG"] + avgData["p_l3evOG"] + avgData["pHeat"])): #null heater consumption, if total consumption is too small so it would result in negative UG consumption avgData["pHeat"] = -avgData["P_Load"] - (-avgData["p_l1og"] - avgData["p_l2og"] - avgData["p_l3og"]) - 300; #reduce heater consumption in case PPV power is not gathered correctly if(-avgData["P_Load"] < (-avgData["p_l1og"] - avgData["p_l2og"] - avgData["p_l3og"] + avgData["p_l1ev"] + avgData["p_l2ev"] + avgData["p_l3ev"] + avgData["p_l1evOG"] + avgData["p_l2evOG"] + avgData["p_l3evOG"] + avgData["pHeat"])): #null car consumption, of total consumption is too small so it would result in negative UG consumption avgData["p_l1ev"] = 0 avgData["p_l2ev"] = 0 avgData["p_l3ev"] = 0 avgData["p_l1evOG"] = 0 avgData["p_l2evOG"] = 0 avgData["p_l3evOG"] = 0 if(avgData["pHeat"] < 0): #when we reduced too much from heater, there must have been more PV power available (inverters didn't report production) avgData["P_PV"] = avgData["P_PV"] - avgData["pHeat"] avgData["pHeat"] = 0 if avgData["P_Load"] > 0 or -avgData["P_Load"] < -avgData["og"] + avgData["p_l2ev"] + avgData["p_l3ev"] + avgData["p_l1evOG"] + avgData["p_l2evOG"] + avgData["p_l3evOG"] + avgData["pHeat"]: #if load is not negative something is wrong avgData["P_Load"] = -(avgData["P_PV"] + avgData["P_Akku"]) + 20 #try to recalculate real consumption from corrected PV production if avgData["P_Load"] > 0 or -avgData["P_Load"] < -avgData["og"] + avgData["p_l2ev"] + avgData["p_l3ev"] + avgData["p_l1evOG"] + avgData["p_l2evOG"] + avgData["p_l3evOG"] + avgData["pHeat"]: #if the correction still is not matching assume zero consumption for UG for smallest error avgData["P_Load"] = -(-avgData["og"] + avgData["p_l2ev"] + avgData["p_l3ev"] + avgData["p_l1evOG"] + avgData["p_l2evOG"] + avgData["p_l3evOG"] + avgData["pHeat"]) try: with connect( host=mysqlHost, port=mysqlPort, user=mysqlUser, password=mysqlPW, database=mysqlDB, ) as connection: query = ("INSERT INTO EnergyFlow (datetime, " "totalConsumption, soc, battP, " "pvP, autonomy, gridP, " "gridPcons, gridPfeed, " "battI, battU, battTemp, " "IL1_EVU, IL2_EVU, IL3_EVU, " "IL1_OG, IL2_OG, IL3_OG, " "PL1_EVU, PL2_EVU, PL3_EVU, " "PL1_OG, PL2_OG, PL3_OG, " "PL1_EG, PL2_EG, PL3_EG, " "PL1_UG, PL2_UG, PL3_UG, " "PL1_EV, PL2_EV, PL3_EV, " "PL1_EVog, PL2_EVog, PL3_EVog, " "HeizungOG, HeizungEG, heaterPwr, " "invErr, pvP_est) VALUES (" "NOW()," +str(avgData["P_Load"])+","+str(avgData["SOC"])+","+str(avgData["P_Akku"])+"," +str(avgData["P_PV"])+","+str(avgData["autarky"])+","+str(avgData["P_Grid"])+"," +str(avgData["P_GridCons"])+","+str(avgData["P_GridFeed"])+"," +str(avgData["ibatt"])+","+str(avgData["ubatt"])+","+str(avgData["tbatt"])+"," +str(avgData["i_l1evu"])+","+str(avgData["i_l2evu"])+","+str(avgData["i_l3evu"])+"," +str(avgData["i_l1og"])+","+str(avgData["i_l2og"])+","+str(avgData["i_l3og"])+"," +str(avgData["p_l1evu"])+","+str(avgData["p_l2evu"])+","+str(avgData["p_l3evu"])+"," +str(avgData["p_l1og"])+","+str(avgData["p_l2og"])+","+str(avgData["p_l3og"])+"," +str(avgData["p_l1eg"])+","+str(avgData["p_l2eg"])+","+str(avgData["p_l3eg"])+"," +str(avgData["p_l1ug"])+","+str(avgData["p_l2ug"])+","+str(avgData["p_l3ug"])+"," +str(avgData["p_l1ev"])+","+str(avgData["p_l2ev"])+","+str(avgData["p_l3ev"])+"," +str(avgData["p_l1evOG"])+","+str(avgData["p_l2evOG"])+","+str(avgData["p_l3evOG"])+"," +str(0)+","+str(0)+","+str(avgData["pHeat"])+"," +str(invErrAcc)+","+str(avgData["P_PV_est"])+");") with connection.cursor() as cursor: cursor.execute(query) connection.commit() newDay = datetime.datetime.now() + datetime.timedelta(hours=24-6) #run this at 6 o'clock if(newDay.strftime('%d') != lastDay.strftime('%d')): lastDay = newDay sunrise = sun.get_sunrise_time(newDay,tz.gettz('Europe/Berlin')) #tz.gettz('Europe/Kaliningrad') tz.gettz('Europe/Berlin') sunset = sun.get_sunset_time(newDay,tz.gettz('Europe/Berlin')) if(is_summer_time(sunrise) == False): sunrise = sunrise + datetime.timedelta(hours=1) #_LOGGER.info("Wintertime!!") if(is_summer_time(sunset) == False): sunset = sunset + datetime.timedelta(hours=1) #_LOGGER.info(str(sunrise.strftime('%H:%M:%S'))) query = "REPLACE INTO daylight (date, sunrise, sunset) VALUES (CURDATE()+1, '"+str(sunrise.strftime('%H:%M:%S'))+"', '"+str(sunset.strftime('%H:%M:%S'))+"');" with connection.cursor() as cursor: cursor.execute(query) connection.commit() query = "SELECT SUM(power)/2 AS estProd FROM simPower WHERE DATE(period_end) = DATE(NOW());" with connection.cursor() as cursor: cursor.execute(query) myresult = cursor.fetchone() connection.commit() estProduction = myresult[0] except Error as e: _LOGGER.error(e) for key in avgData: if isinstance(avgData[key],float): avgData[key] = 0.0 avgCounter = 0 invErrAcc = 0 #if(rtData["SOC"] > 70.0): #await charger_goE.setPVparameters((rtData["P_Grid"]+rtData["P_Akku"])+(4000*(100-rtData["SOC"])/100),rtData["P_PV"]+rtData["P_PV2"]+rtData["P_PV3"],0) #else: #await charger_goE.setPVparameters(500,0,0) #if(chrg.mode == "eco" and avgCounter == 5): # await charger_goE.setChargePower(rtData["P_PV"],chrg.Phase_set_ev,chrg.Iset_ev,chrg.AllowCharging_ev) #print(json.dumps(rtData)) publishData = json.dumps(rtData, cls=EnhancedJSONEncoder) webSocketServer.message_all(publishData) mqttClient.publish(rtData) if(rtData["SOC"] > 70.0): chrgCons = (rtData["P_Grid"]+rtData["P_Akku"])+(4000*(100-rtData["SOC"])/100) pv_ges = rtData["P_PV"] await charger_goE.setPVparameters(chrgCons,pv_ges,0) #_LOGGER.error(f"goE Parameters Sent PV") else: await charger_goE.setPVparameters(500,0,0) #_LOGGER.error(f"goE Parameters Sent") async def main(): await webSocketServer.serveWebSocket() await asyncio.gather( repeat(3) ) await webSocketServer.closeWebSocket() loop = asyncio.get_event_loop() loop.run_until_complete(main())