Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

marcelj
Beiträge: 4
Registriert: 23. Jun 2022 11:56

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von marcelj »

Die erste Hürde ist genommen - Deine Hilfestellung hat mein Problem gelöst, vielen Dank nochmal :)

Jetzt kommt allerdings der nächste Block, der mit Zeiten hantiert. Problematisch wird es bei

Code: Alles auswählen

val DateTime dtForecast_03h = (new DateTime(Wx_OWM_Forecast_Time_03h.state.toString)).toDateTime
Ich verstehe, dass dtForecast_03h hier wieder als DateTime definiert ist. Das ließe sich analog zu Deinem Post ja easy lösen zu:

Code: Alles auswählen

val ZonedDateTime dtForecast_03h = (new DateTime(Wx_OWM_Forecast_Time_03h.state.toString)).toDateTime
Daraufhin wird Wx_OWM_FOrecast_Time_03h (ein epoch-Wert, das habe ich via persistence gecheckt), in einen string überführt, um dann wieder in das DateTime-Format zu kommen. Mir erschließt sich nicht, warum das nötig sein sollte.

Beim debugging kommt dann außerdem folgender Error, der sich mit meiner Vermutung, dass hier irgendwas mit dem Formatieren der (Zeit-)Werte nicht hinhaut, deckt:

Code: Alles auswählen

An error occurred during the script execution: null in openweathermap
Straight forward einfach nur jedes DateTime durch ein ZonedDateTime funktioniert nicht - das wäre ja auch zu schön gewesen :lol:

Tobii
Beiträge: 53
Registriert: 18. Sep 2020 19:43

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von Tobii »

marcelj hat geschrieben: 23. Jun 2022 12:21 (...)
Mir ist es gelungen, die Beregungsregel auf mein OH3 (inkl. openweathermap-API-workaround gemäß https://community.openhab.org/t/openwea ... ules/68513) zu adaptieren.

(...)
Auf die schnelle konnte mir Google nicht erklären welche Beregnungsregel das sein soll? Bitte um kurze Erklärung.

marcelj
Beiträge: 4
Registriert: 23. Jun 2022 11:56

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von marcelj »

Im ersten Post kannst Du nachlesen, auf welche Beregnungsregel sich dieser gesamte Thread bezieht. :-)

DavGre
Beiträge: 84
Registriert: 11. Mär 2019 15:47

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von DavGre »

Hallo zusammen,

erst einmal Danke für diese überragende Regel zur Gartenbewässerung. Ich bin gerade dabei, diese auch für mein Projekt zu adaptieren.

Bei der unten abgebildeten Regel bekomme ich aber immer folgenden Fehler angezeigt:

Code: Alles auswählen

2023-05-05 19:17:53.149 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'gardena-5' failed: 'before' is not a member of 'java.time.ZonedDateTime'; line 83, column 9, length 68 in gardena

Ich habe schon Ewigkeiten mit der Fehlersuche verbracht, aber finde einfach nichts. Kann mir jemand von euch auf die Sprünge helfen?

Code: Alles auswählen

rule "Rain Delay"
when
    Time cron "5 15 23 ? * * *" //23:15:05
then
    if (ProgramA_Master_Weather.lastUpdate.before(now.minusDays(maxOffDays))) {
        ProgramA_Master_Weather.sendCommand(OFF)
    }
    else {
        var boolean delay = false
        //Es hat heute geregnet min. 4mm
        if ((RainToday.state as QuantityType<Number>).doubleValue >= minPrecip) {
             delay = true
        }
        //Regen im Forecast min. 50%
        if ((ForecastProbaPrecip_day1.state as QuantityType<Number>).doubleValue >= minPrecipPercent) {
             delay = true
        }
        if (delay) {
            ProgramA_Master_Weather.sendCommand(ON)    
            logInfo(filename,"Beregnung: Es hat geregnet oder Regen im Forecast")
            sendNotification("david.xxxxx@web.de", "Es hat geregnet heute geregnet oder die Regenwahrscheinlichkeit für morgen liegt über 50%. Die beregnung wird für 2 tage deaktiviert")
        }
        else {
            ProgramA_Master_Weather.sendCommand(OFF)
        }
    }
end

Benutzeravatar
udo1toni
Beiträge: 13859
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von udo1toni »

Die Funktion heißt unter openHAB3 mutmaßlich .isBefore und nicht .before.

Hintergrund: die ursprüngliche Rule wurde unter openHAB2 entwickelt.
openHAB2 nutzte noch Joda Time als Bibliothek (die gab es schon in openHAB1, welches unter Java6 lief).
openHAB3 nutzt hingegen JavaTime (das wurde erst mit Java8 eingeführt und ersetzt Joda Time vollständig).

JavaTime nutzt an vielen Stellen identische Funktionsaufrufe, an einigen Stellen sind die Namen der Funktionen leicht anders (z.B. .getHour statt .getHourOfDay oder hier .isBefore statt .before), andere Dinge funktionieren komplett anders (z.B. .plusMillis(Wert) ist beliebt, um einen Timer um <Wert> Millisekunden zu verschieben. JavaTime kennt kein .plusMillis(Wert), dafür aber ein .plusNanos(Wert). Es gäbe noch die Möglichkeit mit .plus(Wert, ChronoUnit(MILLIS)) zu arbeiten, plusNanos(Wert*10000000) ist kürzer)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

DavGre
Beiträge: 84
Registriert: 11. Mär 2019 15:47

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von DavGre »

udo1toni hat geschrieben: 6. Mai 2023 07:28 Die Funktion heißt unter openHAB3 mutmaßlich .isBefore und nicht .before.

Hintergrund: die ursprüngliche Rule wurde unter openHAB2 entwickelt.
openHAB2 nutzte noch Joda Time als Bibliothek (die gab es schon in openHAB1, welches unter Java6 lief).
openHAB3 nutzt hingegen JavaTime (das wurde erst mit Java8 eingeführt und ersetzt Joda Time vollständig).

JavaTime nutzt an vielen Stellen identische Funktionsaufrufe, an einigen Stellen sind die Namen der Funktionen leicht anders (z.B. .getHour statt .getHourOfDay oder hier .isBefore statt .before), andere Dinge funktionieren komplett anders (z.B. .plusMillis(Wert) ist beliebt, um einen Timer um <Wert> Millisekunden zu verschieben. JavaTime kennt kein .plusMillis(Wert), dafür aber ein .plusNanos(Wert). Es gäbe noch die Möglichkeit mit .plus(Wert, ChronoUnit(MILLIS)) zu arbeiten, plusNanos(Wert*10000000) ist kürzer)
Danke dir. Das hat funktioniert!
Könntest du mir die "Übersetzung" für

Code: Alles auswählen

now.withTimeAtStartOfDay
auch noch verraten? Bei der Codezeile bekomme ich nämlich auch noch den Fehler ausgespielt. Von Java habe ich leider null Ahnung.

:?

Benutzeravatar
udo1toni
Beiträge: 13859
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von udo1toni »

so aus dem Kopf:

Code: Alles auswählen

now.toInstant.with(Localtime.MIDNIGHT)
aber ohne Gewähr...
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

DavGre
Beiträge: 84
Registriert: 11. Mär 2019 15:47

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von DavGre »

Danke dir, das hat geklappt.

Momentan hänge ich mich an der Regel mit der Startzeit auf. Die Punkte unter "// Zeitpunkt des Programmstarts festlegen" habe ich schon selbstständig in JavaTime API konvertiert. Ich bekomme in den Logs aber immer wieder die folgende Fehlermeldung ausgespielt:

Code: Alles auswählen

Script execution of rule with UID 'gardena-8' failed: Text cannot be parsed to a Duration in gardena
Hier die Regel um die es geht:

Code: Alles auswählen

rule "Set Program A Startime"
when
    Item ProgramA_StartTime_Minutes received update or
    Item ProgramA_StartTime_Hours received update
then
	if (ProgramA_StartTime_Minutes.state == 60){
		ProgramA_StartTime_Minutes.sendCommand(0)
	}
	if (ProgramA_StartTime_Hours.state == 24){
		ProgramA_StartTime_Hours.sendCommand(0)
	}
    var int minutes = (ProgramA_StartTime_Minutes.state as DecimalType).intValue()
    var int hours = (ProgramA_StartTime_Hours.state as DecimalType).intValue()

   	// Zeitpunkt des Programmstarts festlegen
	var DateTime startTime = parse(now.getYear() + "-" + now.getMonthValue() + "-" + now.getDayOfMonth() + "T" + hours + ":" + minutes)

    // update der Startzeit in der für Rules und Anzeige  
    ProgramA_StartTime.sendCommand(String::format("%02d:%02d", startTime.getHour(), startTime.getMinute()))
end

Benutzeravatar
udo1toni
Beiträge: 13859
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von udo1toni »

Mein Tipp an der Stelle: Denk mal ganz genau über den Code nach, den Du da verzapft hast.

Du kommst von zwei Number Items, welche Stunde und Minute darstellen. Das ist aus verschiedenen Gründen suboptimal.
Du prüfst, ob es einen Überlauf gibt, für die Stunde >23, für die Minute >59 . Die Idee an sich ist gut, leider funktioniert es aber nicht so, wie Du Dir das vorstellst, beginnend damit, dass sendCommand hier mit allerhöchster Wahrscheinlichkeit ungeeignet ist. Erschwerend kommt hinzu, dass die Rule auf received update triggert, auch dafür gibt es keinen Grund.

received command -> triggert, wenn das Item einen Befehl empfangen hat. Dieser Trigger löst z.B. aus, wenn man in der UI den Wert eines Items sendet.
changed -> triggert, wenn sich der Wert eines Items geändert hat.
received update -> triggert, sobald ein Item ein Status Update erhalten hat, unabhängig davon, ob dies eine Änderung bewirkt hat oder nicht.

Du hast also einen Trigger gewählt, der immer auslöst, obwohl die Rule nur bei einer Wertänderung triggern muss.

Schlimmer: in der Rule verwendest Du sendCommand auf die Items, welche die Rule triggern. sendCommand führt (default Verhalten) zu einem Update des Status des Items (hier sicher auch zu einer Wertänderung), allerdings erst als Folge des bereits ausgeführten Befehls. Du maximierst also die Laufzeit des Befehls, obwohl Du doch eigentlich möglichst schnell aus der 60 oder der 24 eine 0 machen willst. Die Rule wird also sich selbst triggern, allerdings wird die Ausführung des Triggers verzögert, bis die Rule vollständig abgearbeitet ist. Das heißt, die nachfolgende Berechnung erhält definitiv zunächst den 60er Wert oder den 24er Wert, erst im nächsten oder gar übernächsten Durchlauf der Rule passt der Wert dann.

Dann bestimmst Du Startstunde und Startminute, versuchst damit (auf absurd komplizierte Weise) eine DateTime Variable zu füllen, die Du dann nutzt, um daraus wieder Stunde und Minute zu extrahieren. Was soll das?

Und dann kann ich an den Namen der Items ablesen, dass es fast sicher mindestens weitere neun Items und weitere drei Rules gibt, die alle exakt das gleiche erledigen...

Je nachdem, wie die Oberfläche definiert ist, wäre es wesentlich sinnvoller, für jede Zeit (zum Einstellen) nur ein Item zu nutzen. Das Item enthält dann die Minute des Tages. Du definierst vier Knöpfe, der erst Knopf zieht 60 ab, der zweite Knopf addiert 60, der drite Knopf zieht 1 ab, der vierte Knopf addiert 1. Alternativ kannst Du natürlich auch andere Schrittweiten wählen, aber das wäre naheliegend. Du erhältst damit also Stunde +/- und Minute +/-, nur musst Du Dich nicht mehr um den Überlauf der Minute kümmern. das Item bekommt Minimum -1 und Maximum 1440, die Rule macht aus 1440 eine 0 und aus -1 eine 1439.
Die Rule triggert auf received command, so dass die Rule nur noch auslöst, wenn Du in der UI einen der Knöpfe drückst.
Die Rule errechnet alle notwendigen Werte, schickt sie dann aber mit postUpdate in das TagesminutenItem, so dass die Rule selbst dadurch nicht ein weiteres Mal getriggert wird.

Code: Alles auswählen

rule "Set Program A Startime"
when
    Item ProgramA_StartTimeM received command                               // Item hat Befehl empfangen
then
    var Integer iVal = -2                                                   // initialisiere mit ungültigem Wert
    if(receivedCommand instanceof Number)                                   // Falls Befehl eine Zahl ist
        iVal = (receivedCommand as Number).intValue                         // schreibe die Zahl in die Variable
    if(iVal < -1) {                                                         // Falls Wert außerhalb des erwarteten Bereichs
        logWarn("setTimer","Received illegal command {}",receivedCommand)   // Warnmeldung
        return;                                                             // und Abbruch der Rule
    }
                                                                            // ab hier ist alles gut!
    if(iVal == 1440)                                                        // Überlauf nach oben
        iVal = 0                                                            // also auf Minimum setzen
    else if (iVal == -1)                                                    // Überlauf nach unten
        iVal = 1439                                                         // also auf Maximum setzen

    val hour   = (iVal/60).intValue                                         // Stunde ermitteln
    val minute = iVal - hour * 60                                           // Minute ermitteln

    // update der Startzeit in der für Rules und Anzeige  
    ProgramA_StartTime.sendCommand(String.format("%02d:%02d", hour, minute) // Zeit senden
    ProgramA_StartTimeM.postUpdate(iVal)                                    // und Steuer-Item setzen
end
Auch diese Rule kümmert sich zunächst nur um eine Zeit. Wenn Du allerdings die Items passend organisierst, reicht eine einzige Rule für alle Schaltzeiten. Du brauchst immer noch zwei Items pro Zeitpunkt (das eine für die Anzeige, das andere für die Wahl des Werts), aber eben nur noch eine einzige Rule. Dazu müssen die Items in zwei Gruppen zusammengefasst werden. Also alle ...TimeM-Items kommen z.B. in die Gruppe gProgramTimeM und alle ...Time-Items kommen in die Gruppe gProgramTime. Dann sieht die eine Rule, die sich um alle Items kümmert, so aus:

Code: Alles auswählen

rule "Set Program Times"
when
    Member of gProgramTimeM received command                                // Item hat Befehl empfangen
then
    var Integer iVal = -2                                                   // initialisiere mit ungültigem Wert
    if(receivedCommand instanceof Number)                                   // Falls Befehl eine Zahl ist
        iVal = (receivedCommand as Number).intValue                         // schreibe die Zahl in die Variable
    if(iVal < -1) {                                                         // Falls Wert außerhalb des erwarteten Bereichs
        logWarn("setTimer","Received illegal command {}",receivedCommand)   // Warnmeldung
        return;                                                             // und Abbruch der Rule
    }
                                                                            // ab hier ist alles gut!
    if(iVal == 1440)                                                        // Überlauf nach oben
        iVal = 0                                                            // also auf Minimum setzen
    else if (iVal == -1)                                                    // Überlauf nach unten
        iVal = 1439                                                         // also auf Maximum setzen

    val hour   = (iVal/60).intValue                                         // Stunde ermitteln
    val minute = iVal - hour * 60                                           // Minute ermitteln

    // update der Startzeit in der für Rules und Anzeige  
    
    gProgramTime.members.filter[i|
        triggeringItem.name.startsWith(i.name)
    ].head.sendCommand(String.format("%02d:%02d", hour, minute)             // Zeit senden

    triggeringItem.postUpdate(iVal)                                         // und Steuer-Item setzen
end
Die Rule musste also nur minimal angepasst werden, um nun mit den beiden Gruppen zu arbeiten.
triggeringItem liefert das Item, welches die Rule über Member of getriggert hat. Es handelt sich dabei dann um ein "echtes" Item, es hat also alle Methoden, die auch ein gewöhnliches Item hat. triggeringItem.name ist also der Name des Items, welches die Rule ausgelöst hat.
filter[] liefert eine gefilterte Liste aller Items der Liste, die aufgerufen wird (die Liste besteht aus den Membern der gewählten Gruppe)
Am Itemnamen fehlt lediglich das M am Schluss, das heißt also, der Name des triggernden Items beginnt mit dem vollständigen Namen des Items, welches selektiert werden soll.
Zum Schluss wird das triggernde Item per postUpdate auf den neuesten Stand gebracht.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

spirit
Beiträge: 17
Registriert: 28. Nov 2019 08:19

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff (neuer Thread)

Beitrag von spirit »

Hallo zusammen :)

Hat schon jemand die Gartenbewässerung wie Cyrelian sie gebaut hat auf das aktuelle Openhab und Openweathermap umgebaut? Ich habe schon angefangen, doch schon bei der dritten Regel (rule "Calculate irrigation scale factor") fängt es an zu hängen.

Leider sind die Openweathermap Daten ein bisschen unterschiedlich.

Meine KNX Installation kann alle werte bis auf die Regenmenge liefern. Der MDT Regensensor kann lediglich Regen ja/nein anzeigen.

Wäre schön wenn wir diese umfangreiche Steuerung auf aktuellen Stand bringen können.
openHAB 4.0.0 Milestone auf RPi 4 4GB

Antworten