Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

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

Moderatoren: Cyrelian, seppy

Gesperrt
Benutzeravatar
Cyrelian
Beiträge: 601
Registriert: 24. Sep 2015 17:55
Answers: 4

Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von Cyrelian »

Hallo Forumgemeinde,

in den letzten Wochen hab ich mich intensiv mit meiner automatischen Gartenbewässerung / Beregnung beschäftigt und möchte nun die Ergebnisse mit euch teilen.
Als erstes mal jede Menge PE-HD Rohr unter die Erde bringen :mrgreen:
Verbaut habe ich Rain Bird Regner und Hunter Magentventile (Empfehlung von Seppy ;) )
Wer weitere Details zu den Komponenten der eingentlichen Bewässerung haben möchte, bitte PN an mich.

Steuerung:
Für die Steuerung der Beregnung habe ich folgende Komponenten verbaut:

Aktor(WIFI): Sonoff 4CH R2 (sehr günstige Alternative zum HomeMatic Funk-Schaltaktor 4-fach / Hutschiene)

Wichtig ist hier die PRO R2 Version!

Trafo(24VAC): Vemer vn318200 Trafo TMC 24/24


Auf den Sonoff habe ich selbstverständlich Tasmota geflashed :D

In der Unterverteilung sieht das Ganze dann so aus:
Verteiler.jpeg
So nun kommen wir mal zum opemHAB-Teil des Projektes. Die ITEMS und Rules wurden unter openHAB 2.3 erstellt!

ITEMS:
Als erstes nutze ich das Wunderground-Binding und seine ITEMS
Wunderground-Items

irrigation.items

Code: Alles auswählen

/* -------------  BEREGNUNG --------------------
 */
//---------------  Magnetventilschalter Hutschiene (Sonoff 4CH Pro R2)  ----------------
Group:Switch:OR(ON, OFF)	gABBeregnung			"Gartenbewässerung"						<irrigation>    (gGarten)
Switch						ABBeregnungMGV1			"MGV1 - Beregnung Segment (vorne)"		<irrigation>	(gABBeregnung,gIrrigation,gInitializeOff)	{mqtt=">[mosquitto:sonoff/ABBeregnung/cmnd/POWER1:command:*:default], <[mosquitto:sonoff/ABBeregnung/stat/POWER1:state:default]"}
Switch						ABBeregnungMGV2			"MGV2 - Beregnung Segment (mitte)"		<irrigation>	(gABBeregnung,gIrrigation,gInitializeOff)	{mqtt=">[mosquitto:sonoff/ABBeregnung/cmnd/POWER2:command:*:default], <[mosquitto:sonoff/ABBeregnung/stat/POWER2:state:default]"}
Switch						ABBeregnungMGV3			"MGV3 - Beregnung Segment (hinten)"		<irrigation>	(gABBeregnung,gIrrigation,gInitializeOff)	{mqtt=">[mosquitto:sonoff/ABBeregnung/cmnd/POWER3:command:*:default], <[mosquitto:sonoff/ABBeregnung/stat/POWER3:state:default]"}
Switch						ABBeregnungMGV4			"MGV4 - Beregnung Segment (xxxx)"		<irrigation>	(gABBeregnung,gIrrigation,gInitializeOff)	{mqtt=">[mosquitto:sonoff/ABBeregnung/cmnd/POWER4:command:*:default], <[mosquitto:sonoff/ABBeregnung/stat/POWER4:state:default]"}
Number						ABBeregnung_RSSI		"Magnetventilschalter RSSI [%d %%]"    	<network>   	(gSysRSSI)        				         	{mqtt="<[mosquitto:sonoff/ABBeregnung/tele/STATE:state:JSONPATH($.Wifi.RSSI)]"}
Switch						ABBeregnung_Unreach		"Magnetventilschalter unreachable"     	<siren>     	(gSysUnreach)     			        		{mqtt="<[mosquitto:sonoff/ABBeregnung/tele/LWT:state:MAP(unreach.map)]"}
String						ABBeregnung_FW			"Magnetventilschalter Firmware [%s]"   	<sonoff_4chpro> (gSysSonoff_Maintenance)					{mqtt="<[mosquitto:stat/ABBeregnung/STATUS2:state:JSONPATH($.StatusFWR.Version)"}

/* -------------  GRUPPEN --------------------
 */
Group	gProgramSettings	"Einstellungen"	(gIrrigation)	
//Programm A
Group	gProgramASettings   "Programm A - Einstellungen" <settings>	(gProgramSettings)	
Group	gProgramADuration	"Laufzeit"	                (gProgramASettings)
Group	gProgramADayOfWeek	"Wochentag"	                (gProgramASettings)	
//Programm B
Group	gProgramBSettings	"Programm B - Einstellungen" <settings>  (gProgramSettings)	
Group	gProgramBDuration	"Laufzeit"	                (gProgramBSettings)
Group	gProgramBDayOfWeek	"Wochentag"                 (gProgramBSettings)	

/* -------------  ITEMS --------------------
 */

//MISC
Number		ABBeregnung_Scale_Factor	"Skalierungsfaktor (Rain, Temp., Humidity) [%d %%]"       <water>         (gIrrigation)

//Virtuelle Schalter Beregnung
Switch	ABBeregnungMGV1_State 	"MGV1 - Beregnungssegment (vorne)"  		<irrigation>	(gIrrigation,gInitializeOff)
Switch  ABBeregnungMGV2_State	"MGV2 - Beregnungssegment (mitte)"	    	<irrigation>	(gIrrigation,gInitializeOff)
Switch	ABBeregnungMGV3_State	"MGV3 - Beregnungssegment (hinten)"		    <irrigation>	(gIrrigation,gInitializeOff)
Switch	ABBeregnung_Disable		"Deaktivierung der kompletten Beregnung"    <irrigation>	(gIrrigation,gInitializeOff)

//letzter Beregnungslauf
DateTime    ABBeregnungMGV1_LastRun    "Letzte Beregnung (vorne) [%1$td.%1$tm.%1$tY %1$tH:%1$tM]"  <time>  (gIrrigation)
DateTime    ABBeregnungMGV2_LastRun    "Letzte Beregnung (mitte) [%1$td.%1$tm.%1$tY %1$tH:%1$tM]"  <time>  (gIrrigation)
DateTime    ABBeregnungMGV3_LastRun    "Letzte Beregnung (hinten) [%1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time>  (gIrrigation)

// Programm A Master Einstellungen
Switch	ProgramA_Master             "Bewässerungsprogramm A"                <irrigation>	(gProgramASettings)
Switch	ProgramA_Master_DayofWeek   "Programm A Wochentag [%s]"	            <calendar>	    (gProgramASettings)
Switch	ProgramA_Master_Weather     "Regen im Forecast (Rain Delay) [%s]"   <rain>	        (gProgramASettings)	
Number	ProgramA_ScaleFactor        "Scale Factor [%d %%]"	                <water>	        (gProgramASettings)
String	ProgramA_StartTime          "nächste Startzeit [%s]"                <calendar>	    (gProgramASettings)
Number	ProgramA_StartTime_Hours    "Startzeit - Stunden [%d]"              <time>          (gProgramASettings)
Number	ProgramA_StartTime_Minutes  "Startzeit - Minuten [%d]"              <time>          (gProgramASettings)	

// Programm A Einstellungen
Number	ABBeregnungMGV1_Duration_A	"Laufzeit Beregnungssegment (vorne) [%d Min.]"  <time>	(gProgramASettings, gProgramADuration)	
Number	ABBeregnungMGV2_Duration_A	"Laufzeit Beregnungssegment (mitte) [%d Min.]"  <time>	(gProgramASettings, gProgramADuration)	
Number	ABBeregnungMGV3_Duration_A	"Laufzeit Beregnungssegment (hinten) [%d Min.]" <time>	(gProgramASettings, gProgramADuration)	
Number	ABBeregnungMGV4_Duration_A	"Laufzeit Beregnungssegment 4 [%d Min.]"        <time>	(gProgramASettings, gProgramADuration)	

Switch	Monday_ProgramA     "Montag [%s]"       <calendar>	(gProgramASettings, gProgramADayOfWeek)
Switch	Tuesday_ProgramA    "Dienstag [%s]"     <calendar>	(gProgramASettings, gProgramADayOfWeek)
Switch	Wednesday_ProgramA  "Mittwoch [%s]"     <calendar>	(gProgramASettings, gProgramADayOfWeek)
Switch	Thursday_ProgramA   "Donnerstag [%s]"   <calendar>	(gProgramASettings, gProgramADayOfWeek)
Switch	Friday_ProgramA     "Freitag [%s]"      <calendar>	(gProgramASettings, gProgramADayOfWeek)
Switch	Saturday_ProgramA   "Samstag [%s]"      <calendar>	(gProgramASettings, gProgramADayOfWeek)
Switch	Sunday_ProgramA     "Sonntag [%s]"      <calendar>	(gProgramASettings, gProgramADayOfWeek)	

// Programm B Master Einstellungen	
Switch	ProgramB_Master             "Bewässerungsprogramm B"        <irrigation>    (gProgramBSettings)
Switch	ProgramB_Master_DayofWeek   "Programm B Wochentag [%s]"	    <calendar>	    (gProgramBSettings)
Switch	ProgramB_Master_Weather     "Programm B Rain Delay [%s]"	<water>	        (gProgramBSettings)	
Number	ProgramB_ScaleFactor        "Scale Factor [%d %%]"	        <water>	        (gProgramBSettings)
String	ProgramB_StartTime          "Startzeit [%s]"	            <calendar>	    (gProgramBSettings)
Number	ProgramB_StartTime_Hours	"Stunden [%d]"	                <time>          (gProgramBSettings)
Number	ProgramB_StartTime_Minutes	"Minuten [%d]"                  <time>          (gProgramBSettings)		

// Programm B Einstellungen	
Number	ABBeregnungMGV1_Duration_B	"Segment (vorne) Laufzeit[%d Min.]"     <water>	(gProgramBSettings)	
Number	ABBeregnungMGV2_Duration_B	"Segment (mitte) Laufzeit[%d Min.]"     <water>	(gProgramBSettings)	
Number	ABBeregnungMGV3_Duration_B	"Segment (hinten) Laufzeit[%d Min.]"	<water>	(gProgramBSettings)	
Number	ABBeregnungMGV4_Duration_B	"Segment 4 Laufzeit[%d Min.]"           <water>	(gProgramBSettings)

Switch	Monday_ProgramB     "Montag [%s]"       <calendar>	(gProgramBSettings)
Switch	Tuesday_ProgramB    "Dienstag [%s]"     <calendar>	(gProgramBSettings)
Switch	Wednesday_ProgramB  "Mittwoch [%s]"     <calendar>	(gProgramBSettings)
Switch	Thursday_ProgramB   "Donnerstag [%s]"   <calendar>	(gProgramBSettings)
Switch	Friday_ProgramB     "Freitag [%s]"      <calendar>	(gProgramBSettings)
Switch	Saturday_ProgramB   "Samstag [%s]"      <calendar>	(gProgramBSettings)
Switch	Sunday_ProgramB     "Sonntag [%s]"      <calendar>	(gProgramBSettings)
RULES:

irrigation.rules

Der nachfolgende Code steht in einem Rule File, aber der Übersicht halber splitte ich mal Rule für Rule und kommentiere ein bischen.

Los geht es mit den globalen Variablen.

Code: Alles auswählen

val String filename = "irrigation.rules"                        // Loggername

// Automatische Beregnungstimer
var Timer MGV1StartTimer  = null
var Timer MGV1StopTimer   = null
var Timer MGV2StartTimer  = null
var Timer MGV2StopTimer   = null
var Timer MGV3StartTimer  = null
var Timer MGV3StopTimer   = null 
//var Timer WateringStopTimer   = null

// Manuelle Beregnugstimer
var Timer IrrigationTimer = null

//
val int maxOffDays = 2 //nach 2 Tagen wird der ProgramA_Master_Weather OFF geschaltet
val int minPrecipPercent = 50 //die minimale Niederschlagswahrscheinlichkeit zum Einschalten des ProgramA_Master_Weather
val int minPrecip = 4 //die Mindestmenge an Regen in den letzten 24 Stunden zum Einschalten des ProgramA_Master_Weather

Nach einem Systemneustart, wird geprüft ob ggf. noch Magnetventile offen sind und werden entsprechend geschlossen.

Code: Alles auswählen

rule "Irrigation startup"
when
    System started
then       
        gABBeregnung?.allMembers.filter(x | x.state != OFF).forEach[ item |
            logInfo(filename,"Beregnung: Beregnung wird deaktiviert")
            item.sendCommand(OFF) 
        ]
end
In dieser Rule wird geschaut, ob es heute geregnet hat, oder ob Regen im Forecast für morgen ist. Dazu werden die die IST-Werte mit den beiden Variablen minPrecip und minPrecipPercent verglichen. Sollte es hier eine Übereinstimmung geben, wird die Beregnung für die nächsten 2 Tage deaktiviert.

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")
            sendPushoverMessage(pushoverBuilder("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
Da Joda Time leider kein now.withTimeAtEndOfDay kann, schreibe ich den Regen Tageswert um 23:59 weg und schiebe es in die persistence.

Code: Alles auswählen

rule "Update rain yesterday"
when
   		Time cron "0 59 23 * * ?" //23:59:00
then
	if (RainToday.state !== null)
	{
		RainYesterday.postUpdate(RainToday)
	}
end
Nun folgt einer der wichtigsten Teile der Beregnung, die Berechnung des Scale Factors nach der Zimmermann Methode von Opensprinkler. Der Scale Factor dient dazu die Laufzeit der Regner dem Wetter anzupassen.
Beispiel: Normale Laufzeit eines Regners sind 15Min.(100%). Wenn nun der Scale Factor bei 115% liegt, läuft der Regner 17,25Min.

Code: Alles auswählen

rule "Calculate irrigation scale factor"
when
    Time cron "35 0/15 * * * ?" //alle 15Min und 15sek
then
    // die Durchschnittswerte der letzten 24 Stunden via persistence ermitteln
    
    // Luftfeuchtigkeit
    var Number averageHumidity = 30.0
        averageHumidity = Humidity.averageSince(now.minusHours(24), "influxdb")
    
    // Temperatur
    var Number averageTemp = 20.0
        averageTemp = Temperature.averageSince(now.minusHours(24), "influxdb")  

    // Regen
    var Number rainToday = 0 
        rainToday = RainToday.state

    var Number rainYesterday = 0

 	if (RainYesterday.historicState(now.withTimeAtStartOfDay, "influxdb") !== null) {
		rainYesterday = RainYesterday.historicState(now.withTimeAtStartOfDay, "influxdb").state as DecimalType
	}

    // Berechnung der verschiedenen Skalierungsfaktoren
    var Number humidityFactor = (30.0 - averageHumidity) * 1
    var Number tempFactor = (averageTemp - 21.0) * 4
    var Number rainFactor = (rainToday * -10.0) + (rainYesterday * -6.0)
    // Berechnung des Gesamtskalenfaktors
    var Number scaleFactor = (100 + humidityFactor + tempFactor + rainFactor)

    // apply limits (0 to 200%)
    if (scaleFactor < 0)
        scaleFactor = 0
    else if (scaleFactor > 200)
        scaleFactor = 200

    // Update veröffentlichen, damit die Bewässerungsregeln es verwenden können.
    ABBeregnung_Scale_Factor.postUpdate(scaleFactor.intValue)

    // die berechneten Werte protokollieren
    logInfo(filename,"Beregnung: Scale factor parameters: avgHumidity=" + String::format("%.2f", averageHumidity.floatValue) + ", avgTemp=" + String::format("%.2f", averageTemp.floatValue) + ", rainToday=" + String::format("%.1f", rainToday.floatValue) + ", rainYesterday=" + String::format("%.1f", rainYesterday.floatValue))
    logInfo(filename,"Beregnung: Calculated scale factor is " + scaleFactor.intValue + "% (humidity=" + String::format("%.2f", humidityFactor.floatValue) + ", temp=" + String::format("%.2f", tempFactor.floatValue) + ", rain=" + String::format("%.2f", rainFactor.floatValue) + ")")

end
Hier wird die Startzeit gesetzt, die man via Sitemap eingegeben hat.

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.getMonthOfYear() + "-" + now.getDayOfMonth() + "T" + hours + ":" + minutes)

    // update der Startzeit in der für Rules und Anzeige  
    ProgramA_StartTime.sendCommand(String::format("%02d:%02d", startTime.getHourOfDay(), startTime.getMinuteOfHour()))
end
Jetzt kommt das Herzstück der automatischen Beregnung. Hier werden die Faktoren aktivierte oder deaktivierte Beregnung, Wochentag, Automower, Wind, Regen und Scale Factor berücksichtigt.

Code: Alles auswählen

rule "Automatic Irrigation"
when
    Item ProgramA_Master received update ON or
	Time cron "15 30 5 ? * * *"
then
   var dayOfWeekSetting = newArrayList(
		Monday_ProgramA.state, 
		Tuesday_ProgramA.state, 
		Wednesday_ProgramA.state, 
		Thursday_ProgramA.state, 
		Friday_ProgramA.state, 
		Saturday_ProgramA.state, 
		Sunday_ProgramA.state
	)
    if (dayOfWeekSetting.get(now.getDayOfWeek-1) == OFF){
        ProgramA_Master_DayofWeek.sendCommand(OFF)
    	return
    } else {
		    ProgramA_Master_DayofWeek.sendCommand(ON)
        }
    
    if (ABBeregnung_Disable.state == ON) {                   
        //Das gesamte Bewässerungssystem ist deaktiviert.
        logInfo(filename,"Beregnung: Gesamte Beregnung deaktiviert!")
        return
    }

    if (ProgramA_Master_Weather.state == ON) {                   
        //Regen im Forecast.
        logInfo(filename,"Beregnung: Es hat geregnet oder Regen im Forecast")
        return
    }

    if (ABBeregnung_Scale_Factor.state < 10) {                   
        //Scale Factor ist kleiner 10%..keine Beregnung nötig
        logDebug(filename,"Beregnung: Der Boden ist feucht genug, Beregung nicht notwendig")
        return
    }

    if (ProgramA_Master.state == ON) {
		logInfo(filename,"Beregnung: Programm A wird geladen")
        // liefert den Skalierungsfaktor - wird verwendet, um die Laufzeiten zu reduzieren
        var Number scaleFactor = ABBeregnung_Scale_Factor.state as DecimalType
        logInfo(filename,"Beregnung: Skalierungsfaktor " + scaleFactor)

        // Startzeit in eine joda.time.DateTime für heute umwandeln
        var int minutes = (ProgramA_StartTime_Minutes.state as DecimalType).intValue()
		var int hours = (ProgramA_StartTime_Hours.state as DecimalType).intValue()
		var DateTime startTime = parse(now.getYear() + "-" + now.getMonthOfYear() + "-" + now.getDayOfMonth() + "T" + hours + ":" + minutes)
        logInfo(filename,"Beregnung: Startzeit Programm A: " + startTime)
        var DateTime endTime  
        
       	sendPushoverMessage(pushoverBuilder("Das Wetter sieht gut aus und die Beregnung wird für " + hours + ":" + minutes + " eingeplant"))

        // liefert die Rohlaufzeiten für jede Zone (in mins)
        var Number MGV1Mins = ABBeregnungMGV1_Duration_A.state as DecimalType
        var Number MGV2Mins = ABBeregnungMGV2_Duration_A.state as DecimalType
        var Number MGV3Mins = ABBeregnungMGV3_Duration_A.state as DecimalType

        // in die tatsächlichen Laufzeiten umrechnen (durch Anwendung des Skalierungsfaktors)
        var int MGV1Time = ((MGV1Mins * scaleFactor) / 100).intValue
        var int MGV2Time = ((MGV2Mins * scaleFactor) / 100).intValue
        var int MGV3Time = ((MGV3Mins * scaleFactor) / 100).intValue

        // jede Zone nacheinander einschalten (mit einem Abstand von einer Minute zwischen jeder Zonenaktivierung)
        if (startTime.isAfter(now)){
            if (MGV1Time > 0) {
                endTime = startTime.plusMinutes(MGV1Time)
                MGV1StartTimer = createTimer(startTime) [|
                            //Prüfen ob der Automower in der Ladestation ist (laden oder warten)
                            if (Automower_StatusCode.state != 1014 && Automower_StatusCode.state != 1056 && Automower_StatusCode.state != 1016) {     
                                logInfo(filename,"Beregnung: Automower fährt noch! Timer werden gestoppt.")
                                sendPushoverMessage(pushoverBuilder("Automower fährt noch! Timer werden gestoppt."))
                                MGV1StartTimer.cancel
        	                    MGV1StartTimer = null
                                MGV1StopTimer.cancel
        	                    MGV1StopTimer = null
                            }
                            if ((WindSpeed.state as QuantityType<Number>).doubleValue >= 4) {
                                //Prüfen der Windgeschwindigkeit
                                logInfo(filename,"Beregnung: Derzeit ist es zu windig! Timer werden gestoppt.")
                                sendPushoverMessage(pushoverBuilder("Derzeit zu windig! Timer werden gestoppt."))
                                MGV1StartTimer.cancel
        	                    MGV1StartTimer = null
                                MGV1StopTimer.cancel
        	                    MGV1StopTimer = null
                            } else {
                                ABBeregnungMGV1.sendCommand(ON)
                                ABBeregnungMGV1_State.postUpdate(ON)
                                }
                            ]
                MGV1StopTimer = createTimer(endTime) [|
                                ABBeregnungMGV1.sendCommand(OFF)
                                ABBeregnungMGV1_State.postUpdate(OFF)
                                ABBeregnungMGV1_LastRun.postUpdate(new DateTimeType())
                                ]
                logInfo(filename,"Beregnung: Beregnung für Segment (vorne) gestartet um ["+ startTime +"] und endet ["+ endTime +"]")
                startTime = endTime.plusMinutes(1)
            }
            
            if (MGV2Time > 0) {
                endTime = startTime.plusMinutes(MGV2Time)
                MGV2StartTimer = createTimer(startTime) [|
                            //Prüfen ob der Automower in der Ladestation ist (laden oder warten)
                            if (Automower_StatusCode.state != 1014 && Automower_StatusCode.state != 1056 && Automower_StatusCode.state != 1016) {     
                                logInfo(filename,"Beregnung: Automower fährt noch! Timer werden gestoppt.")
                                MGV2StartTimer.cancel
        	                    MGV2StartTimer = null
                                MGV2StopTimer.cancel
        	                    MGV3StopTimer = null
                            }
                            if ((WindSpeed.state as QuantityType<Number>).doubleValue >= 4) {
                                //Prüfen der Windgeschwindigkeit
                                logInfo(filename,"Beregnung: Derzeit ist es zu windig! Timer werden gestoppt.")
                                sendPushoverMessage(pushoverBuilder("Derzeit zu windig! Timer werden gestoppt."))
                                MGV1StartTimer.cancel
        	                    MGV1StartTimer = null
                                MGV1StopTimer.cancel
        	                    MGV1StopTimer = null
                            } else {                                
                                ABBeregnungMGV2.sendCommand(ON)
                                ABBeregnungMGV2_State.postUpdate(ON)
                                }
                            ]
                MGV2StopTimer = createTimer(endTime) [|
                                ABBeregnungMGV2.sendCommand(OFF)
                                ABBeregnungMGV2_State.postUpdate(OFF)
                                ABBeregnungMGV2_LastRun.postUpdate(new DateTimeType())
                                ]         
                logInfo(filename,"Beregnung: Beregnung für Segment (mitte) gestartet um ["+ startTime +"] und endet ["+ endTime +"]")
                startTime = endTime.plusMinutes(1)
            }

            if (MGV3Time > 0) {
                endTime = startTime.plusMinutes(MGV3Time)
                MGV3StartTimer = createTimer(startTime) [|
                            //Prüfen ob der Automower in der Ladestation ist (laden oder warten)
                            if (Automower_StatusCode.state != 1014 && Automower_StatusCode.state != 1056 && Automower_StatusCode.state != 1016) {     
                                logInfo(filename,"Beregnung: Automower fährt noch! Timer werden gestoppt.")
                                MGV3StartTimer.cancel
        	                    MGV3StartTimer = null
                                MGV3StopTimer.cancel
        	                    MGV3StopTimer = null
                            }
                            if ((WindSpeed.state as QuantityType<Number>).doubleValue >= 4) {
                                //Prüfen der Windgeschwindigkeit
                                logInfo(filename,"Beregnung: Derzeit ist es zu windig! Timer werden gestoppt.")
                                sendPushoverMessage(pushoverBuilder("Derzeit zu windig! Timer werden gestoppt."))
                                MGV1StartTimer.cancel
        	                    MGV1StartTimer = null
                                MGV1StopTimer.cancel
        	                    MGV1StopTimer = null
                            } else {                  
                                ABBeregnungMGV3.sendCommand(ON)
                                ABBeregnungMGV3_State.postUpdate(ON)
                                }
                            ]
                MGV3StopTimer = createTimer(endTime) [|
                                ABBeregnungMGV3.sendCommand(OFF)
                                ABBeregnungMGV3_State.postUpdate(OFF)
                                ABBeregnungMGV3_LastRun.postUpdate(new DateTimeType())
                                ]
                logInfo(filename,"Beregnung: Beregnung für Segment (hinten) gestartet um ["+ startTime +"] und endet ["+ endTime +"]")
                startTime = endTime.plusMinutes(1)
            }
    
        } else {
		    logInfo(filename,"Beregnung: Startzeit liegt in der Vergangenheit")
        }
    }  else {
		logInfo(filename,"Beregnung: Programm A nicht ausgeführt, Master Switch deaktiviert.")
        sendPushoverMessage(pushoverBuilder("Bewässerungsprogramm A ist deaktiviert, es wird heute keine Bewässerung eingeplant"))
	}   
end
Da man von Zeit zu Zeit ja auch mal manuell beregnen möchte, folgen hier die manuellen Rules unter Berücksichtigung der entpsrechenden Laufzeiten für die einzelnen Segmente.

Code: Alles auswählen

rule "MGV1 manual Irrigation"
when
	Item ABBeregnungMGV1_State received command 
then
	if (ABBeregnung_Disable.state == ON) {                   
       //Das gesamte Bewässerungssystem ist deaktiviert
       logInfo(filename,"Beregnung: Gesamte Beregnung deaktiviert!")
    return
    }
    
    if (receivedCommand == ON) {
		if (IrrigationTimer === null){
			logInfo(filename,"Beregnung: Beregnung für \"Beregnungssegment (vorne)\" manuell aktiviert, starte Timer")
			IrrigationTimer = createTimer(now.plusMinutes(Integer::parseInt(ABBeregnungMGV1_Duration_A.state.toString))) [|
				ABBeregnungMGV1_State.sendCommand(OFF)
				ABBeregnungMGV1_LastRun.postUpdate(new DateTimeType())
				logInfo(filename,"Beregnung: Manuelle Bewässerung für \"Beregnungssegment (vorne)\" beendet")
				sendPushoverMessage(pushoverBuilder("Manuelle Bewässerung für \"Beregnungssegment (vorne)\" nach einer Laufzeit von " + ABBeregnungMGV1_Duration_A.state.toString + " Minuten beendet"))
                IrrigationTimer = null
			]
		}
		ABBeregnungMGV1.sendCommand(ON)
		logInfo(filename,"Beregnung: Magnetventil \"Beregnungssegment (vorne)\" geschaltet [ON]")
	} else {
		ABBeregnungMGV1.sendCommand(OFF)
		ABBeregnungMGV1_LastRun.postUpdate(new DateTimeType())
		if (IrrigationTimer !== null){
			IrrigationTimer.cancel()
			IrrigationTimer = null
		}
		logInfo(filename,"Beregnung: Magnetventil \"Beregnungssegment (vorne)\" geschaltet [OFF]")
	}	
end

rule "MGV2 manual Irrigation"
when
	Item ABBeregnungMGV2_State received command 
then
	if (ABBeregnung_Disable.state == ON) {                   
       //Das gesamte Bewässerungssystem ist deaktiviert
       logInfo(filename,"Beregnung: Gesamte Beregnung deaktiviert!")
    return
    }
    
    if (receivedCommand == ON) {
		if (IrrigationTimer === null){
			logInfo(filename,"Beregnung: Beregnung für \"Beregnungssegment (mitte)\" manuell aktiviert, starte Timer")
			IrrigationTimer = createTimer(now.plusMinutes(Integer::parseInt(ABBeregnungMGV2_Duration_A.state.toString))) [|
				ABBeregnungMGV2_State.sendCommand(OFF)
				ABBeregnungMGV2_LastRun.postUpdate(new DateTimeType())
				logInfo(filename,"Beregnung: Manuelle Bewässerung für \"Beregnungssegment (mitte)\" beendet")
				sendPushoverMessage(pushoverBuilder("Manuelle Bewässerung für \"Beregnungssegment (mitte)\" nach einer Laufzeit von " + ABBeregnungMGV2_Duration_A.state.toString + " Minuten beendet"))
                IrrigationTimer = null
			]
		}
		ABBeregnungMGV2.sendCommand(ON)
		logInfo(filename,"Beregnung: Magnetventil \"Beregnungssegment (mitte)\" geschaltet [ON]")
	} else {
		ABBeregnungMGV2.sendCommand(OFF)
		ABBeregnungMGV2_LastRun.postUpdate(new DateTimeType())
		if (IrrigationTimer !== null){
			IrrigationTimer.cancel()
			IrrigationTimer = null
		}
		logInfo(filename,"Beregnung: Magnetventil \"Beregnungssegment (mitte)\" geschaltet [OFF]")
	}	
end

rule "MGV3 manual Irrigation"
when
	Item ABBeregnungMGV3_State received command 
then
	if (ABBeregnung_Disable.state == ON) {                   
       //Das gesamte Bewässerungssystem ist deaktiviert
       logInfo(filename,"Beregnung: Gesamte Beregnung deaktiviert!")
    return
    }

	if (receivedCommand == ON) {
		if (IrrigationTimer === null){
			logInfo(filename,"Beregnung: Beregnung für \"Beregnungssegment (hinten)\" manuell aktiviert, starte Timer")
			IrrigationTimer = createTimer(now.plusMinutes(Integer::parseInt(ABBeregnungMGV3_Duration_A.state.toString))) [|
				ABBeregnungMGV3_State.sendCommand(OFF)
				ABBeregnungMGV3_LastRun.postUpdate(new DateTimeType())
				logInfo(filename,"Beregnung: Manuelle Bewässerung für \"Beregnungssegment (hinten)\" beendet")
				sendPushoverMessage(pushoverBuilder("Manuelle Bewässerung für \"Beregnungssegment (hinten)\" nach einer Laufzeit von " + ABBeregnungMGV3_Duration_A.state.toString + " Minuten beendet"))
                IrrigationTimer = null
			]
		}
		ABBeregnungMGV3.sendCommand(ON)
		logInfo(filename,"Beregnung: Magnetventil \"Beregnungssegment (hinten)\" geschaltet [ON]")
	} else {
		ABBeregnungMGV3.sendCommand(OFF)
		ABBeregnungMGV3_LastRun.postUpdate(new DateTimeType())
		if (IrrigationTimer !== null){
			IrrigationTimer.cancel()
			IrrigationTimer = null
		}
		logInfo(filename,"Beregnung: Magnetventil \"Beregnungssegment (hinten)\" geschaltet [OFF]")
	}	
end
Seppy sagt mir, dass das Ganze nicht ohne einen "Watchdog" laufen sollte...es sei denn man möchte einen Sumpf anlegen :mrgreen:
Der Watchdog schaut alle 15Min. nach, ob ein Magnetventil fälschlicherweise geöffnet ist

Code: Alles auswählen

rule "Irrigation Watchdog"
when
	Time cron  "0 0/15 5-23 * * ?"
then
	if (ABBeregnung_Disable.state == ON) {                   
       //Das gesamte Bewässerungssystem ist deaktiviert
        gABBeregnung?.allMembers.filter(x | x.state != OFF).forEach[ item |
            logInfo(filename,"Beregnung: Beregnung wird deaktiviert")
            item.sendCommand(OFF) 
        ]
    return
    }
    if (ABBeregnungMGV1.state == ON && ABBeregnungMGV1_State.state == OFF){
		ABBeregnungMGV1.sendCommand(OFF)
		logInfo(filename,"Beregnung: MGV1 per Watchdog abgeschaltet")
	} 
	else if (ABBeregnungMGV2.state == ON && ABBeregnungMGV2_State.state == OFF){
		ABBeregnungMGV2.sendCommand(OFF)
		logInfo(filename,"Beregnung: MGV2 per Watchdog abgeschaltet")
	}
	else if (ABBeregnungMGV3.state == ON && ABBeregnungMGV3_State.state == OFF){
		ABBeregnungMGV3.sendCommand(OFF)
		logInfo(filename,"Beregnung: MGV3 per Watchdog abgeschaltet")
	}    
end
Zum guter letzt möchte man eine laufende Beregnung ggf. mal abbrechen. Dazu dient diese Rule.

Code: Alles auswählen

rule "Abort Irrigation"
	when 
		Item ABBeregnung_Disable received update ON
	then
		// Beregnung abbrechen, wenn sie gestartet wurde 
     	if (MGV1StartTimer !== null) {
       		    MGV1StartTimer.cancel
        	    MGV1StartTimer = null
        	    logInfo(filename, "Beregnung: MGV1StartTimer gestoped") 
    	}
    	
    	if  (MGV1StopTimer !== null) {
       		    MGV1StopTimer.cancel
        	    MGV1StopTimer = null
        	    logInfo(filename, "Beregnung: MGV1StopTimer gestoped") 
    	}
    	
     	if  (MGV2StartTimer !== null) {
       		    MGV2StartTimer.cancel
        	    MGV2StartTimer = null
        	    logInfo(filename, "Beregnung: MGV2StartTimer gestoped")  
    	}
    	
    	if  (MGV2StopTimer !== null) {
       	    	MGV2StopTimer.cancel
        	    MGV2StopTimer = null
        	    logInfo(filename, "Beregnung: MGV2StopTimer gestoped")  
    	}

     	if  (MGV3StartTimer !== null) {
       		    MGV3StartTimer.cancel
        	    MGV3StartTimer = null
        	    logInfo(filename, "Beregnung: MGV3StartTimer gestoped") 
    	}
    	
    	if  (MGV3StopTimer !== null) {
       		    MGV3StopTimer.cancel
            	MGV3StopTimer = null
        	    logInfo(filename, "Beregnung: MGV3StopTimer gestoped") 
    	}

    /*	if(WateringStopTimer !== null) {
       		WateringStopTimer.cancel
        	WateringStopTimer = null
        	logInfo(filename, "Watering_starting/stoping: WateringStopTimer stoped") 
    	} */
        ABBeregnungMGV1_State.sendCommand(OFF)
        ABBeregnungMGV2_State.sendCommand(OFF)
        ABBeregnungMGV3_State.sendCommand(OFF)
end
So, ich weiß, das ist erstmal ne Menge Holz, aber ich habe versucht im Code viele Kommentare zur Erklärung einzufügen.
Natürlich ist das hier nicht alles auf meinem Mist gewachsen und deshalb möchte ich mich bei folgenden Leuten bedanken:

Seppy, Alexander H., ben_jones, udo1toni, Michal_Szymanski, Spilota und Joshua A,

Hoffe wie immer hilft es dem einen oder anderen von Euch weiter und bin für Verbesserungsvorschläge immer offen ;)

CYA
Cyrelian
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Fahren
Beiträge: 23
Registriert: 28. Nov 2017 08:59

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von Fahren »

Danke fürs posten Deines Projektes.
OpenHab3 auf RSP4
Max Heizungssteuerung
Sonoff Licht und Energiermessung
Homematic CCU2 für Licht, Rolladen

swohf
Beiträge: 2
Registriert: 14. Mai 2018 07:36

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von swohf »

Vielen Dank für das Projekt.
Ich will mich jetzt auch an die Gartenbewässerung machen...

Ich habe nur noch ein paar kurze Fragen:
- Warum ist beim Sonoff die Pro Variante entscheident? Ich dachte, dass das alles per WLAN und MQTT eingebunden wird. Da bräuchte man doch die 433MHz gar nicht, oder?
- Hast Du ggf. einen Schaltplan, damit ich auch wirklich alles richtig anklemme?

Vielen Dank schon mal für Deine Hilfe

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

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von udo1toni »

Auszug aus https://github.com/arendst/Sonoff-Tasmo ... nd-4CH-Pro
Compared to the 4CH the main differences/improvements of the 4CH Pro are:

Relays are isolated from mains and can each switch their own circuit (mains or low voltage).
With stock firmware special modes are supported (stand-alone schedules, inching, interlocking).
RF receiver (optional key fob or Sonoff RF Bridge 433 required).
Dual microcontroller, both a ESP8285 and a STM32.
Vermutlich laufen die Ventile mit 24 Volt, da wäre es dann ziemlich unpraktisch, wenn man nur 230 Volt schalten könnte.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

swohf
Beiträge: 2
Registriert: 14. Mai 2018 07:36

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von swohf »

Ups, das hatte ich gar nicht gesehen.
Dann ist es dieser Punkt jetzt klar. Eine Frage habe ich dann aber leider doch noch:
Betriebt ihr den Sonoff mit 230V oder Nutzt ihr den 24V Trafo auch dafür?

bloody83
Beiträge: 1
Registriert: 1. Aug 2018 11:35

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von bloody83 »

Hallo @Cyrelian,

ich habe eine Frage bezüglich der Verkabelung.

Wie hast du dein 4CH Pro mit den Hunter Ventilen verbunden?

Denn die Ventile sind meines Erachtens alle 24V AC und das Sonoff biete ja nur 24V DC.

Oder hast du vor jedem Ventil ein Trafo hängen?
Wäre nett, wenn du das mal skizzieren könntest, oder den Aufbau genauer beschreiben.


Vielen Dank
Markus

Benutzeravatar
Cyrelian
Beiträge: 601
Registriert: 24. Sep 2015 17:55
Answers: 4

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von Cyrelian »

Hallo zusammen,

ich habe mal ein paar mehr Bilder gemacht...denke dann wird es deutlicher wie die Verkabelung aussehen muss.

1.) Die 433MHz sind uninteressant für das Projekt.
2.) Ihr brauchst die "Pro" Variante, da die "normale" nur 90-250V schalten kann und keine 24V.

Nun zu den Bildern:
Das ist der Trafo, der wird mit 230v (oben 1 und 6) angeschlossen. Unten geht rechts der NULL(gelb 12) zu den Ventilen(ein Nullleiter für alle Ventile). Die drei schwarzen Kabel sind die 24V für die Ventile. Diese kommen in den Sonoff in den mittleren Anschluss(COM). Das Kabel was zu den Ventilen geht, also die 24V zu jeden einzelnen Ventil liefert kommt in "NO" (normaly OPEN).
Der Sonoff selber wird wiederum mit 230V versorgt, das ist aber unabhängig von den 24V die er schaltet. Hier besteht der unterschied zu dem "normalen" Sonoff.
2018-08-01_18-13-56_305.jpg
2018-08-01_18-14-07_633.jpg
2018-08-01_18-14-21_810.jpg
2018-08-01_18-15-04_606.jpg
CYA
Cyrelian
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

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

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von udo1toni »

Nur, um das nochmal klarzustellen:

Das Sonoff 4CH R2 Pro hat einfach 4 potentialfreie Kontakte, die mittels Relais ausgeführt sind. Ob da nun AC oder DC (oder auf deutsch Wechselstrom oder Gleichstrom) drüber geht, ist ziemlich wurscht, allenfalls muss man Strom und Spannung im Auge behalten. Da die Magnetventile jeweils eine induktive Last darstellen, gilt das im besonderen Maße.

Ich kenne das Hunter System bisher noch nicht (eine Bekannte von mir möchte das aber für ihren Garten...), aber oftmals ist es bei Elektromagneten, die als AC angeboten werden, unerheblich, ob man sie mit AC oder DC betreibt. Auch hier gilt natürlich wieder, dass man Spannung und Strom im Auge behalten muss, denn 24V AC ist etwas komplett anderes als 24V DC.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Benutzeravatar
Cyrelian
Beiträge: 601
Registriert: 24. Sep 2015 17:55
Answers: 4

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von Cyrelian »

ACHTUNG!!!

Die Ventile bitte nicht mit 24V DC betreiben. Das wird zwar anfangs funktionieren, aber auf Dauer raucht euch die Spule ab.
Die Ventile von Rain Bird und Hunter brauchen 24 VAC!

CYA
Cyrelian

Rui785Red
Beiträge: 2
Registriert: 21. Aug 2018 19:27

Re: Automatisch Gartenbewässerung / Beregnung mit openHAB und Sonoff

Beitrag von Rui785Red »

Danke @Cyrelian für alle detaillierte Infos
Ich bin auch dabei meine Gartenbewässerung mit ein Sonoff 4CH Pro 2 aufzubauen.
Du steuerst 3 Ventilen mit dein 24VA Trafo. Ist es genug für alle 3 Ventilen?

Gesperrt