How to get string value within current value

I am struggling inserting a string to get a driver attribute value. My code is below where i am trying to take an input value and pass to get a devices attribute value.

input (name: "SelectedAttribute", title: "Select PM25 Sensor Attribute", type: "enum", options: attributeList.sort(), submitOnChange:true, width:3, defaultValue: 1)

def sAttribute = String.valueOf(SelectedAttribute)

If i use the string variable either just the variable itself or by trying to impose the value as a string i get a null value. Even though sAttribute is "pm25"
Integer value = ChosenDevice.currentValue("${sAttribute}")

If i use the following code and put a string directly into the currentValue method i get the result and see the sensors value.
Integer value2 = ChosenDevice.currentValue("pm25")

First, have you verified that sAttribute is really "pm25"? Before this line:

Inset a line like:

log.debug "sAttribute = ${sAttribute}"

to see for sure.

Also, enum preference values will always be strings, so there should be no need to convert.

The other thing to make sure of is that ChosenDeivce is set to something (though since you aren't using null-safe navigation, you'd probably get a different error if it were, and you're using it fine later, though with only one line each, it's not possible to tell if this is in the same context). You could also log that, maybe right before or after the above, to see for sure:

log.debug "ChosenDevice = ${ChosenDevice}"

Finally, it's convention to follow camel case for Groovy variable names and also Hubitat inputs that ultimately get stored into these. I'd recommend changing this to chosenDevice but don't think it should cause problems (there are times where it does create things you you, like currentXyz based on an xyz attribute, and this would make this clearer then but still likely not a problem).

If that doesn't help, I would suggest providing an example of a minimal app that demonstrates this problem. Someone may be able to help better then -- or often when paring things down to just a demonstration of the problem, people will figure the problem out on their own.

Thank you. I included a cope snip and my app output.

I did change my variable naming convention and added a log output to validate. i had been using paragraphs to spit out values on the screen while i was running the app.

Here is a code output

and here is the app output with log output. sAttribute displays properly in the log but when passed into currentValue it passes null. If i take what the value of sAttribute is and hardcode and pass to currentValue i get the sensor reading. I am sure this is a property syntax thing I am not understanding with groovy.

A screenshot probably isn't the best way to share code, but I guess it shows more context than a line or two. :joy:

For you problem: I wonder if it's a GString (interpolated string, more or less) versus String thing. This rarely matters but can for some things like Map keys, depending on how the comparison is made. There is way to convert that; perhaps that's what you were trying before.

But in your case, I don't see a reason for the intermediate variable at all. Why not use selectedAttribute directly?

If that doesn't help, try forming a minimal example as I suggested above (an app big enough to demonstrate only this specific problem) and share that code (as text--use the toolbar button or triple tick marks to format it).

Wondering if maybe the quotes are a problem?

ChosenDevice.currentValue(${sAttribute})

Here is the code. I am not sure how to make it much simpler because i think it has to do with how a strings value is extracted in the currentValue method. I am not sure if i can extract. every example i see has a literal string value passed which doesnt help make the application dynamic. I would be assuming every person is using the same driver.



definition(
    name: "AQI Calculator",
    namespace: "DicksonJ",
    author: "Jeff Dickson",
    description: "This Application will read PM25 sensor from users device and calculates USA AQI",
    category: "Air Quality",
    iconUrl: "",
    iconX2Url: "")

preferences {
    page(name: "mainPage") 
}
def mainPage(){
	dynamicPage(name: "mainPage", title: "Calculate AQI", nextPage: null, install: true, uninstall: true, refreshinterval: 0){
		section("Select your device"){
			//get device from user
			input "chosenDevice", "capability.polling", title: "Choose your Sensoring Device", multiple: false, required: true, submitOnChange:true

			
		}
		section("Display Attributes"){
			//get attributes available from device and make a list
			
			if(chosenDevice != null ){
			String strAttributes = chosenDevice?.supportedAttributes
			def attributeList = strAttributes.substring(1, strAttributes.size() -1).split(",").collect{it as String}
				
				if(strAttributes != null){
					// grab attribute from user
					input (name: "selectedAttribute", title: "Select PM25 Sensor Attribute", type: "enum", options: attributeList.sort(), submitOnChange:true, width:3, defaultValue: 1)
					
					
					// Run Calculation method
					if(selectedAttribute != null){
						
						Integer value = chosenDevice.currentValue("${selectedAttribute}".toString())
						Integer value2 = chosenDevice.currentValue("pm25")
						//Show Value of chosen sensor
						
						paragraph "passed through value turned into ${value}"
						paragraph "hardcoding pm25 string is ${value2}"

					}
				}
			
			}

			
		}
		

	}
}




def installed() {
	log.debug "Installed Application"
	unsubscribe()
}

def updated(){
	log.debug "Updated Application"
	unsubscribe()
	unschedule()
	initialize()
}

def initialize(){
	logi.info("Initializing with settings: ${settings}")
	subscribe(settings.Device,"sensor", evenHandler)
	runEvery15Minute(refresh)
}

def eventHandler(evt){
	log.debug "Device was chosen ${evt.value}"
		
}

@jad
Does removing the quotes around ${selectedAttribute} cause syntax error or fix issue?
…. And the toString() may not work there.

That will cause an error. The dollar sign is for string interpolation and must be inside a (double quoted) string.

@bertabcd1234
Hmm, so why are they not needed around ${sAttribute} here?

So i put a switch statement in for now that will give me the value. Two issues for some reason the value coming out of the attribute field on both drivers has a space prefixing the value so instead of "pm25" its needing " pm25" to enter the case statement. I still do not understand why the .currentValue() method is forcing a literal string passed and i cant pull that from a variable. In other languages i would use variable.ToSTring() to force or getvalue(variable) but you cant use a method call inside of the currentValue method so idk for now.



definition(
    name: "AQI Calculator",
    namespace: "DicksonJ",
    author: "Jeff Dickson",
    description: "This Application will read PM25 sensor from users device and calculates USA AQI",
    category: "Air Quality",
    iconUrl: "",
    iconX2Url: "")

preferences {
    page(name: "mainPage") 
}
def mainPage(){
	dynamicPage(name: "mainPage", title: "Calculate AQI", nextPage: null, install: true, uninstall: true, refreshinterval: 0){
		section("Select your device"){
			//get device from user
			input "chosenDevice", "capability.polling", title: "Choose your Sensoring Device", multiple: false, required: true, submitOnChange:true

			
		}
		section("Display Attributes"){
			//get attributes available from device and make a list
			
			if(chosenDevice != null ){
			String strAttributes = chosenDevice?.supportedAttributes
			def attributeList = strAttributes.substring(1, strAttributes.size() -1).split(",").collect{it as String}
				
				if(strAttributes != null){
					// grab attribute from user
					input (name: "selectedAttribute", title: "Select PM25 Sensor Attribute", type: "enum", options: attributeList.sort(), submitOnChange:true, width:3, defaultValue: 1)
					
					
					// Run Calculation method
					if(selectedAttribute != null){
						switch(selectedAttribute){
							case " pm25":
								Integer value = chosenDevice.currentValue("pm25")
								paragraph "hardcoding awair string is ${value}"
								break;
							case " Pm25":
								Integer value = chosenDevice.currentValue("Pm25")
								paragraph "hardcoding awair string is ${value}"
								break;
							case " PM25":
								Integer value = chosenDevice.currentValue("PM25")
								paragraph "hardcoding awair string is ${value}"
								break;
							
						}
						

					}
				}
			
			}

			
		}
		

	}
}




def installed() {
	log.debug "Installed Application"
	unsubscribe()
}

def updated(){
	log.debug "Updated Application"
	unsubscribe()
	unschedule()
	initialize()
}

def initialize(){
	logi.info("Initializing with settings: ${settings}")
	subscribe(settings.Device,"sensor", evenHandler)
	runEvery15Minute(refresh)
}

def eventHandler(evt){
	log.debug "Device was chosen ${evt.value}"
		
}



example of output pulling sensor value

They are needed. Note that it appears inside quotation marks.

If you are not familiar with this, I suggest doing a web search for something like "Groovy string interpolation."

1 Like

@bertabcd1234 Thanks, learning, slowly.

That's because that's what your code is telling it to do. :smiley:

First, you're probably accidentally making a String out of this List with this line:

String strAttributes = chosenDevice?.supportedAttributes

Then, you're manually splitting that back into a list with the next line.

This is not necessary -- though it's theoretically fine. Groovy happily converts the list to the comma-separated string (with a space in between), which you then split back out into the list. The issue there is that you're splitting on "," and not ", " (or trimming the result), giving you the extra space. Of course, the best solution isn't to change that; it's to deal directly with the list in the first place.

I assume you're doing the above because you just want the name of each attribute, not the list of actual attribute objects. Here's a Groovy-idiomatic way you can do that without any of the above:

def attributeList = chosenDevice?.supportedAttributes.collect { it.name }

Back to your original issue:

You can, and I suspect this will work as expected once you're feeding it the correct value (i.e., the problem is that, not this).

I'm unable to easily test that due to having only a screenshot of a portion of your original code.

Thank you that fixed my issue. it was pushing the list to the string and back to a list that was messing up the string value.

def attributeList = chosenDevice?.supportedAttributes.collect {it.name}
				if(attributeList != null){

input (name: "selectedAttribute", title: "Select PM25 Sensor Attribute", type: "enum", options: attributeList.sort(), submitOnChange:true, width:3, defaultValue: 1)
					
					
					// Run Calculation method
					if(selectedAttribute != null){

						Integer value = chosenDevice.currentValue("${selectedAttribute}")
					

Download the Hubitat app