Input to array / collection?

someMap.each{} is equivalent to someMap

settings[modes].each {} in your original code is probably not doing what you want unless you have a variable called modes

And I have a feeling that you may need to store the value in the actions map using
actions = [("$a.name") : settings['modes']].

It would really help to see what you get from log.debug settings and what you want your actions map to look like.

That is so true! Cleaned up the code a little :slight_smile:

Ok, so I played around with your other advise, but it did not help unfortunately.

Log.debug actions:
[((test)) (O) virtual switch:[In de avond, In de nacht]]

Log.debug settings:
[motions:[((test)) (I) virtual motion sensor], switches:[((test)) (O) virtual switch], modes_((test)) (O) virtual switch:[In de avond, In de nacht], levelIn de avond:90, levelIn de nacht:40]

I actually found out my problem might be somewhere else... I am trying to use this "actions" list in multiple pages... So I thought it would be a global thing. But it's not. How can I make it global within my app instance?

Store it in state

Was afraid of that... To be continued in a couple of days :slight_smile:

Ok, so I finally had some spare time to dive into this state story... But I'm still missing the big picture about multidimensional array's in Groovy. I come from PHP and I can't get this to make sense to me... I have read so many Google pages by now that I'm getting a little tired of Groovy. Can someone please tell me how this language thinks? I'm not the first one trying to store level values of switches per mode right? I've also looked through code of others but even then I can't make any sense of it. This is what I have now what does NOT work, but IMHO shouldn't be soo hard:

            input name: "switchChoices", type: "capability.switch", title: "Control these Switches", multiple: true, submitOnChange: true, hideWhenEmpty: true
            input name: "switch_by_modes", type: "bool", title: "Use modes for settings?", submitOnChange: true
            if (switch_by_modes == true) {
                input name: "modeChoices", type: "mode", title: "Which modes do you want to set the lights for?", multiple: true, submitOnChange: true, hideWhenEmpty: true
                modeChoices.each { modeName ->
                    state.levels = [modeName]
                    paragraph "Mode: <strong>$modeName</strong>",  style:"margin-top: 1rem; margin-bottom: -0.5rem;"
                    switchChoices.each { switchName ->
                        state.levels["$modeName"] = [switchName]
                        input name: "levelChoices", type: "number", title: "Light: <strong>$switchName</strong><br>Turn on to level:", hideWhenEmpty: true, style: "padding-left: 2rem;"
                        state.levels.["$modeName"]["$switchName"] = levelChoices
                    }
                }
            }

You need to have a study of maps, that's the data structure you're looking for.
I use maps for everything beyond a simple list.

I did that, but I can't get it to work or the manuals / tutorials I'm running into on Google aren't clear enough for me. And most of them don't say anything about multidimensional.

Exactly, i dont beleive there is any such thing, in groovy you have maps and lists, those are your data structures, maps and json are very similar have a look there has well.
You're going to have to architect your structures around those constraints.
A map is a key value pair, think of the key as being a nameable version of an array index, and it's used the same way.

Yeah. Forget about multidimentional, or arrays in general in terms of how they work in other languages. As even 1 dimentional "array" isn't an "array" in groovy - it is an ArrayList (so back to map and list again...)... And that's an important distinction, too, as an ArrayList can do many things a regular array can not.

Learn map, change your thought process from multidimentional array to map. That is the only way to proceed in groovy or js.

I'm fond of this description/examples:
http://grails.asia/groovy-map-tutorial

2 Likes

Thank you both for the replies. I have set down and read through the explanations again. But I just don't see how I can save the level values of dimmers per mode. Please enlighten me in how one would do such a thing.
To put it in layman's terms:
day -> light A -> 60
day -> light B -> 50
evening -> light A -> 30
evening -> light B -> 10

I might use something like:

state.levels = [
	"day":[
		"s1":20
		,"s2" 30
	]
	,"evening":[
		"s1":30
		,"s2":25
	]
]

That's what I thought. But if I do:

state.levels = ["day":["s1":20]]
state.levels = ["evening":["s1":10]]

it only saves the last line. Even though the key is a different one.
And if I do:

state.levels = state.levels + ["day":["s1":20]]
state.levels = state.levels + ["evening":["s1":10]]

It appends on every page refresh, ending up with a huge map after several page refreshes.

Once the initial map is created an update to a specific element would be

State.levels."${mode}"."${switch}" = level

Thank you again. I'll try that in the next couple of days :slight_smile:

So I've tried it again. Still not working. I've tried al sorts of different ways of styles to write this, but I keep getting the same error. Here the last version of code:

            input name: "switchChoices", type: "capability.switch", title: "Control these Switches", multiple: true, submitOnChange: true, hideWhenEmpty: true
            input name: "switch_by_modes", type: "bool", title: "Use modes for settings?", submitOnChange: true
            if (switch_by_modes == true) {
                input name: "modeChoices", type: "mode", title: "Which modes do you want to set the lights for?", multiple: true, submitOnChange: true, hideWhenEmpty: true
                modeChoices.each { modeName ->
                    state.levels = modeName
                    log.debug state.levels
                    paragraph "Mode: <strong>$modeName</strong>",  style:"margin-top: 1rem; margin-bottom: -0.5rem;"
                    switchChoices.each { switchName ->
                        log.debug modeName
                        state.levels."${modeName}" = switchName
                        input name: "levelChoices", type: "number", title: "Light: <strong>$switchName</strong><br>Turn on to level:", hideWhenEmpty: true, style: "padding-left: 2rem;"
                        levelchoices.each { level ->
                            state.levels."${modeName}"."${switchName}" = level
                        }
                    }
                }
            }

And this is the error:


Line 33 is the line that says: state.levels."${modeName}" = switchName

you need to first check if state.levels.modeName exists, something like

if (state.levels."${modeName}") {
    state.levels."${modeName}".put("${switchName}",null)
} else {
    state.levels.put("${modeName}",["${switchName}",null])
}

The error shown is actually telling you that the modeName property is missing from the current map...

So I just did it exactly like you said:

            input name: "switchChoices", type: "capability.switch", title: "Control these Switches", multiple: true, submitOnChange: true, hideWhenEmpty: true
            input name: "switch_by_modes", type: "bool", title: "Use modes for settings?", submitOnChange: true
            if (switch_by_modes == true) {
                input name: "modeChoices", type: "mode", title: "Which modes do you want to set the lights for?", multiple: true, submitOnChange: true, hideWhenEmpty: true
                modeChoices.each { modeName ->
                    paragraph "Mode: <strong>$modeName</strong>",  style:"margin-top: 1rem; margin-bottom: -0.5rem;"
                    switchChoices.each { switchName ->
                        log.debug modeName + " - " + switchName + " - " + state.levels
                        if (state.levels."${modeName}") {
                            state.levels."${modeName}".put("${switchName}",null)
                        }
                        else {
                            state.levels.put("${modeName}",["${switchName}",null])
                        }                        
                        input name: "levelChoices", type: "number", title: "Light: <strong>$switchName</strong><br>Turn on to level:", hideWhenEmpty: true, style: "padding-left: 2rem;"
                        levelchoices.each { level ->
                        }
                    }
                }
            }

And this is what I get. I'm really getting the idea that Groovy isn't really meant to help development improve... It only seems to make it harder (hence the excess of special characters to call a variable)


Line 32 is the line with: state.levels."${modeName}".put("${switchName}",null)

I think it is likely totally directed at you and making your life difficult. :wink:

If he/she thinks groovy is hard, try writing in pure Java. You'll think groovy is simple, and understand EXACTLY why it was created. :smile: