TDS Sensor in ESPHome with ESP32 and CQRobot Sensor

Wanting to measure TDS in and out of my RO water system as a rough gauge of quality. Generally, following Aquarium water quality TDS sensor
but found a problem which I solved below.

I have this “CQRobot” sensor : CQRobot TDS (Total Dissolved Solids) Meter Sensor Compatible with Raspberry Pi/Arduino Board. for Liquid Quality Analysis Teaching, Scientific Research, Laboratory, Online Analysis, etc.: Amazon.com: Industrial & Scientific

I can see the voltages with my voltmeter responding as expected in my standard samples and tried to hookup the output to the ESP32’s ADC.
This worked OK for higher voltages, but fails at low voltages < 100mV. Apparently, this is a known issue with the ESP32 ADC which is not easily fixed by adjusting attenuation.

So used a better ADC to get the low end voltages via the ESP32’s I2C.

After hooking it all up and testing in my standard TDS solutions, I can see the full voltage range - yay!.
But, using the CQrobot’s suggested conversion function of V to PPM of:
f(x)=(133.42⋅x3−255.86⋅x2+857.39⋅x)⋅0.5
does not result in correct values. Plus, the coefficients on the function are insane… and are likely a poor attempt at fitting a voltage curve.

Anyhow, following their polynomial form, I re-fit the coefficients in a way that gave good values verified in multiple solutions and confirmed by two different TDS sensors and ended up with the following:

My final ESPHome config for the sensor is as follows:

ads1115:
  - address: 0x48
i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true
  id: bus_a
sensor:
  - platform: ads1115
    multiplexer: 'A0_GND'
    name: "Water TDS"
    gain: 2.048      # optimized for output range of device, up to 2V [6.144]
    update_interval: 2s
    unit_of_measurement: "ppm"
    accuracy_decimals: 0
    filters:
#orig      - lambda: return (((133.42*x*x*x) - (255.86*x*x) + (857.39*x))*0.5);
      - lambda: return (308.2*x*x) + (400.7*x) - 5.8;   #properly calibrated using other meters and standard soln.

Now, the device sensor is easily placed inline in my RO system by inserting the probe into a 1/4" push-connect fitting:

[edit, updated better fit formula and sensor gain]

You should pick up a new sensor or try a different multiplexer. I was having tremendous issues with one of mine, until I tried using the other probe I had and on A3_GND.

I applied the same formulas for both, including the one CQRobot applied, and a temperature compensation one. The first probe I was using is wildly off (measuring 0.03V to the other’s 1.01V). After applying everything to the second probe, the TDS was dead on the money among several testing solutions and TDS handheld probes

sensor:
  - platform: ads1115
    multiplexer: 'A3_GND'
    name: "TDS probe voltage"
    id: tds_voltage
    accuracy_decimals: 3
    update_interval: 2s
    gain: 6.144

  - platform: template
    name: "TDS (ppm)"
    id: tds01
    icon: "hass:water-opacity"
    unit_of_measurement: "PPM"
    accuracy_decimals: 1
    update_interval: 5s
    lambda: |-
      float voltage = (id(water_temp_c).state > -100) ? (id(tds_voltage).state) : 0.0;
      float temp = id(water_temp_c).state;
      float compensated = voltage / (1.0 + 0.02 * (temp - 25.0));
      return (((133.42 * compensated * compensated * compensated) - (255.86 * compensated * compensated) + (857.39 * compensated)) * 0.5);

Thanks for sharing your experience. My problem with the provided curve is that is should be nearly linear - these cubic terms make little sense to me from an electronics/physics standpoint. More important is how do the two compare using known test solutions. In my case, the quadratic fit perfectly.