openHAB – Sanftes Aufwachen mittels konfigurierbarem Lichtwecker

openHAB - konfigurierbarer Lichtwecker
openHAB – konfigurierbarer Lichtwecker

Lichtwecker sind grundsätzlich nichts neues, aber warum ein Gerät kaufen, wenn man das Smart Home dafür nutzen kann. Mit einem Dimmer (bei mir der von Homematic) im Schlafzimmer ist das mit openHAB schnell erledigt.

Zum Thema wecker liefert openhab im wiki ja bereits einige Beispiele aber irgendwie war mir das zu kompliziert. Timer, Locks, … – das muss doch einfacher gehen.

Als Anforderungen habe ich für mich festgelegt:

  • konfigurierbare Weckzeit und Wecktage
  • konfigurierbare Ziel-Helligkeit
  • konfigurierbare Geschwindigkeit für’s heller werden
  • Konfigurierbare maximale Helligkeit
  • Abbruchmöglichkeit, wenn Taste im Raum für betroffenen Lichtschalter gedrückt wurde

Hier nun mein Lösungsansatz:

Die Items

Grundsätzlich gibt es Items, über welche die Weckzeit und die ganze Konfiguration gesteuert wird.

Hier der relevante Auszug der Items-Datei:

Switch  weckerMontag     "Montag"     <switch>
Switch  weckerDienstag   "Dienstag"   <switch>
Switch  weckerMittwoch   "Mittwoch"   <switch>
Switch  weckerDonnerstag "Donnerstag" <switch>
Switch  weckerFreitag    "Freitag"    <switch>
Switch  weckerSamstag    "Samstag"    <switch>
Switch  weckerSonntag    "Sonntag"    <switch>

String weckerZeitMessage "%s"

Number weckerZeitStunde "Stunde [%d]" <clock>
Number weckerZeitMinute "Minute [%d]" <clock>

Number weckerMaxHelligkeit "Helligkeit Max. [%d]" <switch>
Number weckerDimmerSleep "Dimmer-Schritte (Sekunden) [%d]" <clock>

Die Sitemap

Hier der relevante Auszug der Sitemap:

Text label="Wecker [%s]" item=weckerZeitMessage icon="clock" {
    Frame label="Zeit" {
        Setpoint item=weckerZeitStunde minValue=0 maxValue=23 step=1
        Setpoint item=weckerZeitMinute minValue=0 maxValue=55 step=5
    }
    Frame label="Wochentage" {
        Switch item=weckerMontag
        Switch item=weckerDienstag
        Switch item=weckerMittwoch
        Switch item=weckerDonnerstag
        Switch item=weckerFreitag
        Switch item=weckerSamstag
        Switch item=weckerSonntag
    }
    Frame label="Konfiguration" {
        Setpoint item=weckerMaxHelligkeit minValue=10 maxValue=100 step=5
        Setpoint item=weckerDimmerSleep minValue=1 maxValue=20 step=1
    }
}

Die Rules

Hier gibt es drei relevante Rules – einmal Initialisieren, dann das Handling der eventuell geänderten Weckzeiten und zum andren den Wecker selbst

Initiales Setzen der Weckzeiten

Entweder kann dies beim Hochfahren des Systems erfolgen oder – wenn es die Variable / einen Wert für das Item einmal gibt – über eine Persistence gelöst werden, welche den Wert grundsätzlich speichert und mit der Strategie „RestoreOnStartup“ dann auch automatisch wieder lädt.

Bei mir übernimmt das Persistieren mapDB. Dies speichert zu jedem Item immer den letzten Wert – mehr brauche ich zu den Items auch nicht.

rule "Initialization"
 when 
   System started
 then
     // Muss nur temporär benutzt werden für erstes Initialisieren von Items
     // da diese ab erstmaliger Benutzung in der mapDB gespeichert werden. Werden die nicht persistiert hier Defaultwerte hinterlegen

    postUpdate(weckerZeitStunde,     06)
    postUpdate(weckerZeitMinute,     00)
    postUpdate(weckerMontag,         ON)
    postUpdate(weckerDienstag,       ON)
    postUpdate(weckerMittwoch,       ON)
    postUpdate(weckerDonnerstag,     ON)
    postUpdate(weckerFreitag,        ON)
    postUpdate(weckerSamstag,        OFF)
    postUpdate(weckerSonntag,        OFF)
    postUpdate(weckerMaxHelligkeit,    30)
    postUpdate(weckerDimmerSleep,    5)
end

Geänderte Weckzeiten

Wird die Weckzeit geändert, dann wird zwar das Item bereits selbst geändert, hier muss also nichts gemacht werden, da ich aber die Weckzeit in „schön“ auch in der GUI sehen will, muss das hierzu künstlich erschaffene Icon ein Update erfahren:

rule "Wecker - Aenderung der Konfiguration"
when
    Item weckerZeitStunde received update or
    Item weckerZeitMinute received update 
then
    var weckerStunde =  weckerZeitStunde.state as DecimalType
    var weckerMinute =  weckerZeitMinute.state as DecimalType
    
    var String weckerText = ''
    if (weckerStunde.intValue < 10) weckerText = '0'
    weckerText = weckerText + weckerStunde.intValue + ':'
    if (weckerMinute.intValue < 10) weckerText = weckerText + '0'
    weckerText = weckerText + weckerMinute.intValue
    
    postUpdate(weckerZeitMessage, weckerText)
end

Der Wecker selbst

Der Wecker selbst läuft via Cron. Jede Minute wird geprüft, ob der Wecker ausgelöst werden soll. Für Debugzwecke sind Log-Ausgaben dabei, die natürlich ausgeklammert werden können.

rule "Wecker - prüfen"
when 
    Time cron "0 0/1 * * * ?"   // minütlicher Aufruf
then
    var weckerStunde =  (weckerZeitStunde.state as DecimalType).intValue
    var weckerMinute =  (weckerZeitMinute.state as DecimalType).intValue
    var weckerHelligkeit = (weckerMaxHelligkeit.state as DecimalType).intValue
    var weckerWartezeit = 1000 * (weckerDimmerSleep.state as DecimalType).intValue
    //logInfo('rules','helligkeit: ' + weckerHelligkeit +' wartezeit ' + weckerWartezeit)

    if (
        (now.getHourOfDay.intValue == weckerStunde) && (now.getMinuteOfHour.intValue == weckerMinute)
        && (
            ((weckerMontag.state == ON) && now.getDayOfWeek.intValue == 1) ||
            ((weckerDienstag.state == ON) && now.getDayOfWeek.intValue == 2) ||
            ((weckerMittwoch.state == ON) && now.getDayOfWeek.intValue == 3) ||
            ((weckerDonnerstag.state == ON) && now.getDayOfWeek.intValue == 4) ||
            ((weckerFreitag.state == ON) && now.getDayOfWeek.intValue == 5) ||
            ((weckerSamstag.state == ON) && now.getDayOfWeek.intValue == 6) ||
            ((weckerSonntag.state == ON) && now.getDayOfWeek.intValue == 7)
            )
    ) {
        logInfo ('rules','Wecker wird aktiviert...')
        // Wecker nur notwendig, wenn Licht aus ist
        if (dg_licht_schlafen.state < weckerHelligkeit) {
            var Number dimmer = 0
            while (dimmer < weckerHelligkeit) {
                // Licht auf Dimmstufe schalten
                sendCommand(dg_licht_schlafen, dimmer.intValue)
                // Konfigurierte Anzahl an Sekunden warten
                Thread::sleep(weckerWartezeit)
                // prüfen ob zwischenzeitlich Dimmerhelligkeit manuell veraendert wurde und damit der Wecker ausgemacht wurde
                var dimmerStatus = (dg_licht_schlafen.state as DecimalType).intValue
                if (dimmer == dimmerStatus) {
                    dimmer = dimmer + 1
                    logInfo('rules', 'Wecker: Dimmer plus 1 gesetzt auf ' + dimmer)
                } else {
                    dimmer = 100 // Abbruchbedingung
                    logInfo('rules', 'Wecker: Abbruch durch Tastendruck')
                }
            }
            logInfo('rules', 'Wecker abgeschlossen, Zielhelligkeit erreicht')
        } else {
            logInfo('rules', 'Wecker nicht gestartet da Licht bereits heller als Ziel-Helligkeit des Weckers. Helligkeit Licht: ' + dg_licht_schlafen.state)
        }
    } else {
        logInfo('rules','Wecker nicht aktiviert, Bedingung für Wecker trifft nicht zu')
    }
end

Fazit

Nun lässt es sich über die GUI bequem einstellen, wann der Wecker wecken soll, wie schnell er heller werden soll und wie hell er überhaupt werden soll und wenn man aufgewacht ist oder weiterschlafen will, einfach den Lichtschalter kurz drücken.

12 Antworten auf „openHAB – Sanftes Aufwachen mittels konfigurierbarem Lichtwecker“

  1. Guten Tag

    Wäre es möglich ein Image von dieser Konfiguration zu erhalten bzw. fachmännische Hilfe? Ich müsste ein Projekt realisieren, welches bei Alarmzeit 2 Ausgänge des RPi Relayboard (230/12V) ansteuert. Die Hardwareumgebung ist soweit realisiert und funktioniert bei einfachen Testansteuerungen. Diese nun mit dem Wecker zu „verbinden“ gelingt mir nicht.

    Hierfür war ihre Konfiguration hilfreich, allerdings will es nicht so richtig. Alleine schon der Wecker „refresht“ seine Einstellungen jeweils in Sekundentakt.

    Ich weiss echt nicht mehr weiter und wäre heilfroh für einen Rat (Abschlussarbeit). Natürlich würde ich die aufgewendete Zeit entschädigen.

    Liebe Grüsse
    Marco

    1. Hallo Marco,

      wie erfolgt denn die Ansteuerung des RPi-Relay-Boards im Test-Fall? Ich kenne das Board selbst nicht, aber wahrscheinlich werden auf der Shell Commandos ausgeführt, welche dann die Relais schalten?
      Sogesehen müsste nach „logInfo (‚rules‘,’Wecker wird aktiviert…‘)“ doch einfach nur das gewünschte Kommando zum Schalten des Relais platziert werden, oder?

      Was ist mit der Wecker refreshed im Sekundentakt gemeint?
      Was heißt „allerdings will es nicht so richtig“?

      Ein komplettes Image meines Raspberry Pis will ich leider so nicht weitergeben, da die hier veröffentlichten Auszüge nur Teile der Aufgaben sind, welche der Raspberry für mich übernimmt und da ist viel Privates dabei, was nicht zur Weitergabe gedacht ist.

      Wenn es Probleme gibt, grundsätzlich mit openHAB zurecht zu kommen, empfehle ich die dortige Community http://community.openhab.org/ in welcher i.d.R. rasch weitergeholfen wird.

      Viele Grüße
      Florian

    2. Hi,

      ich versuche gerade einen Zeitschalter in meinem OpenHab zu implementieren. Ich habe eigentlich alles so übernommen wie hier gepostet. Ich habe eine Lampe in items definiert: Switch dg_licht_schlafen „Wecker“ { channel=“hue:0220:ecb5fa085c82:7:brightness“ }
      Ich habe deine Rules in eine „zeitschaltuhr.rules“ gepackt.
      Leider schaltet die Lampe nicht. In den Logs kommt diese Meldung:
      „2019-06-06 10:42:00.378 [INFO ] [eclipse.smarthome.model.script.rules] – Wecker nicht aktiviert, Bedingung f�r Wecker trifft nicht zu
      2019-06-06 10:43:00.072 [INFO ] [eclipse.smarthome.model.script.rules] – Wecker nicht aktiviert, Bedingung f�r Wecker trifft nicht zu
      2019-06-06 10:44:00.069 [INFO ] [eclipse.smarthome.model.script.rules] – Wecker nicht aktiviert, Bedingung f�r Wecker trifft nicht zu
      2019-06-06 10:45:00.131 [INFO ] [eclipse.smarthome.model.script.rules] – Wecker wird aktiviert…
      2019-06-06 10:45:00.145 [INFO ] [eclipse.smarthome.model.script.rules] – Wecker nicht gestartet da Licht bereits heller als Ziel-Helligkeit des Weckers. Helligkeit Licht: OFF
      2019-06-06 10:46:00.557 [INFO ] [eclipse.smarthome.model.script.rules] – Wecker nicht aktiviert, Bedingung f�r Wecker trifft nicht zu
      2019-06-06 10:47:00.072 [INFO ] [eclipse.smarthome.model.script.rules] – Wecker nicht aktiviert, Bedingung f�r Wecker trifft nicht zu
      2019-06-06 10:48:00.080 [INFO ] [eclipse.smarthome.model.script.rules] – Wecker nicht aktiviert, Bedingung f�r Wecker trifft nicht zu“

      Ich weiss im Moment nicht wo ich den fehler suchen soll.
      Startet die Rule und ist in den Items, etc. irgendetwas falsch?
      oder startet die Rule erst gar nicht?
      Ich hänge hier fest und komme nicht weiter.
      Eigentlich brauche ich nur eine Rule um einen Schalter zu einer Uhrzeit an und zu einer anderen wieder aus zu schalten.
      Es wäre toll wenn du mir hier helfen könntest. Ich denke es ist irgendwo nur ein denkfehler.

      Danke

      1. Haha, kaum schreibt man um ein problem zu lösen und schon findet man selber die Lösung….
        Sorry, habs gefunden:
        Switch dg_licht_schlafen „Wecker“ { channel=“hue:0220:ecb5fa085c82:7:brightness“ } war falsch definiert es muß:
        Dimmer dg_licht_schlafen „Wecker“ { channel=“hue:0220:ecb5fa085c82:7:brightness“ }

  2. Tolle Anleitung, Respekt !
    genau so etwas habe ich noch gesucht.
    Habe es 1:1 umgesetzt und funktioniert auch (fast)
    Mein Problem: ich verwende Ikea Lampen und habe diese auch direkt über PaperUI eingebunden.
    kleine Anpassung in der rule und es läuft, alledings wird das Licht nur eingeschalten und nicht gedimmt. Hast du einen Ansatz für mich ?
    Gruss
    Andreas

    1. Hallo Andreas,

      Schön, dass dir die Anleitung geholfen hat.
      Die Ikea Lampen kenne ich nicht. Am besten ist es da, in der openhab Community nachzufragen, gerne mit Verweis auf diesen Artikel. Gerne kannst du hier anschließend die Lösung anfügen, dann ist anderen, die vor dem gleichen Problem stehen, auch gleich geholfen.
      Viele Grüße
      Florian

  3. Hallo,
    Florian hat mich ja gebeten, eine angepasste rule für openhab2 und Ikea-Lampe(n) hier abzulegen.
    Die rule wurde zusammen mit dem Spezialisten beim openhabforum.de (Wecker mit TRADFRI realisieren) entwickelt und läuft zuverlässig. Zudem wurde das hier vorgestellte Script noch optimiert. Hier die Vorteile:
    – Die Rule kommt ohne Thread::sleep() aus, womit die Rule auch nur sehr kurz Ressourcen benötigt.
    – Der Timer wird nur einmal täglich ausgeführt (und einmal pro Dimmschritt)
    – Auch der Timer benötigt nur sehr kurz Ressourcen, in der inaktiven Phase kümmert sich der Scheduler von openHAB um alles Nötige.
    – Die Rule kann nicht aus Versehen mehrfach gestartet werden, bzw. es kommt dadurch nicht zu Störungen.
    Vielen Dank an udo1toni.
    Hier nun die rule:
    „// Globale Variablen immer zu Beginn der Datei definieren!

    var Timer tWecker = null

    rule „Wecker Change“
    when
    Member of gWecker changed
    then
    logInfo(„wecker_test“,“Rule Wecker Change getriggert“)
    if(previousState == NULL) return;

    // initialize all items that are of status NULL
    if(!(WeckDimmzeit.state instanceof Number)) WeckDimmzeit.postUpdate(1)
    if(!(WeckMaximum.state instanceof Number)) WeckMaximum.postUpdate(100)
    gWecker.members.filter[i | i.state == NULL && i instanceof SwitchItem].forEach[ n | n.postUpdate(OFF)]
    gWecker.members.filter[i | i.state == NULL && i instanceof NumberItem].forEach[ n | n.postUpdate(0)]

    var Number nWeckZeit = (WeckZeitStunde.state as Number) * 60 + (WeckZeitMinute.state as Number)
    WeckZeit.postUpdate(nWeckZeit.intValue)

    logInfo(„wecker_test“,“1 Status WeckDimmzeit: {}“,WeckDimmzeit.state)
    tWecker?.cancel
    tWecker = createTimer(now.withTimeAtStartOfDay.plusMinutes(nWeckZeit.intValue).plusDays(if(now.getMinuteOfDay < nWeckZeit.intValue) 0 else 1), [ |
    if((gWecker.members.filter[i | i instanceof SwitchItem && i.name.contains(now.getDayOfWeek.toString)].head.state == ON && (MyDimmer.state as Number) < (WeckMaximum.state as Number)) {
    MyDimmer.sendCommand( (MyDimmer.state as Number) + 1)
    tWecker.reschedule(now.plusSeconds((WeckDimmzeit.state as Number).intValue)))
    }
    else
    tWecker.reschedule(now.withTimeAtStartOfDay.plusMinutes((WeckZeit.state as Number).intValue).plusDays(1))
    ])
    end
    "
    Ich hoffe OH2 user mit Tradfri können das hier nutzen 😉
    EIn kleiner "Dämpfer" ist allerdings dabei: Während die rule läuft, kann man das Licht zwar manuell abschalten, sie wird aber nach der eingestellten Dimmerzeit wieder aktiviert. Die rule läuft eben, bis der Lichtwert erreicht ist (z.B. 80%) Dies kann man umgehen, indem man per FB die Lampe auf 100% bringt und die Dimmerzeit (meist zwischen 5-20sec) abwartet. Dann kann man die Lampe abschalten.
    Gruss
    Andreas

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.