import sunspec2.modbus.client as client import time import os from datetime import datetime import logging from constants import ( INVERTER_IP, INVERTER_PORT, TOPIC_PREFIX, windows_root, linux_root, daily_data_file, monthly_data_file, yearly_data_file ) from service_helpers import save_data_to_csv, get_energy_totals, connect_mqtt # Logging instellen voor foutopsporing logging.basicConfig(level=logging.INFO) logger = logging.getLogger("SolarEdgeService") class SolarEdgeReader: def __init__(self): self.daily_data_path = None self.monthly_data_path = None self.yearly_data_path = None def set_data_paths(self): jaar_str = datetime.now().strftime('%Y') if os.name == 'nt': data_root = f"{windows_root}\\{jaar_str}" else: data_root = f"{linux_root}/{jaar_str}" self.daily_data_path = os.path.join(data_root, daily_data_file) self.monthly_data_path = os.path.join(data_root, monthly_data_file) self.yearly_data_path = os.path.join(data_root, yearly_data_file) def get_current_energy_totals_from_solaredge_portal(self): daily_data, monthly_data, yearly_data = None, None, None try: vandaag = datetime.now().strftime('%Y-%m-%d') start_maand = datetime.now().strftime('%Y-%m-01') start_jaar = datetime.now().strftime('%Y-01-01') start_install = datetime.now().strftime('2017-01-01') daily_data = get_energy_totals('DAY', start_jaar, vandaag) if daily_data is not None: save_data_to_csv(self.daily_data_path, daily_data) monthly_data = get_energy_totals('MONTH', start_install, vandaag) if monthly_data is not None: save_data_to_csv(self.monthly_data_path, monthly_data) yearly_data = get_energy_totals('YEAR', start_install, vandaag) if yearly_data is not None: save_data_to_csv(self.yearly_data_path, yearly_data) except Exception as e: logger.error(f"Fout retrieving solaredge totals: {e}") return daily_data, monthly_data, yearly_data def read_and_publish(self): inv_device = None mqtt_client = connect_mqtt() # runs a thread in the background to call loop() automatically. # This frees up the main thread for other work that may be blocking. # This call also handles reconnecting to the broker. # Call loop_stop() to stop the background thread. start_energy_total_wh = None start_dag = None start_maand = None start_jaar = None current_date = datetime.now() prev_date = None dag_total = 0 month_total = 0 year_total = 0 laatste_check = None try: while True: try: huidige_datum = datetime.now().date() day_changed = laatste_check is None or huidige_datum > laatste_check # 1. Verbind met Inverter als dat nog niet is gebeurd if inv_device is None: logger.info("Verbinden met SolarEdge...") inv_device = client.SunSpecModbusClientDeviceTCP( slave_id=1, ipaddr=INVERTER_IP, ipport=INVERTER_PORT, timeout=5 ) inv_device.scan() # 2. Data lezen # Model 101/103 bevatten de inverter data # We zoeken dynamisch naar het juiste model itf = inv_device.inverter_single_phase[0] itf.read() # odict_keys(['ID', 'L', 'A', 'AphA', 'AphB', 'AphC', 'A_SF', 'PPVphAB', 'PPVphBC', 'PPVphCA', 'PhVphA', 'PhVphB', 'PhVphC', 'V_SF', 'W', 'W_SF', 'Hz', 'Hz_SF', 'VA', 'VA_SF', 'VAr', 'VAr_SF', 'PF', 'PF_SF', 'WH', 'WH_SF', 'DCA', 'DCA_SF', 'DCV', 'DCV_SF', 'DCW', 'DCW_SF', 'TmpCab', 'TmpSnk', 'TmpTrns', 'TmpOt', 'Tmp_SF', 'St', 'StVnd', 'Evt1', 'Evt2', 'EvtVnd1', 'EvtVnd2', 'EvtVnd3', 'EvtVnd4']) power_w = itf.W.get_value() / 100.0 energy_total_wh = itf.WH.get_value() /100.0 status = itf.St.get_value() if start_energy_total_wh is None or day_changed: self.set_data_paths() start_energy_total_wh = energy_total_wh logger.info("Retrieving totals from solaredge api") daily_data, monthly_data, yearly_data = self.get_current_energy_totals_from_solaredge_portal() start_dag = daily_data[-1].get('value', 0) start_maand = monthly_data[-1].get('value', 0) start_jaar = yearly_data[-1].get('value', 0) dag_total = start_dag month_total = start_maand year_total = start_jaar laatste_check = huidige_datum else: delta_energy_total_wh_dag = energy_total_wh - start_energy_total_wh dag_total = start_dag + delta_energy_total_wh_dag month_total = start_maand + delta_energy_total_wh_dag year_total = start_jaar + delta_energy_total_wh_dag logger.info(f"dag_totaal={dag_total/1000.0}kWh, month_total={month_total/1000.0}kWh, year_total={year_total/1000.0}kWh") # 3. Publiceren naar MQTT if mqtt_client: mqtt_client.publish(f"{TOPIC_PREFIX}/power", power_w) mqtt_client.publish(f"{TOPIC_PREFIX}/total_day_kwh", dag_total/1000.0) mqtt_client.publish(f"{TOPIC_PREFIX}/total_month_kwh", month_total / 1000.0) mqtt_client.publish(f"{TOPIC_PREFIX}/total_year_kwh", year_total / 1000.0) mqtt_client.publish(f"{TOPIC_PREFIX}/total_energy_kWh", energy_total_wh/1000.0) mqtt_client.publish(f"{TOPIC_PREFIX}/status", status) logger.info(f"Update verzonden: Current power: {power_w}W total_day_kwh: {dag_total/1000.0}kWh status: {status}") else: mqtt_client = connect_mqtt() # Herstel MQTT verbinding except Exception as e: logger.error(f"Fout tijdens uitlezen: {e}") # Forceer nieuwe verbinding bij de volgende poging if inv_device: inv_device.close() inv_device = None time.sleep(5) # Korte pauze bij fout om CPU te sparen time.sleep(15) # Wacht 15 seconden voor de volgende update finally: if mqtt_client: mqtt_client.loop_stop() if __name__ == "__main__": reader = SolarEdgeReader() reader.read_and_publish()