I've been working on a simple app (still) to calculate DEW point from temperature and humidity.
I have most of it working but the math functions are giving me a hard time. I received a number of java method exceptions but can't figure how to resolve them.
I had tried this code for the calculation line with no success:
Any suggestions or where to look would be appreciated. I read through the groovy language on the Apache site and have a "groovy in action" book but neither gives me a hint (at least that I can find)
Latest Code:
def initialize() {
def averageDev = getChildDevice("DEWPoint_${app.id}")
if(!averageDev) averageDev = addChildDevice("hubitat", "Virtual Temperature Sensor", "DEWPoint_${app.id}", null, [label: thisName, name: thisName])
averageDev.setTemperature(0)
subscribe(tempSensor, "temperature", handlerTEMP)
subscribe(humidSensor, "humidity", handlerHUMID)
state.lastHUMID = 50 // these are in the app and will not display in the child
state.lastTEMP = 50 // 50/50 DEWPoint = 32
}
def calcDEW() {
def averageDev = getChildDevice("DEWPoint_${app.id}")
log.debug " 56 state.lastTEMP ${state.lastTEMP}"
log.debug " 57 state.lastHUMID ${state.lastHUMID}"
def dewPointL = ((state.lastTEMP) - (9 / 25) * (100-state.lastHUMID)).toDouble().round(1)
averageDev.setTemperature(dewPoint)
//return
}
def handlerHUMID(evt) {
state.lastHUMID = evt.value
log.debug " 65 last Humidity = ${evt.value}"
calcDEW()
}
def handlerTEMP(evt) {
state.lastTEMP = evt.value
log.debug " 71 last Temperature = ${evt.value}"
calcDEW()
}
// --- eof ---
Latest Errors: (the last error is for the code above:
Are any of your humidity sensor devices returning strings instead of numeric types as the humidity value? (Or temperature or whatever value you're trying to use on the line where this error occurs.) This is hard to tell--I'm not sure anywhere that would tell the user what the data type is--and probably won't happen with any built-in drivers but might be something to look out for in a community driver.
Something else to note is that [EDIT: see posts from Bruce below with better explanations about data types in state; they are objects, but not necessarily Strings, though apparently event values are Strings regardless of what the event sends]
Also, if it's of any help, I'm pretty sure something like this would at least help figure out the data type your code things any specific object is:
log.debug "x is String? = ${x instanceof String}"
I think getClass() (which would otherwise just tell you what it is) is blocked by Hubitat's security model, so good guesses with instanceof are the only thing I can think of that we have left.
Another easy way to find out is to intentionally throw an error. Pass the object to a method that isn't defined. The logged error message will tell you the type of the object passed.
state will always return a string. So if you know what is there, you can just use state.x.toDouble() or state.x.toInteger() upon pulling it from state.
For what you're doing, either will work. I'm just used to .toDouble() -- fewer characters than Double.parseDouble(), and you can avoid some errors with the safe navigation operator:
myNumber = state.x?.toDouble()
state.x.toDouble or Double.parseDouble(state.x) will both throw an error is state.x is null. Whereas state.x?.toDouble() will return a null without an error.
I'm not sure that could be the problem. I just created a minimal app and used these lines (cheating a bit to set the state as it may have been for you), and it worked:
What is the error you're getting? Does "above" mean the first post? I'm not sure how the above could possibly get a string, but you'd definitely get problems if state.lastHUMID is null or something that isn't actually able to be converted (is this a custom driver? did the author inadvertently include the units in the value?).
(EDIT: Fixed screenshot to show that argument was Integer...accidentallly copied the wrong thing before)
...which suggests that it isn't written to state as a String (nor was the result different if I removed the first line and just read the value on a second execution, eliminating any effect that the app writing out state upon finishing execution might have) but rather an Integer like ST would, so perhaps I'm misinterpreting something Bruce said (otherwise, this behavior looks a lot like the behavior ST documents where int is specifically called out as a supported type for state, which Groovy automatically boxes to Integer, resulting in the above).
You can also check "state.stringNumber.class.name" most other routes to the class name are restricted in the sandbox.
Yes, but that is not what I have seen on HE. Or it may actually be what we see, dumped to and from JSON we would get datatypes like BigDecimal. For a simple test, set a state variable to a number in one command method, access that state variable in another command method and check the class.
State is turned into a json object when written. So, 14 becomes Integer, 1.4 becomes BigDecimal.
Values in events get turned into String. So when an Integer, BigDecimal or Double value is sent in an event, you're going to get a String that needs to be converted before you can do math on it.
Obviously, if you put the event value into state, as a String, its going to come back as a String.