/* * Reguly zwiazane z systemem podlewania ogrodka */ import java.util.Date import org.joda.time.DateTime var int maxNoWtrDays = 2 // maksymalna ilosc dni bez opadow var DateTime lastWtrDate = null // data ostatniego podlewania albo kiedy padalo var minimumReqRainfall = 6 // minimalny przewidywany opad ktory powoduje zatrzymanie podlewania var rainfallMm = 0.0 // przewidywana ilosc opadow w trakcie nastepnych 24h var missingRainfall = 0.0 // ilosc w mm ile powinno dopadac w kolejnej dobie (ile napada - ile powinno) var isWatering = false // czy jest uruchomiony proces podlewania // timery do podlewania // W poprzedniej wersji byla hashmapa z timerami niestety z powodu bledu w OH czasami // hashmapa ustawiala sie na null i nie mozna bylo tego zmienic var Timer WtrValveFront_StartTimer var Timer WtrValveFront_StopTimer var Timer WtrValveBack_StartTimer var Timer WtrValveBack_StopTimer var Timer WtrValveLine_StartTimer var Timer WtrValveLine_StopTimer var Timer Wtr_StopTimer // Stale pozawalajace sterowac stykami o przeciwnej logice var OnOffType ON_R var OnOffType OFF_R // === Dane potrzebne do pobranie danych pogodowych z serwisu OpenWeatherMap === val APPID = "fdfdfdfdfd" // UWAGA! To nie powinno byc udostepniane na zewnatrz val cityId = 3092909 // dla Lublewo Gdanskie val cnt = 8 // ilosc 3h segmentow dla ktorych chcemy pobrac dane, 8 to 24h val openwheatherUrl = "http://api.openweathermap.org/data/2.5/" // ============================================================================= // Debug - dla celow testowania val checkUserStartTime = true // jesli true to sprawdza godzine podlewania, uzywane dla testow reguly val checkWtrRainSensor = true // jesli true to sprawdza czujnik opadow // Wylaczenie wszystkich elektrozaworow przy starcie systemu rule "Wtr_garden_startup" when System started then logInfo( "FILE", "Wtr_garden_startup: -START-") // pseudo stale initializacja ON_R = OFF OFF_R = ON isWatering = false logInfo( "FILE", "Wtr_garden_startup: Setting default values to valves") // wstepne ustawienie przekaznikow na wylaczone (glownie na potrzeby wyswietlania) WtrValveFront.sendCommand(OFF_R) WtrValveBack.sendCommand(OFF_R) WtrValveLine.sendCommand(OFF_R) if(WtrStartTime.state==NULL) { WtrStartTime.sendCommand("05:00") logInfo( "FILE", "Wtr_garden_startup: WtrStartTime SET TO [05:00]") } else { logInfo( "FILE", "Wtr_garden_startup: WtrStartTime [" + WtrStartTime.state + "]") } if(WtrDurationFront.state==NULL) { WtrDurationFront.sendCommand(15) logInfo( "FILE", "Wtr_garden_startup: WtrDurationFront SET TO [15]") } else { logInfo( "FILE", "Wtr_garden_startup: WtrDurationFront [" + WtrDurationFront.state + "]") } if(WtrDurationBack.state==NULL) { WtrDurationBack.sendCommand(15) logInfo( "FILE", "Wtr_garden_startup: WtrDurationBack SET TO [15]") } else { logInfo( "FILE", "Wtr_garden_startup: WtrDurationBack [" + WtrDurationBack.state + "]") } if(WtrDurationLine.state==NULL) { WtrDurationLine.sendCommand(20) logInfo( "FILE", "Wtr_garden_startup: WtrDurationLine SET TO [20]") } else { logInfo( "FILE", "Wtr_garden_startup: WtrDurationLine [" + WtrDurationLine.state + "]") } if(WtrScaleFactor.state==NULL) { WtrScaleFactor.sendCommand(100) logInfo( "FILE", "Wtr_garden_startup: WtrScaleFactor SET TO [10]") } else { logInfo( "FILE", "Wtr_garden_startup: WtrScaleFactor [" + WtrScaleFactor.state + "]") } if(MinimumReqRainfallCfg.state==NULL) { MinimumReqRainfallCfg.sendCommand(5) logInfo( "FILE", "Wtr_garden_startup: MinimumReqRainfallCfg SET TO [10]") } else { logInfo( "FILE", "Wtr_garden_startup: MinimumReqRainfallCfg [" + MinimumReqRainfallCfg.state + "]") } // wyswietlam po 80s bo ustawienie zmiennych przez zajmuje chwile logInfo( "FILE", "Wtr_garden_startup: ================ Wtr param initialization ================") logInfo( "FILE", "Wtr_garden_startup: WtrAuto [" + WtrAuto.state + "]") logInfo( "FILE", "Wtr_garden_startup: WtrRainSensor [" + WtrRainSensor.state + "]") logInfo( "FILE", "Wtr_garden_startup: checkWtrRainSensor [" + checkWtrRainSensor + "]") logInfo( "FILE", "Wtr_garden_startup: checkUserStartTime [" + checkUserStartTime + "]") logInfo( "FILE", "Wtr_garden_startup: isWatering [" + isWatering + "]") end // czujnik deszczu zarejestrowal podlewanie przerywa podlewanie jesli aktualnie ma miejsce rule "Wtr_Rain_sensor_rain_activated" when Item WtrRainSensor changed to OPEN then logInfo( "FILE", "Wtr_Rain_sensor_rain_activated: Rain detected, stopping watering if running") EventHist.sendCommand("Czujnik jest mokry - zaczelo padac") Notification_Proxy_Wtr.sendCommand("STOP") end rule "Wtr_Rain_sensor_rain_deactivated" when Item WtrRainSensor changed to CLOSED then logInfo( "FILE", "Wtr_Rain_sensor_rain_deactivated: Rain detected is dry") EventHist.sendCommand("Czujnik jest suchy") end // ustawienie podlewania na automatyczne rule "Wtr_auto_ON" when Item WtrAuto changed to CLOSED then logInfo( "FILE","Wtr_auto_OFF: Automatic watering set") EventHist.sendCommand("Ustawiono tryb Podlewanie Automatyczne") end // ustawienie podlewania na manualne rule "Wtr_auto_OFF" when Item WtrAuto changed to OPEN then logInfo( "FILE","Wtr_auto_OFF: Manual watering set") EventHist.sendCommand("Ustawiono tryb Podlewanie Manualne") end // Reczne zalaczanie/wylaczanie podlewania (przycisk wyprowadzony na panelu) rule "Wtr_manual_start_stop" when Item WtrStartBtn changed to OFF or Item WtrStartAppBtn changed to ON then logInfo( "FILE", "Wtr_manual_start_stop: isWatering[" +isWatering+ "]" ) // jesli wlaczone podlewanie to zatrzymuje w innym przypadku wlacza podlewanie if ( isWatering == false ) { logInfo( "FILE", "Wtr_manual_start_stop: Start watering, manual activation") EventHist.sendCommand("Zostało wciśnięty przycisk START podlewania") Notification_Proxy_Wtr.sendCommand("START") } else { logInfo( "FILE", "Wtr_manual_start_stop: Stoping watering, manual activation") EventHist.sendCommand("Zostało wciśnięty przycisk STOP podlewania") Notification_Proxy_Wtr.sendCommand("STOP") } end // Regula uruchomiajaca / zatrzymujaca podlewanie rule "Wtr_starting_stoping" when Item Notification_Proxy_Wtr received update then logInfo( "FILE", "Wtr_starting_stoping:============== Watering starting/stoping ==========") var String msg = Notification_Proxy_Wtr.state.toString logInfo( "FILE", "Wtr_starting_stoping: Stoping watering if already started") logInfo( "FILE", "Wtr_starting_stoping: msg [" + msg + "]") // zatrzymuje podlewanie jesli jest zalaczone, nie sprawdzam czy trwa czy nie // To zabezpiecza nas przed sytuacja gdzie np. dana strefa byla wlaczana recznie z poziomu // interfejsu graficznego // zatrzymanie timerow logInfo( "FILE", "Wtr_starting_stoping: WtrTimers") if(WtrValveFront_StartTimer !== null) WtrValveFront_StartTimer.cancel if(WtrValveFront_StopTimer !== null) WtrValveFront_StopTimer.cancel if(WtrValveBack_StartTimer !== null) WtrValveBack_StartTimer.cancel if(WtrValveBack_StopTimer !== null) WtrValveBack_StopTimer.cancel if(WtrValveLine_StartTimer !== null) WtrValveLine_StartTimer.cancel if(WtrValveLine_StopTimer !== null) WtrValveLine_StopTimer.cancel if(Wtr_StopTimer !== null) Wtr_StopTimer.cancel WtrValveFront.sendCommand(OFF_R) WtrValveBack.sendCommand(OFF_R) WtrValveLine.sendCommand(OFF_R) WtrLED.sendCommand(OFF) // proces podlewania zostal wylaczony isWatering = false // sprawdzam czy mam uruchomic podlewanie if (msg == "START") { logInfo( "FILE", "Wtr_starting_stoping: starting watering") // wlaczenie kontrolki podlewania WtrLED.sendCommand(ON) // proces podlewania zostal zalaczony isWatering = true // ustawione czasy podlewania - pobranie z itemow var Number durationFront = WtrDurationFront.state as DecimalType var Number durationBack = WtrDurationBack.state as DecimalType var Number durationLine = WtrDurationLine.state as DecimalType var DateTime startTime = now var DateTime endTime = now // ustawienie ostatniej daty podlewania dla wyswietlania w sitemap var String NowTime = String::format( "%1$td.%1$tm.%1$tY %1$tH:%1$tM", new Date() ) logInfo( "FILE","Wtr_starting_stoping: NowTime[" + NowTime + "]") WtrLastDate.sendCommand(NowTime) // wspolczynnik korygujacy do czasu podlewania var Number scaleFactor = WtrScaleFactor.state as DecimalType // uwzglednienie wspolczynnika korygujacego var int wtrFrontTime = ((durationFront * scaleFactor) / 100).intValue var int wtrBackTime = ((durationBack * scaleFactor) / 100).intValue var int wtrLineTime = ((durationLine * scaleFactor) / 100).intValue logInfo( "FILE","Wtr_starting_stoping: durationFront[" + durationFront + "]") logInfo( "FILE","Wtr_starting_stoping: durationBack [" + durationBack+ "]") logInfo( "FILE","Wtr_starting_stoping: durationLine [" + durationLine + "]") logInfo( "FILE","Wtr_starting_stoping: scaleFactor [" + scaleFactor + "]") logInfo( "FILE","Wtr_starting_stoping: wtrFrontTime [" + wtrFrontTime + "]") logInfo( "FILE","Wtr_starting_stoping: wtrBackTime [" + wtrBackTime + "]") logInfo( "FILE","Wtr_starting_stoping: wtrLineTime [" + wtrLineTime + "]") logInfo( "FILE","Wtr_starting_stoping: WtrRainSensor[" + WtrRainSensor.state + "]") // uruchamiam podlewania - przod if (wtrFrontTime > 0) { endTime = startTime.plusMinutes(wtrFrontTime) logInfo( "FILE", "Wtr_starting_stoping: Watering front starts [" + startTime + "] finish [" + endTime + "]") WtrValveFront_StartTimer= createTimer(startTime) [| logInfo( "FILE", "Wtr_starting_stoping: WtrValveFront[ON_R]") WtrValveFront.sendCommand(ON_R) ] WtrValveFront_StopTimer= createTimer(endTime) [| logInfo( "FILE", "Wtr_starting_stoping: WtrValveFront[OFF_R]") WtrValveFront.sendCommand(OFF_R) ] startTime = endTime.plusSeconds(10) } // uruchamiam podlewania - tyl if (wtrBackTime > 0) { endTime = startTime.plusMinutes(wtrBackTime) logInfo( "FILE", "Wtr_starting_stoping: Watering back start [" + startTime + "] finish [" + endTime + "]") WtrValveBack_StartTimer= createTimer(startTime) [| logInfo( "FILE", "Wtr_starting_stoping: WtrValveBack[ON_R]") WtrValveBack.sendCommand(ON_R) ] WtrValveBack_StopTimer= createTimer(endTime) [| logInfo( "FILE", "Wtr_starting_stoping: WtrValveBack[OFF_R]") WtrValveBack.sendCommand(OFF_R) ] startTime = endTime.plusSeconds(10) } // uruchamiam podlewania - linia kropelkujaca if (wtrLineTime > 0) { endTime = startTime.plusMinutes(wtrLineTime) logInfo( "FILE", "Wtr_starting_stoping: Watering line starts [" + startTime + "] finish [" + endTime + "]") WtrValveLine_StartTimer= createTimer(startTime) [| logInfo( "FILE", "Wtr_starting_stoping: WtrValveLine[ON_R]") WtrValveLine.sendCommand(ON_R) ] WtrValveLine_StopTimer= createTimer(endTime) [| logInfo( "FILE", "Wtr_starting_stoping: WtrValveLine[OFF_R]") WtrValveLine.sendCommand(OFF_R) ] startTime = endTime.plusSeconds(10) } sendPushoverMessage(pushoverBuilder("(2)Podlewanie ogrodka rozpoczete, zakonczenie o [" + endTime + "]").withPriority(-2)) // wykonuje operacje po zakonczeniu calego cyklu podlewania Wtr_StopTimer = createTimer(startTime) [| lastWtrDate = now logInfo( "FILE", "Wtr_starting_stoping: ==== Watering ended ====") WtrLED.sendCommand(OFF) isWatering = false EventHist.sendCommand("Podlewanie zostało zakończone") sendPushoverMessage(pushoverBuilder("Podlewanie zostało zakończone").withPriority(-2)) ] logDebug( "FILE", "Wtr_starting_stoping: Wtr_StopTimer[" + Wtr_StopTimer + "]") } end // Glowny algorytm podlewania rule "Wtr_algorithm" when Time cron "0 0 0/1 1/1 * ? *" //uruchamiane co godzine moze zmienic na co 15min // Time cron "0 0/5 * 1/1 * ? *" // Dla celow testowych wywolywane co 5 minut then logInfo( "FILE", "Wtr_algorithm: -START- ") // Sprawdzenie czy aktualna godzina jest godzina podlewania oraz czy system jest ustawiony na automatyczne podlewanie // oraz czy ma sprawdzac faktycznie godzine podlewania (checkUserStartTime) var DateTime userStartTime = parse(now.getYear() + "-" + now.getMonthOfYear() + "-" + now.getDayOfMonth() + "T" + WtrStartTime.state + ":00") logInfo( "FILE", " ======= Wheather algorithm ======= ") logInfo( "FILE", "Wtr_algorithm: now [" + now + "]") logInfo( "FILE", "Wtr_algorithm: userStartTime [" + userStartTime + "]") logInfo( "FILE", "Wtr_algorithm: checkUserStartTime [" + checkUserStartTime + "]") logInfo( "FILE", "Wtr_algorithm: isWatering [" + isWatering + "]") logInfo( "FILE", "Wtr_algorithm: WtrAuto.state [" + WtrAuto.state + "]") //sprawdzam czas godzina z godzina minuta z minuta, czy sprawdzamy ustawiony czas. Jesli system juz podlewa to nie sprawdza warunkow i nie podlewa. if ( ( ( userStartTime.getHourOfDay == now.getHourOfDay() && userStartTime.getMinuteOfHour() == now.getMinuteOfHour() ) || checkUserStartTime == false ) && WtrAuto.state == CLOSED && (isWatering == false) ) { logInfo( "FILE", "Wtr_algorithm: WtrRainSensor.state [" + WtrRainSensor.state + "]") logInfo( "FILE", "Wtr_algorithm: lastWtrDate [" + lastWtrDate + "]") logInfo( "FILE", "Wtr_algorithm: maxNoWtrDays [" + maxNoWtrDays + "]") logInfo( "FILE", "Wtr_algorithm: checkWtrRainSensor [" + checkWtrRainSensor + "]") logInfo( "FILE", "Wtr_algorithm: checkUserStartTime [" + checkUserStartTime + "]") logInfo( "FILE", "Wtr_algorithm: MinimumReqRainfallCfg [" + (MinimumReqRainfallCfg.state as DecimalType).intValue + "]") /* * Pobranie ilosci mm wody ktora potencjalnie spadnie do nastepnego rana w mm */ var forecastUrl = openwheatherUrl + "forecast?id=" + cityId + "&APPID=" + APPID + "&units=metric&cnt=" + cnt logInfo( "FILE", "Wtr_algorithm: Getting wheather forecast [" + forecastUrl + "]") // Probuje pobrac prognoze pogody do 3 razy var forecastJson="" try { forecastJson = sendHttpGetRequest(forecastUrl) var getCounter=0 while ( (forecastJson===null) && (getCounter<3)) { forecastJson = sendHttpGetRequest(forecastUrl) getCounter++ logInfo( "FILE", "Wtr_algorithm: getCounter[" + getCounter + "]") Thread::sleep(5000) } } catch(Throwable t) { logInfo("FILE", "Wtr_algorithm: Exception happen during getting heather data") forecastJson = null } logInfo( "FILE", "Wtr_algorithm: forecastJson[" + forecastJson + "]") rainfallMm = 0 if ( !(forecastJson === null)) { // Gdy blad zwracany jest NULL if( ! (forecastJson=="NULL")) { // wycinam liste - powinna miec tylko elementami 3h opadow/\ // https://community.openhab.org/t/solved-smhi-weather/22300/20 // Narzedzie do testow http://www.jsonquerytool.com/ // forecastJson="{\"cod\":\"200\",\"message\":0.0025,\"cnt\":8,\"list\":[{\"dt\":1534572000,\"main\":{\"temp\":18.32,\"temp_min\":18.32,\"temp_max\":19.62,\"pressure\":1021.48,\"sea_level\":1031.67,\"grnd_level\":1021.48,\"humidity\":83,\"temp_kf\":-1.31},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":68},\"wind\":{\"speed\":2.71,\"deg\":337.008},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2018-08-18 06:00:00\"},{\"dt\":1534582800,\"main\":{\"temp\":22.64,\"temp_min\":22.64,\"temp_max\":23.51,\"pressure\":1022.21,\"sea_level\":1032.39,\"grnd_level\":1022.21,\"humidity\":74,\"temp_kf\":-0.87},\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"clouds\":{\"all\":24},\"wind\":{\"speed\":3.02,\"deg\":354.507},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2018-08-18 09:00:00\"},{\"dt\":1534593600,\"main\":{\"temp\":24.32,\"temp_min\":24.32,\"temp_max\":24.76,\"pressure\":1022.01,\"sea_level\":1032.15,\"grnd_level\":1022.01,\"humidity\":74,\"temp_kf\":-0.44},\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":{\"all\":20},\"wind\":{\"speed\":2.51,\"deg\":350.5},\"rain\":{\"3h\":0.495},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2018-08-18 12:00:00\"},{\"dt\":1534604400,\"main\":{\"temp\":24.38,\"temp_min\":24.38,\"temp_max\":24.38,\"pressure\":1021.82,\"sea_level\":1032.09,\"grnd_level\":1021.82,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":{\"all\":0},\"wind\":{\"speed\":3.06,\"deg\":348.503},\"rain\":{\"3h\":2.1},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2018-08-18 15:00:00\"},{\"dt\":1534615200,\"main\":{\"temp\":21.07,\"temp_min\":21.07,\"temp_max\":21.07,\"pressure\":1021.97,\"sea_level\":1032.35,\"grnd_level\":1021.97,\"humidity\":56,\"temp_kf\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":{\"all\":0},\"wind\":{\"speed\":2.81,\"deg\":325.002},\"rain\":{},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2018-08-18 18:00:00\"},{\"dt\":1534626000,\"main\":{\"temp\":15.67,\"temp_min\":15.67,\"temp_max\":15.67,\"pressure\":1023.38,\"sea_level\":1033.67,\"grnd_level\":1023.38,\"humidity\":68,\"temp_kf\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"}],\"clouds\":{\"all\":0},\"wind\":{\"speed\":2.56,\"deg\":333.501},\"rain\":{},\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2018-08-18 21:00:00\"},{\"dt\":1534636800,\"main\":{\"temp\":12.21,\"temp_min\":12.21,\"temp_max\":12.21,\"pressure\":1023.52,\"sea_level\":1033.85,\"grnd_level\":1023.52,\"humidity\":89,\"temp_kf\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"}],\"clouds\":{\"all\":0},\"wind\":{\"speed\":1.28,\"deg\":157.002},\"rain\":{},\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2018-08-19 00:00:00\"},{\"dt\":1534647600,\"main\":{\"temp\":11.15,\"temp_min\":11.15,\"temp_max\":11.15,\"pressure\":1023,\"sea_level\":1033.33,\"grnd_level\":1023,\"humidity\":87,\"temp_kf\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"}],\"clouds\":{\"all\":0},\"wind\":{\"speed\":1.72,\"deg\":177.001},\"rain\":{},\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2018-08-19 03:00:00\"}],\"city\":{\"id\":3092909,\"name\":\"Lublewo Gdanskie\",\"coord\":{\"lat\":54.2846,\"lon\":18.5039},\"country\":\"PL\"}}" var String[] rainValues = transform("JS","rainvalues.js",forecastJson).replace("[", "").replace("]", "").split(",") rainfallMm = 0 // Sprawdzenie czy pojawila sie chociaz raz sekcja rain // Gdy w JSON nie ma sekecji rain to byl jedna wartosci i pusty string try { for (var i = 0; i < rainValues.length; i++) { rainfallMm = rainfallMm + (Double::parseDouble(rainValues.get(i))) } } catch(Throwable t) { // nie udalo sie pobrac prognozy opadow ustawiam ze nie bedzie opadow logInfo( "FILE", "Wtr_algorithm: Cannot find rain section - rainfallMm is 0mm ") rainfallMm = 0 } } else { logInfo( "FILE", "Wtr_algorithm: Wheather forecast is NULL - rainfallMm is 0mm ") } } // zaktualizwanie prognozy opadow i daty prognozy - wyswietlana w interfejscie WtrRainfallForecast.sendCommand(rainfallMm) var String NowTimeF = String::format( "%1$td.%1$tm.%1$tY %1$tH:%1$tM", new Date() ) WtrRainfallForecastDate.sendCommand(NowTimeF) minimumReqRainfall = (MinimumReqRainfallCfg.state as DecimalType).intValue logInfo( "FILE", " ======= Wheather forecast ======= ") logInfo( "FILE", "Wtr_algorithm: rainfallMm [" + rainfallMm + "]") logInfo( "FILE", "Wtr_algorithm: minimumReqRainfall [" + minimumReqRainfall + "]") // sprawdzenie stanu czujnika deszczu if ( WtrRainSensor.state == CLOSED || checkWtrRainSensor==false ) { logInfo( "FILE", "Wtr_algorithm: RainSensor is dry, check other conditions") //sprawdzenie czy spodziewana ilosc opadow bedzie wystarczajaca if (rainfallMm > minimumReqRainfall) { // opady w ciagu nastpnych 24h powinny byc wystarczajace // ale sprawdzam ile dni nie bylo podlewane jesli wiecej niz maxNoWtrDays to podlewam if(lastWtrDate===null) { logInfo( "FILE", "Wtr_algorithm: lastWtrDate is null, for safety starting watering") EventHist.sendCommand("Zostało załączone automatyczne podlewanie (S1a)") Notification_Proxy_Wtr.sendCommand("START") } else if(lastWtrDate.isBefore(now.minusDays(maxNoWtrDays))) { logInfo( "FILE", "Wtr_algorithm: lastWtrDate[" +lastWtrDate+ "] is later than now-maxNoWtrDays[" +maxNoWtrDays+ "]") EventHist.sendCommand("Zostało załączone automatyczne podlewanie (S1b)") Notification_Proxy_Wtr.sendCommand("START") } else { sendPushoverMessage(pushoverBuilder("(2)Nie podlewam - przewidywane opady " + rainfallMm + "mm w ciągu kolejnych 24 godzinych").withPriority(-2)) } } else { // przewidywana ilosc opadow w ciagu 24h jest niewystarczajaca missingRainfall = minimumReqRainfall - rainfallMm logInfo( "FILE", "Wtr_algorithm: Missing [" + missingRainfall + "] mm rainfall") EventHist.sendCommand("Zostało załączone automatyczne podlewanie (S2)") Notification_Proxy_Wtr.sendCommand("START") } logInfo( "FILE", " ======= End of Watering algorithm ======= ") } else { // czujnik daszczu jest zalaczony pada lub padalo lastWtrDate = now // ustawiam ze byl opad/podlewanie logInfo( "FILE", "Wtr_algorithm: watering not started, RainSensor is wet - watering is not needed") sendPushoverMessage(pushoverBuilder("(2)Nie podlewam - czujnik deszczu jest mokry").withPriority(-2)) } } else { logInfo( "FILE", "Wtr_algorithm: not started. checkUserStartTime[" +checkUserStartTime+ "] WtrAuto.stat[" +WtrAuto.state + "] isWatering[" +isWatering+ "] WtrRainSensor.state[" + WtrRainSensor.state + "]" ) } end