def update(ipaddress: str): log.debug("Beginning update") client = ModbusClient(ipaddress, port=502) #40074 EVU Punkt negativ -> Einspeisung in Watt power_all = client.read_holding_registers(40073, ModbusDataType.INT_32, wordorder=Endian.Little, unit=1) #40130 Phasenleistung in Watt # max 6 Leistungsmesser verbaut ab 410105, typ 1 ist evu # bei den meisten e3dc auf 40128 #for i in range (40104,40132,4): for i in range(40128, 40103, -4): #powers = client.read_holding_registers(40129, [ModbusDataType.INT_16] * 3, unit=1) powers = client.read_holding_registers(i, [ModbusDataType.INT_16] * 4, unit=1) log.debug("I: %d, p[0] typ %d p[1] a1 %d p[2] a2 %d p[3] a3 %d", i, powers[0], powers[1], powers[2], powers[3]) if powers[0] == 1: log.debug("Evu Leistungsmessung gefunden") break counter_import, counter_export = SimCountFactory().get_sim_counter()( ).sim_count(power_all, prefix="bezug") get_counter_value_store(1).set( CounterState(imported=counter_import, exported=counter_export, power=power_all, powers=powers[1:])) log.debug("Update completed successfully")
def update_solaredge_battery(client: ModbusClient, slave_ids: Iterable[int]): all_socs = [client.read_holding_registers( 62852, ModbusDataType.FLOAT_32, wordorder=Endian.Little, unit=slave_id ) for slave_id in slave_ids] storage_powers = [ client.read_holding_registers( 62836, ModbusDataType.FLOAT_32, wordorder=Endian.Little, unit=slave_id ) for slave_id in slave_ids ] log.debug("Battery SoCs=%s, powers=%s", all_socs, storage_powers) get_bat_value_store(1).set(BatState(power=sum(storage_powers), soc=mean(all_socs)))
def update(ipaddress: str, modbusport: int, slaveid: int): log.debug("Beginning update") client = ModbusClient(ipaddress, port=modbusport) def read_scaled_int16(address: int, count: int): return scale_registers( client.read_holding_registers(address, [ModbusDataType.INT_16] * (count + 1), unit=slaveid)) # 40206: Total Real Power (sum of active phases) # 40206/40207/40208: Real Power by phase # 40210: AC Real Power Scale Factor powers = [-power for power in read_scaled_int16(40206, 4)] # 40191/40192/40193: AC Current by phase # 40194: AC Current Scale Factor currents = read_scaled_int16(40191, 3) # 40196/40197/40198: Voltage per phase # 40203: AC Voltage Scale Factor voltages = read_scaled_int16(40196, 7)[:3] # 40204: AC Frequency # 40205: AC Frequency Scale Factor frequency, = read_scaled_int16(40204, 1) # 40222/40223/40224: Power factor by phase (unit=%) # 40225: AC Power Factor Scale Factor power_factors = [ power_factor / 100 for power_factor in read_scaled_int16(40222, 3) ] # 40234: Total Imported Real Energy counter_imported = client.read_holding_registers(40234, ModbusDataType.UINT_32, unit=slaveid) # 40226: Total Exported Real Energy counter_exported = client.read_holding_registers(40226, ModbusDataType.UINT_32, unit=slaveid) get_counter_value_store(1).set( CounterState(imported=counter_imported, exported=counter_exported, power=powers[0], powers=powers[1:], voltages=voltages, currents=currents, power_factors=power_factors, frequency=frequency)) log.debug("Update completed successfully")
def update_sma_modbus(addresses: Iterable[str]): power_total = 0 energy_total = 0 for ipaddress in addresses: with ModbusClient(ipaddress) as client: # AC Wirkleistung über alle Phasen (W) [Pac]: power = client.read_holding_registers(30775, ModbusDataType.INT_32, unit=3) # Gesamtertrag (Wh) [E-Total]: energy = client.read_holding_registers(30529, ModbusDataType.UINT_32, unit=3) log.debug("%s: power = %d W, energy = %d Wh", ipaddress, power, energy) if power == SMA_INT32_NAN: log.debug("Power value is NaN - ignoring") else: power_total += power energy_total += energy power_total = -max(power_total, 0) get_inverter_value_store(1).set( InverterState(counter=energy_total, power=power_total))
def update(address: str, second_battery: int): # `second_battery` is 0 or 1 log.debug("Beginning update") bat_info = ComponentInfo(None, "Solaredge", "bat") with SingleComponentUpdateContext(bat_info): with ModbusClient(address) as client: update_solaredge_battery(client, range(1, 2 + second_battery)) log.debug("Update completed successfully")
def update(ipaddress: str, slave_id0: str, slave_id1: str, slave_id2: str, slave_id3: str, batwrsame: int, extprodakt: int, zweiterspeicher: int, subbat: int): log.debug("Beginning update") with ModbusClient(ipaddress) as client: update_solar_edge( client, list( map( int, filter(lambda id: id.isnumeric(), [slave_id0, slave_id1, slave_id2, slave_id3]))), batwrsame, extprodakt, zweiterspeicher, subbat) log.debug("Update completed successfully")
def update_e3dc_battery(addresses: Iterable[str], read_external: int, pv_other: bool): soc = 0 count = 0 battery_power = 0 # pv_external - > pv Leistung die als externe Produktion an e3dc angeschlossen ist # nur auslesen wenn als relevant parametrisiert (read_external = 1) , sonst doppelte Auslesung pv_external = 0 # pv -> pv Leistung die direkt an e3dc angeschlossen ist pv = 0 for address in addresses: log.debug("Battery Ip: %s, read_external %d pv_other %s", address, read_external, pv_other) count += 1 with ModbusClient(address, port=502) as client: # 40082 SoC soc += client.read_holding_registers(40082, ModbusDataType.INT_16, unit=1) # 40069 Speicherleistung battery_power += client.read_holding_registers(40069, ModbusDataType.INT_32, wordorder=Endian.Little, unit=1) # 40067 PV Leistung pv += (client.read_holding_registers(40067, ModbusDataType.INT_32, wordorder=Endian.Little, unit=1) * -1) if read_external == 1: # 40075 externe PV Leistung pv_external += client.read_holding_registers(40075, ModbusDataType.INT_32, wordorder=Endian.Little, unit=1) soc = soc / count log.debug("Battery soc %d battery_power %d pv %d pv_external %d count ip %d", soc, battery_power, pv, pv_external, count) counter_import, counter_export = SimCountFactory().get_sim_counter()().sim_count(battery_power, prefix="speicher") get_bat_value_store(1).set(BatState(power=battery_power, soc=soc, imported=counter_import, exported=counter_export)) # pv_other sagt aus, ob WR definiert ist, und dessen PV Leistung auch gilt # wenn 0 gilt nur PV und pv_external aus e3dc pv_total = pv + pv_external # Wenn wr1 nicht definiert ist, gilt nur die PV Leistung die hier im Modul ermittelt wurde # als gesamte PV Leistung für wr1 if not pv_other or pv_total != 0: # Wenn wr1 definiert ist, gilt die bestehende PV Leistung aus Wr1 und das was hier im Modul ermittelt wurde # als gesamte PV Leistung für wr1 if pv_other: try: pv_total = pv_total + files.pv[0].power.read() except: pass log.debug("wr update pv_other %s pv_total %d", pv_other, pv_total) _, counter_pv = SimCountFactory().get_sim_counter()().sim_count(pv_total, prefix="pv") get_inverter_value_store(1).set(InverterState(counter=counter_pv, power=pv_total))
def update_solar_edge(client: ModbusClient, slave_ids: List[int], batwrsame: int, extprodakt: int, zweiterspeicher: int, subbat: int): storage_slave_ids = slave_ids[0:1 + zweiterspeicher] storage_powers = [] if batwrsame == 1: all_socs = [ client.read_holding_registers(62852, ModbusDataType.FLOAT_32, wordorder=Endian.Little, unit=slave_id) for slave_id in storage_slave_ids ] storage_powers = [ client.read_holding_registers(62836, ModbusDataType.FLOAT_32, wordorder=Endian.Little, unit=slave_id) for slave_id in storage_slave_ids ] log.debug("Battery SoCs=%s, powers=%s", all_socs, storage_powers) get_bat_value_store(1).set( BatState(power=sum(storage_powers), soc=mean(all_socs))) total_energy = 0 total_power = 0 total_currents = [0, 0, 0] for slave_id in slave_ids: # 40083 = AC Power value (Watt), 40084 = AC Power scale factor power_base, power_scale = client.read_holding_registers( 40083, [ModbusDataType.INT_16] * 2, unit=slave_id) total_power -= power_base * math.pow(10, power_scale) # 40093 = AC Lifetime Energy production (Watt hours) energy_base, energy_scale = client.read_holding_registers( 40093, [ModbusDataType.UINT_32, ModbusDataType.INT_16], unit=slave_id) # 40072/40073/40074 = AC Phase A/B/C Current value (Amps) # 40075 = AC Current scale factor currents = client.read_holding_registers( 40072, [ModbusDataType.UINT_16] * 3 + [ModbusDataType.INT_16], unit=slave_id) # Registers that are not applicable to a meter class return the unsupported value. (e.g. Single Phase # meters will support only summary and phase A values): for i in range(3): if currents[i] == UINT16_UNSUPPORTED: currents[i] = 0 log.debug( "slave=%d: power=%d*10^%d, energy=%d*10^%d, currents=%s * 10^%d", slave_id, power_base, power_scale, energy_base, energy_scale, currents[0:3], currents[3]) total_energy += energy_base * math.pow(10, energy_scale) currents_scale = math.pow(10, currents[3]) for i in range(3): total_currents[i] += currents[i] * currents_scale if extprodakt == 1: # 40380 = "Meter 2/Total Real Power (sum of active phases)" (Watt) try: total_power -= client.read_holding_registers(40380, ModbusDataType.INT_16, unit=slave_ids[0]) except Exception: # catch wrong configured "extprodakt" log.error( "Unable to read secondary SmartMeter! Check configuration!") if subbat == 1: total_power -= sum(min(p, 0) for p in storage_powers) else: total_power -= sum(storage_powers) get_inverter_value_store(1).set( InverterState(counter=total_energy, power=min(0, total_power), currents=total_currents))
def main(address: str, second_battery: int): # `second_battery` is 0 or 1 log.debug("Beginning update") with ModbusClient(address) as client: update_solaredge_battery(client, range(1, 2 + second_battery)) log.debug("Update completed successfully")