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 bydo-overnight.shon 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
Calonce it holds steady. - Decimal parsing. Readings such as
6.079000000000001and0.6800000000000002come from the C parser, not the circuit (#32).