Sunrise emulation via group of lamps (separate brightness control)

Tags: #<Tag:0x00007f5ca4e0fd50> #<Tag:0x00007f5ca4e0fc60> #<Tag:0x00007f5ca4e0fb98>

Hi all,

I want to share my Sunrise emulation solution. Features:

  • Has settings of full run time and step size.
  • Can be interrupted, script stops if user turns off lights.
  • No sleep() function usages.
  • Controls group of lamps to provide smothness: first lamp slightly goes from 0% to 100%, then second from 0% to 100% and so on.

In my case it starts at 5:00 and finishes at 6:00. I used 3 Ikea zigbee-driven filament lamps (as main decoration light) and one Yeelight Wight lamp (as night light).

Code of my rule:

// Sinrise emulation

var Timer sunriseTimer = null
var Boolean sunriseStarted = false
var Integer sunriseBrightness = 0
var Integer sunriseModeValue = 0

rule "Sinrise emulation start"
when
    Time cron "0 00 05 ? * MON-FRI"
    //Item testSwSunrise changed
then
    logWarn("light", "Sunrise emulation started")

    sunriseBrightness = 0;    
    sunriseStarted = false;
    
    sunriseTimer = createTimer(now, [ |

        if (sunriseStarted) {
            if (g_light_eg_sz_night.state == OFF) { // Group to be used as "switch-detector"
                logWarn("light", "Sunrise emulation stopped: group switched off")
                return
            }
        }

        sunriseStarted = true

        // How long full programm runs (seconds)
        var brightPeriod = 60 * 60
        // How much percent changed for every step
        var brightPeriodStep = 1

        // Items to set ON
        // We do not use groups, we must have exact order of lamps defined
        // You can replace this for group if you dont care of order (e.q. g_light_eg_sz_night)
        var lightGroupItems = newArrayList(yel_white_1_brightness, ikea_led_007b_brightness, ikea_led_2203_brightness, ikea_led_2819_brightness)

        // 1/100 from hour (3600 sec)
        var brightLoopSize = lightGroupItems.size

        // Calculate timer
        var brightTimerMs = (brightPeriod * 1000) / ( (100 / brightPeriodStep) * brightLoopSize)

        sunriseModeValue = sunriseBrightness

        lightGroupItems.forEach [s |

            var setBright = sunriseModeValue
            sunriseModeValue = sunriseModeValue - 100

            if (setBright < 0) {
                return
            }

            if (setBright > 100) {
                return
            }

            logWarn("light", "Sunrise item " + s.label + " -> " + setBright)
            s.sendCommand(setBright)
        ]

        // All items 100% ?
        if (sunriseBrightness > (lightGroupItems.size * 100)) {
            sunriseTimer = null
            logWarn("light", "Sunrise emulation done")
        } else {
            // New timer loop
            sunriseBrightness = sunriseBrightness + brightPeriodStep
            sunriseTimer.reschedule(now.plusMillis(brightTimerMs))
        }
    ])
end

Full source avaliable in my Github: https://github.com/petrows/smarthome-openhab/blob/master/rules/light-sunrise.rules

Tested, provided nice results =)

6 Likes

Thanks for sharing! I’m sure a lot of users will appreciate this.

I’ve only a couple of comments:

  • Don’t define variable types when you don’t have to. The more specific you are the harder the Rules parser has to work when loading the .rules file. If you have lots of variables and you specify the types for all of them you can add minutes to your OH startup time.
var Timer sunriseTimer = null
var sunriseStarted = false
var sunriseBrightness = 0
var sunriseModeValue = 0
  • I like the way you used the Timer for this.

  • For reusability, I’d move the definition of brightPeriod and brightPeriodStep to be globals and make them constant using val instead of var. That makes it easier for other users of the Rule to customize it for their own purposes.

  • You could use a Group and name your Items so they get sorted in the order you want to control the. For example if you use 1_yel_white_1_brightness, 2_ikea_led_007b_brightness, etc. than you can use var lightGroupItems = java.util.Collections.sort(LightsGroup.members.map(name)) and then later use sendCommand(s, setBrigtht) since all you will have is the name of the Item at that point instead of the actual Item.

1 Like

Thanks for notes! I will update code, test it and update post then.