Rule to slowly fade in or out any given item based on variables

You didn’t mention whose version you were using. The code snippet you mention that needs fixing isn’t in my version. Your symptoms sound like problems I had with the one originally posted.

See my post from Sept 20 for a version that works much better. It has been working flawlessly for me.

I’ve been using your version for months without issues, although upgrading to OpenHAB 3 has broken the universaldimmer script, as it doesn’t seem to work at all.

I receive the following error in my openhab.log file when I attempt to execute a dimming function:

2021-01-23 00:55:01.396 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID ‘universaldimmer-1’ failed: The name ‘ScriptServiceUtil’ cannot be resolved to an item or type; line 40, column 20, length 17 in universaldimmer

Thinking it may have been caused by the import line at the very top, I commented out

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

and replaced it with

import org.openhab.core.model.script.ScriptServiceUtil

after reading My experience migrating from OH2.5 to OH 3.0 although that made no difference and the same error shows up in my logs when I try to use the universaldimmer command on a light.

The only other thing I’ve noticed that has broken for me as well is googletts, everything appears to be set up the same, although I’m just trying to work out one issue at a time.

I didn’t realise OH3 was out. Will look into upgrading and fixing the script.

Oh that’ll be great, thank you so much! :slight_smile: I wasn’t aware either until 3 or 4 days ago, when I randomly visited the OpenHab blog and saw it came out on Dec 21.

I’ve loved the universalfader script so much because it’s worked so well with my TP-Link Kasa Dimmer Switches to slowly fade certain lights with an offset of when it gets to be dusk, so as it gets dark outside, my office slowly gets brighter over the course of about 12.5 minutes so you don’t even really realize the lights are coming on. :slight_smile:

All done.

  • Revision 4 of the gist supports OH3. :warning: Requires Regex transformation to be installed
  • Revision 3 contains the OH2 version
1 Like

Thanks for such a prompt update! It seems I’m running into a small hiccup where it begins the dimming, but then fails within a 100ms. I seem to already have the Regex transformation installed, but here is what my logs show when I attempt to trigger the dimming:

2021-01-27 15:08:54.793 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model 'dimmer.rules'
2021-01-27 15:09:28.997 [INFO ] [ab.core.model.script.UniversalDimmer] - Dim Light_UL_OfficeCeilingBrightness PercentType from 0 => 50 over 5000 ms
2021-01-27 15:09:29.000 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.13, iteration=1, elapsedMs=13
2021-01-27 15:09:29.002 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.15, iteration=2, elapsedMs=15
2021-01-27 15:09:29.003 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.16, iteration=3, elapsedMs=16
2021-01-27 15:09:29.008 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.21, iteration=4, elapsedMs=21
2021-01-27 15:09:29.008 [WARN ] [el.script.internal.actions.TimerImpl] - Rescheduling failed as execution has already started!
2021-01-27 15:10:19.715 [WARN ] [ore.io.rest.auth.internal.AuthFilter] - Unauthorized API request: Invalid Basic authentication credentials
2021-01-27 15:11:36.296 [INFO ] [ab.core.model.script.UniversalDimmer] - Cancelling existing timer for Light_UL_OfficeCeilingBrightness
2021-01-27 15:11:36.296 [INFO ] [ab.core.model.script.UniversalDimmer] - Dim Light_UL_OfficeCeilingBrightness PercentType from 0 => 50 over 5000 ms
2021-01-27 15:11:36.298 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.02, iteration=1, elapsedMs=2
2021-01-27 15:11:36.300 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.04, iteration=2, elapsedMs=4
2021-01-27 15:11:36.304 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.08, iteration=3, elapsedMs=8
2021-01-27 15:11:36.305 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.10, iteration=4, elapsedMs=10
2021-01-27 15:11:36.306 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.11, iteration=5, elapsedMs=11
2021-01-27 15:11:36.307 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.12, iteration=6, elapsedMs=12
2021-01-27 15:11:36.314 [INFO ] [ab.core.model.script.UniversalDimmer] - itemName=Light_UL_OfficeCeilingBrightness set to 0.13, iteration=7, elapsedMs=13
2021-01-27 15:11:36.315 [WARN ] [el.script.internal.actions.TimerImpl] - Rescheduling failed as execution has already started!

That looks like an OH3.0 bug

Oh interesting, I’ll follow that thread to keep an eye on that. With all new things there will be some bugs and kinks to work out, but at least I’ve primed my environment by upgrading and am ready at least. :slight_smile:

Thanks again for updating your script!

1 Like

I fixed a bug - 1,000,000 ns in 1 ms, not 1000. That may/may not help your issue. See revision 5

That’s true! ZonedDateTime is weird not giving a plusMillis or even plusMicros method.

Thank you for this! It’s working well in OH3 for me, after making the changes mentioned further up in the thread, specifically:

import org.eclipse.smarthome.model.script.ScriptServiceUtil
changes to
import org.openhab.core.model.script.ScriptServiceUtil

fade_Timer = createTimer(now.plusMillis(mytime))
changes to
fade_Timer = createTimer(now.plusNanos(mytime*1000000))

fade_Timer.reschedule(now.plusMillis(mytime))
changes to
fade_Timer.reschedule(now.plusNanos(mytime*1000000))

I’m using it to fade up / down the volume for my Sonos when arriving / leaving the house, which is working great.

What changes would need to be made to be able to call several of these concurrently? I’m thinking about using it for a slow fade-in of my lights for sunrise / sunset, and it would be on for 15 mins. Am I better off making another string item and copy / pasting for the specific case?

Thanks again - a great rule!

Using it to control volume is an interesting idea I hadn’t thought of.
You must be using the original one from way up thread.
My version (see linked gist up thread) doesn’t contain fade_timer

Usage in parallel works fine with my version - for example this is my fade out when a video plays on Kodi:

        universaldimmer.sendCommand("light_tv_1_dimmer,0,2000")
        universaldimmer.sendCommand("light_tv_2_dimmer,0,2000")
        
        universaldimmer.sendCommand("light_hallway_dimmer,5,5000")
        universaldimmer.sendCommand("light_hallway_color,26,1000")

It’s a real pain and almost feels deliberately malicious. That’s Oracle for you.

If you want to use milliseconds though it is possible.

import java.time.temporal.ChronoUnit
...

now.plus(500, CronoUnit.MILLIS)

Even though it’s awkward, in many cases it’ll be worth importing CronoUnit and using it for clarity.

Nice to see UniversalDimmer getting better and better :slight_smile:

Here are two suggestions for additional functionalities:

  1. Groups of Devices

To handle groups of devices easily, I use an Item universaldimmer_group and this rule:

rule "UniversalDimmer Group"
when 
    Item universaldimmer_group received command 
then 
    val commandArray            = receivedCommand.toString.split(",")
    val String GroupName        = commandArray.get(0)   // Group of Items to handle
    var String targetValue      = commandArray.get(1)   // where to go to
    val String fadePeriodMs     = commandArray.get(2)   // time for fading
  
    (ScriptServiceUtil.getItemRegistry.getItem(GroupName) as GroupItem).getAllMembers().forEach[i | 
      universaldimmer.sendCommand(i.name + "," + targetValue + "," + fadePeriodMs)
    ]
end

Remark: getAllMembers() returns the direct members of a GroupItem and recursively all members of the potentially contained GroupItems as well

  1. OnOff Devices

To handle the case where there is an OnOff-Device in your group of devices for dimming, I added the following:

val type = transform("REGEX", ".*(PercentType|HSBType).*", item.getAcceptedDataTypes().toString())

val itemType = transform("REGEX", ".*(PercentType|HSBType|OnOffType).*", item.getAcceptedDataTypes().get(0).toString.split(" ").get(1).toString)

As you can link Dimmer- and Switch-Items to a brightness channel resp. Color- and Switch-Items to a color channel, you get potentially ambiguous results from getAcceptedDataTypes(). Therefore, I take only the first entry in the result list from getAcceptedDataTypes to determine the type of the item.

Then you have a third case besides HSBType and PercentType:

…else if (itemType == "OnOffType") {
 		if (targetValue == 100 || targetValue == 0) {
 			if (targetValue == 100) item.sendCommand("ON") else item.sendCommand("OFF")
 		} else {
            // You could implement another logic e.g. targetValue >= 50 -> set to ON, targetValue < 50 -> set to OFF.
 		}	
 		return; // for OnOffType: no further action
 	}

Your revision 5 works! Thank you so very much! :slight_smile: I have dimming lights again! Well, except for one minor thing…

The previous version of the script in the OpenHAB 2.5 days, I actually had the timerTickEveryMs set to 750, because too low of a value seemed to cause issues with my Kasa switches almost locking up or lagging behind almost as if the commands were too frequent and caused some issues. 750 was a good sweet spot, although I’ve just played with 500, and 1000 for the setting as well.

Now for long dimming times (30+ seconds) It appears all good, although anything shorter I’m seeing, that when I initiate a universaldimmer.sendCommand(“Light_UL_OfficeCeilingBrightness,50,10000”)

It actually ends randomly between 45 and 48% rather than 50. No huge deal, a few percent isn’t critical, although when I dim them off…

universaldimmer.sendCommand(“Light_UL_OfficeCeilingBrightness,0,10000”)

It only seems to dim down to 1 or 2%, and never right down to 0 unless I dim over a longer time period, It’s like the script overshoots but because of how my Kasa dimmers lag behind, they don’t get that final update to go right down to 0.

I did find a quick and easy workaround to fix it, and that was duplicating the
item.sendCommand(targetValue)
line, directly above the final logInfo, just after the if(!isAtTarget) so it looks like this:

    timerPool.remove(itemName)
    if (!isAtTarget)
    {
        item.sendCommand(targetValue)
    }
    item.sendCommand(targetValue)
    logInfo("UniversalDimmer", String::format("Finished dimming %s from %d => %d", itemName, startingBrightness, targetValue))

Which appears to do the trick as it sends that final value once more after the script thinks it’s at the target, which pushes it down below the 1-2%, as well as up past that 47-48%.

On a side note, I’ve also just ordered several H801 LED Dimming modules off AliExpress, so I’m sure I’ll be back with questions once I get them and flash them with Tasmota, and hope that your script plays nicely with those too, as my current cheap LED Controllers that came with my LED strips don’t use PWM, so they flicker incredibly badly at anything below 100%, the H801’s seem to have programmable PWM frequencies so I should have less headaches (literally) and a better looking dimmed light on several light strips I have installed. :slight_smile:

Hi guys

ZacR - You uncovered a bug which I hadn’t noticed as I don’t dim to zero. Latest revision fixed :slight_smile:

Joachim

  1. My first thought was the dimmer handles groups - but I noticed you mention recursion - so you mean we could have a hierarchy of lights in a group which are then grouped into downstairs and we can recurse down the tree?

  2. On/off devices now handled. I used a non greedy regex (.*?) which should handle take the first match and solve the ambiguity issue

2 Likes

Hi,
where can i find Revision 3 for openhab 2.5. Is this the last one for oh2?
Thanks and greetings,
Markus

Hi Brent,
thanks for the quick answer.

ad 1.: I have organized my lamps in a hierarchy of groups.
To handle all Items in a group, I just have to trigger universaldimmer_group for that group, e.g.

universaldimmer_group.sendCommand("gLights,50,2000")

This handles all Items in gLights and recusively all Items in groups within gLights in one loop.

ad 2.: Non greedy regex is a very good alternative to my solution!

Thank you for your work.

The rule was used to dim a light which I dont use anymore and therefore I stopped using my own rule early 2019.

Because of all the updates I think might restart using it. The Idea is to slowly decrease sound volume in the kids room to 30% every time the volume is above 70%. :innocent:

:+1:

2 Likes

Master79 - Script is stored in a github gist as it is too big to post in the form. OH3 is the head version, OH2 is no longer maintained, frozen in revision 3

Joachim - try the latest version. It should deal with your gLights group without the need for your universaldimmer_group extension.

PeterK - :joy::joy: