[Released] Control Switches by Mode

A new app, called Mode Switches, is now available in our Public Repo. This provides the functionality of turning switches on or off upon mode changes. Here is what it looks like:

The source code for Mode Switches is in GitHub:

14 Likes

Great timing. I was just about to redo a similar rule and will now use this app :slight_smile:

I assume that this will one day be part of the firmware, and if so, will my setup be ported over the future built-in app?

No, setup would not port over.

I put this up in the Public repo so that those who want to learn how to create table based apps have another example (and because our next release is some weeks out). Some may want to modify it, enhance it, etc. It's a simple but effective app for those who want this particular functionality.

9 Likes

Very nice. I have six rules that trigger as my modes cycle. I will definitely give this a try in the next few days.

Any chance of adding a second table for setting variables?

Help yourself, but variables are much more complicated than on/off switches. Part of the appeal of this particular app is its simplicity.

1 Like

@bravenel Thank you very much for posting this app. You not only accepted my feature request but you posted it in record time and made it available for others in the community to learn from. Really appreciate it and I hope you and family have a wonderful Independence Day!

1 Like

@bravenel Again thank you very much for posting this example code. I have expanded it to include locks since I have 4 that I want to lock for specific modes. I would like to also include dimmers but instead of a checkbox for On, I would like to have a small text box to enter a 1-100 value similar to this mock up:

I am struggling with how to allow the value from the input box to be captured when you navigate out of the field into the state variable. In your example you are using "buttonLink" which won't work in this scenario since that expects a click. Do you have any example code you could share to get me going?

1 Like

This is more than I care to attempt here. Use Room Lights as an example, and see what happens when you click on a number in a box there. That may give you a clue. There needs to be something in the input box to click on, and it does use buttonLink.

1 Like

@bravenel thank you again. With the Light Usage Table example I was able to accomplish what I need:

If anyone is interested in my version, I am happy to post to Github but know my use case is pretty specific to my needs.

1 Like

@bravenel I added the following code to the initialize() function because if you remove a device from the Switch selection, it didn't remove it from the modeSwitch state variable. Of course mine includes Locks and Dimmers too.

def settingsList = [
        lights: "modeSwitch",
        locks: "modeLock",
        dimmers: "modeDimmer"
    ]
    def settingsListKeys = settingsList.keySet()
    for (int s = 0; s < settingsListKeys.size(); s++) {
        def settingItem = settingsListKeys[s]
        def stateItem = settingsList[settingItem]
        def deviceList = []
        for (int d = 0; d < settings[settingItem].size(); d++) {
            deviceList.push(settings[settingItem][d].id)
        }
        
        def stateItemKeys = state[stateItem].keySet()
        for (int v = 0; v < stateItemKeys.size(); v++) {
            def key = stateItemKeys[v]
            if (deviceList.indexOf(key) == -1) {
                state[stateItem].remove(key)
            }
        }
    }

@bravenel, Thank you for this example. I have created a simple table framework with rows based on modes. Inside the TD elements I would like to use something like this:

input name: "${it.id}Main" type: "enum", optons: presets, defaultValue: "---", submitOnChange: true

Is it possible to embed the input into a TD element cleanly or do I need to use an HTML select and build the controls in a different way?

I can create the table just fine with strings based on iterating through an object (modes in this case) but I'm not sure how to include a control in there.

You can't embed an input in a table. What you can do is set a state variable, and then use that to pull up an input. For example, in Room Lights clicking on the RGB link in the table next to "a LIFX bulb" causes the table to be grayed out and the enum input below to be brought up. Once a selection is made or the Cancel button hit, the input goes away and the table is shown without the gray-out. This is all done with the method buttonLink, as shown in the example app. The combination of graying-out the table and bringing up the input makes it pretty obvious what the cause and effect of clicking on RGB is.

Hmm, that could work. I’m already playing around with a toggle that does something similar.

It will make the table a bit cleaner too.

Thanks

Oh, is there a way to hook into the onChange handler? For example, the input has the submitOnChange: true.

Technically you can as I did it in the GCal Search app that I maintain for the community. Here is example:

Using browser inspect I determined what the buttonLink method was actually calling and there is a
/installedapp/btn POST endpoint being called which will then invoke the appButtonHandler() function within your app. I realize that this is an unofficial API that could change with any release but I did want to call out this is possible. I don't want to go into a ton of detail about it being unofficial but you can view my example code in this app on Github starting around line 540 in the getParseFieldDescription() function. You have to include your own client side function for the on change behavior you are looking for which you will find an example of in my code.

This causes the entire page to be re-rendered. That means the dynamic page method runs again. So you have to use a state object to keep track of what's expected to happen on this (or the next) rendering.

That makes sense.

Thanks for the info. I’ll take a look at the code of it comes to that. I think bravenel‘s approach will work for my app. I just needed to understand it a little better.

I’m not too worried about the interface as this is something specific to my integration. Although even though I will be the only one to see it I still want it to be clean. I used to do UI design and bad UIs still make me cringe. :wink:

At the very least this is helping me understand how the Hubitat apps are put together.

So close yet so far away...

I see how buttonLink is being called. What I don't understand is how that can be used to show the enum. Is it possible to look at a snip of code from Room Lighting that handles this?

For example:

The first column contains the hub modes. The second column is a link that gets populated with the enum for that mode. Below the table is a list of the enum inputs.

Selecting something from one of the controls changes the name in second column. This works fine. Now I'm trying to hide the enums and show one when I click on the link in the column. I can trigger javascript snippets from the link but I can't show/hide the input. I understand I need to use your buttonLink example but I'm still missing an important part. I'm guessing Room Lights has some special sauce I'm not getting.

All buttonLink() does is render a text-link that acts like a button input. It causes appButtonHandler() to be called with whatever value. For the link/button in question appButtonHandler() sets a state variable to true, and the page is refreshed. The code for the page tests for that state variable, and if true does a number of thing, including putting up the enum input, and setting the state variable back to false.