Neurio (Tesla Powerwall): Phasenströme = 0 A – warum keine Berechnung aus P/Q/U (Schieflast)?

Fragen zur Nutzung, Features, usw..
Antworten
nicop
Beiträge: 47
Registriert: Sa Dez 03, 2022 7:46 pm
Has thanked: 1 time

Neurio (Tesla Powerwall): Phasenströme = 0 A – warum keine Berechnung aus P/Q/U (Schieflast)?

Beitrag von nicop »

Hallo zusammen,

ich habe eine Verständnisfrage zum Lastmanagement am Hausübergabepunkt in openWB.

Setup kurz:
  • openWB 2
  • HÜP über Tesla Powerwall 2 / Neurio W2
Anbindung getestet über
  • neurio_w2_mb (RS-485)
  • neurio_w2_tcp (lokale Gateway-API, LAN)
Lastmanagement mit phasenspezifischen Stromlimits (L1–L3)

Beobachtung:
Der Neurio liefert zuverlässig:
  • Spannung je Phase
  • Wirkleistung + Blindleistung je Phase
Die Stromwerte sind jedoch immer:
  • i_a_current / i_b_current / i_c_current = 0
In der Tesla One App sind die Phasenströme sichtbar, werden aber über die lokale API nicht exportiert.

Auswirkung in openWB:
  • Phasenbasierte Strombegrenzung greift nicht
  • Schieflast-Erkennung/-Begrenzung kann so ebenfalls nicht korrekt arbeiten
  • Begrenzung über max. Leistung (kW) funktioniert, ist aber nicht phasengenau
Frage:
Da pro Phase P, Q und U bekannt sind, ließe sich der Strom sehr gut näherungsweise berechnen:

Code: Alles auswählen

S = √(P² + Q²)
I ≈ S / U
Gibt es einen bewussten Grund, warum openWB diese Berechnung nicht nutzt, wenn gemessene Ströme 0 sind?
(z. B. Genauigkeit, Designentscheidung, Vermeidung von Fehlregelungen?)

Gerade im Hinblick auf Schieflast wäre eine solche Näherung m. E. besser als „0 A je Phase“.

Vielen Dank für eine kurze Einordnung!
Viele Grüße
Nico
openWB
Site Admin
Beiträge: 9862
Registriert: So Okt 07, 2018 1:50 pm
Has thanked: 116 times
Been thanked: 280 times

Re: Neurio (Tesla Powerwall): Phasenströme = 0 A – warum keine Berechnung aus P/Q/U (Schieflast)?

Beitrag von openWB »

Der Code zum PW Modul, bzw. der EVU Auslesung ist hier:
https://github.com/openWB/core/blob/mas ... counter.py

Demnach gibt es grundsätzlich den current je Phase. Scheinbar aber nicht bei allen.
Wieviele das betrifft (außer dir) kann ich nicht sagen.

Denkbar wäre eine Erweiterung die bei nicht vorhandenen Currents P/V rechnet.
Kommt P denn positiv und negativ an?
Supportanfragen bitte NICHT per PN stellen.
Hardwareprobleme bitte über die Funktion Debug Daten senden mitteilen oder per Mail an support@openwb.de
nicop
Beiträge: 47
Registriert: Sa Dez 03, 2022 7:46 pm
Has thanked: 1 time

Re: Neurio (Tesla Powerwall): Phasenströme = 0 A – warum keine Berechnung aus P/Q/U (Schieflast)?

Beitrag von nicop »

Ja, P kommt sowohl positiv als auch negativ an.

In den Neurio-Daten (Tesla Powerwall 2, lokal im LAN) werden pro Phase geliefert:
  • real_power_a / b / c → Wirkleistung mit Vorzeichen
    • positiv = Netzbezug / Verbraucher
    • negativ = Einspeisung
  • zusätzlich:
    • reactive_power_a / b / c
    • v_l1n / v_l2n / v_l3n
Die Vorzeichen sind konsistent und ändern sich korrekt bei Bezug ↔ Einspeisung.
nicop
Beiträge: 47
Registriert: Sa Dez 03, 2022 7:46 pm
Has thanked: 1 time

Re: Neurio (Tesla Powerwall): Phasenströme = 0 A – warum keine Berechnung aus P/Q/U (Schieflast)?

Beitrag von nicop »

Ich habe anhand des von dir verlinkten Codes die Änderungen eingearbeitet und bei mir getestet... es hat mich einfach genervt, dass ich kein echtes phasengenaues Lastmanagement hatte!

Im Details sind folgende Änderungen eingearbeitet:
  • Wenn alle Phasenströme 0 sind und P/Q/U vorliegen, die Ströme berechnen
  • Leistungsfaktor wird berechnet: cosφ = P / S

Das Ergebnis in Verbindung einer Tesla Powerwall mit einer OpenWB:
  • Plausible Phasenströme (Abweichung zu Tesla One ~0,03–0,05 A)
  • Lastmanagement & Schieflast funktionieren korrekt
  • Keine Änderung für Setups mit echten Stromwerten (greift nur bei I = 0)

Spricht aus eurer Sicht etwas dagegen, diese Logik in den Trunk aufzunehmen? Und könnte dies ggf. jemand übernehmen. Ich möchte mich nicht in eurer Github einarbeiten...

Anbei der überarbeitete Code der counter.py:

Code: Alles auswählen

#!/usr/bin/env python3
import logging
import math
from requests import HTTPError

from modules.common.abstract_device import AbstractCounter
from modules.common.component_state import CounterState
from modules.common.component_type import ComponentDescriptor
from modules.common.fault_state import ComponentInfo, FaultState
from modules.common.store import get_counter_value_store
from modules.devices.tesla.tesla.config import TeslaCounterSetup
from modules.devices.tesla.tesla.http_client import PowerwallHttpClient

log = logging.getLogger(__name__)


class TeslaCounter(AbstractCounter):
    def __init__(self, component_config: TeslaCounterSetup) -> None:
        self.component_config = component_config

    def initialize(self) -> None:
        self.store = get_counter_value_store(self.component_config.id)
        self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config))

    def update(self, client: PowerwallHttpClient, aggregate):
        # read firmware version
        status = client.get_json("/api/status")
        log.debug('Firmware: ' + status.get("version", "unknown"))

        try:
            # read additional info if firmware supports
            meters_site = client.get_json("/api/meters/site")
            cached = meters_site[0]["Cached_readings"]

            # per-phase voltages and active powers
            voltages = [float(cached["v_l" + str(phase) + "n"]) for phase in range(1, 4)]
            powers = [float(cached["real_power_" + phase]) for phase in ["a", "b", "c"]]

            # reactive power may be missing in some firmwares
            reactive = []
            for phase in ["a", "b", "c"]:
                q = cached.get("reactive_power_" + phase)
                try:
                    reactive.append(float(q) if q is not None else None)
                except (TypeError, ValueError):
                    reactive.append(None)

            # currents from API (often 0 for Neurio in some Tesla firmwares)
            currents = []
            for phase in ["a", "b", "c"]:
                i = cached.get("i_" + phase + "_current", 0)
                try:
                    currents.append(float(i) if i is not None else 0.0)
                except (TypeError, ValueError):
                    currents.append(0.0)

            # --- calculate power factors per phase (PF = P / S) ---
            # S = sqrt(P^2 + Q^2); if Q missing -> assume Q=0 => S=abs(P)
            power_factors = []
            for p, q in zip(powers, reactive):
                s = math.hypot(p, q) if q is not None else abs(p)
                pf = (p / s) if s > 1e-6 else 0.0

                # If you want PF always positive (0..1), use:
                # pf = abs(pf)

                power_factors.append(pf)

            # --- if currents are missing (all 0), calculate them from P/Q/U ---
            if all(abs(i) < 1e-3 for i in currents):
                calc_currents = []
                for p, u, q in zip(powers, voltages, reactive):
                    if u <= 1e-6:
                        calc_currents.append(0.0)
                        continue

                    s = math.hypot(p, q) if q is not None else abs(p)
                    i = (s / u) if s > 0 else 0.0

                    # Keep direction consistent with P (import +, export -)
                    if p < 0:
                        i = -abs(i)
                    else:
                        i = abs(i)

                    calc_currents.append(i)

                if any(abs(i) > 1e-3 for i in calc_currents):
                    currents = calc_currents
                    log.debug(
                        "Tesla/Neurio phase currents missing (all 0). Calculated currents from P/Q and U."
                    )

            powerwall_state = CounterState(
                imported=aggregate["site"]["energy_imported"],
                exported=aggregate["site"]["energy_exported"],
                power=aggregate["site"]["instant_power"],
                voltages=voltages,
                currents=currents,
                powers=powers,
                power_factors=power_factors,
            )

        except (KeyError, HTTPError, IndexError, TypeError, ValueError):
            log.debug("Firmware seems not to provide detailed phase measurements. Fallback to total power only.")
            powerwall_state = CounterState(
                imported=aggregate["site"]["energy_imported"],
                exported=aggregate["site"]["energy_exported"],
                power=aggregate["site"]["instant_power"],
            )

        self.store.set(powerwall_state)


component_descriptor = ComponentDescriptor(configuration_factory=TeslaCounterSetup)
Anbei noch ein Screenshot des Ergebnis:
Unbenannt.png
Unbenannt.png (18.5 KiB) 23 mal betrachtet
Vielen Dank und viele Grüße

NicoP.
openWB
Site Admin
Beiträge: 9862
Registriert: So Okt 07, 2018 1:50 pm
Has thanked: 116 times
Been thanked: 280 times

Re: Neurio (Tesla Powerwall): Phasenströme = 0 A – warum keine Berechnung aus P/Q/U (Schieflast)?

Beitrag von openWB »

Danke Nico, du kannst gerne einen PR bei GitHub stellen.
Supportanfragen bitte NICHT per PN stellen.
Hardwareprobleme bitte über die Funktion Debug Daten senden mitteilen oder per Mail an support@openwb.de
nicop
Beiträge: 47
Registriert: Sa Dez 03, 2022 7:46 pm
Has thanked: 1 time

Re: Neurio (Tesla Powerwall): Phasenströme = 0 A – warum keine Berechnung aus P/Q/U (Schieflast)?

Beitrag von nicop »

Hi, könnt ihr das nicht übernehmen?
Antworten