Dawn Simulator Clock

I wrote a simple piece of code to allow your lights to behave as a dawn simulator clock. To use this, create a new scene, and paste the code below in to the luup tab. Change the device number(s) at the top of the file to the device number you want to dim up, and optionally change the length of the dawn cycle. The default is 40 minutes. The light will then turn up over that period, following a sigmoid pattern. You can set the start and end level for the dim, so, for example, it can run from 10 to 100%, or it can dim too if you want. You can also set the minimum time between messages to prevent overloading the switch - that defaults to 30 seconds. If you have more than one device that you want to run together, separate their IDs with a comma.

Set a timer for the scene to wake you up each day. Donā€™t forget that if you want to wake up at 7am and the cycle is set for 40 minutes, set the timer for 6:20am.

Also, if you feel lazy and donā€™t want the lights to continue, just turn them off and it will stop the cycle.

Anyway, hereā€™s the code. Let me know how it goes for you.

Martin

[code]do

ā€“ the numbers of the devices to control
local device_numbers={50,48}

ā€“ the number of minutes to run the cycle over
local cycle_minutes=45

ā€“ the starting level for the cycle
local start_level=5
ā€“ the ending level for the cycle
local end_level=50

ā€“ minimum time between steps in seconds. To avoid too frequent updates
local minimum_time=30

local step_increment=math.ceil(minimum_time4/(cycle_minutes3))
local seconds_delay=step_increment * math.ceil(cycle_minutes*0.75)
local dimmingUp=true
local onDetected=false

function setLevel(percent)

-- convert the percentage through to a number
local percentNum=tonumber(percent)


-- check if the first light is on - abort if someone has turned it off when rising. Give it a couple of cycles to check
local lul_tmp = luup.variable_get("urn:upnp-org:serviceId:SwitchPower1", "Status", device_numbers[1])
if (onDetected and dimmingUp and lul_tmp == "0" ) then
  luup.log("SUNRISE: device is off, so quitting")
  return
end


-- calculate the dim level based on a sinusoidal curve
local dimLevel=start_level+ math.ceil((end_level-start_level)/(1+math.pow(2.71828183,((50-percentNum)*12/100) ) ))

luup.log("SUNRISE: percent="..percent..", dim level="..dimLevel)

local currentLevelNum=0
local currentLevel=""

for i,device_number in pairs(device_numbers) do

  currentLevel=luup.variable_get("urn:upnp-org:serviceId:Dimming1", "LoadLevelStatus", device_number)
  currentLevelNum=tonumber(currentLevel)
  
  if( (dimmingUp and currentLevelNum<dimLevel) or (not dimmingUp and currentLevelNum>dimLevel)) then
    luup.call_action("urn:upnp-org:serviceId:Dimming1", "SetLoadLevelTarget", {newLoadlevelTarget = dimLevel}, device_number)
  else 
    if( dimmingUp and currentLevelNum>= end_level) then
      -- the light is already beyond the final level, so stop
      luup.log("SUNRISE: light already up to  "..currentLevelNum.." out of "..end_level..". Quitting")
      return
    end
    if(  currentLevelNum<=end_level and not dimmingUp) then
      -- the light is already beyond the final level, so stop
      luup.log("SUNRISE: light already down to "..currentLevelNum.." out of "..end_level..". Quitting")
      return
    end
  end
  
  
      if(not onDetected) then
        local currentLevel = luup.variable_get("urn:upnp-org:serviceId:SwitchPower1", "Status", device_number)
        if(currentLevel=="1") then
          onDetected=true
          luup.log("SUNRISE: setting onDetected to true")
          
        end
      end


end


-- keep going until the dim level reaches the final level


if( (dimmingUp and dimLevel<end_level) or (not dimmingUp and dimLevel>end_level) ) then
  percentNum=percentNum+step_increment;
  luup.call_delay('setLevel', seconds_delay , percentNum,true)
end

end

  local device_id_list="";
  
  if (end_level<start_level) then
    dimmingUp=false
  end

for i,device_number in pairs(device_numbers) do
device_id_list=device_id_listā€¦device_numberā€¦ā€œ,ā€
luup.call_action(ā€œurn:upnp-org:serviceId:Dimming1ā€, ā€œSetLoadLevelTargetā€, {newLoadlevelTarget = start_level}, device_number)
end

  luup.log("SUNRISE: starting for devices "..device_id_list.." starting from "..start_level.." going to "..end_level.." in "..(80/step_increment).." steps in "..cycle_minutes.." minutes, stepping every ".. seconds_delay.. " seconds.")

setLevel(10)

end[/code]

Nicely done, martin12345. See if thereā€™s anything in the Wakeup Ramp plugin you can borrow; thereā€™s clearly some overlap in your two designs.

Thanks for pointing that one out. I did a search for this before writing my own, and I guess because that one is a linear ramp rather than a sunrise/dawn simulator, I didnā€™t find it.

Itā€™s an interesting idea to have both a device and a scene to control the switch rather than just having a scene with some code in it. Iā€™m curious as to what people prefer. Personally I find my home screen too cluttered already, so wouldnā€™t want to have even more devices, but I can see that it is less technical for people.

Martin

The looks cool! I already use a scene to wakeup, but it just turns my lamps on immediately. Iā€™ve modified this code for my setup and will test it when Iā€™m home. :stuck_out_tongue:

Having a device also gives you the ability for the ramp to resume if a Luup restart happens. WakeupRamp doesnā€™t do this, but Iā€™m this ā†’ ā† far from adding it, my Veraā€™s Luup engine restarts so frequently. One morning in two my ramp never reaches the target amount.

Thanks, I have beeen wanting to attempt this but I didnā€™t know how!
I implemented it on my bedroom light (changed only the device number and length of ramp time ) and my dimmer ramps up immediately, did I miss something?

Edit:
I re-read the article and see where you have made some changes and I wanted you to know, it works okay as I needed now. Thanks

Having a device also gives you the ability for the ramp to resume if a Luup restart happens. WakeupRamp doesnā€™t do this, but Iā€™m this ā†’ ā† far from adding it, my Veraā€™s Luup engine restarts so frequently. One morning in two my ramp never reaches the target amount.[/quote]

How would you make it do that? By having variables associated with the device storing itā€™s progress?

Martin

[quote=ā€œRastusB2, post:6, topic:169288ā€]Thanks, I have beeen wanting to attempt this but I didnā€™t know how!
I implemented it on my bedroom light (changed only the device number and length of ramp time ) and my dimmer ramps up immediately, did I miss something?[/quote]

10 minutes might be a bit short for my code - it would be sending an update every 8 seconds (it aims for 80 steps), which might be overloading your system. Perhaps I need to add a minimum step time.

The best thing to do is to look in your logs to see what message is being sent. You can do that by going to the log directory and typing ā€œgrep SUNRISE L*ā€.

Martin

Yep. At ramp start, store the current time (os.time()) and the finish time (os.time() + duration) in two variables. Then in the deviceā€™s startup function, see if os.time() is in between those two variables, there was a Luup restart, so do whatever you can to resume the ramp.

I havenā€™t made the code in to a device, but I have allowed for setting a start and end level, so you can transition from any dim level to any other dim level (e.g. dim up from 10 to 50, or dim down from 100 to 0), and also I set a (configurable) minimum interval and allow for multiple devices to be controlled at the same time if required. The new code is above.

Martin

I ran into an issue the other morning. I woke up early to go to the airport and my bedroom light was just starting the sunrise cycle. I turned the light up and I got out of bed, and within a minute it had returned to the sunrise light level. You have a check to cancel the scene when the light is turned off ā€¦how about also canceling the scene when the light has been turned up bright?

I added two additional checks to the base code.

The first one checks to see if the light is already on before starting the dawn simulator - this is for those early mornings when I get up before the sunrise is supposed to start. I added this at the top, right after the device_number declaration.

ā€“ check if the light is already on
local lul_tmp = luup.variable_get(ā€œurn:upnp-org:serviceId:SwitchPower1ā€, ā€œStatusā€, device_number)
if (lul_tmp == ā€œ1ā€) then
luup.log(ā€œSUNRISE: light is already on, so quitā€)
return
end

The next check is to see if someone has turned the lights up during the dawn ramp (i.e. dawn starts at 5:30 and at 5:45 I get up and turn the lights up full - I donā€™t want them going back to halfway through the sunrise). Right after the new dimLevel is calculated I added the code below. It polls the switch to get fresh data, waits 1 second for the poll to complete, then reads the LoadLevelStatus and checks to see if that is higher than what it should be. If it is higher, someone has overridden the ramp and the script exits.

-- check if the light is higher than scheduled - abort if so 

luup.call_action(ā€œurn:micasaverde-com:serviceId:HaDevice1ā€, ā€œPollā€, {}, device_number)
luup.sleep(1000)
local dimStatus = luup.variable_get(ā€œurn:upnp-org:serviceId:Dimming1ā€, ā€œLoadLevelStatusā€, device_number)
if (tonumber(dimStatus) > dimLevel) then
luup.log("SUNRISE: device is on, so quitting. Current dim level = " ā€¦ dimStatus ā€¦ " scheduled level = " ā€¦ dimLevel)
return
end

Iā€™m new at this, so I would not be surprised if there are better ways to code this. One key thing to note is that my code is based off the first version of the script which only supported a single deviceā€¦you probably canā€™t drop this into the latest script without some edits.

I would like to add the functionality to enable/disable with a virtual switch. I am confused as to what I would need to add. Can someone point me in the right direction?

The Wakeup Ramp plugin has this functionality, so start by reading its source code for ideas.

Perfect! Thank you for the pointer.

[quote=ā€œChrisAZ, post:12, topic:169288ā€]I added two additional checks to the base code.

The first one checks to see if the light is already on before starting the dawn simulator - this is for those early mornings when I get up before the sunrise is supposed to start. I added this at the top, right after the device_number declaration.

The next check is to see if someone has turned the lights up during the dawn ramp (i.e. dawn starts at 5:30 and at 5:45 I get up and turn the lights up full - I donā€™t want them going back to halfway through the sunrise). Right after the new dimLevel is calculated I added the code below. It polls the switch to get fresh data, waits 1 second for the poll to complete, then reads the LoadLevelStatus and checks to see if that is higher than what it should be. If it is higher, someone has overridden the ramp and the script exits.

Iā€™m new at this, so I would not be surprised if there are better ways to code this. One key thing to note is that my code is based off the first version of the script which only supported a single deviceā€¦you probably canā€™t drop this into the latest script without some edits.[/quote]

Chris,

great suggestions. Thanks for those. They are totally appropriate for using this as sunrise, but would need some tweaking to support sunset (i.e. end level lower than start level). Iā€™ll see what I can do.

Martin

The Wakeup Ramp plugin has this functionality, so start by reading its source code for ideas.[/quote]
Agreed. Although you could just add this line to check the status of the switch before starting;

local virtual_switch_state = luup.variable_get("urn:upnp-org:serviceId:SwitchPower1", "Status",[i]device number[/i])
if (virtual_switch_state == "0" ) then
  return;
end

I have updated the code with the recent suggestions - i.e. stop dimming if the light is beyond itā€™s target level already

Martin

@martin12345 is it possible to use this script with a dumb lamp plugged into a smart outlet/dimmer?

If itā€™s a dimmable bulb I would imagine so. Not like this, but one of the first things I did with home automation was exactly this, on an old X10 system with smart plugs and incandescent bulbs

C