Updating Temp Sensor Device


(JukeBox) #1

Two questions for the community:

  1. What is the best way to do input validation on incoming data from GET APIs etc? I’ve got a very rudimentary way at present which I’m sure is very clunky…

  2. I’ve created a new Temperature Sensor and would like to update it based on the temperature and humidity values received by the API (sounds simple enough?)

Error Messages:

error java.lang.NullPointerException: Cannot invoke method setTemperature() on null object @ line 68

error error: groovy.lang.MissingMethodException: No signature of method: cript14342832688371907786814.$() is applicable for argument types: script14342832688371907786814$_makeJSONWeatherRequest_closure2_closure4) values: script14342832688371907786814$_makeJSONWeatherRequest_closure2_closure4@16a09c76] Possible solutions: is(java.lang.Object), now(), url(), run(), any(), app(java.util.Map)

Code:

def makeJSONWeatherRequest() {

	//variables
    def vtemp = 0.0
    def vhumi = 0

    def params = [
        uri:  'http://host.com',
        path: '/api/',
        contentType: 'application/json',
        query: [device:'1', token: 'xxx']
    ]
    try {
        httpGet(params) {resp ->
            log.debug "raw response data: ${resp.data}"
            vtemp = ${resp.data.temp}
            vhumi = ${resp.data.humi}
        }
    } catch (e) {
        log.error "error: $e"
    }
    
 //silly way of doing input validation?
    if (vtemp.toString().isDouble() && vhumi.toString().isInteger()) {
    	if (vtemp.toString().length() <= 7 && vhumi.toString().length() <= 3) {
        	log.debug "Correct data recieved."
            
            //Update temp
            //settings.target.parse("temperature: ${vtemp}")
            //settings.target.parse("humidity: ${vhumi}")
           target.setTemperature(vtemp)
    	}
    
	} else {
    	    log.error "error: dataset was incomplete or invalid."
            System.exit(0)
	}
}

Really do appreciate the help! I’m trying to translate my ancient perl skills into groovy! oh, how things have changed.

Cheers,
JB.


(sidjohn1) #2

I’m not sure if this line will work. You set vtemp and vhumi to strings. i don’t think they can be a string and a double or a interger as well.

To my knowledge string = text, integer = whole number, double = decimal places. You might want to kill the .toString and see if that works better.


(John S) #3

target isn’t set anywhere in this method, so it’s null. Unless I missed something. That’s exactly what the error message is saying, at least.

Did you mean to use settings.target?


(John S) #4

Separate question :smile:

Everything comes in as a string. Groovy mostly feels like java for string processing, and also has the same try/catch things

so, doing something like this should work

def dvtemp = -1.0
def ivhumi = -1
try {
  dvtemp = vtemp.toDouble();
  ivhumi = vhumi.toInteger();
  // still here? seems plausible. validate dvtemp and ivhumi to be within whatever range
  // you accept, and if so, call the set() methods
  if ((dvtemp > 30.0) && (dvtemp < 90.0)) settings.target.setTemperature(dvtemp)

} catch (e) {
  // invalid data passed in. Ignore it
  // DON'T exit here  
}

No need to exit, your SmartApp only runs when its needed


(JukeBox) #5

Thanks John and Sid. Appreciate the help, and I have been able to tighten up the error checking. However, I’m still getting the following error:

error: groovy.lang.MissingMethodException: No signature of method: script1434322929919539404578.$() is applicable for argument types: (script1434322929919539404578$_makeJSONWeatherRequest_closure2_closure4) values: [script1434322929919539404578$_makeJSONWeatherRequest_closure2_closure4@6565730]
Possible solutions: is(java.lang.Object), now(), url(), run(), any(), app(java.util.Map)

Which seems to relate to this code:

def vtemp = 0.0
def vhumi = 0
httpGet(params) {resp ->
            vtemp = ${resp.data.temp}
            vhumi = ${resp.data.humi}
}

Is this an incorrect process for setting these values?

Thanks,
JB.


(JukeBox) #6

OK, would seem like you just use resp.data.humi minus the ${}


(JukeBox) #7

The next piece in the puzzle:

settings.target.setTemperature(vtemp)

Error:

error: dataset was incomplete or invalid. java.lang.IllegalArgumentException: Command 'setTemperature' is not supported. Supported commands: []

(John S) #8

What is settings.target? Where is that initialized? It’s telling you that whatever that is, it doesn’t have any commands at all.


(JukeBox) #9

Hi John,

target is the device (that I created manually) that I am trying to set the temp/humi on.

I initialise it with the following:

preferences {
    section("Choose a target virtual temperature tile... "){
        input "target", "capability.temperatureMeasurement", title: "Tile"
    }
}

(JukeBox) #10

It would seem that you can’t set the temperature (or humidity) on a Thermostat Sensor manually created in the IDE… Not sure what is missing? Any clues?


(John S) #11

I made one with setters for you from the template - the templates don’t have setters


(John S) #12

Using custom device types is pretty much the same as Smart Apps. Here is a great writeup if you don’t want to slog through the docs

For this, save this as a new device type, and then edit the device you made to use this new device type, and you should be good to go


(JukeBox) #13

Hi John,

Thanks very much for your help. So, lesson: I was trying to update the default device which couldn’t be updated.

I’ve been able to now get the SmartApp to work with the Custom Device. The data is flowing, I need to make some tweaks to the device code as I’m using C not F.

Last question on this topic: where do you get the code for the Devices? You used the Temperature Sensor template - are they all available?

Thanks again for your help!


(John S) #14

See the link in my post above :smile:

tl;dr version:
Click Create New Device Type
Select From Template
Scroll down list of template device types - if you see the device type you want to modify, choose it and modify away!


(Casper) #15

Hi, I’m looking for the exact same thing, could you share the code on the device type that pull data from an API?