Steinhart-Hart calculation for NTC

Hello all, Im complete lost with the datatypes in the OpenHab :frowning:
My background is C++ and I´m strugling with the math to put my Steinhart-Hart convertion working.

Just for start, whats rhe diference between the Number and Double datatypes ??

My below code just dont work, it gives the error 0 / div message, can you point to me where it´s worng (I´m using Openhab 1.8.3)

"
// the entrance variable with the resistance value is analog1

 var Number Resistance=0.0
 var Number steinhart=0.0
	
 Resistance = (1023 / analog1.floatValue) -1.0 
 Resistance = 6800 / Resistance       
 steinhart = Resistance / 5000                 	
 steinhart = Math::log(steinhart.floatValue)                  
 steinhart = steinhart / 3470.0                  
 steinhart = steinhart + (1.0 / (25.0 + 273.15))
 steinhart = (1.0 / steinhart)                   
 steinhart = steinhart - 273.15                
 postUpdate(REM01_ana1,steinhart)

"
Thanks in advance :slight_smile:

I believe it’s a BigDecimal under its DecimalType and the Java code looks like it has a toBigDecimal method. (at least in the current smarthome and openHAB2 code I’m looking at)

Why not using Double to calculate?

Thomas

HI.

If I change the variables to Double I get the following error starting in the first calculation:

“Incompatible types. Expected java.lang.Double or double but was java.math.BigDecimal”

code:
"
var Double Resistance
var Double steinhart

Resistance = (1023 / analog1.floatValue) - 1.0

"
even if I remove the .floatValue from the analog1 the error still maintains

:frowning:

Could you Post a little bit more information? What is analog1 an item? And of what type and whats about REM01_ana1?

Thomas

I just created a little rule, but without defining the items

rule "Steinhart"
when
	Item analog1 received update
then

	var double Resistance=0.0
 	var double steinhart=0.0
 	
 	Resistance = (1023 / (analog1.state as DecimalType).doubleValue) -1.0 
 	Resistance = 6800 / Resistance       
 	steinhart = Resistance / 5000                 	
 	steinhart = Math::log(steinhart)                  
 	steinhart = steinhart / 3470.0                  
 	steinhart = steinhart + (1.0 / (25.0 + 273.15))
 	steinhart = (1.0 / steinhart)                   
 	steinhart = steinhart - 273.15                
 	postUpdate(REM01_ana1, steinhart)
end

hello, back from weekend :slight_smile:

Replying to you Dibbler42, analog1 is an variable with the float value result from a parcing of a string received by a remote sensor using MQTT.


var String[] buffer= REM01_rec.state.toString.split(”,")
var Double analog1 = new Double(buffer.get(1))
"

Using your last code as:
"
Resistance = (1023 / (analog1.floatValue) -1.0
Resistance = 6800 / Resistance
steinhart = Resistance / 5000
"
at the third line
"steinhart = Resistance / 5000
"
i get the error in tge Eclipse: Incompatible types. Expected double or java.lang.Double but was java.math.BigDecimal.

Can it be a missing include, whai I have is:
"
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.openhab.model.script.actions.Timer
import org.openhab.core.types.CommandcamelCase
import org.openhab.core.library.items.*
import org.joda.time.*

import java.lang.Math
import java.lang.Integer
import java.lang.Double
"

Im realy lost :slight_smile:

Could you please post your full rule with all declarations.

Thanks
Thomas

Here it goes :slight_smile:
"
//REM-01
rule “REM-01_rec"
when
Item REM01_rec received update
then
if (REM01_rec.state.toString.contains(“Slave,”)) {
var String[] buffer= REM01_rec.state.toString.split(”,")
var Double analog1 = new Double(buffer.get(1))
var Double analog2 = new Double(buffer.get(2))

   var   BigDecimal Resistance=0.0
   var   steinhart=0.0

    Resistance = (1023 / analog1.floatValue) -1.0 
    Resistance = 6800 / Resistance       
    steinhart = Resistance / 5000                 	
    steinhart = Math::log(steinhart.floatValue)                  
    steinhart = steinhart / 3470.0                  
    steinhart = steinhart + (1.0 / (25.0 + 273.15))
    steinhart = (1.0 / steinhart)                   
    steinhart = steinhart - 273.15                
    postUpdate(REM01_ana1,steinhart)
	
    Resistance = (1023 / analog2.floatValue) - 1.0
    Resistance = 6800 / Resistance       
    steinhart = Resistance / 5000                 		
    steinhart = Math::log(steinhart.floatValue)                  
    steinhart = steinhart / 3470                  
    steinhart = steinhart + (1.0 / (25 + 273.15))
    steinhart = 1.0 / steinhart                   
    steinhart = steinhart - 273.15                	
    postUpdate(REM01_ana2,steinhart)

} 	

end
"

Good luck!!!

Sorry.
One mistake in the previous rule code (I have been playing a bit to fix it).
where you see:
"
var BigDecimal Resistance=0.0
var steinhart=0.0
"
You should have


var Double Resistance=0.0
var Double steinhart=0.0

It is alittle bit confusing. In your previous post you got an error based on BigDecimal and this error is valid if you have declared steinhart as BigDecimal. With Double the error should not be there.

Thomas

Hello Dibbler,thanks for your support. :grimacing:
Let me try to clarify, for that I’m putting the original code below:

"
rule “REM-01_rec”
when
Item REM01_rec received update
then
if (REM01_rec.state.toString.contains(“Slave,”)) {
var String[] buffer= REM01_rec.state.toString.split(",")
var Double analog1 = new Double(buffer.get(1))
var Double analog2 = new Double(buffer.get(2))
var Double Resistance=0.0
var Double steinhart=0.0

    Resistance = (1023 / analog1.floatValue) -1.0 
    Resistance = 6800 / Resistance       
    steinhart = Resistance / 5000                 	
    steinhart = Math::log(steinhart.floatValue)                  
    steinhart = steinhart / 3470.0                  
    steinhart = steinhart + (1.0 / (25.0 + 273.15))
    steinhart = (1.0 / steinhart)                   
    steinhart = steinhart - 273.15                
    postUpdate(REM01_ana1,steinhart)
	
    Resistance = (1023 / analog2.floatValue) - 1.0
    Resistance = 6800 / Resistance       
    steinhart = Resistance / 5000                 		
    steinhart = Math::log(steinhart.floatValue)                  
    steinhart = steinhart / 3470                  
    steinhart = steinhart + (1.0 / (25 + 273.15))
    steinhart = 1.0 / steinhart                   
    steinhart = steinhart - 273.15                	
    postUpdate(REM01_ana2,steinhart)
} 	

end

As you can see bellow the printscreen from the Eclipse with the error:

I hope this can clarify the problem.
Thanks

I have currently no real idea, but try the following

Write 1023.0 instead of 1023 and 6800.0 instead of 6800

The goal should be to eliminate the first error.

Another try is maybe to user double instead of Double

Thomas

back.

after lots of tests I was able to have the calculations in the OpenHab with no errors on the Eclipse
"
var double Resistance=0.0
var double steinhart=0.0

    Resistance = ((1023.0 / analog1.doubleValue)  -1.0).doubleValue 
    Resistance = (6800.0 / Resistance.doubleValue).doubleValue       
    steinhart = (Resistance.doubleValue  / 5000.0).doubleValue       
    steinhart = Math::log(steinhart.doubleValue)                  
    steinhart = (steinhart / 3470.0).doubleValue         
    steinhart = (steinhart.doubleValue + (1.0 / (25.0 + 273.15))).doubleValue
    steinhart = (1.0 / steinhart.doubleValue).doubleValue                   
    steinhart = (steinhart.floatValue - 273.15).doubleValue                
    postUpdate(REM01_ana1,steinhart.doubleValue)

"
But … :frowning: the result calculation is not correct. I have realy big rounding of the values along the calculaton!!!
In the log(x) part, for an input analog1 value of 600 value on excel is around 0.00043… I have around 0.000193… on OpenHab. !!!

To say the least I´m a but dissapointed. So, I cant do hard calculation on OpenHab??
My problem is that I’m using a microlontroller and a ESP8266 in some low consumption battery (AA) operated remote sensors around my Farm. Among the sensors I have some ntc resistors that are ideal for the job, they are cheap, water resistent and reliable. Problem is that neither the microcontroller neither the Esp8266 have the math capacity for the steinhart-hart-calculation.

Well … I´m going to make an C++ service that gets the sensors values from the MQTT broquer, make the calculation and send them back to the MQTT with a diferent reference. Finaly get the already calculated values by OpenHab :triumph:

Thans for all the help :slight_smile:

By the way if someone wants the plans for the semote sensors, just give me an hello.
The remote sensor gets the above soil temperature, soil temperature and soil humidity (by capacitance), the sensors comunicate with my centrall wifi (I have around 200meters os coverage) 4 times a day(0:00, 6:00, 12:00 and 18:00). My calculations give me 4 months of autonomy for the sensors.

I would think you need to be using BigDecimal typing

I believe OH Items are nativly BigDecimal, implying you will lose precision when converting to double

Hi,

The result will always be incorrect using double. The moment you read sensors, BigDecimal is a must! If I am not wrong the DecimalType in Openhab is inherited from the BigDecimal type.

Try defining your variables as Number (which is DecimalType), I think this works in the IDE.

BR,

George

While I won’t argue that some calculations may need more precision than is available in a Java Double, blanket statements like “The result will always be incorrect using double. The moment you read sensors, BigDecimal is a must!” are very misleading.

I don’t know any hobbyist/tinkerer grade that has a precision, not to mention an accuracy or repeatability of anywhere near 64 bits. You might have a 20- or 24-bit ADC, or even a 32-bit one if you spend a few hundred dollars, but even that isn’t anywhere near close to 64 bits.

A Java Double is a double-precision 64-bit IEEE 754 floating point number. That has been serving computational needs well for years and is more than sufficient in most cases. 2^64 is around 19 digits of precision.

I’d look elsewhere for the discrepancy between the Excel and openHAB calculations.

Yes, but if the Rules DSL is converting to double at each step, approximations creep in and are compounded

Looking at the implementation, the only place you’ve got rounding error problems is potentially with (steinhart + (1.0 / (25.0 + 273.15))) and the values are different by well more than an order of magnitude and of the same sign. This could be a problem if it were a difference as its reciprocal is used later.

(A quick check of estimating the reciprocal of this with the first-order Taylor series 1/(1+x) ~ 1 - x results in less than a degree of difference than the full-precision calculation)

It doesn’t look to me as though either 0.00043 or 0.000193 are correct. Has the OP determined that the calculation is providing the right values in either situation?

>> sensor = 600
sensor =  600
>> resistance = (1023/sensor)-1
resistance =  0.70500
>> resistance = 6800/resistance
resistance =  9645.4
>> steinhart = resistance / 5000
steinhart =  1.9291
>> steinhart = log(steinhart)
steinhart =  0.65704
>> steinhart = steinhart / 3470
steinhart =    1.8935e-04
>> additive_term = 1/(25.0 + 273.15)
additive_term =  0.0033540
>> steinhart/additive_term
ans =  0.056455
>> steinhart = steinhart + (1.0 / (25.0 + 273.15))
steinhart =  0.0035434
>> steinhart = 1/steinhart
steinhart =  282.22
>> steinhart = steinhart - 273.15
steinhart =  9.0675

Given that 273.15 is the offset of absolute zero from 0°C, I take the output to be in °C, which is a believable value for those of us in the northern hemisphere.

@eXadra

Given that you’ve probably got a 10-bit ADC (from the 1023/sensor scaling), and that you’ve got a power-sensitive application, why not just use a lookup-table with the 1024 possible values on the sensor’s microcontroller? While it easily could compute the values, if you’ve got the memory, a table lookup is going to take the least number of cycles.