2026-11-01: pH and DO circuits over Linux I2C

Status: complete. This is the first run of ezo-driver against real circuits.

  • Passed: identity, status, LED, readings, and the NOT_READY, NO_DATA and transport errors. Also a 3-point pH calibration, a 2-point DO calibration, and Sleep and wake on DO firmware 2.17.
  • Failed: Sleep on the pH circuit, firmware 2.15. It never woke, and only a power cycle brought it back (#33).
  • New issues from this session: #32, #33 and #34.

Verifies: 0.8.0 from PyPI, including:

  • status-specific read errors (#23, released in 0.7.0);
  • errno, bus and address on EzoTransportError (#29, released in 0.8.0).

By: @CameronBrooks11, 2026-11-01 to 2026-11-02.

Setup

   
Library ezo-driver 0.8.0 from PyPI, Python 3.13.5. LinuxI2CDevice(bus=1, ...) via ezo_bench.py
Controller Raspberry Pi 4 Model B. /dev/i2c-1 at 50 kHz, shared with two other devices, at 0x13 and 0x15
Circuits EZO-pH at 0x63, firmware 2.15, 5.31 to 5.32 V. EZO-DO at 0x61, firmware 2.17, 5.37 to 5.41 V. Both in I2C mode (LED blue) and uncalibrated at the start
Probes pH probe in buffers pH 7, 4 and 10. DO: the first probe, refilled with electrolyte, read 0.92 mg/L in air, then fell to 0.6, and was replaced. The second read 28 mg/L in air uncalibrated

Steps and Results

Step Expected Observed Result
E1 info, status, led, calq, tempq on both; compq on DO identity, restart code, voltage, LED, calibration and compensation decode pH: pH 2.15, restart P, 5.32 V, LED on, cal NONE, 25.0 C. DO: DO 2.17, restart P, 5.38 V, LED on, cal 0, 20.0 C, 101.3 kPa, salinity 0 pass
E2 read 5 on each readings decode pH 6.076 to 6.081, uncalibrated. DO 0.92 mg/L, 10.1 %, output mask 3 (both outputs) pass
E3 early: a read 13 ms after R (#23) EzoNotReadyError, then a successful read after the wait both raised EzoNotReadyError, then gave a reading after 900 ms (pH) and 600 ms (DO) pass
E4 nodata: a second read with no new command (#23) EzoDeviceStatusError with status NO_DATA both: status=NO_DATA pass
E5 noaddr 0x62 (#29) EzoTransportError with errno, bus and address errno=5 (EIO), bus=1, address=98 pass
E6 pH calibration: watch until stable, then Cal,mid,7.00, Cal,low,4.00, Cal,high,10.00 status NONE, ONE_POINT, TWO_POINT, THREE_POINT; readings at each buffer afterwards Before each point: 7.44 to 7.48, 3.858 to 3.862, and 9.05 (still rising 0.01 per 30 s). After: 6.988 to 7.012, 3.996 to 4.000, 9.995 to 10.000. Status went through each level pass
E7 slope after the 3-point calibration the slope decodes acid 104.8 %, base 68.9 %, neutral -27.94 mV pass for the driver. The probe is outside the vendor’s new-probe range (Notes)
E8 pH Sleep, wait 5 s, wake with i no response to Sleep; any command wakes it Wake tries failed with EREMOTEIO, then EIO; reads with EIO. 10 raw one-byte writes 100 ms apart all failed with EIO, and the address was not ACKed. LED blue. After a power cycle: 2.15, restart P, cal THREE_POINT, slope unchanged fail on firmware 2.15 (#33)
E9 DO zero point: second probe in zero solution, watch until stable, Cal,0 readings reach about 0, or the vendor’s limit (12 h after new electrolyte) is reached with a flat reading; status 0 to 1; readings 0.00 afterwards First pour: 20.38 mg/L, plateauing near 6.1 after 3.5 h. Fresh pour in a narrow, nearly full container: 5.23 at 21:47, 2.91 at 09:01, then flat at 2.85 to 2.95 for 2 h. About 14 h in the fresh pour, then Cal,0: level 0 to 1, readings 0.00 mg/L, 0.0 % pass
E10 DO air point: rinse, dry, watch until stable, Cal status 1 to 2; about 9.09 mg/L (vendor value at the default compensation) Fell from 12.36 to 10.12 over 7 min, then 10.03 to 10.12 for 4.5 min. Cal: level 1 to 2, 9.13 mg/L, 100.4 %. 8 min later 9.48 mg/L, 104.3 % (Notes) pass
E11 DO Sleep, wait 5 s, wake with i wakes on the first command first wake try answered (DO 2.17); restart code still P; cal level 2; readings normal pass

Raw Output

  • raw-session.txt: every command and its output. The logger restarts and process checks are in it too.
  • do-overnight.log: the DO reading in the fresh zero solution, once a minute from 21:47 to 11:11, written by do-overnight.sh on the controller.

Not Checked

  • UART, and every product other than pH and DO.
  • Sleep on a pH circuit at firmware 2.16 or later.
  • Calibration export and import, protocol lock, Find, and name.
  • Temperature-compensated reads.

Notes

  • Sleep on pH firmware 2.15.
    • The vendor’s pH firmware changelog lists 2.16 as “Fixed bug in I2C mode with timing and sleep mode”. The DO circuit, on 2.17, after the DO sleep fixes, woke normally (E11).
    • That 2.16 fixes the pH failure is inferred from the changelog entry, not tested on a pH circuit.
    • #33 covers documenting this; #34 covers a firmware-version lookup for callers.
  • pH slope.
    • Base 68.9 % and a -27.9 mV offset are outside the vendor’s typical figures for a new probe: above 95 %, and within about ±5 mV.
    • The pH 10 bottle was fresh, so the probe is the more likely cause. Cleaning the probe and recalibrating would tell.
  • DO after the air calibration. It rose from 9.13 to 9.48 mg/L within 8 minutes, after about 18 h in zero solution. Check it in air again, and repeat Cal once it holds steady.
  • Decimal parsing. Readings such as 6.079000000000001 and 0.6800000000000002 come from the C parser, not the circuit (#32).