Skip to main content

Jason Slade

IIoT Director | SCADA | MQTT | Controls Engineering

Three Numbers and a Float Switch: Instrumenting a Fish Tank

A fish tank is a small chemical reactor that punishes inattention slowly. Nothing looks wrong until something is very wrong, and by then the thing that went out of range did so days ago.

So this is an ESP32 sitting on the tank, reading the three numbers that actually move — pH, dissolved solids, and temperature — plus a float switch for the one failure that is sudden rather than gradual.

What is on the board

MeasurementSensorInterface
pHAtlas Scientific EZO-pH circuitI²C, address 0x63
TemperatureDS18B201-Wire, GPIO32
Dissolved solidsAnalog TDS probeADC
Water levelFloat switchGPIO13, INPUT_PULLUP, inverted

It runs ESPHome, so all four land in Home Assistant as native entities with no bridge code in between.

The two parts worth explaining

Calibration is exposed, not buried. The EZO pH circuit supports three-point calibration, and the config surfaces each point as a button in Home Assistant:

button:
  - platform: template
    name: "PH 7 Calibrate"
    on_press:
      - lambda: id(ph_ezo).set_calibration_point_mid(7.00);

Four buttons — 4, 7, 10, and clear — mean recalibrating is a thing you do from your phone while standing at the tank with the buffer solutions, rather than a thing you reflash firmware for. A pH probe drifts; if calibrating is inconvenient, it stays drifted.

TDS is temperature-compensated, because otherwise it is fiction. Conductivity rises with temperature, so a raw TDS reading tracks the room as much as the water. The probe voltage is corrected against the DS18B20 first, then converted:

// temperature-compensated voltage
return id(tds01_raw).state / (1 + 0.02 * (id(probe01).state - 25.0));

// compensated voltage -> PPM
return (133.42*V*V*V - 255.86*V*V + 857.39*V) * 0.5;

The cubic is the standard Gravity TDS response curve; the 0.5 is the TDS factor converting conductivity to dissolved solids. Skipping the compensation step produces a number that swings with the afternoon sun and tells you nothing about the water.

An ORP circuit at 0x62 is stubbed out in the config — planned, never fitted.

Status

In progress — logging live, write-up pending data.

The node is reading correctly (pH 7.57, 102 PPM, 23.8 °C at the time of writing) and is now recording into Home Assistant, but it spent a long stretch disconnected without anyone noticing, so there is no history worth charting yet. The full write-up follows once there are enough days behind it to show what the numbers actually do — the daily temperature swing, what a water change looks like in TDS, and whether the pH probe has drifted since it was last calibrated.

← All posts

→ Subscribe by RSS