Ankündigung

Einklappen
Keine Ankündigung bisher.

Bewässerungsventile nacheinander aktivieren

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Bewässerungsventile nacheinander aktivieren

    Hallo zusammen,

    ich habe 3 Bewässerungsventile, die ich getrennt und nacheinander aktivieren muss. Um die einzelne Dauer beinflussen zu können, habe ich 3 items erstellt.

    NumberIrrigationTimer_1"Timer 1"<faucet>
    NumberIrrigationTimer_2"Timer 2"<faucet>
    NumberIrrigationTimer_3"Timer 3"<faucet>
    Diese sind in meiner Sitemap, so das ich die Werte verändern kann

    Nun wollte ich mit einer Regel die Ventile nacheinander starten, finde aber nicht die richtige Methode

    Ich hatte es mit Timern probiert, aber da hapert es an der Reihenfolge und ich bekomme die Werte aus meinen Items nicht übergeben und habe für den Test zunöchst mit festen Sekunden gearbeitet (daher unterscheiden sich die auskommentierten Watering Timer Werte)

    Code:
    [COLOR=#c586c0]rule[/COLOR][COLOR=#4ec9b0]TestIrrigation[/COLOR]  [COLOR=#c586c0]when[/COLOR]
      [COLOR=#569cd6]Item[/COLOR][COLOR=#4ec9b0]Sw_Irrigation[/COLOR][COLOR=#d4d4d4] received command[/COLOR]
      [COLOR=#c586c0]then[/COLOR]
      [COLOR=#c586c0]if[/COLOR][COLOR=#d4d4d4] (receivedCommand [/COLOR][COLOR=#d4d4d4]==[/COLOR][COLOR=#b5cea8]ON[/COLOR][COLOR=#d4d4d4]&&[/COLOR][COLOR=#4ec9b0]Sw_Bewaesserung[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]state [/COLOR][COLOR=#d4d4d4]==[/COLOR][COLOR=#b5cea8]ON[/COLOR][COLOR=#d4d4d4]&&[/COLOR][COLOR=#4ec9b0]Holiday[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]state [/COLOR][COLOR=#d4d4d4]==[/COLOR][COLOR=#b5cea8]OFF[/COLOR][COLOR=#d4d4d4]&&[/COLOR][COLOR=#4ec9b0]Sensor_humidity[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]state [/COLOR][COLOR=#d4d4d4]<[/COLOR][COLOR=#b5cea8]60[/COLOR][COLOR=#d4d4d4]) {[/COLOR]
      [COLOR=#d4d4d4]        logInfo([/COLOR][COLOR=#ce9178]"TEST"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#ce9178]"Bewässerung EIN"[/COLOR][COLOR=#d4d4d4])[/COLOR]
      [COLOR=#c586c0]if[/COLOR][COLOR=#d4d4d4] (t_green [/COLOR][COLOR=#d4d4d4]==[/COLOR][COLOR=#569cd6]null[/COLOR][COLOR=#d4d4d4]){[/COLOR]
      [COLOR=#d4d4d4]            pushNotification([/COLOR][COLOR=#ce9178]"TEST"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#ce9178]"Starte Ventil 1 - "[/COLOR][COLOR=#d4d4d4])[/COLOR]
      [COLOR=#d4d4d4]            logInfo([/COLOR][COLOR=#ce9178]"TEST"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#ce9178]"Starte Ventil 1"[/COLOR][COLOR=#d4d4d4])[/COLOR]
      [COLOR=#6a9955]//          Watering_Timer_1.sendCommand(15)[/COLOR]
      [COLOR=#d4d4d4]            t_green [/COLOR][COLOR=#d4d4d4]=[/COLOR][COLOR=#d4d4d4] createTimer(now[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]plusSeconds([/COLOR][COLOR=#b5cea8]55[/COLOR][COLOR=#d4d4d4]))[|[/COLOR]
      [COLOR=#d4d4d4]                pushNotification([/COLOR][COLOR=#ce9178]"TEST"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#ce9178]"Starte Ventil 2"[/COLOR][COLOR=#d4d4d4])[/COLOR]
      [COLOR=#d4d4d4]            logInfo([/COLOR][COLOR=#ce9178]"TEST"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#ce9178]"Starte Ventil 2"[/COLOR][COLOR=#d4d4d4])[/COLOR]
      [COLOR=#6a9955]//          Watering_Timer_2.sendCommand(15)[/COLOR]
      [COLOR=#d4d4d4]                t_green[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]cancel[/COLOR]
      [COLOR=#d4d4d4]                t_green [/COLOR][COLOR=#d4d4d4]=[/COLOR][COLOR=#569cd6]null[/COLOR]
      [COLOR=#d4d4d4]            ][/COLOR]
      [COLOR=#d4d4d4]            t_green [/COLOR][COLOR=#d4d4d4]=[/COLOR][COLOR=#d4d4d4] createTimer(now[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]plusSeconds([/COLOR][COLOR=#b5cea8]35[/COLOR][COLOR=#d4d4d4]))[|[/COLOR]
      [COLOR=#d4d4d4]                pushNotification([/COLOR][COLOR=#ce9178]"TEST"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#ce9178]"Starte Ventil 3"[/COLOR][COLOR=#d4d4d4])[/COLOR]
      [COLOR=#d4d4d4]            logInfo([/COLOR][COLOR=#ce9178]"TEST"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#ce9178]"Starte Ventil 1"[/COLOR][COLOR=#d4d4d4])[/COLOR]
      [COLOR=#6a9955]//          Watering_Timer_2.sendCommand(15)[/COLOR]
      [COLOR=#d4d4d4]                t_green[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]cancel[/COLOR]
      [COLOR=#d4d4d4]                t_green [/COLOR][COLOR=#d4d4d4]=[/COLOR][COLOR=#569cd6]null[/COLOR]
      [COLOR=#d4d4d4]            ][/COLOR]
      [COLOR=#d4d4d4]        }[/COLOR]
      [COLOR=#d4d4d4]    } [/COLOR][COLOR=#c586c0]else[/COLOR][COLOR=#c586c0]if[/COLOR][COLOR=#d4d4d4] (receivedCommand [/COLOR][COLOR=#d4d4d4]==[/COLOR][COLOR=#b5cea8]ON[/COLOR][COLOR=#d4d4d4]&&[/COLOR][COLOR=#4ec9b0]Sw_Bewaesserung[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]state [/COLOR][COLOR=#d4d4d4]==[/COLOR][COLOR=#b5cea8]OFF[/COLOR][COLOR=#d4d4d4]&&[/COLOR][COLOR=#4ec9b0]Holiday[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]state [/COLOR][COLOR=#d4d4d4]==[/COLOR][COLOR=#b5cea8]OFF[/COLOR][COLOR=#d4d4d4]) {[/COLOR]
      [COLOR=#d4d4d4]        pushNotification([/COLOR][COLOR=#ce9178]"TEST - Auto. Bewässerung"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#4ec9b0]Sw_Bewaesserung[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]state[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]toString)[/COLOR]
      [COLOR=#4ec9b0]Sw_Irrigation[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]sendCommand([/COLOR][COLOR=#b5cea8]OFF[/COLOR][COLOR=#d4d4d4])[/COLOR]
        [COLOR=#d4d4d4]    } [/COLOR][COLOR=#c586c0]else[/COLOR][COLOR=#c586c0]if[/COLOR][COLOR=#d4d4d4] (receivedCommand [/COLOR][COLOR=#d4d4d4]==[/COLOR][COLOR=#b5cea8]OFF[/COLOR][COLOR=#d4d4d4]) {[/COLOR]
      [COLOR=#d4d4d4]        logInfo([/COLOR][COLOR=#ce9178]"TEST Irrigation"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#ce9178]"Irrigation stopped"[/COLOR][COLOR=#d4d4d4])[/COLOR]
      [COLOR=#c586c0]if[/COLOR][COLOR=#d4d4d4] (t_green [/COLOR][COLOR=#d4d4d4]!=[/COLOR][COLOR=#569cd6]null[/COLOR][COLOR=#d4d4d4]){[/COLOR]
      [COLOR=#d4d4d4]                t_green[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]cancel[/COLOR]
      [COLOR=#d4d4d4]                t_green [/COLOR][COLOR=#d4d4d4]=[/COLOR][COLOR=#569cd6]null[/COLOR]
      [COLOR=#d4d4d4]        }[/COLOR]
      [COLOR=#6a9955]          Watering_Timer_1sendCommand(0)[/COLOR]
      [COLOR=#6a9955]          Watering_Timer_2.sendCommand(0)[/COLOR]
      [COLOR=#6a9955]          Watering_Timer_3.sendCommand(0)[/COLOR]
      [COLOR=#d4d4d4]        logInfo([/COLOR][COLOR=#ce9178]"TEST Irrigation"[/COLOR][COLOR=#d4d4d4], [/COLOR][COLOR=#4ec9b0]Valves[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]state[/COLOR][COLOR=#d4d4d4].[/COLOR][COLOR=#d4d4d4]toString)[/COLOR]
      [COLOR=#d4d4d4]    }[/COLOR]
      [COLOR=#c586c0]end[/COLOR]
    Die Werte der Timer würden dann quasi aufeinander aufbauen, die Watering_Timer würden dann den Wert aus den IrrigationTimer erhalten und laufen automatisch gegen 0
    Somit müsste das zweite Ventil t-10 Sekunden von IrrigationTimer 1 den Einschaltbefehl erhalten, damit diese 10 Sekunden überlappend laufen um die Pumpe nicht abzuschalten.

    Habt ihr hier einen Tip wie ich diese Regel angehen sollte?

    Viele Grüße,
    Jörg

    #2
    Die Reihenfolge ist immer Ventil 1, Ventil 2, Ventil 3, nur die Einschaltdauer soll über die Items gesteuert werden?

    Das Einfachste wäre eine einfache State Machine:
    Code:
    var Timer tWater = null
    var Number nWater = 0
    
    rule "Bewässerung"
    when
        Item Starte_Bewaesserung received command ON
    then
        if (tWater === null) {
            nWater = 0
            tWater = createTimer(now,[ |
                var Number nTime = 30
                nWater += 1
               switch (nWater) {
                   case 1: {
                       Ventil1.sendCommand(ON)
                       if((Watering_Timer_1.state instanceof Number)) nTime = Watering_Timer_1.state as Number
                       tWater.reschedule(now.plusSeconds(nTime))
                   }
                   case 2: {
                       Ventil2.sendCommand(ON)
                       tWater.reschedule(now.plusSeconds(10))
                   }
                   case 3: {
                       Ventil1.sendCommand(OFF)
                       if((Watering_Timer_2.state instanceof Number)) nTime = Watering_Timer_2.state as Number
                       tWater.reschedule(now.plusSeconds(nTime))
                   }
                   case 4: {
                       Ventil3.sendCommand(ON)
                       tWater.reschedule(now.plusSeconds(10))
                   }
                   case 5: {
                       Ventil2.sendCommand(OFF)
                       if((Watering_Timer_3.state instanceof Number)) nTime = Watering_Timer_3.state as Number
                       tWater.reschedule(now.plusSeconds(nTime))
                   }
                   default: {
                       Ventil1.sendCommand(OFF)
                       Ventil2.sendCommand(OFF)
                       Ventil3.sendCommand(OFF)
                       tWater = null
                   }
               }
            ])
        }
    end
    Folgendes passiert:
    Sobald die Rule getriggert wird, erfolgt eine Prüfung, ob der Timer bereits läuft. Ist dies nicht der Fall, wird der Zähler zurückgesetzt und der Timer angelegt. Der Code im Timer wird anschließend sofort ausgeführt (falls es zu einer Fehlermeldung kommt, kann man für den ersten Timer noch eine kleine Verzögerung einbauen, z.B. 200Millisekunden).
    Als erstes wird der Zähler erhöht. Anschließend werden in Abhängigkeit vom Zähler verschiedene Aktionen ausgeführt. Zuerst wird das erste Ventil geöffnet, anschließend wird eine erneute Ausführung des Timers geplant. Läuft der Timer ab, wird das zweite Ventil geöffnet und der Timer erneut geplant. Zehn Sekunden später wird das erste Ventil geschlossen. In den nächsten Schritten wiederholt sich das Spiel mit den übrigen Ventilen.
    nWater wird jedesmal zuerst auf einen Default Wert gesetzt, danach wird geprüft, ob das jeweilige Item eine gültige Zahl enthält, falls das der Fall ist, wird der Default Wert überschrieben.
    Als letzten Schritt werden alle Ventile geschlossen (nur zur Sicherheit...) und der Zeiger auf den Timer wieder gelöscht. Damit kann die Rule erneut den Timer starten.

    Um die Beregnung jederzeit stoppen zu können, braucht es im Zweifel eine weitere Rule:
    Code:
    rule "BEwässerung stoppen"
    when
        Item Start_Bewaesserung received command OFF
    then
        tWater?.cancel
        tWater = null
        Ventil1.sendCommand(OFF)
        Ventil2.sendCommand(OFF)
        Ventil3.sendCommand(OFF)
    end
    Natürlich kannst Du auch plusMinutes() statt plusSeconds() verwenden

    Falls man während der Beregnung die Zeiten ändert, wirkt sich das nur auf die Schritte aus, die noch nicht aktiv sind, da der Timer zum Abschaltzeitpunkt des vorherigen Regners gesetzt wird.

    Es gäbe durchaus noch Spielraum für Optimierungen, so dass man den Code innerhalb des Timers weiter drücken könnte (alle Ventile in eine Gruppe, die Namen der Ventile berechnen und entsprechend des Schritts steuern, dabei keine sturen Schritte verwenden sondern etwas Mathe...) aber dazu reicht gerade meine Denkleistung nicht mehr aus.
    Zuletzt geändert von udo1toni; 16.06.2019, 08:15.

    Kommentar


      #3
      Zitat von udo1toni Beitrag anzeigen
      Die Reihenfolge ist immer Ventil 1, Ventil 2, Ventil 3, nur die Einschaltdauer soll über die Items gesteuert werden?
      Ja, wobei ich evtl. auch mal 1 Ventil überspringen möchte. Geht da auch 0 als Timerwert? Oder müsste ich dies separat abfangen??

      Zitat von udo1toni Beitrag anzeigen
      aber dazu reicht gerade meine Denkleistung nicht mehr aus.
      So einen Code hätte ich mit meiner Denkleistung nicht erreicht!! Danke für den Schubs.

      wie funktioniert denn das ‚hochzählen‘ der Switchvariablen nWater?? Da blicke ich noch nicht durch

      VG Jörg

      Kommentar


        #4
        Zitat von JoergA Beitrag anzeigen
        Ja, wobei ich evtl. auch mal 1 Ventil überspringen möchte. Geht da auch 0 als Timerwert? Oder müsste ich dies separat abfangen??
        Letzteres, durch die Verzögerung zum Ausschalten läuft das Wasser mindestens 10 Sekunden. Man kann das aber mit in den Code einbauen.

        wie funktioniert denn das ‚hochzählen‘ der Switchvariablen nWater?? Da blicke ich noch nicht durch
        Naja, ich habe abgekürzt
        Code:
        nWater += 1
        bedeutet das gleiche wie
        Code:
        nWater = nWater + 1
        Ich hab noch etwas über den Code nachgedacht. das ist dabei heraus gekommen:

        Items:
        Code:
        Group:Switch gVentEnable "Ventil erlauben"
        Group:Number gVentTimer "Einschaltdauer"
        Group:Switch gVentile "Ventile"
        
        Switch VentEnable_1 "Ventil 1 enable [%s]" (gVentEnable)
        Switch VentEnable_2 "Ventil 2 enable [%s]" (gVentEnable)
        Switch VentEnable_3 "Ventil 3 enable [%s]" (gVentEnable)
        Switch Ventil_1 "Ventil 1 [%s]" (gVentile)
        Switch Ventil_2 "Ventil 2 [%s]" (gVentile)
        Switch Ventil_3 "Ventil 3 [%s]" (gVentile)
        Number VentTimer_1 "Einschaltdauer Ventil 1 [%.0f min]" (gVentTimer)
        Number VentTimer_2 "Einschaltdauer Ventil 2 [%.0f min]" (gVentTimer)
        Number VentTimer_3 "Einschaltdauer Ventil 3 [%.0f min]" (gVentTimer)
        Rule
        Code:
        var Timer tWater = null
        var Number nWater
        
        rule "Bewässerung"
        when
            Item Starte_Bewaesserung received command                                                                     // start oder stop mittels ON oder OFF
        then
            if(receivedCommand == OFF) {                                                                                  // stoppen
                tWater?.cancel                                                                                            // timer beenden, falls vorhanden
                tWater = null                                                                                             // Zeiger löschen
                gVentile.members.forEach[v | v.sendCommand(OFF)]                                                          // und alle Ventile schließen
            }
            if(receivedCommand == ON && tWater === null) {                                                                // starten und kein Timer vorhanden
                nWater = - 1                                                                                              // Zähler mit -1 initialisieren
                tWater = createTimer(now, [ |                                                                             // timer mit code initialisieren und ausführen
                    var Number nTime = 30                                                                                 // Default Einscahltzeit definieren
                    nWater += 1                                                                                           // Zähler erhöhen
                    if((nWater/2).intValue == nWater/2) {                                                                 // gerade
                        var gVent = gVentile.members.filter[i | i.name.contains((nWater/2 + 1).toString)]                 // Ventil bestimmen
                        if(gVent.size > 0)                                                                                // Ventil existiert
                            if(gVentEnable.members.filter[i | i.name.contains((nWater/2 + 1).toString)].head.state == ON) // und soll aktiviert werden
                                gVent.head.sendCommand(ON)                                                                // einschalten
                        tWater.reschedule(now.plusSeconds(10))                                                            // und nach 10 Sekunden nächster Schritt
                    } else {                                                                                              // ungerade
                        var gVent = gVentile.members.filter[i | i.name.contains(((nWater/2 + 1) - 1).toString)]           // Ventil bestimmen
                        if(gVent.size > 0)                                                                                // Ventil existiert
                            gVent.head.sendCommand(OFF)                                                                   // ausschalten
                        var gTime = gVentTimer.members.filter[i | i.name.contains(((nWater +1)/2).intValue.toString)]     // Zeit bestimmen
                        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
                            tWater.reschedule(now.plusMinutes(nTime).minusSeconds(20))                                    // nach gewählter Zeit nächster Schritt
                        } else {                                                                                          // kein weiterer Timer vorhanden, also
                            tWater = null                                                                                 // Zeiger löschen
                        }
                    }
                ])
            }
        end
        Der Witz bei dieser Form ist, dass die Anzahl der Ventile keine Rolle spielt. Du könntest also auch 30 oder 300 Ventile einsetzen, die Rule muss dafür nicht mehr geändert werden.
        Aber selbst bei drei Ventilen braucht die Rule schon weniger Zeilen als mit der switch-case Konstruktion. Zugegebenermaßen ist der Code aber nicht mehr ganz einfach zu verstehen
        Die Laufzeit muss pro Ventil mindestens 21 Sekunden betragen, damit die Kompensation der Laufzeit funktioniert. Da die Regner wohl eher jeweils einige Minuten laufen werden, habe ich das oben schon mal angepasst.
        Zuletzt geändert von udo1toni; 16.06.2019, 08:19.

        Kommentar


          #5
          Da muss ich jetzt erst einmal 5-12 mal lesen um halbwegs hinter diesen Code zu kommen Wie immer bin ich beeindruckt über Deine Programierkenntnisse

          Mir fällt gerade auf, dass Du die Ventile mit (ON) einschaltest, was bei dem Gardena Binding für die "Irrigation Control" nicht funktioniert, diese benötigen die Zeit gesendet, mit der diese laufen sollen. Diese Zeit läuft dann automatisch ab und die Ventile benötigen (nicht zwingend) einen Ausschaltbefehl. Sinvoll ist aber allemal die Ausschaltroutine, falls der Ausschaltbefehl zur Laufzeit der Ventile kommt.

          Item
          Code:
          // smart Irrigation Control
          Number Watering_Timer_1 "Watering Timer 1 [%d min] {channel="gardena:ic24:home:myIrrigationController:watering#watering_timer_1" }
          Und dann in der Rule
          Code:
          Watering_Timer_1.sendCommand(30) // turn on for 30 minutes
          Watering_Timer_1.sendCommand(0) // turn off watering
          Somit müsste ich dann den jeweiligen Zeitwert aus VentTimer_x an das Ventil senden Ich habe nur noch nicht gefunden in welche Variable to dies schickst um diese zu setzen. (Oder es ist noch zu früh für mich)

          Und was bewirkt bitte: ".head.state" Dies habe ich so noch nicht gelesen und finde derzeit keine Erklärung im www
          Zuletzt geändert von JoergA; 16.06.2019, 10:37. Grund: Erweiterte Info's ergänzt

          Kommentar


            #6
            Ich habe dann mal die obere Variante (an die untere habe ich mich im ersten Schritt noch nicht gewagt, obwohl ich diesen deutlich smarter finde) angepasst, auf den Umstand, dass die Items/Things ja den Wert erhalten müssen, für den die laufen. Der Übersichtlichkeit halber nur der Teil der Bewässerung, ohne den Rule Anteil (welcher ja funktioniert)

            Code:
                    logInfo("TEST", "Bewässerung EIN")
                    if (tWater === null) {
                        nWater = 0
                        tWater = createTimer(now,[ |
                            var Number nTime = 30
                            nWater += 1
                            logInfo("TEST", "nWater " + nWater)
                            logInfo("TEST", "nWater " + IrrigationTimer_1.state as Number)
                            switch (nWater) {
                                case 1: {
                                    pushNotification("TEST", "Starte Ventil 1 für: " + IrrigationTimer_1.state as Number + " Min")
            //                        Watering_Timer_1.sendCommand(IrrigationTimer_1.state as Number)
                                    if((IrrigationTimer_2.state instanceof Number)) nTime = IrrigationTimer_2.state as Number
                                    nTime -=5
                                    tWater.reschedule(now.plusSeconds(nTime))
                                }
                                case 2: {
                                    pushNotification("TEST", "Starte Ventil 2 für: " + IrrigationTimer_2.state as Number + " Min")
            //                        Watering_Timer_2.sendCommand(IrrigationTimer_2.state as Number)
                                    if((IrrigationTimer_3.state instanceof Number)) nTime = IrrigationTimer_3.state as Number
                                    nTime -=5
                                    tWater.reschedule(now.plusSeconds(nTime))
                                }
                                case 3: {
                                    pushNotification("TEST", "Starte Ventil 3 für: " + IrrigationTimer_3.state as Number + " Min")
            //                        Watering_Timer_.sendCommand(IrrigationTimer_3.state as Number)
                                    if((IrrigationTimer_3.state instanceof Number)) nTime = IrrigationTimer_3.state as Number
                                    nTime +=10
                                    tWater.reschedule(now.plusSeconds(nTime))
                                }
                                default: {
                                    pushNotification("TEST", "Alle AUS")
            //                        Watering_Timer_1.sendCommand(0)
            //                        Watering_Timer_2.sendCommand(0)
            //                        Watering_Timer_3.sendCommand(0)
                                    tWater = null
                                }
                            }
                        ])
                    }
            Die Routine startet, springt jedoch immer direkt auf den default :-/ nWater ist zu diesem Zeitpunkt erwartungsgemäß mit 1 gefüllt.
            Zuletzt geändert von JoergA; 16.06.2019, 11:38. Grund: Code ohne Formatierung

            Kommentar


              #7
              Ah ja, dann muss der Code natürlch ein wenig anders funktionieren. Allerdings hast Du, glaube ich, noch nicht verstanden, wie die Rule funktioniert. Mit der Zusatzinformation, dass Gardena sich selbst um das Ausschalten kümmert, wird die Rule etwas schlanker, da man nun nicht mehr extra Ausschaltbefehle senden muss. Sähe so aus:
              Code:
              var Timer tWater = null
              var Number nWater = 0
              
              rule "Bewässerung"
              when
                  Item Starte_Bewaesserung received command
              then
                  if(receivedCommand == ON) {
                      if(tWater === null) {
                          nWater = 0
                          tWater = createTimer(now,[ |
                              var Number nTime = 30
                              nWater = nWater + 1
                              switch (nWater) {
                                  case 1: {
                                      if((Irrigation_Timer_1.state instanceof Number)) nTime = Irrigation_Timer_1.state as Number
                                      Watering_Timer_1.sendCommand(nTime)
                                      tWater.reschedule(now.plusMinutes(nTime).minusSeconds(10))
                                  }
                                  case 2: {
                                      if((Irrigation_Timer_2.state instanceof Number)) nTime = Irrigation_Timer_2.state as Number
                                      Watering_Timer_2.sendCommand(nTime)
                                      tWater.reschedule(now.plusMinutes(nTime).minusSeconds(10))
                                  }
                                  case 3: {
                                      if((Irrigation_Timer_3.state instanceof Number)) nTime = Irrigation_Timer_3.state as Number
                                      Watering_Timer_3.sendCommand(nTime)
                                      tWater.reschedule(now.plusMinutes(nTime))
                                  }
                                  default: {
                                      tWater = null
                                      Watering_Timer_1.sendCommand(0)
                                      Watering_Timer_2.sendCommand(0)
                                      Watering_Timer_3.sendCommand(0)
                                  }
                              }
                          ])
                      }
                  } else {
                      tWater?.cancel
                      tWater = null
                      Watering_Timer_1.sendCommand(0)
                      Watering_Timer_2.sendCommand(0)
                      Watering_Timer_3.sendCommand(0)
                  }
              end
              Das heißt, der Ausschaltimpuls kommt vom Gardena System, in openHAB läuft der Timer mit, der 10 Sekunden vor Ablauf des Timers im Gardena System das nächste Ventil öffnet.
              Auch hier ist die andere Variante schlanker:
              Code:
              var Timer tWater = null
              var Number nWater
              
              rule "Bewässerung"
              when
                  Item Starte_Bewaesserung received command                                                              // start oder stop mittels ON oder OFF
              then
                  if(receivedCommand == OFF) {                                                                           // stoppen
                      tWater?.cancel                                                                                     // timer beenden, falls vorhanden
                      tWater = null                                                                                      // Zeiger löschen
                      gVentile.members.forEach[v | v.sendCommand(0)]                                                     // und alle Ventile schließen
                  }
                  if(receivedCommand == ON && tWater === null) {                                                         // starten und kein Timer vorhanden
                      nWater = 0                                                                                         // Zähler mit 0 initialisieren
                      tWater = createTimer(now, [ |                                                                      // timer mit code initialisieren und ausführen
                          var Number nTime = 30                                                                          // Default Einschaltzeit definieren
                          nWater += 1                                                                                    // Zähler erhöhen
                          var gVent = gVentile.members.filter[i | i.name.contains(nWater.toString)]                      // Ventil bestimmen
                          var gTime = gVentTimer.members.filter[i | i.name.contains(nWater.toString)]                    // Zeit bestimmen
                          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(nWater.toString)].head.state == ON)  // und soll aktiviert werden
                                      gVent.head.sendCommand(nTime)                                                      // Gardena Timer setzen
                                  tWater.reschedule(now.plusMinutes(nTime).minusSeconds(10))                             // und 10 Sekunden vor Ablauf Gardena Timer nächster Schritt
                              } else {                                                                                   // kein weiterer Timer vorhanden, also
                                  tWater = null                                                                          // Zeiger löschen
                                  gVentile.members.forEach[v | v.sendCommand(0)]                                         // und alle Ventile explizit schließen
                              }
                          }
                      ])
                  }
              end
              Die Rule hat in dieser Form ein paar Schönheitsfehler, wenn z.B. ein Regner deaktiviert wird, läuft trotzdem der zugehörige Timer, der müsste also auf 0 gesetzt werden, was dann aber nicht funktioniert, da ein Timer nicht in der Vergangenheit ausgeführt werden kann. Setzt man den Timer auf 1, gibt es keine Überlappung zwischen den zwei Regnern.

              Zu den Methoden .head:

              Es geht hier um Gruppen. Jede Gruppe besitzt eine Eigenschaft .members, welche eine Liste aller direkt enthaltenen Items liefert. .allMembers liefert alle enthaltenen Items, auch die, welche in Gruppen stecken, die wiederum in der ursprünglichen Gruppe stecken.
              Diese Liste wird gefiltert, mit der Methode .filter[] Diese Methode liefert wieder eine Liste zurück. Mit .size bestimmt man die Mächtigkeit der Liste, also wie viele Einträge die Liste hat. Mit .head greift man auf das erste Item der Liste zu, .head liefert ein Item zurück. Jedes Item kennt die Eigenschaft .state, also das Status des Items.

              Die Idee des Codes ist, eine vorgegebene Gruppe von Items zu durchlaufen. Mit jedem Durchlauf wird das nächste Item der Gruppe zurück geliefert. Wir benötigen 3 verschiedene Items, nämlich die geplante Beregnungsdauer, ob das Ventil überhaupt auf steuern soll und natürlich das Ziel-Item. Da für Zeit und Ziel mehrere Prüfungen vorzunehmen sind, habe ich dort die Liste einer Variablen zugewiesen. Da alle Eigenschaften und Methoden vererbt werden, kann ich diese Variable stellvertretend benutzen.

              Kommentar


                #8
                Zitat von udo1toni Beitrag anzeigen
                ... Allerdings hast Du, glaube ich, noch nicht verstanden, wie die Rule funktioniert. ...
                Das möchte ich in keinster Weise abstreiten bzw wird sicher so sein Aber ich versuche weiterhin zu lernen und zu verstehen.

                Dennoch funktioniert der erste Code immer noch nicht, er springt immer noch direkt in Default
                Auch wenn es etwas unübersichtlich wird, poste ich einmal die komplette Rule in welche dieser Teil eingebettet ist.
                Wie gesagt, die Abfragen funktionieren und der Schalter ist derzeit nur zum test, später kommt eine Zeitabfrage (Die habe ich schon fertig und funktioniert => es wird in die Regel gesprungen) Was noch nicht geht ist die case Abfrage, obwohl ich case auch in anderen Regeln benutze.

                Note: Gerade eben wurde gewässert, daher ist der Rasen nass und ich habe den Sensor auskommentiert
                Code:
                rule TestIrrigation
                when
                    Item Sw_Irrigation received command
                then
                    if (receivedCommand == ON && Sw_Bewaesserung.state == ON && Holiday.state == OFF) {    // && Sensor_humidity.state < 40
                        logInfo("TEST", "Bewässerung EIN")
                        if (tWater === null) {
                            nWater = 0
                            tWater = createTimer(now,[ |
                                var Number nTime = 30
                                nWater = nWater + 1
                                logInfo("TEST", "nWater " + nWater)
                                logInfo("TEST", "Irrigation_Timer_1 " + Irrigation_Timer_1.state as Number)
                                switch (nWater) {
                                    case 1: {
                                        pushNotification("TEST", "Starte Ventil 1 für: " + Irrigation_Timer_1.state as Number + " Min")
                                        if((Irrigation_Timer_1.state instanceof Number)) nTime = Irrigation_Timer_1.state as Number
                                        Watering_Timer_1.sendCommand(nTime)
                                        tWater.reschedule(now.plusMinutes(nTime).minusSeconds(10))
                                    }
                                    case 2: {
                                        pushNotification("TEST", "Starte Ventil 2 für: " + Irrigation_Timer_2.state as Number + " Min")
                                        if((Irrigation_Timer_2.state instanceof Number)) nTime = Irrigation_Timer_2.state as Number
                                        Watering_Timer_2.sendCommand(nTime)
                                        tWater.reschedule(now.plusMinutes(nTime).minusSeconds(10))
                                    }
                                    case 3: {
                                        pushNotification("TEST", "Starte Ventil 3 für: " + Irrigation_Timer_3.state as Number + " Min")
                                        if((Irrigation_Timer_3.state instanceof Number)) nTime = Irrigation_Timer_3.state as Number
                                        Watering_Timer_3.sendCommand(nTime)
                                        tWater.reschedule(now.plusMinutes(nTime))
                                    }
                                    default: {
                                        pushNotification("TEST", "Alle AUS")
                                        tWater = null
                                        Watering_Timer_1.sendCommand(0)
                                        Watering_Timer_2.sendCommand(0)
                                        Watering_Timer_3.sendCommand(0)
                                    }
                                }
                            ])
                        }
                    } else if (receivedCommand == ON && Sw_Bewaesserung.state == OFF && Holiday.state == OFF) {
                        pushNotification("TEST - Auto. Bewässerung", Sw_Bewaesserung.state.toString)
                        Sw_Irrigation.sendCommand(OFF)
                    } else if (receivedCommand == OFF) {
                        logInfo("TEST Irrigation", "Irrigation stopped")
                        tWater?.cancel
                        tWater = null
                        Watering_Timer_1.sendCommand(0)
                        Watering_Timer_2.sendCommand(0)
                        Watering_Timer_3.sendCommand(0)
                        logInfo("TEST Irrigation", Valves.state.toString)
                    }
                end
                Im Log erscheint nach dem einschalten korrekterweise nWater = 1 und Irrigation_Timer_1 mit dem Wert den ich eingestellt hatte.
                Also springt er weiterhin in die Abfrage, macht aber case nicht, sondern springt direkt in default (zu erkennen an der Push Nachricht)

                Ich teste parallel mal Variante 2

                Viele Grüße,
                Jörg

                Kommentar


                  #9
                  Bei der Variante 2 hagelt es Fehler im Log ich habe mal einiges im Vorfeld im Script ins Log schreiben lassen

                  Code:
                  21:57:46.761 [INFO ] [g.eclipse.smarthome.model.script.TEST] - nWater 1
                  21:57:46.777 [INFO ] [g.eclipse.smarthome.model.script.TEST] - gVent: [Ventil_1 (Type=NumberItem, State=0, Label=Ventil 1, Category=null, Groups=[gVentile])]
                  21:57:46.792 [INFO ] [g.eclipse.smarthome.model.script.TEST] - gTime: [VentTimer_1 (Type=NumberItem, State=2, Label=Einschaltdauer Ventil 1, Category=null, Grou
                  ps=[gVentTimer])]
                  21:57:46.839 [INFO ] [smarthome.event.ItemCommandEvent     ] - Item 'Ventil_1' received command 2
                  21:57:46.855 [INFO ] [smarthome.event.ItemStateChangedEvent] - Ventil_1 changed from 0 to 2
                  21:57:46.855 [INFO ] [home.event.GroupItemStateChangedEvent] - gVentile changed from OFF to UNDEF through Ventil_1
                  21:57:46.855 [ERROR] [org.quartz.core.JobRunShell          ] - Job DEFAULT.2019-06-16T21:57:46.730+02:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Proce
                  dure0: [ | {
                    var nTime
                    <XFeatureCallImplCustom> += <XNumberLiteralImpl>
                    logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
                    var gVent
                    logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
                    var gTime
                    logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
                    org.eclipse.xtext.xbase.impl.XIfExpressionImpl@13d6a2b
                  } ] threw an unhandled Exception:
                  java.lang.IllegalStateException: Could not invoke method: org.joda.time.DateTime.plusMinutes(int) on instance: 2019-06-16T21:57:46.855+02:00
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1103) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1061) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1047) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:768) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:460) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:244) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:460) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:244) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]
                          at com.sun.proxy.$Proxy171.apply(Unknown Source) ~[?:?]
                          at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
                          at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
                          at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
                  Caused by: java.lang.IllegalArgumentException: argument type mismatch
                          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
                          at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
                          at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
                          at java.lang.reflect.Method.invoke(Unknown Source) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1086) ~[?:?]
                          ... 47 more
                  21:57:47.339 [ERROR] [org.quartz.core.ErrorLogger          ] - Job (DEFAULT.2019-06-16T21:57:46.730+02:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Proc
                  edure0: [ | {
                    var nTime
                    <XFeatureCallImplCustom> += <XNumberLiteralImpl>
                    logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
                    var gVent
                    logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
                    var gTime
                    logInfo(<XStringLiteralImpl>,<XBinaryOperationImplCustom>)
                    org.eclipse.xtext.xbase.impl.XIfExpressionImpl@13d6a2b
                  } ] threw an exception.
                  org.quartz.SchedulerException: Job threw an unhandled exception.
                          at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
                          at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
                  Caused by: java.lang.IllegalStateException: Could not invoke method: org.joda.time.DateTime.plusMinutes(int) on instance: 2019-06-16T21:57:46.855+02:00
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1103) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1061) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1047) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:768) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:460) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:244) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:460) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:244) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]
                          at com.sun.proxy.$Proxy171.apply(Unknown Source) ~[?:?]
                          at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
                          at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]
                          ... 1 more
                  Caused by: java.lang.IllegalArgumentException: argument type mismatch
                          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
                          at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
                          at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
                          at java.lang.reflect.Method.invoke(Unknown Source) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1086) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1061) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1047) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:768) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:460) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:244) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:460) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:244) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
                          at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]
                          at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]
                          at com.sun.proxy.$Proxy171.apply(Unknown Source) ~[?:?]
                          at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
                          at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]
                          ... 1 more
                  Seltsam finde ich auch, dass die Gruppe gVentile von OFF nach UNDEF wechselt, was wohl an der falschen Gruppendefinition liegt.

                  Group:Switch gVentile "Ventile"

                  Dies war ja bei ON/OFF notwendig, aber die Ventile benötigen ja eine Zeit. Also müsste die Gruppe als Nummer definiert werden, aber da fehlt es mir an knowledge :-/

                  Kommentar


                    #10
                    Zitat von JoergA Beitrag anzeigen
                    Dennoch funktioniert der erste Code immer noch nicht, er springt immer noch direkt in Default
                    Ich vermisse in Deinem Code die Definition der beiden Variablen.
                    Code:
                    var Timer tWater = null
                    var Number nWater = 0
                    muss am Anfang der Rules Datei stehen, noch vor der ersten Rule der Datei.

                    Was mich auch wundert, ist, dass diese Zeile
                    Code:
                    logInfo("TEST", "nWater " + nWater)
                    funktioniert. nWater muss vom Typ Number sein, man kann aber String und Number nicht addieren (bzw. den NumberType nicht einfach an den StringType anhängen).
                    Vermutlich gibt es da einen Typkonflikt, das würde auch erklären, warum switch direkt nach default springt - keine der anderen cases trifft zu.
                    Du kannst den Typ erzwingen:
                    Code:
                    switch (nWater.intValue)
                    immer vorausgesetzt natürlich, dass nWater tatsächlich vom Typ Number ist.

                    Es wäre auch sinnvoll, die PushNotification im Anschluss an das if() zu setzen, schließlich könnte dort auch ein anderer Wert geladen werden. sähe dann so aus:

                    Code:
                    switch (nWater.intValue) {
                        case 1: {
                            if((Irrigation_Timer_1.state instanceof Number)) nTime = Irrigation_Timer_1.state as Number
                            pushNotification("TEST", "Starte Ventil 1 für: " + nTime.toString + " Min")
                            Watering_Timer_1.sendCommand(nTime)
                            tWater.reschedule(now.plusMinutes(nTime).minusSeconds(10))
                        }
                    }
                    Es könnte auch sein, openHAB lieber explizit ein Integer möchte, das wäre dann dies hier:
                    Code:
                    switch (nWater.intValue) {
                        case 1: {
                            if((Irrigation_Timer_1.state instanceof Number)) nTime = Irrigation_Timer_1.state as Number
                            pushNotification("TEST", "Starte Ventil 1 für: " + nTime.toString + " Min")
                            Watering_Timer_1.sendCommand(nTime.intValue)
                            tWater.reschedule(now.plusMinutes(nTime.intValue).minusSeconds(10))
                        }
                    }
                    Wie Du richtig erkannnt hast, muss die Gruppendefinition für gVentile natürlich Group:Number sein, vor lauter codieren hab ich das vergessen zu erwähnen Wobei es eigentlich gar nicht auf die Definition der Gruppe ankommt, die Typzuweisung könntest Du auch komplett weg lassen, es geht ja nur um die Gruppenzugehörigkeit.

                    Der Fehler bezieht sich auf die Methode plusMinutes(), vermutlich möchte openHAB hier explizit Integer als Argument sehen (siehe oben).
                    Code:
                    tWater.reschedule(now.plusMinutes(nTime.intValue).minusSeconds(10))
                    Kann aber gut sein, dass sich da noch weitere Fehler verstecken

                    Kommentar


                      #11
                      für die Geduld und Utnerstützung (und wie immer =>> DANKE!!!!)

                      Ich habe die Variante 2 noch ein wenig ergänzt, da man zunächst ein deaktiviertes Ventil auch noch auf 0 Sekunden setzen musste. Hier gibt es nun eine Lücke von 5 Sekunden, aber die ist sicher vertretbar .

                      Zitat von udo1toni Beitrag anzeigen
                      Ich vermisse in Deinem Code die Definition der beiden Variablen.
                      Code:
                      var Timer tWater = null
                      var Number nWater = 0
                      muss am Anfang der Rules Datei stehen, noch vor der ersten Rule der Datei.
                      Ja, OK. Diese hatte ich nicht mit gepostet, aber waren natürlich ganz oben in der Rules gesetzt, dort wo ich alle Variablen der jeweiligen Rule setze. So vermeide ich Doubletten.

                      Zitat von udo1toni Beitrag anzeigen
                      Was mich auch wundert, ist, dass diese Zeile
                      Code:
                      logInfo("TEST", "nWater " + nWater)
                      Dies ist doch nur das Zusammenfassen von Text und Wert für die Ausgabe und funktioniert problemlos


                      Zitat von udo1toni Beitrag anzeigen
                      Der Fehler bezieht sich auf die Methode plusMinutes(), vermutlich möchte openHAB hier explizit Integer als Argument sehen (siehe oben).
                      Code:
                      tWater.reschedule(now.plusMinutes(nTime.intValue).minusSeconds(10))
                      Dies war in beiden Rules das Problem OpenHab scheint da sehr eigen zu sein.

                      Zitat von udo1toni Beitrag anzeigen
                      Es wäre auch sinnvoll, die PushNotification im Anschluss an das if() zu setzen, schließlich könnte dort auch ein anderer Wert geladen werden. sähe dann so aus:
                      Joar, da ist etwas dran und sollte ich mir so angewöhnen.

                      Für alle Interessierten, hier einmal bei Codes, die bei mir funktionieren. Wie diese Rule dann angesprochen wird, muss jeder für sich entscheiden. Ich hatte zunächst zum testen einen Schalter und baue dies nun auf eine Zeitsteuerung mit Bodenfeuchtigkeitsmessung um.

                      Variante 1 - aktivieren
                      Code:
                      var Timer tWater = null                //Timer, für Rasen Bewässerung
                      var Number nWater = 0
                      
                              if (tWater === null) {
                                  nWater = 0
                                  tWater = createTimer(now,[ |
                                      var Number nTime = 30
                                      nWater += 1
                                      logInfo("TEST", "nWater " + nWater)
                                      logInfo("TEST", "Irrigation_Timer_1 " + Irrigation_Timer_1.state as Number)
                                      switch (nWater.intValue) {
                                          case 1: {
                                              if((Irrigation_Timer_1.state instanceof Number)) nTime = Irrigation_Timer_1.state as Number
                                              pushNotification("TEST", "Starte Ventil 1 für: " + Irrigation_Timer_1.state as Number + " Min")
                                              Watering_Timer_1.sendCommand(nTime)
                                              tWater.reschedule(now.plusMinutes(nTime.intValue).minusSeconds(10))
                                          }
                                          case 2: {
                                              if((Irrigation_Timer_2.state instanceof Number)) nTime = Irrigation_Timer_2.state as Number
                                              Watering_Timer_2.sendCommand(nTime)
                                              pushNotification("TEST", "Starte Ventil 2 für: " + Irrigation_Timer_2.state as Number + " Min")
                                              tWater.reschedule(now.plusMinutes(nTime.intValue).minusSeconds(10))
                                          }
                                          case 3: {
                                              if((Irrigation_Timer_3.state instanceof Number)) nTime = Irrigation_Timer_3.state as Number
                                              pushNotification("TEST", "Starte Ventil 3 für: " + Irrigation_Timer_3.state as Number + " Min")
                                              Watering_Timer_3.sendCommand(nTime)
                                              tWater.reschedule(now.plusMinutes(nTime.intValue))
                                          }
                                          default: {
                                              pushNotification("TEST", "Alle AUS")
                                              tWater = null
                                              Watering_Timer_1.sendCommand(0)
                                              Watering_Timer_2.sendCommand(0)
                                              Watering_Timer_3.sendCommand(0)
                                          }
                                      }
                                  ])
                              }
                      Variante 1 - beenden
                      Code:
                              tWater?.cancel                                                            // timer beenden, falls vorhanden
                              tWater = null                                                            // Zeiger löschen
                              Watering_Timer_1.sendCommand(0)
                              Watering_Timer_2.sendCommand(0)
                              Watering_Timer_3.sendCommand(0)
                      Variante 2 - benötgte Gruppen und Zuordnung (Dies muss natürlich auf die eigene Umgebung angepasst werden)
                      Code:
                      Group:Switch gVentEnable "Ventil erlauben"
                      Group:Switch gVentile "Ventile"
                      Group:Number gVentTimer "Einschaltdauer"
                      
                      Switch VentEnable_1 "Ventil 1 enable [%s]" (gVentEnable)
                      Switch VentEnable_2 "Ventil 2 enable [%s]" (gVentEnable)
                      Switch VentEnable_3 "Ventil 3 enable [%s]" (gVentEnable)
                      
                      Number Ventil_1 "Ventil 1 [%d]" (gVentile)
                      Number Ventil_2 "Ventil 2 [%d]" (gVentile)
                      Number Ventil_3 "Ventil 3 [%d]" (gVentile)
                      
                      Number VentTimer_1 "Einschaltdauer Ventil 1 [%.0f min]" (gVentTimer)
                      Number VentTimer_2 "Einschaltdauer Ventil 2 [%.0f min]" (gVentTimer)
                      Number VentTimer_3 "Einschaltdauer Ventil 3 [%.0f min]" (gVentTimer)
                      Variante 2 - aktivieren
                      Code:
                      var Timer tWater = null                //Timer, für Rasen Bewässerung
                      var Number nWater = 0
                      
                              nWater = 0                                                                                         // Zähler mit 0 initialisieren
                              tWater = createTimer(now, [ |                                                                      // timer mit code initialisieren und ausführen
                                  var Number nTime = 30                                                                          // Default Einschaltzeit definieren
                                  nWater += 1                                                                                    // Zähler erhöhen
                                  logInfo("TEST", "nWater " + nWater)
                                  var gVent = gVentile.members.filter[i | i.name.contains(nWater.toString)]                      // Ventil bestimmen
                                  logInfo("TEST", "gVent: " + gVent)
                                  var gTime = gVentTimer.members.filter[i | i.name.contains(nWater.toString)]                    // Zeit bestimmen
                                  logInfo("TEST", "gTime: " + gTime)
                                  logInfo("TEST", "gTime-size: " + gTime.size)
                                  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
                                          logInfo("TEST", "nTime: " + nTime)
                                      if(gVent.size > 0) {                                                                       // Ventil existiert
                                          if(gVentEnable.members.filter[i | i.name.contains(nWater.toString)].head.state == ON) { // und soll aktiviert werden
                                              gVent.head.sendCommand(nTime)                                                      // Gardena Timer setzen
                                              tWater.reschedule(now.plusMinutes(nTime.intValue).minusSeconds(10))                             // und 10 Sekunden vor Ablauf Gardena Timer nächster Schritt
                                          } else {
                                              tWater.reschedule(now.plusSeconds(5))
                                          }
                                      } else {                                                                                   // kein weiterer Timer vorhanden, also
                                          tWater = null                                                                          // Zeiger löschen
                                          gVentile.members.forEach[v | v.sendCommand(0)]                                         // und alle Ventile explizit schließen
                                      }
                                  }
                              ])
                      Variante 2 - deaktivieren
                      Code:
                              tWater?.cancel                                                            // timer beenden, falls vorhanden
                              tWater = null                                                            // Zeiger löschen
                              gVentile.members.forEach[v | v.sendCommand(0)]                            // und alle Ventile schließen
                      Mein Favorit ist definitiv Variante 2

                      Kommentar


                        #12
                        Sehr schön. Allerdings solltest Du den Rahmen der Rule mit dazu posten sonst wird das nix...
                        Zitat von JoergA Beitrag anzeigen
                        Dies ist doch nur das Zusammenfassen von Text und Wert für die Ausgabe und funktioniert problemlos
                        Schon klar. Der Punkt ist hier aber, dass man normalerweise explizit nur Strings miteinander verketten kann, ich weiß auch sicher, dass openHAB an dieser Stelle gerne pingelig war, wenn die Verkettung also problemlos funktioniert, kommt erst mal der Verdacht auf, dass die Variable selbst schon vom Typ String ist. Offensichtlich funktioniert das automatische Type casting in diesem Fall aber.



                        Kommentar


                          #13
                          Zitat von udo1toni Beitrag anzeigen
                          Sehr schön. Allerdings solltest Du den Rahmen der Rule mit dazu posten
                          Ich habe dies nun unter unterschiedlichen Voraussetzungen getestet und noch eine Abhängigkeit zum Bodensensor eingebaut.

                          Hintergrund: Da ich eine Hauswasserwerk zur Bewässerung einsetze, wollte/muss ich meine Ventile nacheinander mit einer kleinen Überlappung (ich habe 10 Sek. gewählt) starten um ein abschalten der Pumpe zwischen den Übergängen zu verhindern.
                          Ich habe einen Gardena Sensor für die Bodenfeuchtigkeit in unmittelbarer Nähe zur zu bewässernden Rasenfläche eingebaut und nutze ein Gardena Smart Irrigation zur Steuerung der drei Ventile in einer Ventilbox.

                          Dank grosser Mithilfe/Unterstützung von Udo konnte dies wie folgt umgesetzt werden.

                          Items
                          Code:
                          Group:Switch gVentEnable "Ventil aktiv"
                          Group:Switch gVentile "Ventile"
                          Group:Number gVentTimer "Einschaltdauer"
                          
                          Switch Sw_Bewaesserung    "Bewässerungsautomatik"    <faucet>
                          Switch Sw_ManIrrigation        "manuelle Bewässerung"      <faucet>    {autoupdate="false"}
                          
                          Switch VentEnable_1        "Rasenfläche Aqua Contour [%s]"                (gVentEnable)
                          Number Watering_Timer_1        "Rasenfläche Aqua Contour [%d min]"    <faucet>    (gVentile, Gardena)    {channel="gardena:ic24:xxx:Irrigation:watering#watering_timer_1"}
                          Number Irrigation_Valve_1    ""                    <faucet>    {autoupdate="false"}
                          Number Irrigation_Timer_1    "Timer Rasenfläche Aqua Contour"    <faucet>    (gVentTimer)
                          
                          Switch VentEnable_2        "Rasenfläche Terrasse [%s]"                (gVentEnable)
                          Number Watering_Timer_2        "Rasenfläche Terrasse [%d min]"        <faucet>    (gVentile, Gardena)        {channel="gardena:ic24:xxx:Irrigation:watering#watering_timer_2"}
                          Number Irrigation_Valve_2    ""                    <faucet>    {autoupdate="false"}
                          Number Irrigation_Timer_2    "Timer Rasenfläche Terrasse"        <faucet>    (gVentTimer)
                          
                          Switch VentEnable_3        "Hecke [%s]"                        (gVentEnable)
                          Number Watering_Timer_3        "Hecke [%d min]"            <faucet>    (gVentile, Gardena)        {channel="gardena:ic24:xxx:Irrigation:watering#watering_timer_3"}
                          Number Irrigation_Valve_3    ""                    <faucet>    {autoupdate="false"}
                          Number Irrigation_Timer_3    "Timer Hecke"                <faucet>    (gVentTimer)
                          
                          Number Sensor_humidity        "Bodenfeuchtigkeit [%d %%]"        <humidity>    (Gardena, Humidity_Chart)    {channel="gardena:sensor:xxx:Sensor:humidity#humidity"}
                          SItemap
                          Code:
                          Switch item=Sw_Bewaesserung
                          Switch item=Sw_ManIrrigation label="Starte Bewässerung" mappings=[ON="Start", OFF="Stop"] //visibility=[Sw_ManIrrigation==OFF, Sw_ManIrrigation=="Uninitialized", Sw_ManIrrigation=="NULL"]
                          
                          Setpoint item=Irrigation_Timer_1 minValue=0 maxValue=30 step=1
                          Switch item=VentEnable_1
                          
                          Setpoint item=Irrigation_Timer_2 minValue=0 maxValue=30 step=1
                          Switch item=VentEnable_2
                          
                          Setpoint item=Irrigation_Timer_3 minValue=0 maxValue=30 step=1
                          Switch item=VentEnable_3
                          
                          Setpoint item=Sensor_Level minValue=0 maxValue=100 step=5
                          Rule
                          Code:
                          var Timer tWater = null                //Timer, für Rasen Bewässerung
                          var Number nWater = 0
                          
                          rule GreenIrrigation
                          when
                              Time cron "0 30 05 ? * MON-SAT" or
                              Time cron "0 00 06 ? * SUN" or
                              Item Sw_ManIrrigation received command
                          then
                              if (Sw_Bewaesserung.state == ON && Holiday.state == OFF && Sensor_humidity.state < Sensor_Level.state) {
                                  pushNotification("Automatische Bewässerung", "Start: "+ now)
                                  logInfo("Automatische Bewässerung", "Start: "+ now)
                                  myIrrigationSwitchVis.postUpdate(ON)
                                  nWater = 0                                                                                         // Zähler mit 0 initialisieren
                                  tWater = createTimer(now, [ |                                                                      // timer mit code initialisieren und ausführen
                                      var Number nTime = 10                                                                          // Default Einschaltzeit definieren
                                      nWater += 1                                                                                    // Zähler erhöhen
                                      var gVent = gVentile.members.filter[i | i.name.contains(nWater.toString)]                      // Ventil bestimmen
                                      var gTime = gVentTimer.members.filter[i | i.name.contains(nWater.toString)]                    // Zeit bestimmen
                                      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(nWater.toString)].head.state == ON) { // und soll aktiviert werden
                                                  gVent.head.sendCommand(nTime)                                                      // Gardena Timer setzen
                                                  pushNotification("Bewässerung", gVent.head.label + " für " + nTime + " Min.")
                                                  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
                                              gVentile.members.forEach[v | v.sendCommand(0)]                                         // und alle Ventile explizit schließen
                                              myIrrigationSwitchVis.postUpdate(OFF)
                                          }
                                      }
                                  ])
                          
                              } else if (receivedCommand == ON && Sensor_humidity.state < Sensor_Level.state) {
                                  pushNotification("Manuelle Bewässerung", "Start: "+ now)
                                  logInfo("Manuelle Bewässerung", "Start: "+ now)
                                  myIrrigationSwitchVis.postUpdate(ON)
                                  nWater = 0                                                                                         // Zähler mit 0 initialisieren
                                  tWater = createTimer(now, [ |                                                                      // timer mit code initialisieren und ausführen
                                      var Number nTime = 10                                                                          // Default Einschaltzeit definieren
                                      nWater += 1                                                                                    // Zähler erhöhen
                                      var gVent = gVentile.members.filter[i | i.name.contains(nWater.toString)]                      // Ventil bestimmen
                                      var gTime = gVentTimer.members.filter[i | i.name.contains(nWater.toString)]                    // Zeit bestimmen
                                      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(nWater.toString)].head.state == ON) { // und soll aktiviert werden
                                                  gVent.head.sendCommand(nTime)                                                      // Gardena Timer setzen
                                                  pushNotification("Bewässerung", gVent.head.label + " für " + nTime + " Min.")
                                                  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?.cancel
                                              tWater = null                                                                          // Zeiger löschen
                                              gVentile.members.forEach[v | v.sendCommand(0)]                                         // und alle Ventile explizit schließen
                                          }
                                      }
                                  ])
                              } else if (receivedCommand == OFF) {
                                  tWater?.cancel                                                          // timer beenden, falls vorhanden
                                  tWater = null                                                           // Zeiger löschen
                                  gVentile.members.forEach[v | v.sendCommand(0)]                          // und alle Ventile schließen
                                  pushNotification("Bewässerung manuell beendet", "Stop: "+ now)
                              }
                          end
                          Wenn es noch Ergänzungen/Verbesserungsvorschläge gibt, bin ich offen, ansonsten hat dies Script aus meiner Sicht einen Platz in der Sample Sektion verdient

                          Viele Grüße

                          Jörg

                          Kommentar


                            #14
                            Ich finde ja immer was zu mäkeln Sobald mehrere Zeilen Code identisch sind, ist das Verbesserungspotential sicher.

                            Du triggerst die Rule entweder automatisch oder per manueller Auslösung. Diese zwei Fäle kann man gut unterscheiden, im automatischen Fall ist receivedCommand NULL.
                            Es gibt mehrere verschiedene Möglichkeiten:
                            1. Die Rule wurde manuell ausgelöst und soll die Beregnung beenden.
                            2. Die Rule wurde manuell ausgelöst und soll die Beregnung starten.
                            3. Die Rule wurde automatisch ausgelöst und soll die Beregnung starten.

                            Im Fall von 2. und 3. gibt es noch die Möglichkeit, dass die Beregnung durch Sensorwerte verhindert wird. Daraus ergibt sich folgender Code:
                            Code:
                            ...
                            then
                                if(receivedCommand == OFF) {
                                    //OFF-Teil
                                    return; // nur zur Sicherheit; der nachfolgende Code wird gar nicht durchlaufen...
                                } else {
                                    if(Sensor_humidity.state < Sensor_Level.state)  // eigentlich: if((Sensor_humidity.state as Number) < (Sensor_Level.state as Number)) {
                                        if(receivedCommand == ON) {
                                            pushNotification("Manuelle Bewässerung", "Start: "+ now)
                                            logInfo("regner", "Manuelle Bewässerung Start: "+ now)
                                          
                                        } else if(Sw_Bewaesserung.state == ON && Holiday.state == OFF) {
                                             pushNotification("Automatische Bewässerung", "Start: "+ now
                                             logInfo("regner", "Automatische Bewässerung Start: "+ now)
                                        } else {
                                             logInfo("regner", "Bewässerung Start abgebrochen!")
                                             return;
                                        }
                                        // Beregnungsroutine starten
                                    } else {
                                        logInfo("regner", "Bewässerung Start abgebrochen, da Bodenfeuchte ausreichend!")
                                    }
                                }
                            end
                            return; bewirkt den Abbruch der Rule.

                            Weiterhin bitte ich zu beachten, dass der Logger zwei Strings erwartet. Dabei ist der erste String der Name des Loggers. Über diesen Namen kann man das Logging steuern. Der Name ist nicht als "Überschrift" gedacht.
                            Dieser Teil des Loggings wird bei Bedarf verkürzt dargestellt. Der angegebene Name sollte keinesfalls Leerzeichen enthalten. Punkte bilden eine Hierachie, wenn man mal verstanden hat, wie das funktioniert, kann man damit extrem effizient Logging ein- und ausschalten (im laufenden Betrieb), dies geht in mehreren Stufen, man kann also z.B. nur Fehler anzeigen lassen (logError()) oder gar Debug- Informationen (logDebug()).
                            Zuletzt geändert von udo1toni; 20.06.2019, 01:01.

                            Kommentar


                              #15
                              Zitat von udo1toni Beitrag anzeigen
                              Ich finde ja immer was zu mäkeln Sobald mehrere Zeilen Code identisch sind, ist das Verbesserungspotential sicher.
                              Na, solange das Ergebnis so ist wie bisher, ist dies für mich absolut OK Mäkeln und konstruktives Feedback sind ja schon sehr unterschiedlich
                              Die Verschachtelung der Abfragen muss ich für mich mal kritischer betrachten, um weitere Rules ähnlich zu optimieren.

                              Zitat von udo1toni Beitrag anzeigen
                              Weiterhin bitte ich zu beachten, dass der Logger zwei Strings erwartet. Dabei ist der erste String der Name des Loggers. Über diesen Namen kann man das Logging steuern. Der Name ist nicht als "Überschrift" gedacht.
                              Dieser Teil des Loggings wird bei Bedarf verkürzt dargestellt. Der angegebene Name sollte keinesfalls Leerzeichen enthalten. Punkte bilden eine Hierachie, wenn man mal verstanden hat, wie das funktioniert, kann man damit extrem effizient Logging ein- und ausschalten (im laufenden Betrieb), dies geht in mehreren Stufen, man kann also z.B. nur Fehler anzeigen lassen (logError()) oder gar Debug- Informationen (logDebug()).
                              Good to know, werde dann mal meine anderen Regeln überarbeiten, da habe ich den logger mitunter dann auch "zweckentfremdet"

                              In nächster Iteration habe ich mir dann noch den manuellen Schalter dynamisch gestalltet; sprich "Starte Bewässerung" solange diese nicht läuft und "Stoppe Bewässerung" sobald die Bewässerung gestartet wurde.

                              Zunächst war ich irritiert/unglücklich das direkt auf die Bodenfeuchtigkeit geprüft wird und ich die Bewässerung nicht mehr manuell starten kann, wenn der Boden noch feucht ist. Im zweiten Gedankenschritt ist diese "SIcherheitsfunktion" dann doch gewünscht, damit auch bei manuellem Start nicht unnütz Wasser verschwendet wird. Und wenn ich es dennoch starten möchte/sollte, kann ich ja die Schwelle der Bodenfeuchtigkeit anheben.

                              Sieht nun "very" smart aus.
                              Code:
                              rule GreenIrrigation
                              when
                                  Time cron "0 30 05 ? * MON-SAT" or
                                  Time cron "0 00 06 ? * SUN" or
                                  Item Sw_ManIrrigation received command
                              then
                                  if(receivedCommand == OFF) {                                                //OFF-Teil
                                      tWater?.cancel                                                            // timer beenden, falls vorhanden
                                      tWater = null                                                            // Zeiger löschen
                                      gVentile.members.forEach[v | v.sendCommand(0)]                            // und alle Ventile schließen
                                      myIrrigationSwitchVis.postUpdate(ON)
                                      pushNotification("Bewässerung manuell beendet", "Stop: "+ now)
                                      return; // nur zur Sicherheit; der nachfolgende Code wird gar nicht durchlaufen.
                                  } else {
                                      if((Sensor_humidity.state as Number) < (Sensor_Level.state as Number)) {
                                          if(receivedCommand == ON) {
                                              pushNotification("Manuelle Bewässerung", "Start: "+ now)
                                              logInfo("irrigation", "Manuelle Bewässerung Start: "+ now)
                                          } else if(Sw_Bewaesserung.state == ON && Holiday.state == OFF) {
                                              pushNotification("Automatische Bewässerung", "Start: "+ now)
                                              logInfo("irrigation", "Automatische Bewässerung Start: "+ now)
                                          } else {
                                              logInfo("irrigation", "Bewässerung Start abgebrochen!")
                                              return;
                                          }
                                          // Beregnungsroutine starten
                                          myIrrigationSwitchVis.postUpdate(OFF)
                                          nWater = 0                                                                                         // Zähler mit 0 initialisieren
                                          tWater = createTimer(now, [ |                                                                      // timer mit code initialisieren und ausführen
                                              var Number nTime = 10                                                                          // Default Einschaltzeit definieren
                                              nWater += 1                                                                                    // Zähler erhöhen
                                              var gVent = gVentile.members.filter[i | i.name.contains(nWater.toString)]                      // Ventil bestimmen
                                              var gTime = gVentTimer.members.filter[i | i.name.contains(nWater.toString)]                    // Zeit bestimmen
                                              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(nWater.toString)].head.state == ON) { // und soll aktiviert werden
                                                          gVent.head.sendCommand(nTime)                                                      // Gardena Timer setzen
                                                          pushNotification("Bewässerung", gVent.head.label + " für " + nTime + " Min.")
                                                          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
                                                      gVentile.members.forEach[v | v.sendCommand(0)]                                         // und alle Ventile explizit schließen
                                                      myIrrigationSwitchVis.postUpdate(OFF)
                                                  }
                                              }
                                          ])
                                      } else {
                                          logInfo("irrigation", "Bewässerung Start abgebrochen, da Bodenfeuchte ausreichend!")
                                          pushNotification("Bewässerung", "Bewässerung Start abgebrochen, da Bodenfeuchte ausreichend!")
                                      }
                                  }
                              end
                              Zuletzt geändert von JoergA; 20.06.2019, 10:22.

                              Kommentar

                              Lädt...
                              X