Build 702, "Fast Pico driver"

If I'm best off by leaving the Hue bulbs attached through the Hue hub... I really want the hold-to-dim functionality. It's the intuitive use for a dimmer button.

The only thing I can think is to "fix webcores button code" (per @mike.maxwell), which aside from almost certainly being beyond my abilities, still wouldn't produce a smooth effect.

Does that leave any options for smooth hold-to-dim?

fixing buttons in webcore isn't going to help smooth dim your hue bulbs using an HE button controller.

I have a Osram Lightfy zigbee RGBW light strip that I wanted to pair with my HUE bridge but I couldn't figure out how to get it to discover. It paired immediately directly to Hubitat. Have you had any experience getting one to pair with HUE bridge?

I have not, but I have heard that depending on age, getting the lightify hub and pairing it to them and doing a firmware update might make them work with Hue. Just going off 3rd party information, not anything I have personally done. My bulbs are Hue, GE Link and Cree that are all working on Hue Bridge.

1 Like

I've tried this, no success, doubt they work.

1 Like

Why do the Pico devices show multiple buttons being pushed or held? For instance:

Current States`

  • held : 3
  • pushed : 4
  • released : 4`

I see the number represents the button number, but if that is the "current state", is that maybe what WebCoRe is picking up on?

If I could use WebCoRe, then with the "released" functionality, then "held" could initiate a "fade", and relase could exit the piston. It's a moot point with WebCoRe not working right, but how do we know it's WebCoRe and not the Pico driver?

Fixing /enhancing webCoRE is not a trivial task. There is a ton of code there...

My advice would be for you to look at @stephackā€™s Advanced Button Controller application which he updated yesterday to support the new Pico remoteā€™s released events. It works amazingly well with directly connected bulbs.

So, I would think you could start with it and hack it to attempt to implement some sort of stair-step dimming for your Hue connected bulbs. I doubt it will work well, as sending repeated commands in rapid succession is likely to cause isssues.

1 Like

That won't help me unless I were to get any bulbs that connect directly.

That's what I have for individual button pushes. I can improve on it a bit, but essentially it increases/decreases by a 1/3rd, with a minimum of 1.

Did not know about groups. Very cool. No more popcorn. At least that's something accomplished today.

This just shows the last button that was pushed/held/released. WebCore would use "events" and not "states" to execute actions so this is not likely the issue with webcore.

A while back I took a look at the button sections of Core to see if I could assist. I can tell you that getting this to work with hubitat is not a trivial task as there are multiple sections that would need to be edited in very specific ways....ST and HE have different button implementations. If you are set on using core, you should reach out on that thread to see if any of the gurus over there are willing to dive in.

Even if I knew what to look for what needed to be "fixed", I wouldn't even try. I have no illusions of being able to do that.

I'll post to the WebCoRe thread, and hope, because I really want the progressive dimming, and really do not want to directly connect all my Hue bulbs.

Same here ...webcore is a monster. But there are folks over there that are doing great things with it. It could hurt to put in a "feature request". :wink:

It occurred to me, if WebCoRe could do it, then I could do it. And I know WebCoRe can slowly raise the level of Hue lights over a period of time (albeit it, never tried with seconds rather than minutes). So, all I need to be able to do is use that rather than "startLevelChange", and figure out how to stop it with "released"....

Yes. To do that, you will need to schedule() a routine to run when your apps receives a button 'held' event. The scheduled routine will adjust the dim level by some amount, and then schedule itself to run again (or schedule() a recurring event, but be careful!) When your app receives the button 'released' event, unschedule() the existing schedule, thereby preventing it from running again.

schedule() and unschedule() are the keys to making this work without creating a an endless loop in groovy (which would be bad for your hub!)

I've tried using

schedule(now() + 500, increaseLevel)

but I get

groovy.lang.MissingMethodException: No signature of method: app153118395552438321064.schedule() is applicable for argument types: (java.lang.Long, java.lang.String) values: [1531183960289, increaseLevel] on line nnn (buttonHeld)

Am I doing something wrong? I got it to work with runIn(), but that uses seconds and I'm hoping to be able do milliseconds.. I'm going by using the SmartThings Developers Guide. TIA.

Use runInMillis, same params as runIn

I'm still not making any progress. Here's what I've got:

. . .
switch_dim_held.each{
	lvl += it.currentLevel
}
lvl = Math.min(Math.round(lvl/switch_dim_pushed.size()),100)
def newLevel = lvl
switch_dim_held.each{
	it.setLevel(lvl+1)
}
def steps = Math.min(Math.round((99-lvl)),100)
for(def i = 1; i <= steps; i++) {
	newLevel = newLevel + 1
	runInMillis(i*750,increaseLevel, [flag: newLevel])
}
. . .
def increaseLevel(flag){
    log.debug "flag: $flag"
	switch_dim_held.each{
		it.setLevel(flag)
	}
}

I never get a log output from the increaseLevel function. Would appreciate any suggestions. Full code, though it's a mess for now:

definition(
    name: "Pico - child",
    namespace: "pico",
    author: "roguetech",
    description: "Pico and Caseta switches",
    parent: "pico:Pico",
    category: "Convenience",
    iconUrl: "http://cdn.device-icons.smartthings.com/Lighting/light13-icn@2x.png",
    iconX2Url: "http://cdn.device-icons.smartthings.com/Lighting/light13-icn@2x.png"
)

preferences {
    page(name: "setup", install: true, uninstall: true) {
        section("Set Custom Name (Optional)") {
            label title: "Assign a name:", required: false
        }
        section("Select Caseta / Pico") {
            input "buttonDevice", "capability.pushableButton", title: "Button", multiple: true, required: true
            input "numButton", "enum", title: "Type of Pico", multiple: true, required: true,
					options: ["2-button", "4- or 5-button"]
        }
        
        section("Devices for On/Off") {
            input "switch_on_pushed", "capability.switch", title: "Pushed", multiple: true, required: false
            input "switch_on_held", "capability.switch", title: "Long push", multiple: true, required: false
        }
        section("Devices for Dimming") {
            input "switch_dim_pushed", "capability.switch", title: "Pushed", multiple: true, required: false
            input "switch_dim_held", "capability.switch", title: "Held", multiple: true, required: false
        }

        section("Devices for Center button") {
            input "switch_center_pushed", "capability.switch", title: "Pushed", multiple: false, required: false
        }
    }
}

def installed() {
    initialize()
}

def updated() {
    unsubscribe()
    initialize()
}

def initialize() {
    log.debug "INITIALIZED"
    subscribe(buttonDevice, "pushed", buttonPushed)
    subscribe(buttonDevice, "held", buttonHeld)
    subscribe(buttonDevice, "released", buttonReleased)
}

def buttonHeld(evt){
    def buttonNumber = evt.value
    // Turn on Held (button 1)
    if (buttonNumber == "1" && settings.numButton[0] == "4- or 5-button"){
        if (switch_on_held == null){
            log.info "No lights selected; exiting."
        } else {
            switch_on_held.each{
                if (it.currentValue('switch') == "off"){
                    it.on()
                    log.info "Turning on $it."
                    /* **************************************
                    if late, set lowwer level and color here
					*************************************** */
                }
            }
        }

        // Brighten (button 2)
    } else if ((buttonNumber == "2" && settings.numButton[0] == "4- or 5-button") || (buttonNumber == "1" && settings.numButton[0] == "2-button")){

        if (switch_dim_held == null){
            log.info "No lights selected; exiting."
        } else {
            def lvl = 0
            switch_dim_held.each{
                lvl += it.currentLevel
            }
            lvl = Math.min(Math.round(lvl/switch_dim_pushed.size()),100)
            def newLevel = lvl
            switch_dim_held.each{
                it.setLevel(lvl+1)
            }

            def steps = Math.min(Math.round((99-lvl)),100)
            for(def i = 1; i <= steps; i++) {
                newLevel = newLevel + 1
                runInMillis(i*750,increaseLevel, [flag: newLevel])
            }
        }


        // No held option for button 3

        // Dim (button 4)
    }  else if ((buttonNumber == "4" && settings.numButton[0] == "4- or 5-button") || (buttonNumber == "2" && settings.numButton[0] == "2-button")){
        if (switch_dim_held == null){
            log.info "No lights selected; exiting."
        } else {
            def lvl = 0
            switch_dim_held.each{
                lvl += it.currentLevel
            }
            lvl = Math.min(Math.round(lvl/switch_dim_pushed.size()),100)
            def newLevel = lvl
            switch_dim_held.each{
                it.setLevel(lvl+1)
            }

            def steps = lvl
            for(def i = 1; i <= steps; i++) {
                newLevel = newLevel + 1
                runInMillis(i*750,increaseLevel, [flag: newLevel])
            }
        }

        // Turn off (button 5
    }  else if (buttonNumber == "5" || (buttonNumber == "2" && settings.numButton[0] == "2-button")){
        if (switch_on_held == null){
            log.info "No lights selected; exiting."
        } else {
            switch_on_held.each{
                if (it.currentValue('switch') == "on"){
                    it.off()
                    log.info "Turning off $it."
                }
            }
        }
    } else {
        log.debug "Error with button '$buttonNumber' with "
    }
}

def increaseLevel(flag){
    log.debug "newLevel: $flag"
    switch_dim_held.each{
        it.setLevel(flag)
    }
}

def decreaseLevel(newLevel){
    switch_dim_held.each{
        it.setLevel(newLevel)
    }
}

def buttonReleased(evt){
    def buttonNumber = evt.value
    if ((buttonNumber == "2" || buttonNumber == "4") && settings.numButton[0] == "4- or 5-button"){
        unschedule()
    }
}

def buttonPushed(evt){

    def buttonNumber = evt.value
    // Turn on (button 1)
    if (buttonNumber == "1"){
        if (switch_on_pushed == null){
            log.info "No lights selected; exiting."
        } else {
            switch_on_pushed.each{
                if (it.currentValue('switch') == "off"){
                    it.on()
                    log.info "Turning on $it."
                    /* **************************************
                    if late, set lowwer level and color here
					*************************************** */
                }
            }
        }

        // Brighten (button 2)
    } else if (buttonNumber == "2" && settings.numButton[0] == "4- or 5-button"){
        if (switch_dim_pushed == null){
            log.info "No lights selected; exiting."
        } else {
            def lvl = 0
            def newLevel = lvl
            switch_dim_pushed.each{
                lvl += it.currentLevel
            }
            newLevel = Math.min(Math.round((lvl+1)*1.33/switch_dim_pushed.size()),100)
            if (newLevel > 100){
                newLevel = 100
            }
            if (lvl == 100){
                log.info "Level at 100; nothing to do."
            } else {
                switch_dim_pushed.each{
                    if(it.currentValue('switch') == "on")  {
                        it.setLevel(newLevel)
                        log.info "Set $it to $newLevel%."
                    }
                }
            }
        }

        //Center (button 3)
    } else if (buttonNumber == "3"){
        if (switch_center_pushed == null){
            log.info "Nothing selected; exiting."
        } else {
            if (switch_center_pushed.currentValue("switch").contains("off")){
                switch_center_pushed.setLevel(99)
                log.info "Turned $switch_center_pushed on high."
            } else if (switch_center_pushed.currentValue('level').toInteger() >75){
                switch_center_pushed.setLevel(60)
                log.info "Set $switch_center_pushed on medium."
            } else if(switch_center_pushed.currentValue('level').toInteger() >50){
                switch_center_pushed.setLevel(33)
                log.info "Set $switch_center_pushed on low."
            } else if (switch_center_pushed.currentValue('level').toInteger() <50){
                switch_center_pushed.off()
                log.info "Turned $switch_center_pushed off."
            }
        }

        // Dim (button 4)
    }  else if (buttonNumber == "4"){
        if (switch_dim_pushed == null){
            log.info "No lights selected; exiting."
        } else {
            def lvl = 0
            def newLevel = lvl
            switch_dim_pushed.each{
                lvl += it.currentLevel
            }
            newLevel = Math.min(Math.round((lvl-1)*0.66/switch_dim_pushed.size()),100)
            if (newLevel == 0){
                newLevel = 1
            }
            if (lvl < 2){
                log.info "Level at $lvl; nothing to do."
            } else {
                switch_dim_pushed.each{
                    if(it.currentValue('switch') == "on")  {
                        it.setLevel(newLevel)
                        log.info "Set $it to $newLevel%."
                    }
                }
            }
        }

        // Turn off (button 5
    }  else if (buttonNumber == "5" || (buttonNumber == "2" && settings.numButton[0] == "2-button")){
        if (switch_on_pushed == null){
            log.info "No lights selected; exiting."
        } else {
            switch_on_pushed.each{
                if (it.currentValue('switch') == "on"){
                    it.off()
                    log.info "Turning off $it."
                } else {
                    it.on()
                }
            }
        }
    }
}

You have runInMillis in a loop, runIn overwrites it self for a given method call, so only the last one will execute.
If the dimmer level starts at 1, the first run in will happen almost a minute later.
The real reason it's not working is that the data params aren't correct
runInMillis(<delay>,<method>,[data:<varName>])
And in method def <method>(<varName>)
You don't need an input for the button count, this can be retrieved from the device via device.currentValue("buttonCount")

Thanks! I've finally got it working!

Sort of. Just FYI, it seems (with just a bit of testing so far) that Hue's minimum response time is about 750 milliseconds per increment. Any lower, and it keeps dimming after the button release. Not sure how to pin down the exact time, which would help to optimize my routine. If you have any ingenious ideas on that .... ?

But 750 millis is workable. Worst case scenario, that puts 10% jumps at being max 6.75 seconds from 1% to full brightness, and 10% is not exactly smooth, but it's not jarring either. From here, I'll work on coming up with a better formula to make the jumps less perceptive (where 1 to 11 is pretty huge, but 70 to 80 isn't as huge). And of course cleaning up the code; maybe make it a bit more presentable if anyone else would like to use it.

Really appreciate all your help on this project. Progressive dimming, even this approximation, was really important to me, and you've made it happen!

1 Like

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