Seite 1 von 2

Wechselrichter per MQTT

Verfasst: 30. Mär 2024 10:55
von Snatsch
Hallo, Ich habe gestern mein Balkonkraftwerk installiert und per MQTT in openhab eingebunden. Ich habe drei Kanäle eingebunden

Code: Alles auswählen

UID: mqtt:topic:MQTTBroker:Solar
label: Solar
thingTypeUID: mqtt:topic
configuration: {}
bridgeUID: mqtt:broker:MQTTBroker
location: Garten
channels:
  - id: SolarAktuell
    channelTypeUID: mqtt:number
    label: Solar Aktuell
    description: ""
    configuration:
      stateTopic: solar/power
  - id: SolarHeute
    channelTypeUID: mqtt:number
    label: Solar Heute
    description: ""
    configuration:
      stateTopic: solar/total_today
  - id: SolarGesamt
    channelTypeUID: mqtt:number
    label: "Solar Gesamt "
    description: ""
    configuration:
      stateTopic: solar/total
welche auch Daten bringen. Dann habe ich folgendes Skript aus diesen Forum im Hintergrund laufen.

Code: Alles auswählen

#!/bin/bash
TMP=/tmp/.grab.$$
USER=admin
PASSWORD=admin
IPINVERTER=192.168.2.154
MQTT=192.168.2.200
SLEEP=5
while [ 1 ]
do
	curl --silent --user ${USER}:${PASSWORD} http://${IPINVERTER}/status.html > $TMP
	if [ $? = 0 ]; then
		CUR_POW=`grep "var webdata_now_p" $TMP | cut -d\" -f2`
		YIE_TOD=`grep "var webdata_today_e" $TMP | cut -d\" -f2`
		YIE_TOT=`grep "var webdata_total_e" $TMP | cut -d\" -f2`
		mosquitto_pub -h ${MQTT} -t solar/power -m "$CUR_POW" -q 1
		mosquitto_pub -h ${MQTT} -t solar/total_today -m "$YIE_TOD" -q 1
		mosquitto_pub -h ${MQTT} -t solar/total -m "$YIE_TOT" -q 1
	fi
	sleep ${SLEEP}
done
meine erste Frage ob es Sinnvoll ist das Skript alle 5 Sekunden durchlaufen zu lassen ?
Ich Errechne mit eurer Hilfe meinen Gasverbrauch per Rule Jetzt dachte ich das ich das auch mit dem Solarertrag machen kann und habe folgende Items angelegt.

Code: Alles auswählen

Group Solarertrag
String Solarertrag_Heute_Item "SolarHeute" <solarplant> (Solarertrag)
String Solarertrag_Woche_Item "SolarWoche"<solarplant> (Solarertrag)
String Solarertrag_Monat_Item "SolarMonat"<solarplant> (Solarertrag)
String Solarertrag_Jahr_Item "SolarJahr"<solarplant> (Solarertrag)
und folgende Rule umgeschrieben.

Code: Alles auswählen

rule "Solarertrag Tag Woche Monat Jahr" // Deutscher Zeichensatz zulässig
when
    Item Solar_Solar_Gesamt_ changed // changed reicht.
then
   
    val Preis = 0.481 
    val ZonedDateTime zdt = ZonedDateTime.now() // jetzt
    val ZonedDateTime start_of_day = zdt.with(LocalTime.MIDNIGHT) // heute, Mitternacht
    val ZonedDateTime start_of_week = start_of_day.minusDays(start_of_day.getDayOfWeek.getValue - 1) // Montag
    val ZonedDateTime start_of_month = start_of_day.withDayOfMonth(1) // Erster Tag des Monats (1)
    val ZonedDateTime start_of_year = start_of_day.withDayOfYear(89) // Läuft seit 29.03.2024
    
    val float Solarertrag_Heute = (Solar__Solar_Aktuell.deltaSince(start_of_day) as Number).floatValue // kWh Delta holen
    val float Solarertrag_Woche = (Solar__Solar_Aktuell.deltaSince(start_of_week) as Number).floatValue
    val float Solarertrag_Monat = (Solar__Solar_Aktuell.deltaSince(start_of_month) as Number).floatValue
    val float Solarertrag_Jahr = (Solar__Solar_Aktuell.deltaSince(start_of_year) as Number).floatValue
    
    val String Euro_Heute = String::format("%.2f €",(Solarertrag_Heute * Preis)) // Summe in Euro berechnen
    val String Euro_Woche = String::format("%.2f €",(Solarertrag_Woche * Preis))
    val String Euro_Monat = String::format("%.2f €",(Solarertrag_Monat * Preis))
    val String Euro_Jahr = String::format("%.2f €",(Solarertrag_Jahr * Preis))
    
    Solarertrag_Heute_Item.postUpdate(Solarertrag_Heute.toString + " kWh/" +  Euro_Heute)
    Solarertrag_Woche_Item.postUpdate(Solarertrag_Woche.toString + " kWh/" +  Euro_Woche)
    Solarertrag_Monat_Item.postUpdate(Solarertrag_Monat.toString + " kWh/" +  Euro_Monat)
    Solarertrag_Jahr_Item.postUpdate(Solarertrag_Jahr.toString + " kWh/" +  Euro_Jahr)

end
leider möchte es nicht funktionieren. Es kommt im Log immer die Fehlermeldung.

Code: Alles auswählen

2024-03-30 10:51:21.347 [WARN ] [ab.binding.mqtt.generic.ChannelState] - Command '' from channel 'mqtt:topic:MQTTBroker:Solar:SolarAktuell' not supported by type 'NumberValue': null
2024-03-30 10:51:21.358 [WARN ] [ab.binding.mqtt.generic.ChannelState] - Command '' from channel 'mqtt:topic:MQTTBroker:Solar:SolarHeute' not supported by type 'NumberValue': null
2024-03-30 10:51:21.371 [WARN ] [ab.binding.mqtt.generic.ChannelState] - Command '' from channel 'mqtt:topic:MQTTBroker:Solar:SolarGesamt' not supported by type 'NumberValue': null
Hat jemand einen Tipp für mich was ich anders machen muss ?

Re: Wechselrichter per MQTT

Verfasst: 30. Mär 2024 11:45
von udo1toni
Das Shell Script brauchst Du mutmaßlich, um die Wechselrichter Daten überhaupt per mqtt verfügbar zu machen?
Bist Du sicher, dass die verwendeten Items auch persistiert werden?
Für alle Datenpunkte, die weiter in der Vergangenheit liegen als die Inbetriebnahme der Anlage, wirst Du natürlich immer null erhalten, das betrifft also mindestens: den Jahresertrag bis nächstes Jahr - den Monatsertrag bis nächsten Monat - den Wochenertrag bis nächste Woche (immerhin, beides übermorgen)
Der Tagesertrag sollte heute funktionieren, natürlich nur unter der Voraussetzung, dass die Rule nicht vorher mit einer nullPointer Exception abbricht.
Und wieder mal wäre bewiesen, dass es wichtig ist, zunächst zu prüfen, ob ein Ausdruck auch eine Zahl liefert, bevor man versucht, damit zu rechnen...

Außerdem greifst Du auf ein Item zu, welches Du nicht erwähnt hast Solar__Solar_Aktuell vielleicht ist auch da schon was schief gegangen.
Was soll das Wort Item im Namen eines Items? Ein Item ist immer eine Item, egal ob man das nun dran schreibt oder nicht. Es sind also fünf gänzlich unnötige Zeichen...

Deine Fehlermeldung unten widerspricht allerdings auch Deiner Aussage von ganz oben, dass die Channel Daten liefern, da steht ja ganz eindeutig

Code: Alles auswählen

Command '' [...] not supported [...]
Allerdings frage ich mich auch, warum openHAB hier von einem Command spricht, wo es sich doch nach den Channeldefinitionen um Status handelt.

Re: Wechselrichter per MQTT

Verfasst: 30. Mär 2024 12:28
von Snatsch
Hallo Udo ja das Skript sendet die Daten.
Screenshot (56).png
Solar__Solar_Aktuell ist das was der Wechselrichter im Moment bringt.



Screenshot (57).png
doch die Regel wird abgebrochen.

Code: Alles auswählen

2024-03-30 12:49:53.130 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Solarertrag-1' failed: cannot invoke method public abstract float java.lang.Number.floatValue() on null in Solarertrag

Re: Wechselrichter per MQTT

Verfasst: 30. Mär 2024 19:46
von udo1toni
Ja, wie gesagt, das ist zu erwarten. Man sollte immer auf Nullwerte prüfen, bevor man einen Status als Number castet.
:)
Gesetzt den Fall, alle Items sind korrekt...

Code: Alles auswählen

rule "Solarertrag Tag Woche Monat Jahr"
when
    Item Solar_Solar_Gesamt_ changed // changed reicht.
then
   
    val Preis = 0.481 
    val start_of_day   = now.with(LocalTime.MIDNIGHT)                                   // heute, Mitternacht
    val start_of_week  = start_of_day.minusDays(start_of_day.getDayOfWeek.getValue - 1) // Montag
    val start_of_month = start_of_day.withDayOfMonth(1)                                 // Erster Tag des Monats (1)
    val start_of_year  = start_of_day.withDayOfYear(89)                                 // Läuft seit 29.03.2024

    var Float Solarertrag_Heute = 0
    var Float Solarertrag_Woche = 0
    var Float Solarertrag_Monat = 0
    var Float Solarertrag_Jahr  = 0
    if(Solar__Solar_Aktuell.deltaSince(start_of_day)   instanceof Number)
        Solarertrag_Heute = (Solar__Solar_Aktuell.deltaSince(start_of_day)   as Number).floatValue // kWh Delta holen
    if(Solar__Solar_Aktuell.deltaSince(start_of_week)  instanceof Number)
        Solarertrag_Woche = (Solar__Solar_Aktuell.deltaSince(start_of_week)  as Number).floatValue
    if(Solar__Solar_Aktuell.deltaSince(start_of_month) instanceof Number)
        Solarertrag_Monat = (Solar__Solar_Aktuell.deltaSince(start_of_month) as Number).floatValue
    if(Solar__Solar_Aktuell.deltaSince(start_of_year)  instanceof Number)
        Solarertrag_Jahr  = (Solar__Solar_Aktuell.deltaSince(start_of_year)  as Number).floatValue

    val Euro_Heute = String.format("%.2f €",(Solarertrag_Heute * Preis))           // Summe in Euro berechnen
    val Euro_Woche = String.format("%.2f €",(Solarertrag_Woche * Preis))
    val Euro_Monat = String.format("%.2f €",(Solarertrag_Monat * Preis))
    val Euro_Jahr  = String.format("%.2f €",(Solarertrag_Jahr  * Preis))
    
    Solarertrag_Heute_Item.postUpdate(Solarertrag_Heute.toString + " kWh/" +  Euro_Heute)
    Solarertrag_Woche_Item.postUpdate(Solarertrag_Woche.toString + " kWh/" +  Euro_Woche)
    Solarertrag_Monat_Item.postUpdate(Solarertrag_Monat.toString + " kWh/" +  Euro_Monat)
    Solarertrag_Jahr_Item.postUpdate(Solarertrag_Jahr.toString   + " kWh/" +  Euro_Jahr)
end
Folgendes ist noch dazu anzumerken:
Es besteht ein Unterschied zwischen der Definition mittels float und Float. Erstere generiert ein Primitive, letztere ein Objekt. Nur das Objekt kennt die im späteren Verlauf genutzte Methode .toString (war mir vorher gar nicht aufgefallen)
Es ist unüblich, Itemnamen mit einem Unterstrich enden zu lassen. Es mag funktionieren, ich würde mich aber nicht darauf verlassen wollen und damit rechnen, dass es dort früher oder später zu einem weiteren Problem kommt.
Statt lokale Variablen oder Konstanten identisch zum Item zu benennen und in der Folge das Item mit der Endung _Item zu versehen wäre es zielführender, die Variablennamen sinnvoll zu wählen, z.B. statt Solarertrag_Heute fErtrag_Heute (wobei das f für Float steht) oder auch statt Euro_Heute strEuro_Heute (str steht für String).
An vielen Stellen kann und sollte man grundsätzlich auf die starre Typisierung verzichten, openHAB wählt dann selbst den besten Typ aus.

Das wichtigste ist hier aber, auf null-Werte zu testen, bevor Du as Number verwendest.

Re: Wechselrichter per MQTT

Verfasst: 30. Mär 2024 21:55
von Snatsch
Vielen Dank Udo für deine Hilfe (wie so oft) Jetzt muss ich bis morgen warten bis der Wechselrichter wieder anspringt :) Eine Frage hätte ich aber noch ;) Ich habe ja das Skript im Hintergrund laufen. Ist es Notwendig es alle 5 Sekunden Durchlaufen zu lassen wenn sich der Wechselrichter ja nur alle 6 Minuten aktualisiert und dann habe ich noch gemerkt das das Skript manchmal einfach aufhört zu laufen :roll: Kann man eine Rule schreiben die überprüft z.B alle 2 Minuten ob das Skript läuft und wenn nicht das man es wieder Startet ? Hoffe du verstehst ungefähr was ich meine ;)

Re: Wechselrichter per MQTT

Verfasst: 31. Mär 2024 01:23
von udo1toni
Wenn die werte ohnehin nur alle 360 Sekunden aktualisiert werden, kannst Du das Script auch anders gestalten, und zwar lässt Du Schleife und Sleep weg. Dafür legst Du einen cron Job an (in GNU/Linux, nicht in openHAB!) der das Script einfach alle sechs Minuten ausführt. Das hat dann auch den Vorteil, dass Du nicht prüfen musst, ob das Script "noch läuft", es wird einfach ganz normal zyklisch gestartet.

Re: Wechselrichter per MQTT

Verfasst: 1. Apr 2024 16:31
von Snatsch
Die Rule läuft und gibt auch Werte aus. Aber leider viel zu hohe :( wäre schön wenn es so wäre. Muss in der Rule noch etwas umgerechnet werden ?
Screenshot (58).png

Re: Wechselrichter per MQTT

Verfasst: 1. Apr 2024 16:41
von udo1toni
Ich kenne Deine Datenquelle nicht :)

Re: Wechselrichter per MQTT

Verfasst: 1. Apr 2024 16:50
von Snatsch
die Daten kommen von MQTT
Screenshot (60).png
und das Item so
Screenshot (59).png
ist das das was du meinst ?

Re: Wechselrichter per MQTT

Verfasst: 1. Apr 2024 20:51
von Snatsch

Code: Alles auswählen

if(Solar__Solar_Aktuell.deltaSince(start_of_day)   instanceof Number)
        Solarertrag_Heute = (Solar__Solar_Aktuell.deltaSince(start_of_day)   as Number).floatValue // kWh Delta holen
    if(Solar__Solar_Aktuell.deltaSince(start_of_week)  instanceof Number)
        Solarertrag_Woche = (Solar__Solar_Aktuell.deltaSince(start_of_week)  as Number).floatValue
    if(Solar__Solar_Aktuell.deltaSince(start_of_month) instanceof Number)
        Solarertrag_Monat = (Solar__Solar_Aktuell.deltaSince(start_of_month) as Number).floatValue
    if(Solar__Solar_Aktuell.deltaSince(start_of_year)  instanceof Number)
        Solarertrag_Jahr  = (Solar__Solar_Aktuell.deltaSince(start_of_year)  as Number).floatValue
könnte es sein das statt Solar__Solar_Aktuell. Solar_Solar_Gesamt_ hin muss ?
Kann es heute nicht testen da mein Wechselrichter OFF ist