Wake Up Light

Thought I would share my wake up light. It’s pretty simple and could definitely been done in a more advance way.

The idea
Set the alarm for a given time based on hours and minutes. When the alarm is triggered
the light (using a dimmer) will slowly increase its intensity. Once it reached 100% (or more), the alarm has finished.
I’ve only used it one night, so probably some bugs, but could give you an idea how to use it.

wakeup.items

Group WakeUpAlarm
Number WakeUpHour           "Wake up hour [%d]" <clock> (gRestore,WakeUpAlarm)
Number WakeUpMinute         "Wake up minute [%d]" <clock> (gRestore,WakeUpAlarm)
Number WakeUpDimStep        "Wake up Dim Step [%d]" <light> (gRestore,WakeUpAlarm)
Number WakeUpTimeStep       "Wake up Time Step [%d]" <clock> (gRestore,WakeUpAlarm)
Switch WakeUpAlarmSwitch    "Wake up alarm [%s]" (gRestore,WakeUpAlarm)
Switch WakeUpAlarmTriggered "Wake up alarm triggered [%s]"  <alarm> (gRestore,WakeUpAlarm)

Sitemap

Group label="Wake up Alarm" icon="clock" {
       Setpoint item=WakeUpHour minValue=0 maxValue=23 step=1
       Setpoint item=WakeUpMinute minValue=0 maxValue=59 step=1
       Setpoint item=WakeUpDimStep minValue=1 maxValue=100 step=1
       Setpoint item=WakeUpTimeStep minValue=1 maxValue=60 step=1
       Switch item=WakeUpAlarmSwitch
       Text item=WakeUpAlarmTriggered

The group gRestore could be removed if you don’t want to persist, or if you already presist everything. For more info on gRestore see Design Pattern: Group Based Persistence

wakeup.rules

import org.eclipse.smarthome.core.library.types.DecimalType
import org.eclipse.smarthome.model.script.actions.Timer

var boolean mAlaramTriggered = false 
var int mCurrentDimLevel = 0
val String LOG = "WakeUp"
var Timer mWakeUpTimer = null
var Timer mDimmerTimer = null
var int mDimStep
var int mTimeStep
val int DEFAULT_DIM_STEP = 2
val int DEFAULT_TIME_STEP = 1

rule "WakeUpAlarmSwitchOn"
when
    Item WakeUpAlarmSwitch changed to ON
then
    if (WakeUpMinute.state == NULL || WakeUpHour.state == NULL) {
        logInfo(LOG, "WakeUpAlarmMinute or WakeUpAlarmHour not set, alarm not processed")
    } else {
      var int nowHour = now.getHourOfDay
      var int wakeUpHour = (WakeUpHour.state as DecimalType).intValue

      var int hours = 0
      val int hourDiff = wakeUpHour - nowHour 
      if (hourDiff >= 0) {
          hours = hourDiff
      } else {
          hours = 24 + wakeUpHour - nowHour
      }
      var int minutes = 0
      val int nowMinute = now.getMinuteOfHour
      val int wakeUpMinute =  (WakeUpMinute.state as DecimalType).intValue
      var int minuteDiff = wakeUpMinute - nowMinute
      if (minuteDiff >= 0) {
          minutes = minuteDiff
      } else {
          minutes = 60 + wakeUpMinute - nowMinute
         if (hourDiff == 0) {
              hours = 24
          }
         hours--
      }
      
      var int totalMinutes = (hours*60) + minutes 
      logInfo(LOG, "Alarm will be set for: " + totalMinutes + " minutes")
      logInfo(LOG, "Alarm: "  + hours + " h " + minutes + " min")
      WakeUpAlarmTriggered.sendCommand(OFF)
      if (mWakeUpTimer != null) {
          mWakeUpTimer.cancel
          mWakeUpTimer = null
      }
      mWakeUpTimer = createTimer(now.plusMinutes(totalMinutes), [|
                                         logInfo(LOG, "Alarm triggered! ")
                                         WakeUpAlarmTriggered.sendCommand(ON)
                                         mWakeUpTimer = null
                                         ])    
}
end

rule "WakeUpAlarmTriggeredOn"
when
    Item WakeUpAlarmTriggered changed to ON
then
   logInfo(LOG, "Alarm trigger starting to dim")
   mCurrentDimLevel = 0
   if (WakeUpDimStep.state == NULL) {
       logInfo(LOG, "Dimstep not defined using default")
       mDimStep = DEFAULT_DIM_STEP 
   } else {
       mDimStep =  (WakeUpDimStep.state as DecimalType).intValue
   }
   
   if (WakeUpTimeStep.state == NULL) {
        logInfo(LOG, "Dimstep not defined using default")
        mTimeStep = DEFAULT_TIME_STEP 
   } else {
       mTimeStep = (WakeUpTimeStep.state as DecimalType).intValue
   }
   mDimmerTimer = createTimer(now.plusMinutes(mTimeStep), [|
                               mCurrentDimLevel += mDimStep
                               logInfo(LOG, "Dimming " + mCurrentDimLevel)
                               if (mCurrentDimLevel >= 100) {
                                   logInfo(LOG,"Dimming is at its max, finished")
                                   mCurrentDimLevel = 100
                               } else {
                                   logInfo(LOG, "Reschedule dimmer " + mTimeStep + " min")
                                   mDimmerTimer.reschedule(now.plusMinutes(mTimeStep))
                               } 
                               // Enter your dimmer name here
                               MYDIMMER.sendCommand(mCurrentDimLevel)
                               if (mCurrentDimLevel == 100) {
                                   WakeUpAlarmSwitch.sendCommand(OFF)
                               }
                    ])
end

rule "WakeUpAlarmSwitchOff"
when
    Item WakeUpAlarmSwitch changed to OFF
then
   logInfo(LOG, "Switch off wakeup")
   if (mDimmerTimer != null) {
       mDimmerTimer.cancel
       mDimmerTimer = null
   }
   if (mWakeUpTimer != null) {
       mWakeUpTimer.cancel
       mWakeUpTimer = null
   }
   WakeUpAlarmTriggered.sendCommand(OFF)
end

8 Likes

I’ve put this configuration to work at home and it runs quite well. Thanks for sharing!

3 Likes

Hi @Seaside Could you help me isolate the function that makes the light dim? I have sleep as android on my phone as alarm, that sends a command to openhab so i only need the sunlight part. Also do the colors fade or is it only brightness? (red, to orange, yellow white)

Hi!

It’s the
MYDIMMER.sendCommand(mCurrentDimLevel)
Where mCurrentDimLevel can be 0 - 100.
If you have a hue or another rgbw dimmer just replace that line with commands setting color etc.

Regards S

Could this be modified to use milight bulbs to simulate sunrise (color changes) ?

Hi @orange this is exactly what im trying to achieve. Got some milight bulbs too. Ill let you know if i get it to work, and if you do, please let me know. Maybe @Seaside could help create the code, as this is somewhat too advanced for me? I saw you sended the items but it is overwhelming for me. Thanks!

1 Like

Good idea. I will modify it, travelling now so might be some days before i can do it.

Regard S

Hi there.

I tested it with “Trust” Bulbs. Nothing happend. Do you think, the Sendcommand could be wrong?
Did you test them with Hue lights?

I can’t get the sitemap part to work. When I paste in the sitemap code have in your post the sitemap will no longer load. I’ve tried adding a close curly brace (}), but that doesn’t seem to help. What am I missing?

I’ve refactored it for JSR223/Jython. I don’t use the built in scheduler and trigger it from Google calendar so I took that part out but it shouldn’t be hard to add it back in if someone wanted to do that.

I assign the items (dimmer or color) to be controlled by the script to the GWakeUpAlarm group, My items now looks like this:

Group  GWakeUpAlarm         "Lights Controlled by Wake Up Alarm"
Number WakeUpDimStep        "Wake up Dim Step [%d]" <light> 
Number WakeUpTimeStep       "Wake up Time Step [%d]" <clock> 
Switch WakeUpAlarmTriggered "Wake up alarm triggered [%s]"  <alarm> 

And here’s the script. It uses a Number item called HouseMode that I have set up on my system (Home, Away, Night, Vacation) to stop it (any many other of my automations) from running if nobody is home or we are away on vacation. It might be able to be tuned a bit more but it works great for me.

from org.slf4j import LoggerFactory, Logger
from core.rules import rule
from core.triggers import when
from threading import Timer

from personal.housemodes import * #Shared list of constants I use across my various scripts
log = LoggerFactory.getLogger("org.openhab.automation.WAKEUP")
log.info("Loading wakeup.py ")

mCurrentDimLevel = 0
mDimmerTimer = None
mDimStep = 0
mTimeStep = 0
DEFAULT_DIM_STEP = 2
DEFAULT_TIME_STEP = 60
hue = 0
sat = 100
bright = 0
HueVal = 2
SatVal = 99

'''
Possible timer states:
NEW - instantiated
RUNNABLE - defined
TIMED_WAITING - timer is running (slight delay after timer is stopped)
TERMINATED - timer completed or stopped
'''
def dimStepEvent():
    global mDimmerTimer, mCurrentDimLevel, mDimStep, mTimeStep, HueVal, SatVal

    mCurrentDimLevel += mDimStep
    log.info("Dimming " + str(mCurrentDimLevel))
    if mCurrentDimLevel >= 100:
        log.info("Dimming is at its max, finished")
        mCurrentDimLevel = 100
        for item in ir.getItem("GWakeUpAlarm").members:
            if str(item.type) == "Color":
                events.sendCommand(item,"24,54,100")
            elif str(item.type) == "Dimmer":
                events.sendCommand(item,"100")
            else:
                log.info(str(item.type))
        mDimmerTimer.stop()
        mDimmerTimer = None
        events.sendUpdate("WakeUpAlarmTriggered","OFF")
    else:
        log.info("Reschedule dimmer " + str(mTimeStep) + " min")
        
        mDimmerTimer = Timer(mTimeStep, lambda: dimStepEvent())
        mDimmerTimer.start()

        log.info("Reschedule dimmer " + str(mTimeStep) + " min")
        bright = str(mCurrentDimLevel)
        hue = str(HueVal)
        sat = str(SatVal)
        light = hue + "," + sat + ","+ bright
        log.info("Light " + light)
        
        for item in ir.getItem("GWakeUpAlarm").members:
            if str(item.type) == "Color":
                events.sendCommand(item,light)
            elif str(item.type) == "Dimmer":
                events.sendCommand(item,bright)
            else:
                log.info(str(item.type))
                
        HueVal = HueVal + 2 # Increment from 0 to 60 over half an hour
        SatVal = SatVal - 1 # Decrement from 100 saturation to 70% over half an hour 
        
@rule("WakeUpAlarmTriggeredOn")
@when("Item WakeUpAlarmTriggered changed to ON")
def wakeUpAlarmEvent(event):
    if str(items["HouseMode"]) == HOUSEMODE_VACATION or str(items["HouseMode"]) == HOUSEMODE_AWAY:
        return

    global mDimmerTimer, mCurrentDimLevel, mDimStep, mTimeStep
    global hue, sat, bright, HueVal, SatVal
    
    mCurrentDimLevel = 0
    mDimmerTimer = None
    
    hue = 0
    sat = 100
    bright = 0
    HueVal = 2
    SatVal = 99
    
    log.info("Alarm trigger starting to dim")

    if items["WakeUpDimStep"] == UnDefType.NULL:
        log.info("Dimstep not defined using default")
        mDimStep = DEFAULT_DIM_STEP 
    else:
        mDimStep =  items["WakeUpDimStep"].intValue()
        
    if items["WakeUpTimeStep"] == UnDefType.NULL:
        log.info("Timestep not defined using default")
        mTimeStep = DEFAULT_TIME_STEP 
    else:
        mTimeStep = items["WakeUpTimeStep"].intValue()
    
    mDimmerTimer = Timer(mTimeStep, lambda: dimStepEvent())
    mDimmerTimer.start()
    
@rule("WakeUpAlarmSwitchOff")
@when("Item WakeUpAlarmTriggered changed to OFF")
def wakeUpAlarmSwitchEvent(event):      
    global mDimmerTimer
    if mDimmerTimer != UnDefType.NULL:
        log.info("WakeUpTimer Cancelled")
        mDimmerTimer.stop()
        mDimmerTimer = None
   

hello! first i wanna thank you @Seaside that made this tutorial, it’s really helpful for me!
now i have a question.
i have modified a little bit the rule to make possible to schedule the air conditioner turn on when i set the scheduled time. this works, but i would like to add the function to set also a running time.
i mean my air conditioner start for example at 10.00 but i want it to run only for 34 mins and then the schedule must stop the conditioner. i want a timer that can be setup manually from basicui to determine for how long the schedule must run before stop and poweroff the conditioner.
can you please help?
following my rule:

import org.eclipse.smarthome.core.library.types.DecimalType
import org.eclipse.smarthome.model.script.actions.Timer

var boolean mAlaramTriggered = false 
var int mCurrentDimLevel = 0
val String LOG = "WakeUp"
var Timer mWakeUpTimer = null
var Timer mDimmerTimer = null
//var int mDimStep
var int mTimeStep
val int DEFAULT_DIM_STEP = 2
val int DEFAULT_TIME_STEP = 1

rule "WakeUpAlarmSwitchOn"
when
    Item WakeUpAlarmSwitch changed to ON
then
    if (WakeUpMinute.state == NULL || WakeUpHour.state == NULL) {
        logInfo(LOG, "WakeUpAlarmMinute or WakeUpAlarmHour not set, alarm not processed")
    } else {
      var int nowHour = now.getHourOfDay
      var int wakeUpHour = (WakeUpHour.state as DecimalType).intValue

      var int hours = 0
      val int hourDiff = wakeUpHour - nowHour 
      if (hourDiff >= 0) {
          hours = hourDiff
      } else {
          hours = 24 + wakeUpHour - nowHour
      }
      var int minutes = 0
      val int nowMinute = now.getMinuteOfHour
      val int wakeUpMinute =  (WakeUpMinute.state as DecimalType).intValue
      var int minuteDiff = wakeUpMinute - nowMinute
      if (minuteDiff >= 0) {
          minutes = minuteDiff
      } else {
          minutes = 60 + wakeUpMinute - nowMinute
         if (hourDiff == 0) {
              hours = 24
          }
         hours--
      }
      
      var int totalMinutes = (hours*60) + minutes 
      logInfo(LOG, "Alarm will be set for: " + totalMinutes + " minutes")
      logInfo(LOG, "Alarm: "  + hours + " h " + minutes + " min")
      WakeUpAlarmTriggered.sendCommand(OFF)
      if (mWakeUpTimer != null) {
          mWakeUpTimer.cancel
          mWakeUpTimer = null
      }
      mWakeUpTimer = createTimer(now.plusMinutes(totalMinutes), [|
                                         logInfo(LOG, "Alarm triggered! ")
                                         WakeUpAlarmTriggered.sendCommand(ON)
                                         mWakeUpTimer = null
                                         ])    
}
end

rule "WakeUpAlarmTriggeredOn"
when
    Item WakeUpAlarmTriggered changed to ON
then
   logInfo(LOG, "Alarm trigger starting to dim")
  // Enter your dimmer name here
   DaikinSala_Power.sendCommand(ON)
end

rule "WakeUpAlarmSwitchOff"
when
    Item WakeUpAlarmSwitch changed to OFF
then
   logInfo(LOG, "Switch off wakeup")
   if (mDimmerTimer != null) {
       mDimmerTimer.cancel
       mDimmerTimer = null
   }
   if (mWakeUpTimer != null) {
       mWakeUpTimer.cancel
       mWakeUpTimer = null
   }
   WakeUpAlarmTriggered.sendCommand(OFF)
end

thanks a lot!

anyone can give me a hint?
i suppose i have to add a new “var int TimeDiff = wakeUpMinute + TimeStop” but i don’t know how to make it work and stop the running task :frowning:

Here’s my quick and dirty method of doing this:

rule “Wake Up Light”
when
Time cron “0 40 06 * * ?” //Starts at 06:40 Daily, if enabled
then
if (WakeUp_Light.state == ON) {
logInfo(“lightwave.rules”, “Wake Up Light Sequence Started”)
val int Wakeup_StartLevel = 10
val int Wakeup_EndLevel = 81
BedroomLight_dimLevel.sendCommand(Wakeup_StartLevel)
Thread::sleep(3000)
BedroomLight_switch.sendCommand(ON)
Thread::sleep(25000)
var int i = Wakeup_StartLevel
while ((i=i+1) < Wakeup_EndLevel) {
sendCommand(BedroomLight_dimLevel, i)
Thread::sleep(25000)
}
logInfo(“lightwave.rules”, “Wake Up Light Sequence Ended”)
}
end

2 Likes