Regeln erstellen

Moderatoren: seppy, udo1toni

Antworten
m.i.c.h.a
Beiträge: 5
Registriert: 4. Apr 2019 10:47

Regeln erstellen

Beitrag von m.i.c.h.a » 4. Apr 2019 11:38

Hallo,

ich habe ganz neu mit openHAB angefangen. Mein System läuft auf einer DS918+. Ich habe folgendes schon hinbekommen:
- Schalten von Sonoff S20
- Schalten meines Onkyo-Receivers
- Anzeige der aktuellen Urzeit
- Anzeige der Sonnenauf- und -untergangszeiten
- Telegram integriert

Mein Problem:
Ich möchte eine Steckdose zu einer wählbaren Urzeit einschalten und zum Sonnenaufgang ausschalten. Dabei sollte die gewählte Zeit angezeigt und nach einem Neustart von openHAB wieder vorhanden sein.

Als erstes möchte ich die vorgewählte Zeit in T_Zeit anzeigen. Das funktioniert schon mal nicht. Wie kann ich dann diese Werte speichern, damit sie nach einem Neustart wieder vorhanden sind?

Test.items

Code: Alles auswählen

Number  N_Stunde   "Stunde[%s]"    <time>
Number  N_Minute "Minute[%s]"    <time>
Switch  S_Zeit   "Zeit"  <settings>
String T_Zeit   "Zeit"
Test.sitemap

Code: Alles auswählen

sitemap Test label="Test"{
    Setpoint item=N_Stunde minValue=0 maxValue=23 step=1
    Setpoint item=N_Minute minValue=0 maxValue=59 step=5
    Switch  item=S_Zeit mappings=[ON="Übernehmen"]
    Text item=T_Zeit
    Text item=Sunrise_Time label="Sonnenaufgang" icon="sunrise" 
}
Test.rules

Code: Alles auswählen

var V_Stunde
var V_Minute


rule "Test1"
when 
    Item S_Zeit changed to ON
then 
    var V_Stunde = N_Stunde
    var V_Minute = N_Minute
    T_Zeit= V_Stunde & V_Minute
end
 
Kann mit bitte jemand helfen.

Micha
Zuletzt geändert von m.i.c.h.a am 5. Apr 2019 12:03, insgesamt 1-mal geändert.

Benutzeravatar
udo1toni
Beiträge: 1259
Registriert: 11. Apr 2018 18:05
Wohnort: Darmstadt

Re: Regeln erstellen

Beitrag von udo1toni » 4. Apr 2019 19:08

Eigentlich solltest Du mit der Suchfunktion hier und im Netz allgemein eine dreistellige Anzahl an Treffern zu diesem Thema finden können. ;)

Alles, was einen Neustart von openHAB überleben soll, muss über einen Persistence Service gespeichert werden. Dabei wird der Status eines Items gespeichert. Dieser wird dann beim Neustart wiederhergestellt, falls das erwünscht ist. Du musst also das/die Item(s) in einer passenden Persistence eintragen. Wenn Du ohnehin Persistence nutzt (z.B. um Temperaturverläufe zu visualisieren) kannst Du diesen Dienst mit nutzen. Ansonsten bietet sich die mapdb Persistence an, die imer den aktuellen Wert speichert. Es wird also nur exakt ein Wert gespeichert, dafür braucht die Datenbank auch nur sehr wenig Platz. Natürlich kann auch nur der letzte Wert wiederhergestellt werden, nämlich wenn openHAB startet.

Wie Du schon gemerkt hast, ist in openHAB eine Funktion "Zeitschaltuhr" nicht vorgesehen. der Grund hierfür ist leicht erklärbar: Zeitschaltuhren sind eine Krücke, um ein Problem zu lösen. In den letzten Jahren wurde beispielsweise in vielen Rollladensteuerungen die Zeitschaltuhr durch eine Sonnenstandssteuerung ersetzt, was dem eigentlichen Wunsch wesentlich näher kommt, nämlich Läden, die bei über/unterschreiten einer bestimmten Helligkeit automatisch in eine vorgegebene Position fahren.
In openHAB geht das sehr bequem über das Astro Binding, wobei hier zusätzlich noch Grenzen definiert werden können, also der früheste und/oder späteste Zeitpunkt, zu dem ein Befehl erfolgen soll, beispielsweise "Öffne 10 Minuten nach Sonnenaufgang, frühestens um 6 Uhr, spätestens um 8 Uhr die Rollläden".

Wenn Du trotzdem mit fixen Zeiten arbeiten willst, kommt gleich die nächste Frage: Wie oft änderst Du die Zeit tatsächlich? In den meisten Fällen ist es das einfachste, eine Rule mittels Time cron Trigger aufzurufen, wobei die Zeit dann natürlich fix ist, es sei denn, man bearbeitet die Rule.

Soll es auf jeden Fall eine über die Oberfläche wählbare Zeit sein?
Überlege gut, ob Du tatsächlich Stunden und Minuten einstellen willst. Ich arbeite z.B. im Schichtdienst. Ich habe lange Zeit in der Größenordnung 20 verschiedene mögliche "Weckzeiten" gehabt, was wohl eher viel ist.
Wenn ich diese Zeiten über die Oberfläche wählbar hätte haben wollen, hätte ich ein Setpoint Item mit Klartextnamen für die verschiedenen Dienste eingerichtet, ich hab doch keine Lust, immer Minuten und Stunden auszuwählen...

Trotzdem kannst Du natürlich Stunden und Minuten einstellbar machen, so wie von Dir angedeutet. :)

Allerdings möchtest Du keinen String, um diese Information zu speichern, allenfalls für die Anzeige taugt ein String, wobei auch das ...
Zum Ausführen des Timers benötigst Du auf jeden Fall eine Zahl, am besten die Anzahl Minuten ab Mitternacht (also Stunde * 60 + Minute), dann kannst Du eine Rule so gestalten, dass sie einen entsprechenden Timer anlegt. Alternativ kannst Du auch das Format DateTime verwenden, aber es ist nicht trivial, aus DateTime passende Timer zu bauen. Die meisten im Netz kursierenden Lösungen verwenden deshalb eine Rule, die regelmäßig gestartet wird und überprüft, ob die Zeit schon erreicht wurde. Das ist natürlich ineffizient, auch wenn eine entsprechende Rule nicht allzusehr aufträgt.
Für die Darstellung in der Sitemap brauchst Du die Zeit in Stunden und Minuten, entweder erzeugst Du einen String passend, oder Du nutzt ein DateTime Item (dort kann man auch die Anzeige so manipulieren, dass nur Stunden und Minuten angezeigt werden.)

Wenn Du innerhalb eine Rule auf den Status eines Items zugreifen willst, passiert das immer über die Eigenschaft .state. Falls es sich um ein Number Item handelt und Du den Status als Zahl verwenden willst, solltest Du den Wert explizit zum Typ Number casten.
Wenn Du den Status eines Items ändern möchtest (z.B. um eine Anzeige in der UI zu setzen) geht das über die Action postUpdate(Item as String, Value as String) bzw. über die Methode Item.postUpdate(Value), wobei letztere Variante grundsätzlich zu bevorzugen ist.
Soll das Item an ein Binding gesendet werden (sei es als Befehl oder als Anzeige) heißen die entsprechende Action bzw. Methode sendCommand. Auf Deine Rule aufsetzend sähe das dann so aus:

Code: Alles auswählen

// globale Variablen werden ganz zu Beginn des *.rules Files definiert
var Timer myTimer = null

rule "Test1"
when 
    Item S_Zeit changed to ON
then 
    if(!(N_Stunde.state instanceof Number)) {
        logWarn("Test1","Stunde ungültig! Abbruch!")
        return;
    }
    if(!(N_Minute.state instanceof Number)) {
        logWarn("Test1","Minute ungültig! Abbruch!")
        return;
    }

    var String sZeit 
    if((N_Stunde.state as Number) < 10)
        sZeit="0"
    sZeit = sZeit + N_Stunde.state.toString + ":"
    if((N_Minute.state as Number) < 10)
        sZeit = sZeit + "0"
    sZeit = sZeit + N_Minute.state.toString
    T_Zeit.postUpdate(sZeit)

    val Number myTime = (N_Stunde.state as Number) * 60 + (N_Minute.state as Number)
    myTimer?.cancel
    myTimer = createTimer(now.withTimeAtStartOfDay.plusMinutes(myTime).plusDays(if(now.getMinuteOfDay < myTime) 0 else 1), [ |
        mySwitchedItem.sendCommand(ON)
        myTimer.reschedule(now.plusDays(1))
    ])
end
Der obere Teil der Rule prüft, ob alle Voraussetzungen für das Anlegen des Timers gegeben sind (also sowohl Stunde als auch Minute einen gültigen Wert haben).
Im nächsten Block wird der String für die Anzeige berechnet. Falls Stunde oder Minute einstellig sind, wird jeweils eine 0 ergänzt. Zum Abschluss wird der errechnete String an das Item geschickt.

Zuletzt wird die Startzeit berechnet, ein eventuell bestehender Timer gelöscht und abschließend erzeugt, wobei der Timer automatisch für den nächsten Tag geplant wird, falls die Schaltzeit am aktuellen Tag schon vergangen ist.

Der Timer selbst wird vom Scheduler zur geplanten Zeit ausgeführt, das Item wird angesteuert, anschließend wird der Timer für den nächsten Tag neu geplant.

m.i.c.h.a
Beiträge: 5
Registriert: 4. Apr 2019 10:47

Re: Regeln erstellen

Beitrag von m.i.c.h.a » 5. Apr 2019 08:15

Hallo udo1toni,

vielen Dank für deine ausführliche Antwort. Da ich nur rudimentäre Englischkenntnisse besitze, fällt es mir nicht leicht, mich durch die openHAB-Anleitung durchzuarbeiten.
udo1toni hat geschrieben:
4. Apr 2019 19:08
Eigentlich solltest Du mit der Suchfunktion hier und im Netz allgemein eine dreistellige Anzahl an Treffern zu diesem Thema finden können.
Der Hinweis auf die mapdb hat mir schon sehr geholfen. Die Werte werden jetzt gespeichert. :D Manchmal fehlt mir nur der richtige Suchbegriff.

Ich habe die erste IF Schleife etwas geändert, sonst kam immer "null" vor einer zweistelligen Stunde.
Die Anzeige der Zeit funktioniert aber noch nicht. Im Telegram kommt die eingestellte Zeit aber nicht in der sitemap. Woran kann das liegen?

Code: Alles auswählen

rule "Test1"
when 
    Item S_Zeit changed to ON
then 
    if(!(N_Stunde.state instanceof Number)) {
        logWarn("Test1","Stunde ungültig! Abbruch!")
        return;
    }
    if(!(N_Minute.state instanceof Number)) {
        logWarn("Test1","Minute ungültig! Abbruch!")
        return;
    }

    var String sZeit 
    if((N_Stunde.state as Number) < 10){
        sZeit="0" + N_Stunde.state.toString + ":"
    }else{
    sZeit = N_Stunde.state.toString + ":"
    }
    if((N_Minute.state as Number) < 10){
        sZeit = sZeit + "0"
    }
    sZeit = sZeit + N_Minute.state.toString
    T_Zeit.postUpdate(sZeit)
    
    sendTelegram("bot1", sZeit)
    
end 
Das andere werde ich versuche, über das Wochenende hinzubekommen. Vielleicht werde ich aber nochmals deine Hilfe in Anspruch nehmen müssen. ;)

m.i.c.h.a
Beiträge: 5
Registriert: 4. Apr 2019 10:47

Re: Regeln erstellen

Beitrag von m.i.c.h.a » 7. Apr 2019 21:01

Hallo,

ich bekomme es einfach nicht hin, dass der Wert in der Sitemap angezeigt wird.

.items

Code: Alles auswählen

String T_Zeit
.sitemap

Code: Alles auswählen

Text item=T_Zeit
In T_Zeit steht der Wert: 20:15
Wo liegt der Fehler?

Benutzeravatar
udo1toni
Beiträge: 1259
Registriert: 11. Apr 2018 18:05
Wohnort: Darmstadt

Re: Regeln erstellen

Beitrag von udo1toni » 7. Apr 2019 22:42

Du musst ein Label setzen. Entweder bei der Definition des Items (das ist so oder so zu empfehlen) oder in der Sitemap:

Code: Alles auswählen

String T_Zeit "Zeit [%s]"

Code: Alles auswählen

Text item=T_Zeit label="Zeit [%s]"
Die zweite Variante kann sinnvoll sein, um an unterschiedlichen Stellen unterschiedliche Label für das selbe Item zu verwenden. Beispielsweise könnte man in einem String Item ein JSON Objekt als Ganzes vorhalten und das Parsen in unterschiedliche Anzeigen in der Sitemap erledigen. Oder man hat eine Seite, auf der alle Lichter angezeigt werden. Da muss das Label den Raum nennen, was nützen einem sieben Items mit dem Label Deckenlicht?
Andererseits möchte man vielleicht auch eine eigene Seite für den Raum haben, da sollte der Raumname explizit nicht im Label auftauchen, unerwünschte Redundanz.

m.i.c.h.a
Beiträge: 5
Registriert: 4. Apr 2019 10:47

Re: Regeln erstellen

Beitrag von m.i.c.h.a » 26. Apr 2019 21:29

Hallo,

ich habe noch ein Problem. Ich möchte eine Steckdose zum Sonnenuntergang einschalten. Leider funktioniert die Rule nicht.

Code: Alles auswählen

if((Sunset_Time.state.format("%1$tH").toNumber*60)+Sunset_Time.state.format("%1$tM").toNumber < (Stunde.state.toNumber * 60) +Minute.state.toNumber){
 	Sonoff_S20_1_Switch.sendCommand(ON)
}
Micha

Benutzeravatar
peter-pan
Beiträge: 221
Registriert: 28. Nov 2018 12:03
Wohnort: Schwäbisch Gmünd

Re: Regeln erstellen

Beitrag von peter-pan » 26. Apr 2019 23:11

Eigentlich ist das ganz einfach, wenn du das Astro-Binding installiert hast.

Dann könnte dier diese Regel weiter helfen:

Code: Alles auswählen

//===============================================================================
rule "Sunset Start"
    when
        Channel 'astro:sun:local:set#event' triggered START
    then
        logInfo("astro-rules" + '_13'," Sunset Start. START")
        //Sonoff_Basic_03.sendCommand(ON)
end
Ich weiß natürlich nicht wie dein Thing genau heisst.??!!. Das triggert dann genau einmal am Tag(soweit ich weiß).

m.i.c.h.a
Beiträge: 5
Registriert: 4. Apr 2019 10:47

Re: Regeln erstellen

Beitrag von m.i.c.h.a » 27. Apr 2019 06:48

Hallo,

hier mal meine ganze Rule.

Code: Alles auswählen

rule "Licht"
when
    Time cron "*/20 * * * * ?"
then
    
    Minute.postUpdate(now.getMinuteOfHour)
    Stunde.postUpdate(now.getHourOfDay)
    
    if(Onkyo_Power1.state == ON){
            if(Sonoff_S20_1_Switch.state == OFF){
                if((Sunset_Time.state.format("%1$tH").toNumber*60)+Sunset_Time.state.format("%1$tM").toNumber < (Stunde.state.toNumber * 60) + Minute.state.toNumber){
                    Sonoff_S20_1_Switch.sendCommand(ON)
                }
            }
        }   
Wenn ich den Onkyo einschalte und der Sonnenuntergang ist vorbei, soll das Licht eingeschaltet werden.
Bis auf den Sonnenuntergang funktioniert es schon.

Micha

Benutzeravatar
udo1toni
Beiträge: 1259
Registriert: 11. Apr 2018 18:05
Wohnort: Darmstadt

Re: Regeln erstellen

Beitrag von udo1toni » 27. Apr 2019 19:34

Deine Rule ist mehr als ungünstig.

Zum ersten lässt Du die Rule alle 20 Sekunden triggern. Im Zweifel dauert es also 20 Sekunden, bis die Rule etwas tut.
Zum zweiten setzt Du Stunde und Minute in zwei Items und greifst unmittelbar darauf zu. openHAB ist stateless und es gibt keinerlei Garantien, wann ein Status fertig gesetzt ist. Es ist auch sinnlos, Stunde und Minuten in zwei Items zu speichern, selbst wenn Du sie in der UI anzeigen willst (denn dazu gibt es DateTime)
Zum dritten fummelst Du Dir Werte zurecht (format().toNumber...) statt das zu nutzen, was openHAB komfortabel bereitstellt.

Mein Lösungesvorschlag:
  1. Du definierst ein ungebundenes Item, in welchem Du die Tageszeit speicherst (je nach Belieben, z.B. als Switch für Tag/Nacht oder als Number für beliebig viele Abstufungen)
  2. eine Rule, die auf einen Trigger Sonnenuntergang reagiert. Diese Rule setzt das Item aus 1.
  3. eine Rule, die auf einen Trigger Sonnenaufgang reagiert. Diese Rule löscht das Item aus 1.
  4. eine letzte Rule, die sich um das Licht kümmert. Sieht dann z.B. so aus:

Code: Alles auswählen

Switch sNacht "Nacht [%s]"

Code: Alles auswählen

rule "Sonnenaufgang"
when
    Channel 'astro:sun:local:rise#event' triggered START
then
    sNacht.postUpadte(OFF)
end

rule "Sonnenuntergang"
when
    Channel 'astro:sun:local:set#event' triggered START
then
    sNacht.postUpadte(ON)
end

rule "Licht an"
when
    Item Onkyo_Power1 changed to ON or
    Item sNacht changed to ON
then
    if(Onkyo_Power1.state == ON && sNacht.state == ON)
        if(Sonoff_S20_1_Switch.state == OFF) Sonoff_S20_1_Switch.sendCommand(ON)
end
Die ersten zwei Rules kümmern sich darum, zweimal täglich den Status des Items zu ändern. Wenn Du in anderen Rules auf Tageszeiten Bezug nehmen willst, kannst Du hier wie erwähnt auch feinere Abstufungen wählen (Stichwort Time of Day im englischen Forum, aber für Dein akonkretes Problem reicht die kleine Lösung). Die beiden Rules werden zusammen zweimal am Tag getriggert und laufen nur wenige Millisekunden; das astro Binding muss natürlich installiert sein.
Die dritte Rule wird getriggert, wenn der Sonnenuntergang erreicht wurde (also das Item sNacht auf ON wechselt) oder der Onkyo eingeschaltet wurde, und zwar unmittelbar. Das heißt, das Licht wird nicht nur automatisch eingeschaltet, wenn der Verstärker nach Sonnenuntergang eingeschaltet wird, sondern auch, wenn der Verstärker schon an ist, und der Sonnenuntergang auftritt.
Wenn Dir das zu viel Automatik sein sollte, kannst Du natürlich den zweiten Trigger (sNacht changed...) und die erste Bedingung (Onkyo_Power1.state == ON) entfernen.
Der Unterschied zu Deiner Rule ist natürlich zmu einen die Einfachheit des Codes, zum anderen die wesentlich geringere Belastung des Systems, da nur bei Bedarf die Rule ausgeführt wird.

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast