Wildcard expressions?


(Tim Slagle) #1

Anyone know if we can create a simple wildcard expression within a smartapp?

I’m having trouble doing it the “normal” way and thought maybe there was a smart things way. lol

I just want to match an input boolean. For instance.

input "${name}_Off"......

if(**wildcard goes here**_Off){
do this thing
}

Any ideas?


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #2

There are a few ways to do this in Groovy (or perhaps 1 good way), but the best choices may depend on more detailed example from you?

Remember the logic you are coding isn’t “SmartThings Code” it is “Groovy Code” so if you can do it in Groovy, then you likely can do it here. And Groovy has lots of shortcuts for writing nifty code.

You could use a List that contains all the values of “name” and then iterate over that List…

Or make the input variables a list to begin with – but, I think THAT is difficult to do in SmartThings. Closest you can manage is use variables with numbers in their names:

input "$Off_1" ...
(i.e., input "$Off_{i})


(Mike Maxwell) #3

( someString.contains("_Off"))


(Tim Slagle) #4

Understood, maybe i’m not familiar with wildcards enough in groovy. They seem to be way different then Java in this case haha. Which is fine, i just need some schooling ;).

Let me give you a little more detail:

settings.dimmers?.each() {
                    input "${it.id}_${name}", "number", title: "${it.displayName} Level", required:false
                    input "${name}_Off", "bool", title: "Turn ${it.displayName} off after setting level?", required: false, defaultValue: false
                }

This statement is used to create an input for each dimmer device for each mode available. They need to be seperate inputs. Which is fine. But then i want to call all inputs marked “true” for the boolean and turn them off later in the code. How would you accomplish this? :smile:

@Mike_Maxwell Your suggestion did not work, but i appreciate the chime in! :slight_smile:


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #5

I can think of a few ways that might work, though not sure as compactly as you hope.

Now that you’ve given an example, I can test & confirm my idea before steering you the wrong way. And that’s educational benefit for both of us.

BTW: It just struck me that all the preference settings is already a List; so there’s something you can consider iterating over. That’s just a hint.

Though I would not be surprised in the least if someone here swoops in like Batman with the magic off the top of their heads!


(Tim Slagle) #6

Much appreciated! I look forward to what you can come up with! :smile:


(Mike Maxwell) #7

OK, here’s a snippit that I’m using in an app…

//setting				
dimmers.each() { dimmer ->
        	def safeName = dimmer.displayName.replaceAll(/\W/,"")
            section ([hideable: true, hidden: true], "${dimmer.displayName} overrides...") {
                input(
                    name					: "${safeName}_dark"
                    ,title					: "Dark level"
                    ,multiple				: false
                    ,required				: false
                    ,type					: "enum"
                    ,options				: ["10","20","30","40","50","60"]
                    ,refreshAfterSelection	:true
                )
				input(
                    name					: "${safeName}_dusk" 
                    ,title					: "Dusk/Dawn level"
                    ,multiple				: false
                    ,required				: false
                    ,type					: "enum"
                    ,options				: ["40","50","60","70","80"]
                    ,refreshAfterSelection	:true
                )
			}
		}
		
//later on when we're needing them back...
def instanceVar = dimmer.displayName.replaceAll(/\W/,"")
	def darkVar = instanceVar + "_dark" //dark input setting
	def duskVar = instanceVar + "_dusk" //dusk input setting

(Tim Slagle) #8

I thought the same thing but i am totally getting hung up for some reason…

This might help. Was trying not to give out a ton of the code because it technically isn’t mine i’m just trying to “enhance it” I’ll give ya a little more lol.

This is the preferences getting pulled:

location.modes?.each() {
            def name = it as String
            section("${name} Mode", hideable:true, hidden:false) {
                name = name.tr(' !+', '___')
                settings.hues?.each() {
                    input "${it.id}_${name}", "number", title: "${it.displayName} Level", required:false
                    input "${it.id}_${name}_color", "enum", title: "${it.displayName} Color?", required: false, multiple:false, metadata: [values:
					["Normal", "Daylight", "Soft", "Warm", "Red", "Green", "Blue", "Yellow", "Orange", "Purple", "Pink"]]
                }
                settings.dimmers?.each() {
                    input "${it.id}_${name}", "number", title: "${it.displayName} Level", required:false
                    input "${it.id}_${name}_Off", "bool", title: "Turn ${it.displayName} off after setting level?", required: false, defaultValue: false
                }
                settings.switches?.each() {
                    input "${it.id}_${name}", "enum", title:it.displayName,
                        metadata:[values: ["on", "off"]], required:false
                }

Below is how i action these. The problem i run into and maybe this is a simpler fix. Basically at the end of the logic below when it sets the dimmer levels i want it to also check for either a enum or bool value and then turn off specific dimmers at that time. For instance if(xyz input == Yes) then turn off the set of lights that match that. I’m having problems with that part.

TRACE("onLocation(${evt.value})")

	state.currentMode = evt.value
    String mode = state.currentMode

	if (state.lastMode != state.currentMode) {
    
	    def allSwitches = []
    	if (settings.hues)
        	allSwitches.addAll(settings.hues)
		if (settings.dimmers)
    	    allSwitches.addAll(settings.dimmers)
	    if (settings.switches)
    	    allSwitches.addAll(settings.switches)

def name = "${it.id}_${mode.tr(' !+', '___')}"
    		    TRACE("name: ${name}")
        		def value = settings[name]
		        TRACE("value: ${value}")
    		    if (value != null) {
        		    if (value == 'on') {
            		    TRACE("Turning '${it.displayName}' on")
                		it.on()
		            } else if (value == 'off') {
    		            TRACE("Turning '${it.displayName}' off")
        		        it.off()
   	
    	        	} else {
        	        	value = value.toInteger()
	            	    if (value > 99) value = 98
    	            	TRACE("Setting '${it.displayName}' level to ${value}")
	    	            it.setLevel(value)
    	    	    }

(Tim Slagle) #9

This could work. But it is a little less “robust” then i need it to be. I need the input names to be based on mode and device name dynamically. I could hard code this for my specific modes. If we can’t figure out how to do it dynamically I will probably just do that and not release it. But i am thinking more broad here as this is something i may share with the community when it’s all done.


(Mike Maxwell) #10

I’m writing another app, where I’m jacking a dynamic list and variable length maps which are created from the preferences into the app state
I can tell you that this works, the structure and map keys are maintained, allowing individual element reads, writes and adds.


(Tim Slagle) #11

Yeah, the code above works perfectly. It’s when i add in the bool or enum values only for the dimmers that things go haywire.

I may of just had an idea though. Let me try something :slight_smile:


(Mike Maxwell) #12

ok, for your consideration, snippits from the other app…
its not done, so there’s plenty of cruft in there, but I think you can crok the concept…

def initialize() {
	//normal stuff
  if (state.members == null) {
        def List members = []
        log.debug "debug working..."
        devices.each { it ->
            members << getNewDeviceSettings(it,true)
            //log.debug "${it.displayName} can do:${it.capabilities.toListString()}"
        }
        state.members = members
        //log.debug members.inspect()
        state.members.each {it ->
        	log.debug "${it.n} r:${it.r} p:${it.sM.p} n:${it.sM.n}"
        }
        
    }
}	

//example reader/writer
def onHandler(event) {
	//log.debug "on"
	def stDevice
    state.members.each { member ->
    	//log.debug "id:${member.id}"
    	stDevice = devices.find{it.id == member.id}
        //log.debug stDevice.inspect()
        //save the devices curent settings
        member.sM.p = getSwitchSettings(stDevice)
        if (member.t in [2,3]) {
        	//log.debug "${member.n} is a dimmer"
            member.dM.p = getDimmerSettings(stDevice)
        }
        if (member.t == 3) {
        	//log.debug "${member.n} is a color light"
            member.cM.p = getColorSettings(stDevice)
        }
      //set device to the new settings
      if (member.sM.n == "off") {
      	stDevice.off()
      } else {
      	stDevice.on()
        if (member.t in [2,3]) stDevice.setLevel(member.dM.n.L)
        if (member.t == 3 ) {
        	stDevice.setHue(member.dM.n.H)
            stDevice.setSaturation(member.dM.n.S)
            stDevice.setColor(member.dM.n.C)
        }
      }
    }
    //log.debug state.members.inspect()
    state.members.each {it ->
        	log.debug "${it.n} r:${it.r} p:${it.sM.p} n:${it.sM.n}"
        }
}

//example reader
def offHandler(event) {
	//log.debug "off"
	def stDevice
    state.members.each { member ->
    	stDevice = devices.find{it.id == member.id}
        //have a look at the restore setting
        if (member.r == true) {
        	//restore previous state
            if (member.sM.p.S == "off") stDevice.off()
            else stDevice.on()
        } else {
        	//simply turn off the device
            stDevice.off()
        }
	}    
}

//constructors
//data methods
def getSwitchSettings(stDevice) {
	def Map thisSwitch = [
        S	: stDevice.currentValue("switch") ?: "off"
    ]
    return thisSwitch
}
def getDimmerSettings(stDevice) {
	def Map thisDimmer = [
        L	: stDevice.currentValue("level") ?: 0
    ]
    return thisDimmer
}
def getColorSettings(stDevice) {
	def Map thisColor = [
    	H	: stDevice.currentValue("hue") ?: 0
        ,S	: stDevice.currentValue("saturation") ?: 0
        ,C	: stDevice.currentValue("color") ?: 0
    ]
    return thisColor
}

def getNewDeviceSettings(stDevice, Boolean restoreWhenOff) {
	//def Map deviceMap = [:]
    def Map sMap = [p:[:], n:[:]] //p, previous settings n, new settings
    def Map dMap = [p:[:], n:[:]]
    def Map cMap = [p:[:], n:[:]]
    def Integer dType
    def Map thisDevice = [
    	id	: stDevice.id
        ,n	: stDevice.displayName
        ,r	: restoreWhenOff	//true: restore to previous settings
        //sM : switch settings
        //dM : dimmer settings
        //cM : color setings
        //t	 : device type 1: switch, 2: dimmer, 3: color
    ]
	def String iCanDo = stDevice.capabilities.toListString()
    //everybody's a switch at least
    sMap.n = getSwitchSettings(stDevice)
    sMap.p = sMap.n
    dType = 1
    thisDevice.sM = sMap
    if (iCanDo.contains("Switch Level")) {
    	dMap.n =  getDimmerSettings(stDevice)
        dMap.p = dMap.n
        thisDevice.dM = dMap
        dType = 2
    }
    if (iCanDo.contains("Color Control")) {
        cMap.n = getColorSettings(stDevice)
        cMap.p = cMap.n
        thisDevice.cM = cMap
        dType = 3
    } 
    thisDevice.t = dType
    return thisDevice
}

(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #13

See, @tslagle13 … “swooped”! I guess Mike = Batman. :sunglasses:


(Tim Slagle) #14

I think i have something going. Im gonna test it more. IDE went down though.

Have either of you ever had this thought?

I think i broke SmartThings!

I have that thought often lol!


(Mike Maxwell) #15

Just once, when I created an infinite loop, that terminated in a very ugly way…


(Tim Slagle) #16

I did this when STs was very young. They weren’t happy. lol


(Eric R) #17

Yes, all the time…