Wake up light script for OH3.4?

I am running OH 3.4 on Orangepi 3 lts. I have a bulb controller by the tuya binding in my bedroom I would like to fade in on the mornings.

There are quite a few examples of wake up light implemetations for OH2, but I have not found any for OH3 and tuya. Are there any?

Well, in fact, the function should have nothing to do with hardware or version.

→ make things for your hardware
→ make appropriate channels which you want to control (i.e. for a dimmable light bulb make a dimmer channel)
→ connect the channel to control with an appropriate Item (i.e. a Dimmer Item here)
→ build a rule to control the Dimmer Item

In question of OH2 vs. OH3, it depends on how the rule is built. In general, if the light should fade over time, the common way is to send a bunch of commands over time, so you will need a timer for that job.

Simple solution in DSL:

// global var has to be on top of file
var Timer tMorningFade = null

rule "fade at morning"
when
    Time cron "0 0 6 * * MON-FRI" // Monday to Friday at 06:00:00 a.m.
then
    tMorningFade?.cancel // get rid of old timer, if there is any
    tMorningFade = createTimer(now.plusSeconds(1), [|   // start fadeing at 06:00:01 a.m.
        var iBright = (myBulb.state as Number).intValue // get current brightness
        iBright = iBright + 1                           // add 1
        myBulb.sendCommand(iBright)                     // send new brightness
        if(iBright < 100)                               // if not at 100 %
            tMorningFade.reschedule(now.plusSeconds(5)) // next step in 5 Seconds
    ])
end

That code will work from OH1 up to OH4 - and I’m pretty sure it will even in OH5…

1 Like

Everything @Udo_Hartmann said was spot on. Once you have Items the hardware doesn’t matter. That’s the power of OH.

I can only add that there’s a rule template for this on the marketplace. Simulate Sunrise

Why code anything at all if you don’t have to?

3 Likes

Where should this code be stored? I pasted the code both under rules as a new Rules DSL script and under scripts under new rule as Rules DSL. In both cases the script fails with the following error in log:

2023-07-16 08:52:33.443 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID '9a8d38e42a' failed: // global var has to be on top of file
var Timer tMorningFade = null

rule "fade at morning"
when
    Time cron "0 0 6 * * MON-FRI" // Monday to Friday at 06:00:00 a.m.
then
    tMorningFade?.cancel // get rid of old timer, if there is any
    tMorningFade = createTimer(now.plusSeconds(1), [|   // start fadeing at 06:00:01 a.m.
        var iBright = (myBulb.state as Number).intValue // get current brightness
        iBright = iBright + 1                           // add 1
        myBulb.sendCommand(iBright)                     // send new brightness
        if(iBright < 100)                               // if not at 100 %
            tMorningFade.reschedule(now.plusSeconds(5)) // next step in 5 Seconds
    ])
end
   1. The method or field rule is undefined; line 4, column 70, length 4
   2. The method or field when is undefined; line 5, column 93, length 4
   3. The method or field cron is undefined; line 6, column 107, length 4
   4. The method or field then is undefined; line 7, column 169, length 4
   5. The method or field myBulb is undefined; line 10, column 353, length 6
   6. The method or field myBulb is undefined; line 12, column 485, length 6
   7. The method or field end is undefined; line 16, column 720, length 3
   8. Cannot refer to the non-final variable tMorningFade inside a lambda expression; line 14, column 643, length 12
   9. This expression is not allowed in this context, since it doesn't cause any side effects.; line 4, column 75, length 17
   10. This expression is not allowed in this context, since it doesn't cause any side effects.; line 6, column 102, length 4
   11. This expression is not allowed in this context, since it doesn't cause any side effects.; line 6, column 112, length 19


This is a pure DSL (DomainSpecificLanguage) rule. You have to create a text file, its name ending with .rules. The file has to be created in $OPENHAB_CONF/rules/, so e.g. (openHABian Image for Raspberry Pi) /etc/openhab/rules/my.rules

myBulb is an Item (the light to be faded) Obviously, you’ll have to change the Item name in the rule to match your Dimmer Item.

Thanks, got it to run when I stored it in the right position.
However, my bulb starts with 100% brightness at 06:00.
The bulb is a Tuya wifi bult that apparently does not use the warm light leds and color leds at the same time.

This is my first attempt at using blockly. This does what I want it to do:

All of those waits give me a little bit of concern. I’m not sure it’s that big of a deal unless there is even a slight chance that this rule could get triggered more than once in the nearly 75 minutes that this rule will currently take to exit you might be facing some problems. For example, if somehow this rule were triggered 20 times in the morning, this rule would be running all day over and over again.

Luckily it’s not that hard to prevent that. You can either add an if statement to only run the above if the light and/or current time ist right (e.g. if the light is already brightness 99 and green >= 167 there’s nothing to do, or if it’s more than an hour past the usual time to run) or, even better, add a condition (i.e. “but only if”) to do these checks and prevent the actions from running if the conditions are not right.

1 Like

Thanks for the heads up! I already ended up in a never ending loop while testing the script and had to restart OH. The code is not of good quality yet. I will add safety measures as per your advice.

Shortly, the script is supposed to during the first 30 minutes make my bedside lamp run through a sunrise palette of colours and then in 15 minutes run up the warm white light from 1% to 100%. The lamp will stay on for half an hour and then shut it self off. I trigger it with cron from the UI. It has now run once. I will now go the bed and see and report what happens tomorrow morning.

If you are really looking to improve the code, you should look into using timers instead of waits. The big difference is that the timer gets scheduled to run in the future instead of blocking execution of the rule for a given amount of time.

But the code can become a little more complex as a result because now it doesn’t just execute from the top to the bottom.

Yes, that would make sense, will try.

Is there a way to provide H, S and B values directly with Blockly? The starting sequence is too bright, and it woul be great to fade up Brightness along with the sunrise palette.

I don’t have this sort of light bulb, but maybe this DSL rule will work as intended:

// global var has to be on top of file
var Timer tMorningFade = null
var Integer    iGreen  = 0
var Integer    iBright = 0

rule "fade at morning"
when
    Time cron "0 0 6 * * MON-FRI"                                  // Monday to Friday at 06:00:00 a.m.
then
    tMorningFade?.cancel                                           // get rid of old timer, if there is any
    iGreen  = 0                                                    // set start values
    iBright = 0
    tMorningFade = createTimer(now.plusSeconds(1), [|              // start fadeing at 06:00:01 a.m.
        var iTime = 10778                                          // don't know if it's worth the millis
        if(iGreen < 168 && iBright == 0) {                         // color fade
            iGreen ++                                              // add 1
            val hsb = new HSBType(new Color(255, 0, iGreen))       // create hsb value
            timonYopoytaValonVarit.sendCommand(hsb)                // send color
        } else if(iBright < 100) {                                 // brightnes fade
            iBright ++                                             // add 1
            timonYopoytaValo.sendCommand(iBright)                  // send brightnes
            iTime = 9000                                           // set different time
        }
        if(iBright == 100) {                                       // end of fading
            iBright = 101                                          // to get to the else-part next time
            iTime = 1800000                                        // set off time
        } else if(iBright == 101) {                                // time to 
            timonYopoytaValo.sendCommand(0)                        // switch off the light
            return;                                                // nothing left to do
        }
        tMorningFade.reschedule(now.plus(iTime,ChronoUnit.MILLIS)) // next step in iTime Miiliseconds
    ])
end

Not sure about Color(red, blue, green), this is according to auto text in VSCode, but maybe it should be Color(red, green, blue) instead.

1 Like

I don’t understand. Isn’t that exactly what you are doing here?

It almost works, but no cigar. The transformation does not allow for setting the B value, Brightness, individually for HSB.

In RGB the higher the number the higher the brightness. So use lower RGB values and the light will be dimmer. For example, 50% brightness white will be 128,128,128 RGB value.

Or construct a String of the HSB value and send that string as a command. H,S,B.

Or just send an integer between 0 and 100 as a command and OH will treat that as a command to change just the brightness.

But note that as soon as you command the light again using your hard coded RGB values in the block above, it will override that previously set brightness with what ever brightness is embedded in the RGB values.

Setting the brightness alone switches the mode of the lamp to White light. I would like to create a hsb string, but how do I do that? There is no concatenation block in blockly?

image

You need to create a variable.

image

[rnal.defaultscope.ScriptBusEventImpl] - Command 'undefined0100100' cannot be parsed for item 'timonYopoytaValonVarit (Type=ColorItem, State=3.0,100,100, Label=Timon Yöpöytävalon värit, Category=colorlight, Tags=[Lightbulb]

Still no cigar…

image

Great success!

When I said you need to use a variable, I meant you needed to assign the values to a variable.

Though, given you are hard coding each value anyway

image

You only need to build up the string if one or more of the values is coming from somewhere else, such as being calculated in a while loop.

As I want to change all three, h, s and b, while the fade in happens this seems to do the trick.