Kostal Piko 10 ins HA integrieren

Hallo Freunde,

hat jemand von Euch evtl. den alten Wechselrichter Kostal Piko 10 ins HA integriert?
Habe einiges in der Comunity gefunden, nur übersteigt die Komplexität meine Fähigkeiten:
Kostal PIKO und Kostal PIKO IQ Support

und direkt zur Entwickung: Kostal Piko 10 BA - Custom Sensor

Scheint nicht unbedingt sehr einfach.
Gibt es Erfahrungen?

Danke und VG
Alex
PS im Kostal Portal gibt es keinerlei Hinweise auf API oder desgleichen.
Die GitHub zeigt die Anbindungsmöglichkeit ab Piko 12

Hallo in die Runde,

heute mein erster Versuch, meine PV Anlage, vertreten durch Wechselrichter Kostal Piko 10 ins HA zu integrieren.

Es hat soweit alles geklappt, nur habe ich das Problem, die dadurch entstandene Sensoren zu lesen, bzw. die Sensoren den eigentlichen Funktionen im Kostal-Portal zuzuordnen. Keine Ahnung, wie diese Funktionen in die Sensoren umgewandelt werden.

Eigentlich wollte ich versuchen, so was umzusetzen:


Außer dem grünen Strom.

Also gesucht wird:
Verbrauch Haus total
Verbrauch aus Solar
Verbrauch aus dem Netz
Einspeisung

Ich habe hin und her gerechnet, ich komme nicht auf die Werte.

Zum Schluss habe ich exakt um 19 Uhr die Sensoren aktualisiert und Bild gemacht. Im Kostal Portal habe ich die um 19Uhr aufgezeichnete Werte aufgenommen (Das Diagramm rechts). Ich kann nicht nachvollziehen, wie diese zusammen kommen.

Was klar ist:
um 19 Uhr haben die Sensoren
den Netzbezug 3709,9W
und Solarbezug 838,2W registriert

Im Diagramm rechts: Hausverbrauch=Netzbezug + Direktverbrauch (Solar)
Einspeisung = Überschuss, welches nicht verbraucht werden konnte.
Warum um 19Uhr Netzbezug bei der stattfinden Einspeisung erfolgt bleibt mir verborgen.

Hat Jemand von Euch mit Kostal-Sensoren rumgespielt und kann mir helfen?

Das Kostalportal liefert nur Tageswerte, keine momentanen.

Danke

Moin Zusammen,

mit Hilfe von KI habe ich folgende Logik raugefunden (kursiv sind die Sensoren, die vorhanden sind):

  • Täglicher Gesamtverbrauch des Hauses:

Piko Daily Home Consumption=Piko Daily Self Consumption+Täglicher Netzbezug

  • Täglicher Netzbezug (was Sie suchten):

Täglicher Netzbezug=Piko Daily Home ConsumptionPiko Daily Self Consumption

(Dies setzt voraus, dass Sie die integrierten Tageswerte für Home Consumption und Self Consumption haben.)

  • Tägliche Netzeinspeisung:

Tägliche Netzeinspeisung=Piko Daily YieldPiko Daily Self Consumption

Für den täglichen Netzbezug habe ich wiederum mit Hilfe von Gemini den Template-Sensor erstellt:

template:
  - sensor:
      - name: "Piko Täglicher Netzbezug"
        unit_of_measurement: "Wh"
        device_class: energy
        state_class: total_increasing
        state: >
          {{ (states('sensor.piko_daily_home_consumption') | float(0)) - (states('sensor.piko_daily_self_consumption') | float(0)) }}

Es gibt auch einen Wert aus, welches rechnerisch stimmt (mal gerundet. mal nicht):

Leider wird dieser Sensor von der Energiekarte nicht erkannt:

Wo könnte der Fehler liegen?

Hallo,
ich kenn mich leider noch nicht wirklich aus, aber hast du deinen Sensor auch in der “/homeassistant/configuration.yaml”?

Hi, nein, ist er nicht. Ich habe ihn über die GU erstellt in der Hoffnung dass es richtig ist.
Muss er in Configuration.yaml auftauchen? Wenn ja, soll ich ihn manuell dort eintragen oder wie? Und was erzwinge ich dann damit?
Vielleicht ist Template falsch?

Wie gesagt, ich hab leider kaum Ahnung.
Aber ich habe alle meine Sensoren in der ‘Configuration.yaml’ und bekomme die dann auch in der Energiekarte angezeigt und kann die dort verwenden.

Ich bin zwar auch nicht der “Auskenner”, aber mE fehlt da die Einheit (also Watt) damit es im Energiedashboard ausgewählt werden kann.Und Wh wäre auch falsch, es sind Watt (W),


Habe nun auf W umgestellt im Text und Einheit W ausgewählt. Da kommt das System damit auch nicht zurecht.
Warum ich Wh drin hatte ist, weil die Werte die ich voneinander abziehe auch Wh sind:

kannst Du bitte ein Bild davon machen wie es in Configuration.yaml aussieht?
Hast Du einfach einen Sensor als Helfer erstellt und dann Zusätzlich noch im Configuration.yaml oder nur dort und nicht über GU?

Für den täglichen Netzbezug/Einspeisung musst du deinen Stromzähler auslesen. Ich habe einen EcoTracker der das macht, da kommen folgende Werte als Bsp raus:
image
Und mein Fehler - das muss natürlich kWh heissen (nicht W)
Dann habe ich einen Helfer erstellt, der den täglichen Verbrauch errechnet.
Das ist ein “Verbrauchszähler” ,der täglich zurückgestellt wird (um Mitternacht). Damit könnte man auch einen wöchentlichen,monatlichen oder jährlichen Verbrauchszähler erstellen.
Entität ist hier dein Stromauslesegerät ,da dann der Bezug (aus dem Stromnetz),Zyklus der Zählerrückstellung ist täglich (bei Stromverbrauch/Einspeisung täglich).
Was hast du für einen Stromausleser?

ich bin nicht sicher was das ist, bzw. bis jetzt nicht gebraucht.
Ich habe Zweirichtungsstromzäler:


Ist es das Teil was über die zwei Pins die Stromdaten smart macht?
Alle Entitäten die ich habe kommen vom Wechselrichter direkt.
Ich befürchte, ich brauche hier etwas Support.

Ist es das Teil was über die zwei Pins die Stromdaten smart macht - Genau,bei mir ein Ecotracker (kannst ja mal googeln).
Damit liest man zB den Zählerstand des Netzbezugs/Einspeisung aus,daraus errechnet sich dann zB der tägliche Netzbezugs/Einspeisung.
Mir ist noch aufgefallen,das dein Template zu viele Zeilen enthält. Ich habe auch ein Templatesensor der wie folgt aussieht:


Der Multipliziert in meinem Fall Volt und Ampere - raus kommt Watt.
Der ganze obere Teil mit Template und. Sensor etc brauchst du nicht. Musst du solange löschen bis die Vorschau was anzeigt. Geräteklasse und Zustandsklasse noch auswählen.

Habe den Sensor umgeändert:

HA neu gestartet. Leider wird er immer noch nicht von Energieboard registriert.

Hast Du den Sensor auch in configuration.yaml zugefügt, wie von User 20011060 erwähnt?

Habe nun den Sensor in configuration.yaml zugefügt (von Gemini geschrieben),
leider mit dem selben Ergebnis, für Energieboard nicht sichtbar :grimacing:

    ####Sensor für den täglichen Netzbezug des Kostal Piko Wechselrichters#####
sensor:
  - platform: template
    sensors:
      beispiel_sensor:
        friendly_name: "Piko Täglicher Netzbezug"
        value_template: "{{ (states('sensor.piko_daily_home_consumption') | float(0)) - (states('sensor.piko_daily_self_consumption') | float(0)) }}"
        unit_of_measurement: "Wh"

Ich würde sagen da fehlt: device_class: entweder energy oder power


Und vor den Neustart die Konfiguration prüfen,die Konfiguration.yaml brauchst du zum Start - nicht das du die zerschießt.

    ####Sensor für den täglichen Netzbezug des Kostal Piko Wechselrichters#####
sensor:
  - platform: template
    sensors:
      beispiel_sensor:
        friendly_name: "Piko Täglicher Netzbezug"
        value_template: "{{ (states('sensor.piko_daily_home_consumption') | float(0)) - (states('sensor.piko_daily_self_consumption') | float(0)) }}"
        unit_of_measurement: "Wh"
        device_class: "energy"

Leider immer noch nicht sichtbar

Dann geht mir jetzt mein bescheidenes Wissen aus - jetzt sind Profis gefragt :disappointed:

Mein configuartion.yaml sieht unter ‘sensor:’ z.B. so aus.

sensor: 
  - platform: rest
    scan_interval: 30
    resource: "http://192.168.0.215/api/data/94141a80-67c4-11eb-8c13-675057e410ce.json?from=now&options=raw"
    name: "Energie Bezug"
    value_template: "{{ value_json.data.tuples[0][1] }}"
    unit_of_measurement: 'Wh'
    state_class: total
    device_class: energy
    unique_id: "0309 hier stehr was anderes..."

Den Eintrag für "ins Netz liefern und die beiden PV Wechselrichter sehen auch so aus…
Die Einträge mit “Energy” bekomme ich auch in Dashboard unter Energie angezeigt, die Ensoren mit Leistung werden dort nicht angezeigt.
Ich hab aber die Gesamtzählerwerte drinnen, keine täglichen Zähler…

Hi, wenn jemand Interesse hat, ich habe hier ein kleines python script:

import urllib.request
import json
import sys
import hashlib
import base64
import time

# --- KONFIGURATION ---
IP = "WECHSELRICHTER_IP"
TARGET_ID = 33556247
# HINWEIS: Wir verwenden das Passwort MIT Unterstrich, da der letzte korrekte Hash dazu passte.
PASS = "DEIN_PASSWORT" 
USER = "pvserver"
MODE = 1 # Anlagebetreiber (Passend zur Browser-Rolle)

print("--- KOSTAL HANDSHAKE SKRIPT V6 (Challenge-Response) ---")

# Wert holen
try:
    if len(sys.argv) > 1:
        target_value = int(float(sys.argv[1]))
    else:
        print("Fehler: Kein Wert übergeben")
        sys.exit(1)
except ValueError:
    print("Fehler: Wert ist keine Zahl")
    sys.exit(1)

# --- HELFER ---
headers = {
    "User-Agent": "Mozilla/5.0",
    "Referer": f"http://{IP}/",
    "Content-Type": "application/json",
    "Accept": "application/json"
}

# --- SCHRITT 1: SALT/CHALLENGE HOLEN (GET api/login.json) ---
url_pre_login = f"http://{IP}/api/login.json"
session_id = 0
salt = ""

print("1. Hole Challenge (Salt)...")

try:
    req = urllib.request.Request(url_pre_login, method='GET', headers=headers)
    with urllib.request.urlopen(req, timeout=5) as response:
        data = json.loads(response.read().decode())
        
        if "session" in data and "sessionId" in data["session"]:
            session_id = data["session"]["sessionId"]
            salt = data.get("salt", "")
            print(f"   -> Session erhalten: {session_id}, Salt: {salt[:8]}...")
        else:
            print("   -> FEHLER: Keine Session ID/Salt bekommen.")
            sys.exit(1)

except Exception as e:
    print(f"Verbindungsfehler Pre-Login: {e}")
    sys.exit(1)

# --- SCHRITT 2: HASH BERECHNEN & ANMELDEN (POST api/login.json) ---
# Hash = SHA1(Passwort-Text + Salt-Text) -> Base64
try:
    raw_pass_salt = PASS.encode('utf-8') + salt.encode('utf-8')
    sha1_hash = hashlib.sha1(raw_pass_salt).digest()
    pwh_base64 = base64.b64encode(sha1_hash).decode('utf-8')
    # print(f"   -> Berechneter Hash: {pwh_base64}") # Debug
except Exception as e:
    print(f"Hash-Berechnung fehlgeschlagen: {e}")
    sys.exit(1)

url_login = f"http://{IP}/api/login.json?sessionId={session_id}"

print(f"2. Sende dynamischen Hash...")

login_payload = {
    "mode": MODE,
    "userId": USER,
    "pwh": pwh_base64
}

try:
    json_data = json.dumps(login_payload, separators=(',', ':')).encode('utf-8')
    req = urllib.request.Request(url_login, data=json_data, method='POST', headers=headers)
    
    with urllib.request.urlopen(req, timeout=5) as response:
        data = json.loads(response.read().decode())
        
        role = data.get("session", {}).get("roleId", 0)
        status = data.get("status", {}).get("code", -1)
        
        if status == 0 and role > 0:
            print(f"   -> ERFOLG! Rolle ist jetzt: {role}")
        else:
            print(f"   -> FEHLER: Login abgelehnt. Status {status}, Rolle {role}")
            sys.exit(1)

except Exception as e:
    print(f"Login Fehler: {e}")
    sys.exit(1)


# --- SCHRITT 3: BEFEHL SENDEN ---
url_send = f"http://{IP}/api/dxs.json?sessionId={session_id}"
print(f"3. Sende Wert {target_value}...")

# Payload ist jetzt clean, nur mit der gültigen Session
payload = {
    "dxsEntries": [
        {"dxsId": 83888896, "value": 2},
        {"dxsId": 33556484, "value": True},
        {"dxsId": 33556249, "value": 50},
        {"dxsId": TARGET_ID, "value": target_value},
        {"dxsId": 33556248, "value": False}
    ],
    "session": {
        "sessionId": session_id,
        "roleId": role
    }
}

try:
    json_data = json.dumps(payload, separators=(',', ':')).encode('utf-8')
    req = urllib.request.Request(url_send, data=json_data, method='POST', headers=headers)
    
    with urllib.request.urlopen(req, timeout=10) as response:
        result = json.loads(response.read().decode())
        code = result.get("status", {}).get("code")
        
        if code == 0:
            print(f"ERFOLG: {target_value}")
        else:
            print(f"FEHLER Code: {code}")
            sys.exit(1)

except Exception as e:
    print(f"Senden Fehler: {e}")
    sys.exit(1)

…welches was macht? Magst Du ein paar Wörter dazu sagen bitte?

Hi, ja sorry,
Das über das Script hat man die Möglichkeit, den Minimalen Batterieladestand zwischen 10 und 100 % setzten. Dadurch kann man die Energie sozusagen zwangsspeichern.
Ich habe das Problem, mit zwei Wechselrichtern, das der alte Piko Wechselrichter bevor er speichert, einspeißt, da er durch die große neue PV meint, es sei kein Strombedarf und somit vermutlich auch der speicher voll.
Dieses Script kann mit Sicherheit auch umgebaut werden, um andere DXS zu setzten.
Zudem ist das schöne an dem Script, es wird überprüft, ob das Kennwort passt und die SessionID wird gespeichert um die Daten abzurufen und zu ändern.