Gardena Gartenbewässerung

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

Moderatoren: Cyrelian, seppy

Antworten
int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Gardena Gartenbewässerung

Beitrag von int5749 »

Hallo zusammen,

vor vielen Monden habe ich mit großer Unterstützung eine Regel zur Steuerung der Gardena Ventile in openHAB eingebaut.
Hintergrund ist das Vorhandensein einer Regenwasserpumpe und somit ein überschneiden der Ventile von 10 Skunden um ein unnötiges ab- und einschalten der Pumpe zu verhindern.

Dies funktioniert auch im Grundsatz, inkl. der Option zum manuellen starten und beenden der Bewässerung.
Daher habe ich die bei meinem Code nur die Rule und keine Items/Variablen angegeben ;-)

Code: Alles auswählen

rule GreenIrrigation
when
    Time cron "0 05 06 ? * MON-SAT" or
    Time cron "0 30 06 ? * SUN" or
	Item Sw_ManIrrigation received command
then
    val actions = getActions("pushover", "pushover:pushover-account:account")
	if(receivedCommand == OFF) {																	// OFF-Teil
		tWater?.cancel																				// timer beenden, falls vorhanden
		tWater = null																				// Zeiger löschen
		gVentStop.members.forEach[ v | v.sendCommand(ON)]											// und alle Ventile schließen
		myIrrigationSwitchVis.postUpdate(ON)														// aktiviere manuellen Start Button
		actions.sendMessageToDevice("J", "Bewässerung manuell um " + OffsetDateTime.now().toString + " beendet.", "Gardena")
		return;
	} else if((Sensor_SoilHumidity.state as Number).intValue > (Sensor_Level.state as Number)) {	// exit, wenn Bodenfeuchtigkeit über definierter Grenze											//OFF-Teil
		logInfo("Gardena", "Bewässerung Start abgebrochen, da Bodenfeuchte mit {} ausreichend!", Sensor_SoilHumidity.state.toString)
		actions.sendMessageToDevice("J", "Start der Bewässerung abgebrochen, da Bodenfeuchtigkeit mit " + Sensor_SoilHumidity.state + " ausreichend ist.", "Gardena")
		return;
	} else if(Sw_Bewaesserung.state == OFF && receivedCommand != ON) {								// exit, wenn Automatik aus und nicht manuell bewässert
		logInfo("Gardena", "Bewässerungsautomatik nicht aktiv")
		actions.sendMessageToDevice("J", "Bewässerungsautomatik nicht aktiv.", "Gardena")
		return;
	} else if(Holiday.state == ON && receivedCommand != ON) {										// exit, wenn Feiertag und nicht bewusst manuell gestartet
		logInfo("Gardena", "Bewässerung Start abgebrochen, heute ist: {}", TodayIs.state)
		actions.sendMessageToDevice("J", "Automatische Bewässerung aufgrund "+ TodayIs + " beendet.", "Gardena")
		return;
	} else {
		if(receivedCommand == ON) {																	// manueller Start
			logInfo("Gardena", "Manuelle Bewässerung - Start.")
			actions.sendMessageToDevice("J", "Bewässerung manuell um " + OffsetDateTime.now().toString + " gestartet.", "Gardena")
		} else if(Sw_Bewaesserung.state == ON) {													// automatischer Start
			logInfo("Gardena", "Automatische Bewässerung - Start.")
			actions.sendMessageToDevice("J", "Bodenfeuchtigkeit bei " + Sensor_SoilHumidity.state + ",  automatische Bewässerung gestartet.", "Gardena")
		} else {
			logInfo("Gardena", "Bewässerung Start unvorhergesehen abgebrochen!")
			myIrrigationSwitchVis.postUpdate(ON)													// nur zur Sicherheit, sollte eigentlich ON sein
			gVentStop.members.forEach[ v | v.sendCommand(ON)]										// und alle Ventile schließen
			return;																					// der nachfolgende Code soll nicht durchlaufen werden.
		}
		// Beregnungsroutine starten
		myIrrigationSwitchVis.postUpdate(OFF)
		iWater = 0																					// Zähler mit 0 initialisieren
		tWater = createTimer(now, [ |																// timer mit code initialisieren und ausführen
			var Number nTime = 10																	// Default Einschaltzeit definieren
			iWater = iWater +1																		// Zähler erhöhen
			var gVent = gVentile.members.filter[ i | i.name.contains(iWater.toString)]				// Ventil bestimmen
			var gTime = gVentTimer.members.filter[ i | i.name.contains(iWater.toString)]			// Zeit bestimmen
			actions.sendMessageToDevice("J", "gVent Size:" + gVent.size.toString + "gVent.head:" + gVent.head.toString, "Gardena")
			if(gTime.size > 0) {																	// Zeit existiert
				if(gTime.head.state instanceof Number)												// und ist eine gültige Zahl
					nTime = gTime.head.state as Number												// Defaultwert überschreiben
				if(gVent.size > 0) {																// Ventil existiert 
					if(gVentEnable.members.filter[ i | i.name.contains(iWater.toString)].head.state == ON) {	// und soll aktiviert werden
						gVent.head.sendCommand(nTime)												// Gardena Timer setzen
						gVentStart.members.filter[ s | s.name.contains(iWater.toString)].head.sendCommand(ON)
						actions.sendMessageToDevice("J", "Starte Bewässerung von " + gVent.head.label + " für " + nTime + " Minuten.", "Gardena")
						if (gVent.head.label == "Hecke" && Sw_TerrasseIrrigation.state == ON) {
							if (nTime <= (WC_Valve_Cmd_Duration.state as Number).intValue) {
								WC_Valve_Cmd_Duration.sendCommand(nTime.intValue)
								actions.sendMessageToDevice("J", "Dauer für Terrasse an Hecke angeglichen: " + nTime + " Minuten.", "Gardena")
							}
							WC_Valve_Cmd_Start.sendCommand(ON)
							actions.sendMessageToDevice("J", "Starte Bewässerung der Terrasse für " + WC_Valve_Cmd_Duration.state + " Minuten.", "Gardena")
						} else if (gVent.head.label == "Hecke" && Sw_TerrasseIrrigation.state == OFF) {
							actions.sendMessageToDevice("J", "Terrasse nicht aktiviert.", "Gardena")
						}
						tWater.reschedule(now.plusMinutes(nTime.intValue).minusSeconds(10))			// und 10 Sekunden vor Ablauf Gardena Timer nächster Schritt
					} else {
						tWater.reschedule(now.plusSeconds(5))										//falls Ventil inaktiv aber Wert gesetzt
					}
				} else {																			// kein weiterer Timer vorhanden, also
					tWater = null																	// Zeiger löschen
					gVentStop.members.forEach[ v | v.sendCommand(ON)]										// und alle Ventile schließen
					myIrrigationSwitchVis.postUpdate(ON)
					actions.sendMessageToDevice("J", "Automatische Bewässerung beendet: " + now.toString, "Gardena")
				}
			}
		])
	}
end
Was nicht klappt ist der letzte Abschnitt, mit einer Info, das die Bewässerung abgeschlossen ist. Hier läuft der Timer nach der letzten Aktivierung einfach aus. Ich würde aber gerne noch eine Nachricht erhalten, wenn die Bewässerung wirklich abgeschlossen ist.

Hat jemand eine Idee dazu, dies hier mit einzubauen? Evtl. mit Timer.hasTerminated oder Timer.isRunning??
Im Moment habe ich aber noch keine Idee, wo ich dies einbauen müsste :-/
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

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

Re: Gardena Gartenbewässerung

Beitrag von udo1toni »

Durch die Menge an Meldungen ist der Code etwas unübersichtlich ;) aber wenn ich richtig verstanden habe, wie die Rule funktioniert, dann ist Dein Problem, dass die Meldung (der letzte else Block) nur ausgeführt wird, wenn zwar eine Zeit vorhanden ist, aber kein Regner.
Im Zweifel musst Du also eventuell lediglich eine geschweifte Klammer vor dem else einfügen und hinter dem else Block eine geschweifte Klammer entfernen, so dass dieser Block ausgeführt wird, sobald keine Zeit mehr vorhanden ist, nicht sobald kein Ventil mehr vorhanden ist.
Da ich gerade in den letzten Tagen eine ähnliche Regel erstellt habe... dort war der Ansatz, über die angegebene Zeit den Regner zu berücksichtigen oder eben nicht. Es ist dann natürlich die Frage, wie oft diese Zeiten angefasst werden. Wenn man sie eh "nie" ändert, ist ein zusätzlicher Schalter natürlich die einfachere Methode.

Allerdings frage ich mich, ob es gerade für die Ende-Meldung nicht logischer wäre, eine eigene Rule zu programmieren, welche auf alle "Ventil geschlossen" Meldungen reagiert und über die Gruppe prüft, ob alle Ventile geschlossen sind. Oder meldet Gardena die Ventilstellung nicht zurück?

Und noch was... Was passiert, wenn Du zwischendrin ein Ventil abschaltest? Dann wird doch der Timer nach fünf Sekunden erneut ausgeführt, oder? Das bedeutet dann, dass hier keine Überlappung von 10 Sekunden mehr vorhanden ist, sondern von nur 5 Sekunden, wenn ein Regner übersprungen wird und 0 Sekunden, wenn zwei Regner übersprungen werden.

Warum liest Du die Listen gVentEnable...filter[] und gVentStart...filter[] nicht ebenfalls in ein Objekt ein? Alternativ direkt .head, so dass Du das Item selbst als Objekt hast? Die Regner haben ja vermutlich alle eine andere Nummer, oder?
nTime könntest Du auch direkt als Integer definieren, dann kannst Du an diversen Stellen das .intValue weg lassen. Wäre dann natürlich iTime, nicht nTime :)

Beim ersten Codeblcok könnte man auch noch mal überlegen, ob das nicht eleganter geht. Setze eine lokale Boolean Variable auf false. An allen Stellen, wo der Regner gestartet werden soll, setzt Du die Variable auf true. Die Abbruchbedingung, welche auch einen manuellen Start verhindert (Boden zu feucht), kommt ganz zum Schluss und setzt gegebenenfalls wieder auf false.

Danach prüfst Du, ob false oder true, bei false stoppst Du eventuell laufende Timer und Regner, bei true startest Du. An der Stelle solltest Du allerdings auch prüfen, ob der Bewässerungsvorgang schon läuft, sonst kann es leicht passieren, dass einfach ein zweiter Timer angelegt wird. da dann der selbe Handle genutzt wird (tWater) verlierst Du die Kontrolle über den bereits laufenden Timer und kannst ihn auch nicht mehr beenden (außer Du beendest openHAB...) Eventuell sind die Auswirkungen nicht extrem, weil ja auch der selbe Rundenzähler iWater verwendet wird, aber es ist mindestens eine potentielle Stolperstelle (Für den Fall, dass die Beregnung kurz vor einem der beiden Time cron Trigger manuell gestartet wurde, ansonsten sperrst Du ja den Startknopf, wenn ich das richtig verstanden habe).
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: Gardena Gartenbewässerung

Beitrag von int5749 »

Nun ja, der meiste Code stammt aus Deiner Feder KNX-User-Forum auch wenn schon fast 3 Jahre alt :) Dort hatte ich in 04/2020 schon ein Problem geschildert, dann aber aufgrund anderer Projekte aus den Augen verloren.

Da ich es hier in vielen Rules sehe und auch smarter finde, habe ich nun den Code umgestellt und die Abbruchbedingungen nach oben gezogen.
Dabei ist mir dann das Problem der fehlenden Abschlußmeldung wieder aufgefallen.
Ich denke, es wird wohl eine 2. Rule werden, denn eigenlich ist der Timer und damit die Rule schon längst beendet, wenn das letzte Ventil startet.
Somit müsste ich einen weiteren Timer nutzen, welcher synchron mit der letzten Beregnungsdauer ist um dann die Info zu senden.
Sauber wäre dies aber nicht, denn wenn ich parallel manuell beende, würde das Ergebnis nicht passen.

Die Ventile haben eine Activity. Dank des Binding ist dies direkt übersetzt. Sprich im Item steht "CLOSED" während in der Sitemap (ohne transform) dann bereits "Ventil geschlossen" steht. Aber man könnte natürlich eine Gruppe erstellen und diese auf "CLOSED" prüfen.

Welchen Vorteil würde es bieten erst am Ende des ersten Blocks auf false zu prüfen? Somit würde doch immer der erste Block komplett durchlaufen? Mit meiner Variante wäre dies nur der Fall, wenn beregnet werden soll. Oder habe ich da etwas übersehen?
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

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

Re: Gardena Gartenbewässerung

Beitrag von udo1toni »

Ich habe ja befürchtet, dass der Code irgendwann mal auf Code von mir beruht hat... ;)

Da der Timer jedes Mal erstellt wird, wenn ein Regner gestartet wird, läuft der ohnehin, auch jetzt schon. Er endet halt zehn Sekunden vor dem Schließen. Wie gesagt, wenn eine andere Rule einfach die Zustände aller Ventile prüfen kann, sollte es zuverlässig funktionieren.
Die Rule Engine ist ohnehin nicht dazu gedacht, möglichst alles in eine Rule zu packen, sondern eher, die verschiedenen Ereignisse individuell zu behandeln. Hier ist es nur so, dass es mehrere Ereignisse gibt, die alle die gleiche Reaktion hervorrufen sollen.

Man könnte das Abschalten in eine eigene Rule packen, da müsste man halt schauen, ob das sinnvoll ist (Verringern der Komplexität <-> Anzahl Codezeilen)

Was das Durchlaufen aller Abbruchbedingungen bzw. Startbedingungen anbelangt: Das ist zu vernachlässigen, da ja nur die erste zutreffende Bedingung abgearbeitet wird. Du kannst Dir damit aber die Verschachtelung der Bedingungen ersparen und die Definition des Timer Codes kann zwei Ebenen nach links rutschen.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

int5749
Beiträge: 1161
Registriert: 4. Nov 2019 22:08
Answers: 9

Re: Gardena Gartenbewässerung

Beitrag von int5749 »

udo1toni hat geschrieben: 21. Jun 2022 07:48 Ich habe ja befürchtet, dass der Code irgendwann mal auf Code von mir beruht hat... ;)
Ja, manche Dinge laufen einem stetig hinterher und irgendwann wird Mann eingeholt :lol:
Aber funktioniert ja auch sehr stabil.
udo1toni hat geschrieben: 21. Jun 2022 07:48 Da der Timer jedes Mal erstellt wird, wenn ein Regner gestartet wird, läuft der ohnehin, auch jetzt schon. Er endet halt zehn Sekunden vor dem Schließen. Wie gesagt, wenn eine andere Rule einfach die Zustände aller Ventile prüfen kann, sollte es zuverlässig funktionieren.
Die Rule Engine ist ohnehin nicht dazu gedacht, möglichst alles in eine Rule zu packen, sondern eher, die verschiedenen Ereignisse individuell zu behandeln. Hier ist es nur so, dass es mehrere Ereignisse gibt, die alle die gleiche Reaktion hervorrufen sollen.

Man könnte das Abschalten in eine eigene Rule packen, da müsste man halt schauen, ob das sinnvoll ist (Verringern der Komplexität <-> Anzahl Codezeilen)
Ich habe dies nun in eine separate Rule gepackt und durch den min. 10 Sekunden Versatz zwischen Timer und schliessen der Ventile passt dies.

Code: Alles auswählen

rule GreenIrrigationEnding
when
	Item gVentActivity changed
then
    val actions = getActions("pushover", "pushover:pushover-account:account")
	if (gVentActivity.state == CLOSED && tWater.hasTerminated == true) {				//Alle Ventile geschlossen und Timer beendet
		actions.sendMessageToDevice("J", "Bewässerung beendet", "Gardena")
		tWater = null																	// Zeiger löschen
		gVentStop.members.forEach[ v | v.sendCommand(ON)]								// zur Sicherheit alle Ventile schließen
		myIrrigationSwitchVis.postUpdate(ON)
	}
end
udo1toni hat geschrieben: 21. Jun 2022 07:48 Was das Durchlaufen aller Abbruchbedingungen bzw. Startbedingungen anbelangt: Das ist zu vernachlässigen, da ja nur die erste zutreffende Bedingung abgearbeitet wird. Du kannst Dir damit aber die Verschachtelung der Bedingungen ersparen und die Definition des Timer Codes kann zwei Ebenen nach links rutschen.
Ich sehe da "nur" 1 Ebene, wenn die einzelenen Abfragen wegfallen und muss mir dies wohl noch einmal genau anschauen ;)
openHAB 4.1.0 Release mit openHABian in einem Debian Bookworm (LXC) unter Proxmox 8.1.3

Antworten