How to configure tds + dallas + d1_mini

I am having trouble getting a proper TDS value using a TDS meter v1.0. I have found multiple articles online about this, but none seem to have the same issue I am seeing. Any help would be much appreciated.

Also, I am really not totally understanding what values I should be getting back from the sensor as raw data. I am seeing a value between 0 and 1, but I am not sure whether multiplying it by 3.3 is needed.

Here is my yaml example:

    esp8266:
      board: d1_mini

    one_wire:
      - platform: gpio
        pin: D1
        id: bus1

    sensor:
      - platform: dallas_temp
        name: temperature
        id: temperature
        update_interval: 5s
        one_wire_id: bus1
        unit_of_measurement: "°C"

      - platform: adc
        name: tds
        update_interval: 5s
        accuracy_decimals: 3
        pin: A0
        unit_of_measurement: ppm
        filters:
          - multiply: 3.3
          - lambda: return x/(1+(0.2 * (id(temperature).state-25.0)));
          - lambda: return (133.42*x*x*x - 255.86*x*x + 857.39*x)*0.5;

here is some output from the logs:

    [23:33:08][D][dallas.temp.sensor:054]: 'temperature': Got Temperature=16.4°C
    [23:33:08][D][sensor:103]: 'temperature': Sending state 16.43750 °C with 1 decimals of accuracy
    [23:33:09][D][sensor:103]: 'tds': Sending state -4995.80566 ppm with 3 decimals of accuracy
    [23:33:13][D][dallas.temp.sensor:054]: 'temperature': Got Temperature=16.4°C
    [23:33:13][D][sensor:103]: 'temperature': Sending state 16.43750 °C with 1 decimals of accuracy
    [23:33:14][D][sensor:103]: 'tds': Sending state -5011.00000 ppm with 3 decimals of accuracy
    [23:33:18][D][dallas.temp.sensor:054]: 'temperature': Got Temperature=16.4°C
    [23:33:18][D][sensor:103]: 'temperature': Sending state 16.43750 °C with 1 decimals of accuracy
    [23:33:19][D][sensor:103]: 'tds': Sending state -5011.00000 ppm with 3 decimals of accuracy
    [23:33:23][D][dallas.temp.sensor:054]: 'temperature': Got Temperature=16.4°C
    [23:33:23][D][sensor:103]: 'temperature': Sending state 16.43750 °C with 1 decimals of accuracy
    [23:33:24][D][sensor:103]: 'tds': Sending state -5011.00000 ppm with 3 decimals of accuracy

On esphome, ADC component prints the voltage seen by the chip, 0-1V in case of Esp8266. D1-mini has voltage divider on-board boosting the range to 3.3V so yes, you need to multiply the voltage by 3.3.

Also you likely want to take more than just one sample. Add
samples: 30 #or whatever you like
to your ADC config.

Also, double check all your calculations on lambdas:

that leads to quite big compensation, maybe you need 0.02?

1 Like

Final thought, I was trying to figure out how to calibrate the sensor and found that a k value should be entered, but I am not sure if I am putting this value in the right place:

      filters:
          - multiply: 3.3 # 3.3v from 0-1
          - lambda: return x/(1.0+(0.02 * (id(temperature).state-25.0))); # temp adjustment
          - multiply: 1.8 # k value calibration
          - lambda: return ((133.42 * x * x * x) - (255.86 * x * x) + (857.39 * x)) * 0.5; # v to tds conversion
          - lambda: return x/500; # convert from ppm to EC

From where did you find that?

I found the process on the wiki page: Analog TDS Sensor Meter for Arduino / ESP32 / Raspberry Pi - DFRobot Wiki

GravityTDS library calibration code applies it like this:

void GravityTDS::update()
{
	this->analogValue = analogRead(this->pin);
	this->voltage = this->analogValue/this->adcRange*this->aref;
	this->ecValue=(133.42*this->voltage*this->voltage*this->voltage - 255.86*this->voltage*this->voltage + 857.39*this->voltage)*this->kValue;
	this->ecValue25  =  this->ecValue / (1.0+0.02*(this->temperature-25.0));  //temperature compensation
	this->tdsValue = ecValue25 * TdsFactor;

Where TdsFactor is 0.5

So I should multiply the initial ec value returned, before the 3.3 (v fix) multiplier?

3.3 multiplier has to be always first.
For the rest, I’m not so sure. The calibration method is confusing and looks like they swapped the order EC/ temp correction.
And factor 1.8 sounds really high.

Would it make sense to grab the raw value from the sensor and then calculate EC using the code you shared?

Sadly, I am not sure what adcRange or aref should be.

After re-reading the wiki page linked above and this discussion, I believe this is the correct way to set up the sensor with a calibration k value:

     - platform: adc
      update_interval: 5s
      name: tds
      accuracy_decimals: 3
      samples: 30
      sampling_mode: avg
      pin: A0
      unit_of_measurement: ppm
      filters:
          - multiply: 3.3 # 3.3v from 0-1 (esp8266)
          - lambda: return x/(1.0+(0.02 * (id(temperature).state-25.0))); # temp adjustment
          - lambda: return ((133.42 * x * x * x) - (255.86 * x * x) + (857.39 * x)) * 0.5; # v to tds conversion
          - multiply: 0.85 # k value calibration

But according to the library that gave you k=1.8, it should go like this:

- multiply: 3.3 # 3.3v from 0-1 (esp8266)

- lambda: return ((133.42 * x * x * x) - (255.86 * x * x) + (857.39 * x)) * 1.8; #kValue here
- lambda: return x/(1.0+(0.02 * (id(temperature).state-25.0))); # temp adjustment 
- lambda: return x * 0.5; #TdsFactor 0.5