Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hot tub water quality #12

Open
5 of 9 tasks
jcallaghan opened this issue Apr 24, 2020 · 40 comments
Open
5 of 9 tasks

Hot tub water quality #12

jcallaghan opened this issue Apr 24, 2020 · 40 comments

Comments

@jcallaghan
Copy link
Owner

jcallaghan commented Apr 24, 2020

Objective

My hot tub requires pH, alkalinity and free chlorine levels to be maintained. The levels of these need to be tested daily using dip test strips and chemicals added to maintain appropriate water quality.
I want to add sensors to help me monitor the quality of the water in my hot tub. As part of this exercise, I also want to learn about water quality and the chemicals I am adding to my hot tub.

So my plan is to try and monitor the following:

  • Temperature
  • TDS
  • pH
  • ORP (free chlorine)
  • Alkalinity
  • Fill with freshwater solenoid (tap switch)
  • ESPHome configuration
  • Home Assistant configuration and automation
  • Enclosure and sensor cable management

Ingredients

Hot tub specifics

My hot tub is a Lay-z Spa Hawaii Hydrojet Pro.

Type Measurement
pH 7.4-7.6
Total Alkalinity 80-120ppm
Free Chlorine 2-4ppm
Volume 795L

Other considerations

@jcallaghan
Copy link
Owner Author

jcallaghan commented Apr 24, 2020

To get the water temperature I'm using a Dallas temperature probe with the native ESPHome integration. This is an example of using this in the ESPHome config.

dallas:
  - pin: GPIO21

sensor:
  - platform: dallas
    address: 0x770316457608FF28
    name: "${system_name}_temperature"

@jcallaghan
Copy link
Owner Author

I'm using a single ESP32 for all of these sensors.

esphome:
  name: ${system_name}
  platform: ESP32
  board: pico32

@jcallaghan
Copy link
Owner Author

jcallaghan commented Apr 24, 2020

The TDS sensor is of the same kind available from Seed Studio. They have a great blog article about the sensor. Amongst the sample sketch, there is a calculation which converts the value returned from the sensor (v) to the TDS ppm value.

  Voltage = sensorValue*5/1024.0;
  tdsValue=(133.42*Voltage*Voltage*Voltage - 255.86*Voltage*Voltage + 857.39*Voltage)*0.5;

I converted this using a lambda filter in ESPHome.

filters:
      - lambda: return (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5;

To integrate this with ESPHome I am using the ADC integration and a filter to allow me to capture a moving average while also capturing data regularly. This prevents fluctuations in the recorded data.

sensor:
  - platform: adc
    pin: GPIO34
    name: "${system_name}_tds"
    update_interval: 10s
    unit_of_measurement: "ppm"
    icon: "mdi:water-percent"
    filters:
      - lambda: return (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5;
      - sliding_window_moving_average:
          window_size: 15
          send_every: 15

@jcallaghan
Copy link
Owner Author

@jcallaghan
Copy link
Owner Author

jcallaghan commented Apr 24, 2020

Here are the test results I captured as soon as I got it working with some repeatable tests (milk and my tap water). I plan to get a TDS pen tester to validate these tests.

TDS water quality test results

  • 0.5m lead from the breakout board
    • Milk = 400ppm
    • Tap water = 40ppm
  • 5m lead from the breakout board
    • Milk = 405ppm
    • Water = 360ppm
    • Hot tub water (few weeks old and chemicals) = 400ppm

@jcallaghan
Copy link
Owner Author

jcallaghan commented Apr 24, 2020

Hands-on for the first time with the TDS sensor. This arrived 23rd April 2020 and I had it up and running in ESPHome within 30 minutes. I was testing it with some milk and fresh tap water. I figured I could easily repeat these tests if I needed to.

Really useful information about the sensor can be found on the DF Robot site.

image

@jcallaghan jcallaghan added this to In progress in The Retreat Apr 24, 2020
@jcallaghan
Copy link
Owner Author

Last weekend I added too much foam remover to the hot tub. To avoid poor water quality and remove the weird white bits that also formed in the water I added some fresh water to the hot tub. The intention was to leave the hose on for 30 minutes or so and let the bad water overfill except I forgot I was running water into the hot tub and I woke a 2am in a panic the hose was still running. I promptly got up, disarmed the house, went downstairs, unlocked the patio and went out and turned the tap off. I then reversed all this and went back to bed. Whilst struggling to sleep I decided I wasn't going to be doing this again. Two things that will help me.

One, an automation to notify me if the temperature drops in the hot tub which is an indication although I plan to make this a little more sophisticated than it currently is and two a solenoid to turn the water tap on and off.

alias: 'Hot Tub - Water temperature falling'

trigger:

  # trigger when the water temperature falls below 35c
  - platform: numeric_state
    entity_id: sensor.esph_hot_tub_water_temperature
    below: '35'

condition:

  # check the automation has not run within the last 60 minutes
  - condition: template
    value_template: "{{ (as_timestamp(states.sensor.date_time.last_changed) - (as_timestamp(state_attr('automation.hot_tub_water_temperature_falling','last_triggered')))) > 3600 }}"

action:

  - service: notify.html5_notification
    data_template:
      title: "Hot Tub water temperature"
      message: "The hot tub water is at {{ states('sensor.esph_hot_tub_water_temperature') }} and falling."

  - service: notify.ios_james_iphone
    data_template:
      title: "Hot Tub water temperature"
      message: "The hot tub water is at {{ states('sensor.esph_hot_tub_water_temperature') }} and falling."

@jcallaghan
Copy link
Owner Author

Since extending the sensor on ~5m cable I'm getting different results from the tests I ran last night. This could be power or a signal issue. I'm going to doing some more testing to ensure the sensor is calibrated correctly.

@jcallaghan
Copy link
Owner Author

jcallaghan commented Apr 26, 2020

To validate the TDS sensor I attached to an ESP32 board and installed in my hot tub I brought a handheld TDS test pen. I will capture a sample of tests and compare them against my ESP readings.

Pen TDS Readings

Sample Result 1
Tap water 58 ppm
Milk (fridge temp) 1362 ppm
Milk (room temp)
Hot tub at 40c 480 ppm

Hot tub

Sample ESP32 TDS Sensor Test Pen TDS
26 April 405ppm 480 ppm

@jcallaghan
Copy link
Owner Author

The pH sensor finally arrived today. Guess I should hook it up and see how well it works.

image

image

@jcallaghan
Copy link
Owner Author

jcallaghan commented May 1, 2020

This evening I hooked up the pH sensor up to the ESP32 board I am using to track my hot tub water quality through ESPHome. The sensor was providing me with data but not with results I expected based on my test samples. The voltage from the sensor was always maxing out with a low voltage 1.1V. With a little more reading I discovered ESP32 boards have an attenuation property which defaults to 1.1V (0db). When I switched this to 3.9V (11db) I was able to get results that I expected.

I used the following two guides to help me with the conversion from volts to pH and including temperature in the pH calculation.

I also found some libraries that were useful to understand how the sensor works.

According to the Instructables guide, the sensor has an accuracy of +/- 0.2%. Therefore the sensor will operate within this accuracy in the temperature range of 7 - 46°C. As the hot tub heats the water to 40°C no temperature compensation or offset is required

Test samples

I filled espresso cups with samples to test the pH levels with liquids I could easily repeat again if needed.

  1. Malt vinegar
  2. Fresh semi-skimmed milk
  3. Cold tap water
  4. Bleach

Tests

  1. Calibration and test samples
  2. Test samples alongside TDS sensor
  3. Testing in hot-tub water

Observations

Sample Expected Test 1 Test 2 Test 3
Vinegar 2 2.09 pH (0.58V) 2.09 ph (0.59V) N/A
Milk 6 6.82 pH (1.96V) 6.65 pH (1.90V) N/A
Water 7 7.74 pH (2.21V) 7.19 (2.06V) 7.58 pH (2.16 V)
Bleach 13 13.65 pH (3.90V) 13.65 pH (3.90V) N/A

I suspect the subtle differences between Test 1 and Test 2 were due to the milk ageing. I also noticed the sensor takes a few minutes to return to a neutral level when added to an acidic or alkaline substance

Hot tub

Sample ESP32 pH Sensor Test Pen pH
2 May 6.7 pH 6.7 pH

pH Sample Charts

image

image

@jcallaghan
Copy link
Owner Author

Some interesting reading on pH sensors. Age/lifetime of the sensor and how the sensor is affected by temperatures.

@jcallaghan
Copy link
Owner Author

@jcallaghan
Copy link
Owner Author

Time to squeeze all the the sensor boards into an enclosure. I want the unit to live beside the hot tub. This is mainly driven by the range of leads and not wanting to run them over a long lead.

This is a pre-production version. This summer I plan to build a wooden frame around my hot tub. I will house the sensor boards amongst this frame and that will be my production board.

image

image

image

image

image

image

@jcallaghan
Copy link
Owner Author

jcallaghan commented May 3, 2020

pH and temperature values are spot on. I have a pH tester arriving today but I don't think there will be any discrepancies with the results I'm getting. What I'm not confident with is the TDS value. My TDS test pen is reporting a value that is 200 points higher than my TDS sensor. I have a feeling this is related to the attenuation or the calculation from volts to TDS. I will carry on reviewing this.

pH test pen confirms my sensor is calibrated and reporting correctly. Both the pen and sensor had identical readings.

@jcallaghan
Copy link
Owner Author

I found a really some helpful articles on pool chemistry which pointed me towards the need for an ORP sensor. This will allow me to measure my chlorine levels.

@jcallaghan
Copy link
Owner Author

jcallaghan commented May 3, 2020

This DF Robot blog post about creating an automatic water sensor calls out a few points for me to consider. Sensors should not be in the water 24/7 as it affects their life.

A random thought came as writing this. What if the pH sensor was in a tube and could be lowered in the hot-tub for a regular sample.

Also when using multiple sensors an analog signal isolator should be used to avoid sensors from affecting other sensors readings.

@jcallaghan
Copy link
Owner Author

Alkalinity

There isn't a sensor for alkalinity which made me think, could I build a sensor to read the colors from a test strip.

@B-Hartley
Copy link

This is all really great stuff. I'm getting a new hot tub is a few weeks.
(I have an inflatable one at the moment).

I'd be really interested to replicate what you've done.

Is it still working sucessfully for you? any learnings ?

@monsieurlatte
Copy link

Just found this as I just started getting into ESP stuff to integrate with my HA. What an amazing write up, I may look into giving this a go myself!

@jcallaghan
Copy link
Owner Author

jcallaghan commented May 12, 2021

https://twitter.com/pvizeli/status/1392532069427863560

https://ufire.co/shop/

Twitter
“I found some nice hardware on @ufire_co. My order comes next Friday, time to start adding upstream support for @esphome_ and make the sensor data easily available on @home_assistant ❤️”

@B-Hartley
Copy link

Looks interesting. Will be following with interest.

@bscuderi13
Copy link

bscuderi13 commented Jan 13, 2022

I found this super useful as I wanted to use esp home to program a sensor for TDS and Im more familiar with raw arduino code. I found that you were struggling with accurate values from your TDS. I believe it may be related to the boards analog port measuring between 0 and 1 volt at the chip level is what is outputted so you have to relate that voltage to a converted value of 3.3 volts at least for a wemos D1 mini thats what I had to do.... heres the rteference on the esp homesite
Note
This component prints the voltage as seen by the chip pin. On the ESP8266, this is always 0.0V to 1.0V Some development boards like the Wemos D1 mini include external voltage divider circuitry to scale down a 3.3V input signal to the chip-internal 1.0V. If your board has this circuitry, add a multiply filter to get correct values:

sensor:
  - platform: adc
    # ...
    filters:
      - multiply: 3.3

so my sensor looks like this and it now matches my handheld tds meter very very close

sensor:
  - platform: adc
    pin: A0
    unit_of_measurement: 'PPM'
    name: "Gary TDS"
    update_interval: 10s
    icon: "mdi:water-percent"
    filters:
      - multiply: 3.3
      - lambda: return (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5;
      - sliding_window_moving_average:
          window_size: 15
          send_every: 15

@Gamerayers
Copy link

This looks awesome, and I'm curious if it means no more need for test strips or anything. How's it been working?

Do you have a full build manual, rather than having to piece it together from each of the different updates?

@SawadeeKC
Copy link

Interesting project!

How did you integrate the ORP sensor?

@Coolie1101
Copy link

    filters:
      - lambda: return (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5;

Doesn't the TDS reading require temperature compensation?

@bscuderi13
Copy link

bscuderi13 commented Mar 17, 2022

```yaml
    filters:
      - lambda: return (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5;

Doesn't the TDS reading require temperature compensation?

Yes and here’s how I solved that dilema if it helps. In a nutshell I take a raw reading of analog for tds then temp compensate that reading before plugging into the formula as per documentation on tds sensors.

# Raw TDS Reading
 - platform: adc
   pin: A0
   unit_of_measurement: 'V'
   name: "Gary Aquarium Raw Voltage"
   id: gary_raw
   update_interval: 60s
   icon: "mdi:eye"
   accuracy_decimals: 3
   filters:
     - multiply: 3.0
         
# Temperature Compensated Voltage
 - platform: template
   name: "Gary Aquarium Compensated Voltage"
   icon: "mdi:eye"
   id: gary_comp
   unit_of_measurement: 'V'
   accuracy_decimals: 3
   lambda: 'return ((id(gary_raw).state) / (1 + (0.02 * ((id(gary_temp).state) - 25.0))));'
   update_interval: 60s    

# Temperature Compensated TDS
 - platform: template
   name: "Gary Aquarium TDS"
   icon: "mdi:water-percent"
   unit_of_measurement: 'PPM'
   accuracy_decimals: 0    
   lambda: return (133.42*(id(gary_comp).state)*(id(gary_comp).state)*(id(gary_comp).state) - 255.86*(id(gary_comp).state)*(id(gary_comp).state) + 857.39*(id(gary_comp).state))*0.5;

@Coolie1101
Copy link

Amazing, are the readings comparable to a pen test?, when I use your formula my reading is more than 100ppm less, see below

The first reading is the result of (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5; without any compensation, which is closer to my TDS pen reading, and the following is the reading after applying your templates.

image

Came across the following which doesn't use any temperature compensation.
https://www.seeedstudio.com/blog/2020/01/19/tds-in-water-what-is-tds-and-how-do-you-measure-tds-in-water/

@bscuderi13
Copy link

Amazing, are the readings comparable to a pen test?, when I use your formula my reading is more than 100ppm less, see below

The first reading is the result of (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5; without any compensation, which is closer to my TDS pen reading, and the following is the reading after applying your templates.

image

Came across the following which doesn't use any temperature compensation. https://www.seeedstudio.com/blog/2020/01/19/tds-in-water-what-is-tds-and-how-do-you-measure-tds-in-water/

Hmmm it was closer for me using the pen one I had to compare. What are you using for the temperature? Celsius it should be if it isn’t already that as that could cause a big difference in the two.

@Coolie1101
Copy link

Coolie1101 commented Mar 17, 2022

What are you using for the temperature? Celsius it should be if it isn’t already that as that could cause a big difference in the two.

O, Fahrenheit, I'll switch it and check.

@Coolie1101
Copy link

@bscuderi13 That was it, thanks for sharing, been trying to figure out how to apply the formula for days.

image

@freekeys
Copy link

freekeys commented Apr 4, 2022

Love this! Want to do something similar this summer. Is the ORP sensor integrated with ESPHome? I saw this on ESPHome docs but don't know if it covers this device.

@admiralroflknife
Copy link

I'm working on doing similar integrations as well. I have a Coleman saluspa which I now have working with the open source wifi board from another GitHub project that lets me control the tub with mqtt and home assistant. Right now I just have a ozone generator dropped in running in cycles throughout the day. Im toying with trying to figure out a cheap electrolyzer and converting it to a salt water as well to really automate the process but I need more data. I hate to leach but I hope this project continues to progress especially with the free chlorine aspect.

@daniloortodontia
Copy link

```yaml
    filters:
      - lambda: return (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5;

Doesn't the TDS reading require temperature compensation?

Yes and here’s how I solved that dilema if it helps. In a nutshell I take a raw reading of analog for tds then temp compensate that reading before plugging into the formula as per documentation on tds sensors.

# Raw TDS Reading
 - platform: adc
   pin: A0
   unit_of_measurement: 'V'
   name: "Gary Aquarium Raw Voltage"
   id: gary_raw
   update_interval: 60s
   icon: "mdi:eye"
   accuracy_decimals: 3
   filters:
     - multiply: 3.0
         
# Temperature Compensated Voltage
 - platform: template
   name: "Gary Aquarium Compensated Voltage"
   icon: "mdi:eye"
   id: gary_comp
   unit_of_measurement: 'V'
   accuracy_decimals: 3
   lambda: 'return ((id(gary_raw).state) / (1 + (0.02 * ((id(gary_temp).state) - 25.0))));'
   update_interval: 60s    

# Temperature Compensated TDS
 - platform: template
   name: "Gary Aquarium TDS"
   icon: "mdi:water-percent"
   unit_of_measurement: 'PPM'
   accuracy_decimals: 0    
   lambda: return (133.42*(id(gary_comp).state)*(id(gary_comp).state)*(id(gary_comp).state) - 255.86*(id(gary_comp).state)*(id(gary_comp).state) + 857.39*(id(gary_comp).state))*0.5;

196 / 5 000
Resultados da tradução
Congrats on the post friend!
I would like to know how you used this temperature compensation function! I would like to implement it in a butane gas pressure project! thanks

@jcallaghan
Copy link
Owner Author

Folks, thanks for your comments and contributions. Life has been a little hectic and I've had my focus elsewhere, forgive me. Over the coming weeks I will respond to each and every one of your comments as well as bring this repo back to life. I have lots to share. 🫶🏼

image

@timmyjane
Copy link

Looking forward to hearing/seeing your progress.

@kars85
Copy link

kars85 commented Aug 12, 2022

Curious where the final placement of the components will be. Great job!

@andyhawkes
Copy link

Very interesting - I have a very simple temperature monitor for my pool house (indoor air temp, outdoor air temp, and water temp) running on Wemos D1 Mini but I would love to be able to add pH, Chlorine, and Total Alkalinity to it at some point!

@ervee
Copy link

ervee commented May 14, 2023

This is a pretty nice project!
I just built my own pool monitoring "box" with an ESP32-C3 2MB (which on its own was a challenge) dev-board and a Dallas temperature probe. I would love to add free chlorine monitoring. Thank you for all the great information above and if I have something to add I'll be happy to do so.

@tyfoon
Copy link

tyfoon commented May 25, 2023

Great stuff @jcallaghan Would be great if you can post the final setup & code. Would love to re-create!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Projects
In-progress
The Retreat
  
In progress
Development

No branches or pull requests