Time Rule

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
AndRe5575
Beiträge: 76
Registriert: 8. Jun 2020 20:16
Answers: 0

Time Rule

Beitrag von AndRe5575 »

Hallo zusammen,

ich habe über die OpenHab App ein Item angelegt, welches die Zeit meines Android Weckers übernimmt.
Das DateTime Format sieht folgendermaßen aus: 2025-07-26T16:00:00.000+0200

Code: Alles auswählen

DateTime AlarmClock "Alarm Clock [%s]" <time>
Des Weiteren habe ich ein zweites Item erstellt, welches über das NTP Binding die aktuelle Zeit enthält:

Code: Alles auswählen

DateTime CurrentTime "Current Time [%1$tH:%1$tM:%1$tS]"
Nun würde ich gerne mittels des AddOns "Simulate Sunrise" meinen Lichtwecker damit starten.
Ziel ist es, dass das AddOn "x" Minuten vor meinem Wecker startet.
Die Minuten würde ich gerne über das PaperUI anpassen.

Hat hier jemand bereits ein ähnliches Projekt realisiert und würde es hier teilen?

Meine aktuellen Probleme sind:
  • Wie kann ich vom DateTime Format x Minuten abziehen?
  • Das aktuelle Datum hat leider immer eine Nachkommastelle bei den Sekunden: 2025-07-26T16:00:00.170+0200, hierdurch fällt ein Vergleich flach

    Code: Alles auswählen

    when CurrentTime = AlarmClock then
Ich freue mich auf Eure Vorschläge.

Harka
Beiträge: 522
Registriert: 30. Apr 2021 13:13
Answers: 19

Re: Time Rule

Beitrag von Harka »

Moin,

theoretisch sollte man die frei einstellbaren Minuten und mit vom Handy kommende Weckzeit in das Script mit einbauen können. Nur wird das vermutlich beim nächsten Einsehen des Scripts wieder verworfen.
Zeit kannst du z.B. mit ".minusMinutes(x)" abziehen. Das mit den Nachkommastellen bei den Sekunden ist nur ein Problem wenn Du ein Vergleich mit Strings machst. Für Date/Time brauchst Du t1.equals(t2)

Ich habe mit Hilfe von Blockly mal eine Regel gebastelt welche Deinem Wunsch nahe kommen sollte. Sie beruht, wie die von Dir genannte Regelvorlage, auf Javascript.
- Wecker_Aufwachzeit ist das Number-Item mit den Minuten, die das Licht früher angehen soll
- Weckzeit ist ein DateTime-Item welches von der Regel automatisch beim werkeln mit dem Handywecker aktualisiert wird
- PixelAlarm ist die Weckzeit vom Handy
- die Variable istStunde kannst Du ggf. nutzen um bei mehreren Weckern die Regel im Zaun zu halten.

Code: Alles auswählen

configuration: {}
triggers:
  - id: "3"
    configuration:
      itemName: Weckzeit
      timeOnly: false
    type: timer.DateTimeTrigger
  - id: "1"
    configuration:
      itemName: PixelAlarm
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: >
        var tAufwachZeitMinuten, PixelWeckZeit, istStunde, Dimmer,  neuerOH_Wecker;
        tAufwachZeitMinuten = items.getItem('Wecker_Aufwachzeit').numericState;
        if (String(event.itemName) == items.getItem('PixelAlarm').name) {
          PixelWeckZeit = event.itemState?.toString();
          if (PixelWeckZeit != 'UNDEF') {
            if (typeof(this['Interval_Wecker2']) != 'undefined') clearInterval(this['Interval_Wecker2']);
            neuerOH_Wecker = (time.toZDT(PixelWeckZeit)).minusMinutes(tAufwachZeitMinuten);
            items.getItem('Weckzeit').sendCommand(neuerOH_Wecker);
          }
        } else {
          istStunde = ((time.ZonedDateTime.now()).hour());
          Dimmer = 0;
          if (typeof(this['Interval_Wecker2']) != 'undefined') clearInterval(this['Interval_Wecker2']); this['Interval_Wecker2'+"_C"] = 0;  this['Interval_Wecker2'] = setInterval(function() {
            Dimmer = (typeof Dimmer === 'number' ? Dimmer : 0) + 100 / 60;
            items.getItem('Philips01_Helligkeit').sendCommand(Math.floor(Dimmer));
            this['Interval_Wecker2'+"_C"]++;
            if (this['Interval_Wecker2'+"_C"] >= 60) clearInterval(this['Interval_Wecker2']);
          }, tAufwachZeitMinuten*1000);
        }
    type: script.ScriptAction

AndRe5575
Beiträge: 76
Registriert: 8. Jun 2020 20:16
Answers: 0

Re: Time Rule

Beitrag von AndRe5575 »

Danke für Deine Antwort, Blockly habe ich bisher noch nicht benutzt.
Ich habe gestern Abend und die Nacht noch an dem Problem gesessen und dann einfach mal Copilot gefragt.

Hier das Ergebnis:

Items:

Code: Alles auswählen

Group gLichtwecker    "Lichtwecker Lampen"

// Hauptschalter und Uhrzeit-Quelle
Switch      AlarmClock                    "Lichtwecker Überwachung Ein/Aus"         <switch>  
DateTime    AlarmClockAndreas             "Weckzeit Andreas"                        <calendar> 

// Dimm-Parameter
Number  Lichtwecker_MaxDimLvl             "Zielhelligkeit Lichtwecker [%.0f %%]"    <time>    
Number  Lichtwecker_Nachlauf              "Nachlaufzeit [%.0f Min. nach Weckzeit]"  <time>   
Number  Lichtwecker_Vorlauf               "Vorlaufzeit [%.0f Min. vor Weckzeit]"    <time>   

// Weckzeit pro Wochentag (Stunde + Minute)
Number  Lichtwecker_Weckzeit_Mo_Stunde    "Montag: Stunde [%d]"
Number  Lichtwecker_Weckzeit_Mo_Minute    "Montag: Minute [%d]"
Switch  Lichtwecker_Enable_Mo             "Wecker Montag aktiv"     <switch>

Number  Lichtwecker_Weckzeit_Di_Stunde    "Dienstag: Stunde [%d]"
Number  Lichtwecker_Weckzeit_Di_Minute    "Dienstag: Minute [%d]"
Switch  Lichtwecker_Enable_Di             "Wecker Dienstag aktiv"    <switch>

Number  Lichtwecker_Weckzeit_Mi_Stunde    "Mittwoch: Stunde [%d]"
Number  Lichtwecker_Weckzeit_Mi_Minute    "Mittwoch: Minute [%d]"
Switch  Lichtwecker_Enable_Mi             "Wecker Mittwoch aktiv"    <switch>

Number  Lichtwecker_Weckzeit_Do_Stunde    "Donnerstag: Stunde [%d]"
Number  Lichtwecker_Weckzeit_Do_Minute    "Donnerstag: Minute [%d]"
Switch  Lichtwecker_Enable_Do             "Wecker Donnerstag aktiv"  <switch>

Number  Lichtwecker_Weckzeit_Fr_Stunde    "Freitag: Stunde [%d]"
Number  Lichtwecker_Weckzeit_Fr_Minute    "Freitag: Minute [%d]"
Switch  Lichtwecker_Enable_Fr             "Wecker Freitag aktiv"     <switch>

Number  Lichtwecker_Weckzeit_Sa_Stunde    "Samstag: Stunde [%d]"
Number  Lichtwecker_Weckzeit_Sa_Minute    "Samstag: Minute [%d]"
Switch  Lichtwecker_Enable_Sa             "Wecker Samstag aktiv"     <switch>

Number  Lichtwecker_Weckzeit_So_Stunde    "Sonntag: Stunde [%d]"
Number  Lichtwecker_Weckzeit_So_Minute    "Sonntag: Minute [%d]"
Switch  Lichtwecker_Enable_So             "Wecker Sonntag aktiv"     <switch>
Sitemap (Auszug):

Code: Alles auswählen

    Frame label="Lichtwecker" icon="Clock" 
    {
   Text label="Einstellung"  icon="Settings"
        {
            Frame label="Einstellungen"
            {
                Switch   item=AlarmClock                  label="Lichtwecker aktivieren" icon="switch" mappings=[ON="Ein", OFF="Aus"]
                Setpoint item=Lichtwecker_MaxDimLvl       label="Zielhelligkeit [%.0f %%]" minValue=1 maxValue=100 step=1 icon="slider"
                Setpoint item=Lichtwecker_Nachlauf        label="Nachlaufzeit [%.0f Min. nach Weckzeit]" minValue=1 maxValue=60 step=1 icon="time"
                Setpoint item=Lichtwecker_Vorlauf         label="Vorlaufzeit [%.0f Min. vor Weckzeit]"  minValue=1 maxValue=60 step=1 icon="time"
            }
        }
   Text label="Zeiten"  icon="TIME"
        {
            Frame label="Weckzeiten (Mo–So)" icon="time" 
            {
                    Switch   item=Lichtwecker_Enable_Mo           label="Aktiv" mappings=[ON="Ein", OFF="Aus"]
                    Setpoint item=Lichtwecker_Weckzeit_Mo_Stunde  label="Mo Stunde"   minValue=0 maxValue=23 step=1
                    Setpoint item=Lichtwecker_Weckzeit_Mo_Minute  label="Mo Minute"   minValue=0 maxValue=59 step=1

                    Switch   item=Lichtwecker_Enable_Di           label="Aktiv" mappings=[ON="Ein", OFF="Aus"]
                    Setpoint item=Lichtwecker_Weckzeit_Di_Stunde  label="Di Stunde"   minValue=0 maxValue=23 step=1
                    Setpoint item=Lichtwecker_Weckzeit_Di_Minute  label="Di Minute"   minValue=0 maxValue=59 step=1

                    Switch   item=Lichtwecker_Enable_Mi           label="Aktiv" mappings=[ON="Ein", OFF="Aus"]
                    Setpoint item=Lichtwecker_Weckzeit_Mi_Stunde  label="Mi Stunde"   minValue=0 maxValue=23 step=1
                    Setpoint item=Lichtwecker_Weckzeit_Mi_Minute  label="Mi Minute"   minValue=0 maxValue=59 step=1

                    Switch   item=Lichtwecker_Enable_Do           label="Aktiv" mappings=[ON="Ein", OFF="Aus"]
                    Setpoint item=Lichtwecker_Weckzeit_Do_Stunde  label="Do Stunde"   minValue=0 maxValue=23 step=1
                    Setpoint item=Lichtwecker_Weckzeit_Do_Minute  label="Do Minute"   minValue=0 maxValue=59 step=1

                    Switch   item=Lichtwecker_Enable_Fr           label="Aktiv" mappings=[ON="Ein", OFF="Aus"]
                    Setpoint item=Lichtwecker_Weckzeit_Fr_Stunde  label="Fr Stunde"   minValue=0 maxValue=23 step=1
                    Setpoint item=Lichtwecker_Weckzeit_Fr_Minute  label="Fr Minute"   minValue=0 maxValue=59 step=1

                    Switch   item=Lichtwecker_Enable_Sa           label="Aktiv" mappings=[ON="Ein", OFF="Aus"]
                    Setpoint item=Lichtwecker_Weckzeit_Sa_Stunde  label="Sa Stunde"   minValue=0 maxValue=23 step=1
                    Setpoint item=Lichtwecker_Weckzeit_Sa_Minute  label="Sa Minute"   minValue=0 maxValue=59 step=1

                    Switch   item=Lichtwecker_Enable_So           label="Aktiv" mappings=[ON="Ein", OFF="Aus"]
                    Setpoint item=Lichtwecker_Weckzeit_So_Stunde  label="So Stunde"   minValue=0 maxValue=23 step=1
                    Setpoint item=Lichtwecker_Weckzeit_So_Minute  label="So Minute"   minValue=0 maxValue=59 step=1
                }
        }
    }
Rule:

Code: Alles auswählen

//File: conf/rules/Lichtwecker.rules

import org.openhab.core.library.types.DecimalType
import java.util.Calendar

rule "Lichtwecker dimmen (pro Wochentag schaltbar)"
when
    // prüft jede Minute
    Time cron "0 * * * * ?"
then
    // 0) Globaler Hauptschalter
    if (AlarmClock.state != ON) {
        // alles zurücksetzen
        gLichtwecker.members.forEach[ light | light.sendCommand(OFF) ]
        Lichtwecker_CurrentDimLevel.postUpdate(0)
        return
    }

    // 1) aktuelle Zeit als Calendar-Instanz holen
    val nowCal = Calendar.getInstance

    // 2) Wochentag ermitteln (Calendar.MONDAY = 2 … SUNDAY = 1)
    val dow = nowCal.get(Calendar.DAY_OF_WEEK)

    // 3) Je nach Wochentag Stunde/Minute aus Items lesen
    var int hour   = 0
    var int minute = 0

    switch (dow) {
        case Calendar.MONDAY: {
            hour   = (Lichtwecker_Weckzeit_Mo_Stunde.state as Number).intValue
            minute = (Lichtwecker_Weckzeit_Mo_Minute.state as Number).intValue
        }
        case Calendar.TUESDAY: {
            hour   = (Lichtwecker_Weckzeit_Di_Stunde.state as Number).intValue
            minute = (Lichtwecker_Weckzeit_Di_Minute.state as Number).intValue
        }
        case Calendar.WEDNESDAY: {
            hour   = (Lichtwecker_Weckzeit_Mi_Stunde.state as Number).intValue
            minute = (Lichtwecker_Weckzeit_Mi_Minute.state as Number).intValue
        }
        case Calendar.THURSDAY: {
            hour   = (Lichtwecker_Weckzeit_Do_Stunde.state as Number).intValue
            minute = (Lichtwecker_Weckzeit_Do_Minute.state as Number).intValue
        }
        case Calendar.FRIDAY: {
            hour   = (Lichtwecker_Weckzeit_Fr_Stunde.state as Number).intValue
            minute = (Lichtwecker_Weckzeit_Fr_Minute.state as Number).intValue
        }
        case Calendar.SATURDAY: {
            hour   = (Lichtwecker_Weckzeit_Sa_Stunde.state as Number).intValue
            minute = (Lichtwecker_Weckzeit_Sa_Minute.state as Number).intValue
        }
        case Calendar.SUNDAY: {
            hour   = (Lichtwecker_Weckzeit_So_Stunde.state as Number).intValue
            minute = (Lichtwecker_Weckzeit_So_Minute.state as Number).intValue
        }
    }

    // 4) Weckzeitpunkt als Calendar auf heute setzen
    val wakeCal = Calendar.getInstance
    wakeCal.timeInMillis = nowCal.timeInMillis
    wakeCal.set(Calendar.HOUR_OF_DAY, hour)
    wakeCal.set(Calendar.MINUTE, minute)
    wakeCal.set(Calendar.SECOND, 0)
    wakeCal.set(Calendar.MILLISECOND, 0)

    // 5) Zeitdifferenz in Minuten
    val long diffMin = (wakeCal.timeInMillis - nowCal.timeInMillis) / 60000

    // 6) Vorlauf, Nachlauf, Zielhelligkeit
    val int vorlauf   = (Lichtwecker_Vorlauf.state as DecimalType).intValue
    val int nachlauf = (Lichtwecker_Nachlauf.state as DecimalType).intValue
    val int zielLvl   = (Lichtwecker_MaxDimLvl.state as DecimalType).intValue

    // 7) Dimmstufe berechnen
    var int sendLevel = 0
    if (diffMin <= vorlauf && diffMin > 0) {
        sendLevel = ((vorlauf - diffMin) * zielLvl / vorlauf).intValue
    }
    else if (diffMin <= 0 && diffMin >= -nachlauf) {
        sendLevel = zielLvl
    }
    // sendLevel bleibt 0, wenn außerhalb beider Intervalle

    // 8) Licht setzen & UI aktualisieren
    gLichtwecker.members.forEach[ light |
        if (sendLevel > 0) light.sendCommand(new DecimalType(sendLevel))
        else                light.sendCommand(OFF)
    ]
end
Persistence:

Code: Alles auswählen

Strategies {
  default = everyChange, restoreOnStartup
}

Items {
  AlarmClock,
  AlarmClockAndreas,
  Lichtwecker_MaxDimLvl,
  Lichtwecker_Vorlauf,
  Lichtwecker_Nachlauf,
  Lichtwecker_Weckzeit_Mo_Stunde, Lichtwecker_Weckzeit_Mo_Minute,
  Lichtwecker_Weckzeit_Di_Stunde, Lichtwecker_Weckzeit_Di_Minute,
  Lichtwecker_Weckzeit_Mi_Stunde, Lichtwecker_Weckzeit_Mi_Minute,
  Lichtwecker_Weckzeit_Do_Stunde, Lichtwecker_Weckzeit_Do_Minute,
  Lichtwecker_Weckzeit_Fr_Stunde, Lichtwecker_Weckzeit_Fr_Minute,
  Lichtwecker_Weckzeit_Sa_Stunde, Lichtwecker_Weckzeit_Sa_Minute,
  Lichtwecker_Weckzeit_So_Stunde, Lichtwecker_Weckzeit_So_Minute,
  Lichtwecker_Enable_Mo, Lichtwecker_Enable_Di, Lichtwecker_Enable_Mi,
  Lichtwecker_Enable_Do, Lichtwecker_Enable_Fr, Lichtwecker_Enable_Sa,
  Lichtwecker_Enable_So
}
Ini Rule:

Code: Alles auswählen

rule "Initialize Lichtwecker Items"
when
    System started
then
    // Dimm-Parameter Standardwerte setzen
    if (Lichtwecker_MaxDimLvl.state == UNDEF)  Lichtwecker_MaxDimLvl.postUpdate(50)
    if (Lichtwecker_Vorlauf.state   == UNDEF)  Lichtwecker_Vorlauf.postUpdate(10)
    if (Lichtwecker_Nachlauf.state  == UNDEF)  Lichtwecker_Nachlauf.postUpdate(5)

    // Weckzeiten Standardwerte für jeden Wochentag
    if (Lichtwecker_Weckzeit_Mo_Stunde.state   == UNDEF) Lichtwecker_Weckzeit_Mo_Stunde.postUpdate(7)
    if (Lichtwecker_Weckzeit_Mo_Minute.state   == UNDEF) Lichtwecker_Weckzeit_Mo_Minute.postUpdate(30)

    if (Lichtwecker_Weckzeit_Di_Stunde.state   == UNDEF) Lichtwecker_Weckzeit_Di_Stunde.postUpdate(7)
    if (Lichtwecker_Weckzeit_Di_Minute.state   == UNDEF) Lichtwecker_Weckzeit_Di_Minute.postUpdate(30)

    if (Lichtwecker_Weckzeit_Mi_Stunde.state   == UNDEF) Lichtwecker_Weckzeit_Mi_Stunde.postUpdate(7)
    if (Lichtwecker_Weckzeit_Mi_Minute.state   == UNDEF) Lichtwecker_Weckzeit_Mi_Minute.postUpdate(30)

    if (Lichtwecker_Weckzeit_Do_Stunde.state   == UNDEF) Lichtwecker_Weckzeit_Do_Stunde.postUpdate(7)
    if (Lichtwecker_Weckzeit_Do_Minute.state   == UNDEF) Lichtwecker_Weckzeit_Do_Minute.postUpdate(30)

    if (Lichtwecker_Weckzeit_Fr_Stunde.state   == UNDEF) Lichtwecker_Weckzeit_Fr_Stunde.postUpdate(7)
    if (Lichtwecker_Weckzeit_Fr_Minute.state   == UNDEF) Lichtwecker_Weckzeit_Fr_Minute.postUpdate(30)

    if (Lichtwecker_Weckzeit_Sa_Stunde.state   == UNDEF) Lichtwecker_Weckzeit_Sa_Stunde.postUpdate(8)
    if (Lichtwecker_Weckzeit_Sa_Minute.state   == UNDEF) Lichtwecker_Weckzeit_Sa_Minute.postUpdate(0)

    if (Lichtwecker_Weckzeit_So_Stunde.state   == UNDEF) Lichtwecker_Weckzeit_So_Stunde.postUpdate(8)
    if (Lichtwecker_Weckzeit_So_Minute.state   == UNDEF) Lichtwecker_Weckzeit_So_Minute.postUpdate(0)

    // Wecker pro Tag standardmäßig aktiv setzen
    if (Lichtwecker_Enable_Mo.state == UNDEF) Lichtwecker_Enable_Mo.postUpdate(OFF)
    if (Lichtwecker_Enable_Di.state == UNDEF) Lichtwecker_Enable_Di.postUpdate(OFF)
    if (Lichtwecker_Enable_Mi.state == UNDEF) Lichtwecker_Enable_Mi.postUpdate(OFF)
    if (Lichtwecker_Enable_Do.state == UNDEF) Lichtwecker_Enable_Do.postUpdate(OFF)
    if (Lichtwecker_Enable_Fr.state == UNDEF) Lichtwecker_Enable_Fr.postUpdate(OFF)
    if (Lichtwecker_Enable_Sa.state == UNDEF) Lichtwecker_Enable_Sa.postUpdate(OFF)
    if (Lichtwecker_Enable_So.state == UNDEF) Lichtwecker_Enable_So.postUpdate(OFF)
end
Nun läuft das ganze recht Rund und so wie ich es mir vorgestellt habe (Anbindung an Android Wecker habe ich verworfen, hat Anfangs aber auch funktioniert). Das schöne ist, Copilot kann das ganze Skript auch noch gut erklären, so dass es für einen selber nachvollziehbar ist.

Copilot und Co sind hier sicher eine gute Unterstützung, kommen aber sicher nicht an die Hilfe dieses Forums ran.
Evtl. sieht hier jemand auch noch Verbesserungspotenzial, was die KI nicht sieht.

Danke und Gruß

AndRe

Harka
Beiträge: 522
Registriert: 30. Apr 2021 13:13
Answers: 19

Re: Time Rule

Beitrag von Harka »

Sehr schön. Wenn es alles so funktioniert wie Du es brauchst -> darum geht es ja schlussendlich. Die Android-Wecker Verbindung fand ich auch erst mal interessant, aber wir bleiben bei der "entkoppelten" Lösung wo dieser nur als Backup dient.
Das mit dem Erklären ist jetzt nicht so meine Stärke ;-) Ist aber auch schwierig wenn man keine Infos zu dem Gegenüber hat. Da hätte ich auf Nachfrage auf jeden Fall noch "nachgebessert"

Wie löst Du das mit Feiertagen, Urlaub u.s.w. ? Über den AlarmClock-Schalter?

AndRe5575
Beiträge: 76
Registriert: 8. Jun 2020 20:16
Answers: 0

Re: Time Rule

Beitrag von AndRe5575 »

Harka hat geschrieben: 27. Jul 2025 15:41 Die Android-Wecker Verbindung fand ich auch erst mal interessant, aber wir bleiben bei der "entkoppelten" Lösung wo dieser nur als Backup dient.
Copilot hat die beiden Lösungen schnell gegeneinander ausgetauscht. Wir nutzen einen klassischen Wecker und haben das Handy nicht am Bett liegen. Ich dachte erst, es wäre leichter den Wecker so zu stellen, aber die Paper UI Variante gefällt mir weit besser.
Harka hat geschrieben: 27. Jul 2025 15:41 Das mit dem Erklären ist jetzt nicht so meine Stärke ;-) Ist aber auch schwierig wenn man keine Infos zu dem Gegenüber hat. Da hätte ich auf Nachfrage auf jeden Fall noch "nachgebessert"
Ich glaube es gibt hier ein kleines Missverständnis. Ich habe nicht Deine Erklärung nicht verstanden, es war einfach so, dass Copilot mir die Präsentierte Lösung im Detail erklärt hat, das war schon super und erleichtert auch das Lernen.
Harka hat geschrieben: 27. Jul 2025 15:41 Wie löst Du das mit Feiertagen, Urlaub u.s.w. ? Über den AlarmClock-Schalter?
Ich kann den Wecker über das Paper UI, welches ich über die Handy App nutze, einfach ein- bzw. ausstellen. das würde ich bei meinem Handywecker ja auch machen. Da das Handy bei uns nicht am Bett liegt, war der Lösungsansatz nicht optimal.

Antworten