Build 702, "Fast Pico driver"

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.