WakeUp Light with OpenHab Android Application, manual Bed-Side Switch and configurable Alarm/Light Items

Goal:
Use an older Phillips Living Colors Iris Light which is already control-able by OpenHab via HomeMatic Wall Switches as a WakeUpLight next to the Bed. The WakeUp light should start its WakeUp Cycle a few minutes prior to the Alarm that is configured on my mobile Android Phone.

Features Implemented:

  • The script works together with the offical OpenHab Android App to receive the timestamp of your alarm clock on your mobile phone
  • the used alarm clock item as well as the used Light (ColorItem) can be configured centrally at the top of the script (this should make adapting it to your environment less error prone)
  • The configured light starts to glow (brightness=1%, saturation = 100%, hue=18) a few (configurable) minutes before your mobile alarm goes on.
  • The intensity of the light is increasing every 30 seconds a bit, at the same time the saturation is reduced a bit and the hue of the light is changed a bit from red towards yellow over time
  • If you turn off the light manually (by a manual switch for example) the wake-up process is being stopped and the light is not turned on again after 30 seconds with the next dim-step
  • if you do not turn off the light manually before or after the alarm goes off it is being turned off automatically at a configurable time span after your alarm clock rings (for example 30 minutes later)
  • if the automatic shut-off did not work the first time (unfortunately zigbee is not a reliable protocol like homematic) the script re-tries until the lamp is off (brightness==0)
  • the wake-up procedure can be started either by setting the alarm timestamp on your phone or by flipping the item vWakeUpOngoing to ON

Features not yet implemented:

  • support for a second alarm timer item (on the phone of your significant other)
  • support for more than one light

Known Issues:

  • The cron job is a bit too agressive right now with (execute every 30 seconds)
  • The script is writing to many info level log entries - I will reduce this once it works fine for a few days untouched
  • If the alarm time on the phone is changed to something that is less then the configured RampUp time (for example alarm in 2 minutes, RampUp 15 Minutes) the shutoff works, but the shutoff timespan is more than the configured seconds.

It works for me now since a few days with my Hue Iris (but today I did a few cleanups to be able to post it here) - and it should work with all Lights that can be controlled via an OpenHab ColorItem - but I did not yet test it with a different concrete Light.

Feedback is welcome!

The Rules File:

import org.eclipse.smarthome.model.script.ScriptServiceUtil

//this script supports the following functionality
// - The script works together with the offical OpenHab Android App to receive the timestamp of your alarm clock on your mobile phone
// - The configured light starts to glow (brightness=1%, saturation = 100%, hue=18) a few minutes before your mobile alarm rings.
// - The intensity of the light is increasing every 30 seconds a bit, at the same time the saturation is reduced a bit
//   and the hue of the light is changed a bit from red towards yellow over time
// - If you turn of the light manually (by a manual switch for example) the wakeup process is being stopped
//   (the light is not turned on again after 30 seconds)
// - if you do not turn off the light manually it is being turned off automatically at a configurable timespan after your
//   alarm clock rings (for example 30 minutes later)
// - if the automatic shut-off did not work the first time the script re-tries until the lamp is off (brightness==0)


// the name of a NumberItem that you configure with the alarm timestamp - YOU HAVE TO CREATE THIS ITEM manualy 
// (this can be done in the OpenHab Android App or manually)
// The script supports milliseconds since 1.1.1970 (java timestamps) or seconds since 1.1.1970 (unix epoch time)
var WeckerItemName = "WeckerFrank"

// the name of a ColorItem - this is the Light that is turned on/off by this Script. I used a Phillips Living Color Iris
// YOU HAVE TO CREATE THIS ITEM manually
var LampItemName = "HueIris1_Farbe"

//after how many seconds after the alarm rings should the light be turned off? defaults to 30 minutes 
var turnOffAfterAlarmTime = 1800

// how many seconds before the alarm rings should the wake-up light start its wake-up sequence 
//(with dim level 1)? Defaults to 15 minutes
var turnOnBeforeAlarmTime = 900





//usually you do not need to change anything below this line


var Timer wakeUpTimer = null
var Number dimmer = 0
var Number dimmer_step = 1
var LampTurnOffRetryCounter = 0



rule "WakeupLightRule"
when
  Time cron "0/30 * * ? * * *"
then
  val logName="WakeupLightRule"
  //logInfo(logName, "WakeupLightrule started....")

  //logInfo(logName,"Weckertimestamp: " + WeckerFrank.state.toString)
  val WeckerItem = ScriptServiceUtil.getItemRegistry.getItem(WeckerItemName)
  val LampItem =   ScriptServiceUtil.getItemRegistry.getItem(LampItemName) 

  if (LampItem.state === NULL) {
    return
  }
  

  logInfo(logName,"Alarm Time Item:"+WeckerItem)
  logInfo(logName,"Lamp Item:"+LampItem)

  var MyEpochFromNumberItem = ((WeckerItem as NumberItem).state as Number).longValue

  if (MyEpochFromNumberItem < 20000000000L) {
    logInfo(logName,"Alarm Time too small, probably in epoch time (seconds) and not in milliseconds - will multiplicate with 1000")
    MyEpochFromNumberItem = MyEpochFromNumberItem * 1000
  }

  val MyJodaFromNumberItem = new DateTime(MyEpochFromNumberItem)
  logInfo(logName,"Alarm Time:" + MyJodaFromNumberItem)
  logInfo(logName,"Light State:" + LampItem.state)
 
  val currentDimLevel= ((LampItem as ColorItem).state as HSBType).getBrightness().intValue()
  logInfo(logName,"Current Lamp DimLevel:"+currentDimLevel)

  val timeToAlarmSeconds = MyJodaFromNumberItem.minus(now.millis).millis/1000
  //logInfo(logName,"now: "+ now.toString)
  //logInfo(logName,"diff:" + timeToAlarmSeconds)

  if (timeToAlarmSeconds > 0 && timeToAlarmSeconds < turnOnBeforeAlarmTime && vWakeUpOngoing.state != ON) {
   
   dimmer = 1

   //trigger the actual wakeup logic in the second rule below this one
   vWakeUpOngoing.sendCommand(ON)
  } else {
    if (vWakeUpEnd.state !== NULL && vWakeUpOngoing.state == ON) {
      var alarmTime = (vWakeUpEnd.state as Number).longValue
      val timeAfterAlarm = -1 * new DateTime(alarmTime).minus(now.millis).millis/1000
      logInfo(logName,"time After Alarm:" + timeAfterAlarm)
      if (timeAfterAlarm > turnOffAfterAlarmTime) {
        //HueIris1_Farbe.sendCommand(OFF)

        //turn off the wakeup light and make sure that it is off
        logInfo(logName,"we are in turnoff phase - lamp turnoff retry counter:"+LampTurnOffRetryCounter) 
        if (currentDimLevel > 0) {
          logInfo(logName,"turning lamp off (post alarm)")  
          LampItem.sendCommand(OFF)
          LampTurnOffRetryCounter = LampTurnOffRetryCounter + 1
        } else {
           logInfo(logName,"lamp is really off now, resetting turn-off request")

           //remember that the wakeup cycle is completed (we are now a few minutes behind the alarm)
           //this also arms the trigger for the next alarm timestamp (usually next morning) 
           vWakeUpOngoing.sendCommand(OFF)
      
           //reset the last alarm time
           vWakeUpEnd.postUpdate(NULL)
           LampTurnOffRetryCounter = 0
        }
      }
    }
  }

end

rule "turnOn WakeupLight"
when Item vWakeUpOngoing changed to ON
then
  logInfo("WakeUpRule","wakeup started....")

  //remember the alarm time - we need this to turn off the light a few minutes after the alarm
  vWakeUpEnd.sendCommand(now.millis + (turnOnBeforeAlarmTime * 1000))

  val logName = "turnOnWakeUpLight"
  var DecimalType hue = new DecimalType(18) 
  var PercentType sat = new PercentType(100)
  dimmer = 1
  dimmer_step = 1

  //logInfo("WakeUpRule","dimmer: " + (dimmer+1))
  var PercentType bright
  bright = new PercentType(dimmer+0.1)
  var HSBType newHsb = new HSBType(hue, sat, bright)
  
  val LampItem = ScriptServiceUtil.getItemRegistry.getItem(LampItemName)
  
  LampItem.sendCommand(newHsb)
  //create the light rampup timer
  wakeUpTimer = createTimer(now.plusSeconds(60), [|
       //logInfo("l","timer fired") 	
       if(vWakeUpOngoing.state != ON || (LampItem.state as HSBType).getBrightness().intValue() < 1) {
	  logInfo(logName, "WakeUp ended")
          dimmer = 0
	  dimmer_step = 1
	  wakeUpTimer = null

          LampItem.sendCommand(OFF)
       } else {
          //logInfo(logName,"else case"+(17+(dimmer/5)).getClass() )
          dimmer = dimmer + dimmer_step
          if (dimmer >100){
             dimmer = 100
          }  
          //logInfo(logName,"dimmer now:" + dimmer)

          val hueX = (17+(dimmer/5)).intValue()

          //logInfo(logName,"hueX:"+hueX)
          hue = new DecimalType(hueX)
          var saturationNumber = 100-(dimmer/3)
          if (saturationNumber < 10){
             saturationNumber = 10
          }
          sat = new PercentType(saturationNumber)

          logInfo(logName,"hue now: "+hue + "  sat now: "+sat)
          newHsb = new HSBType(hue,sat,new PercentType((dimmer/1)+0.5))
          LampItem.sendCommand(newHsb) 

          wakeUpTimer.reschedule(now.plusSeconds(30))
       }


  ])  
end

The items file:

Number WeckerFrank "AlarmTime Mobile 1" 
Number vWakeUpEnd "Last Alarm Time " 
Switch vWakeUpOngoing "WakeUp Ongoing" 
5 Likes

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.