Retrofitting Hayward pool thermistor using ESPHome to integrate into HA

I am inspired by the ESPHome integration, fantastic work by @OttoWinter ! I am trying to measure the pool temperature by using an existing Hayward Thermistor already in place. I have wired the ESP8266 using the instructions here. It works as far as measuring voltage and i get live readings of around 0.5v ! Now I am trying to convert the voltage to temperature using the Steinhart-Hart equation in the same post.
In ESPHome I have the following entry for the sensor:

> sensor:
>   - platform: adc
>     pin: A0
>     name: "Pool Temperature"
>     update_interval: 2s
>     filters:
>       - lambda: return (1 / (0.001129148  + (0.000234125 * ln(x)) + (8.76741*10^-8 * (ln(x))^3))) - 273.15; 

The configuration checks out on validation, but on upload I get the following message :

src/main.cpp: In lambda function:
src/main.cpp:24:56: error: ā€˜lnā€™ was not declared in this scope
return (1 / (0.001129148 + (0.000234125 * ln(x)) + (8.76741*10^-8 * (ln(x))^3))) - 273.15;
^
src/main.cpp:25:3: warning: control reaches end of non-void function [-Wreturn-type]
})});
^
*** [/data/mcu2/.pioenvs/mcu2/src/main.cpp.o] Error 1
========================== [ERROR] Took 16.31 seconds ==========================

And this is where not being a programmer hits you :slight_smile: Any ideas on how to solve this ? How do I declare the log function ?

Thanks everyone !

Try log or std::log instead of ln

Also ^ is not pow. You can do pow(x , y)

Ohh thatā€™s a constant. Input instead 8.76741e-8

Thanks @glmnet, does not work either (assuming i did it right ?)

New code:

sensor:
  - platform: adc
    pin: A0
    name: "Pool Temperature"
    update_interval: 2s
    filters:
      - lambda: return (1 / (0.001129148  + (0.000234125 * std::log(x)) + (8.76741*10e-8 * (std::log(x))^3))) - 273.15;  

New error :

Compiling /data/mcu2/.pioenvs/mcu2/src/main.cpp.o
src/main.cpp: In lambda function:
src/main.cpp:24:98: error: invalid operands of types 'double' and 'int' to binary 'operator^'
return (1 / (0.001129148  + (0.000234125 * std::log(x)) + (8.76741*10e-8 * (std::log(x))^3))) - 273.15;
^
src/main.cpp:25:3: warning: control reaches end of non-void function [-Wreturn-type]
})});
^
*** [/data/mcu2/.pioenvs/mcu2/src/main.cpp.o] Error 1
========================== [ERROR] Took 16.49 seconds ==========================

Did you get this working? Wanna steal it if you did! :slight_smile:

Iā€™m sorry I missed the notification of this thread.

@mviamin in case you still need thisā€¦

Itā€™s complaining about the ^, that does not mean pow in c++ you must use std::pow(x, y)

Try this:

return (1 / (0.001129148 + 0.000234125 * std::log(x) + 8.76741e-8 * std::pow(std::log(x), 3.0))) - 273.15;

Thanks @glmnet Awesome compiles and works but I think itā€™s off One decimal place? Were do I adjust that in the formula?

I stand corrected the Formula seams to be off for me not calculating corectly. I was using the sensor with Arduino with this code.

// Steinhart Coefficients
float a = 0.2476197866e-03, b = 2.943226015e-04, c = -2.129189836e-07;
float temperature;
void tempRead1()
{
   analogRead(meat1);
  
  float analog = analogRead(meat1);
  // Calculate the actual resistance
  float R1 = SERIESRESISTOR * (1023.0 / analog - 1.0);
  // Calculate the temperature
  float steinhart;
  steinhart = a;                                            // A
  steinhart += b * log(R1);                             // + B * ln(R)
  steinhart += c * log(R1) * log(R1)* log(R1);  // + C * (ln(R))^3
  steinhart = 1.0 / steinhart;                              // 1/(...)
  steinhart -= 273.15;
  
  //float temperature = steinhart - 273.15;                   // convert to Ā°C
// Convert Celsius to Fahrenheit
  // source: http://playground.arduino.cc/ComponentLib/Thermistor2#TheSimpleCode
  //if (useFahrenheit)
 // {
    //float 
    
    steinhart = (steinhart * 9.0) / 5.0 + 32.0;
    temperature = steinhart;
Serial.print("Meat_1 = "); Serial.print(steinhart); Serial.println(" *F"); 
delay(1000);  
 
  }

Any Ideas

I gues I should put the results of the Math

[19:38:45][D][sensor.adc:087]: 'Probe 1 Temp': Got voltage=0.51V
[19:38:45][D][sensor.sensor:100]: 'Probe 1 Temp': Sending state 20028.21680 Ā°F with 0 decimals of accuracy```

you can also use the multi line lambda approach, and the code is almost the same, easier to read:

- lambda: |-
    float a = 0.2476197866e-03, b = 2.943226015e-04, c = -2.129189836e-07;
    float steinhart;
    steinhart = a;                                // A
    steinhart += b * std::log(R1);                // + B * ln(R)
    steinhart += c * std::pow(std::log(x), 3.0);  // + C * (ln(R))^3
    steinhart = 1.0 / steinhart;                  // 1/(...)
    steinhart -= 273.15;

    // float temperature = steinhart - 273.15;                   // convert to Ā°C
    // Convert Celsius to Fahrenheit
    // source: http://playground.arduino.cc/ComponentLib/Thermistor2#TheSimpleCode

    steinhart = (steinhart * 9.0) / 5.0 + 32.0;
    return steinhart;

btw, I know nothing about steinhartā€¦

Obviously me niether! lol
Thanks

Hi @DrJeff and @glmnet, sorry i was away for a few days. I managed to figure it out, or at least something out. Steinhart-hart is a formula to translate resistance into temperature. It is not exact but accurate, and it relies on these 3 factors called ā€œaā€, ā€œbā€, and ā€œcā€ which are unique to the specific thermistor being used. Apparently manufacturers are listing in their specs what a/b/c are for a specific model of thermistor. But not pool equipment manufacturersā€¦So the a/b/c that I was able to find in posts and initially used just did not work out for me and the thermistor I used. The reading were just off.

Then I learned that there is a simplified version of the Steinhart-Hart that uses only one unknown variable instead of 3. Might be less accurate but for my needs certainly good enough.

The formula is (credits here)

It relies on 2 (or more) measurements of R and T to determine B. R0 is expected to be 10,000ohm at 25C.

In practice, hereā€™s what I did :

  1. I bought [this] , comes in 2 for $20 (https://www.amazon.com/gp/product/B07Q8RHK7D/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1) thermistor
  2. Configured the ESP to calculate the resistance based on the measured voltage (R = 10000 / (1023/V-1)
sensor:
  - platform: adc
    pin: A0
    name: "Pool Temperature"
    update_interval: 2s
    accuracy_decimals: 0
    filters:
      - lambda: return 10000 / (1023/x-1)

Drop the thermistor in a cup of warm water along with my favorite BBQ thermometre

and started and logging in Excel the resistance reading every time the temperature dropped one degree as read in the BBQ thermometre. This is what it looks like (ā€œADC TOPā€ is my entry, for example when the temperature changed from 45 to 44C I entered 7.78.)

-0.0005923090 -1688.3079
Celcius Kelvin 1/K ADC Top ADC Mid 1/B B F
45 318.15 0.003143 7.88 7.93 -0.0006 -1550.5611 113
44 317.15 0.003153 7.78 7.83 -0.0006 -1567.0208 111
43 316.15 0.003163 7.70 7.74 -0.0006 -1588.3218 109
42 315.15 0.003173 7.60 7.65 -0.0006 -1611.7869 108
41 314.15 0.003183 7.49 7.55 -0.0006 -1626.1842 106
40 313.15 0.003193 7.39 7.44 -0.0006 -1641.8450 104
39 312.15 0.003204 7.29 7.34 -0.0006 -1663.5457 102
38 311.15 0.003214 7.18 7.24 -0.0006 -1682.9510 100
37 310.15 0.003224 7.07 7.13 -0.0006 -1699.2776 99
36 309.15 0.003235 6.96 7.02 -0.0006 -1717.4057 97
35 308.15 0.003245 6.88 6.92 -0.0006 -1757.7645 95
34 307.15 0.003256 6.76 6.82 -0.0006 -1798.6205 93
33 306.15 0.003266 6.61 6.69 -0.0006 -1788.7405 91
32 305.15 0.003277 6.48 6.55 -0.0006 -1762.5140 90
31 304.15 0.003288 6.36 6.42 -0.0006 -1758.0857 88
30 303.15 0.003299 6.25 6.31 -0.0006 -1776.0250 86
29 302.15 0.00331 6.10 6.18 -0.0006 -1743.4930 84
28 301.15 0.003321 5.99 6.05 -0.0006 -1680.1462 82
27 300.15 0.003332 5.89 5.94 -0.0006 -1727.8155 81
26 299.15 0.003343 5.78 5.84 -0.0005 -1853.3981 79
25 298.15 0.003354 5.65 5.72 77

With about 20 readings (30 minutes or so) i was able to get a bunch of B readings, then I averaged them. For this thermistor it appears B = -0.000592309011930316

Now i can change the code to calculate temperature and it looks like this :

sensor:
  - platform: adc
    pin: A0
    name: "Pool Temperature"
    update_interval: 60s
    accuracy_decimals: 0
    filters:
      - lambda: return (1/(0.00335401643468053-0.000592309011930316 * log ((10000/(1023/x-1)) / 5.65) )-273.15) *9/5 + 32;

You can see B in the formula. 0.0033xxx is 1/25C (in Kelvin first). This returns the temp in F.

Bottom line is it works for me. From a science point of view it is probably making a few people cringe, but for measuring the pool temperature it is most definitely good enough ! I have compared the readings from the MCU to those to the BBQ thermometre dunked in the pool and it is within 1 degree F.

Happy to share more if anyone interested !

Disclosure : I am neither an engineer, a coder, a mathematician, or really an expert of any sort :slight_smile: But i now know that my pool temperature drops from 72F in the day to 56 at night and I have a nice chart in HA to show me that. Next step is to wire the MCU to the 24v actuator and i do not have to buy this

1 Like

Awesome! On my pool I just dropped the thermistors made an adapter and used DS18B20. But glad this works for you!! :slight_smile: The thermistors here were for my smoker. To me, you are a coder, engineer, mathematicianā€¦
My pool is controlled by HA via espeasy going to change to ESPHome soon!
What are you using to control the equipment?

:slight_smile: Right now i have a Pentair, probably 10 years old. Itā€™s been bugging me in the sense that it is not connected to the rest of my HA and it really hurts to pay premium $$ to get it connected when really it seems just a bunch of relays connected to a timer. I see the potential of HA to do much more. But i am a novice so moving slowly. My first step was to get the temperature working. Next I am thinking of connecting the 24v actuator (to switch solar heat on/off) to a relay. Next I will do the pool lights and finally the pump. I am thinking Sonoff controlling 20A relays. Have you done this ? Or know of resources ? I have read threads of folks redoing their irrigation, that looks very similarā€¦

i am about to embark on a pump controller alone using a Sonoff running ESPHome. I bought a contactor rather than just a relay because they are designed for high current and 240V. The relay of the Sonoff can control power to the contactor. Basically a relay for a relay.

I also have an old school international timer that my pool guys are responsible for maintaining, so i will have that feeding an AC relay instead of the pump that is just a sensor on the Sonoff. Three relays in a box: one of them kind of smart, and I get a physical timer that is overridable by custom schedules or me yelling from the lounge chair ā€œAlexa, shut off the pool pump!ā€ so i can enjoy the sound of birds instead of motors while sipping on a beer

contactor:
Packard C340B 3 Pole 40 Amp Contactor 120 Volt Coil Contactor https://www.amazon.com/dp/B004ZRWG9C/ref=cm_sw_r_cp_api_i_v2n5Cb4YKE0HC

I built the controller with 20 relays next revision can be a little slimmer that control actuators, lights, peristolic pumps, water fill line, and read the temps from one wire (4 sensors), filter has a pressure sensor (alert when dirty) for the pumps I use the double relays cause I had them a waste really. This could just be done with a transistor may be on my next revision. All the logic is done with Node Red. I really want to move this all to ESPHome in the near future. This pool has 4 pumps and One is a Pentair Variable Speed/Flow that I control via the RS485 comm with Pentair Pool controller NodeJS. Iā€™m horrible about documentation as you are reading here. I scribble some notes and Use. Is your Pentair the Easy touch or similar if so It can be wired via RS485 and temps and control can be had with the NodeJS project. Getting it into HA isnā€™t too hard after that.

Love it! I think having access to the home from voice is a great addition Same here AlwaysYelling at Siri or Alexa :wink:

Hi Mviamin, Iā€™m about to embark on a really similar journey, I was curious how your setup has held up in regards to temperature and I was curious if you had to add the extra 10k resistor to do the conversion from resistance to voltage? Hoping not just becuase Iā€™m trying to keep this packaged up as tiny as possible. Iā€™m waiting for that exact thermistor to come in the mail to get going. I was thinking of trying to use the same hayward ones i have now but theyā€™re old, might as well swap them out now!

Jon

Hi Jon, wow, itā€™s been a year ! Yes, still working as designed. I did not add an extra resistor to the circuit. The temperature sensor is connected directly to the ADC. Again, as disclosure, I am not an engineer by background, but it seems to be working and the readings seem to be accurate :slight_smile:

Thanks! I myself am not an engineer and this is like my first project in the ESP world so i guess maybe weā€™re partially blind leading the blind here :slight_smile: Ill give the ADC pins a shot!

Thank you!
Jon

Hi @mviamin. Do you mean you have the thermistor connected across A0 and ground. No resistor in Series?

Pretty muchā€¦is it bad ? :slight_smile:

I even have a picture of me connecting the circuit

image