Exemple #1
0
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")
Exemple #2
0
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)))
Exemple #3
0
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")
Exemple #4
0
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))
Exemple #5
0
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")
Exemple #6
0
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")
Exemple #7
0
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))
Exemple #8
0
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))
Exemple #9
0
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")