A world of good sensors speak only analog: a voltage, or a 4–20 mA current loop. This node reads them cleanly through an ADS1115 16-bit converter, turns each into a real measurement with a two-number calibration, and pushes it as oat-ods to a place you own.
What it does.
Reads analog sensors through an ADS1115 (a clean 16-bit I²C ADC), applies a two-number linear calibration, and emits each as oat-ods. The bridge for the huge install base of analog and current-loop sensors that have no digital bus.
That’s the Collect layer for one more kind of sensor: it reads the instrument, shapes each reading into the one oat-ods message every Open Agriculture Technology device speaks, and pushes it to a place you own. The value is what you do with the reading later; this just gets it flowing.
What it reads.
Each reading goes out as its own oat-ods message, filed under the place you name, so swapping the hardware later never breaks the record:
What you need.
Wiring. The ADS1115 sits on I²C (SDA / SCL, 3.3 V). Wire each sensor output to a channel input (A0–A3). For a 4–20 mA sensor, put a precise sense resistor across the input so the current becomes a voltage the ADC can read (150 Ω gives 0.6–3.0 V, inside range).
The channel map.
One line per ADS1115 channel on the setup page:
<ch> <stream_id> <measure>:<unit>:<m>:<b> 0 canopy-par par:umol/m2/s:800:0 1 tank level:%:41.667:-25
value = m × volts + b. Two points (volts, value) define the line, so any linear sensor fits, including 4–20 mA turned into a voltage by a sense resistor.
What it sends.
It pushes to wherever you point it (Webhook (HTTP POST) or MQTT) as
oat-ods/0.3. One measurement per message; here’s a reading from this node:
{
"schema": "oat-ods/0.3",
"observed_at": "2026-06-25T14:30:00Z",
"stream": { "id": "canopy-par", "name": "…", "location": "…" },
"measurement": "par",
"value": 642,
"unit": "umol/m2/s",
"source": { "tier": "oat-analog-reader", "gateway_id": "…", "physical_id": "ads1115:0" }
}
That’s the same envelope the whole library speaks. Point it at your webhook, an Home Assistant broker, or Open Agriculture Technology; the receiver can’t tell which node produced it. The developer reference has the full spec.
Get it & build it.
The project downloads whole: the sketch plus the shared oat_ods library it needs, so it
builds as-is:
Full PlatformIO project (.zip) Just the sketch (.ino)
Two ways to put it on a board, both free:
- PlatformIO (builds all four ESP32 chips): unzip, then
cd oat-analog-reader && pio run -t upload. The bundledlib/oat_ods/resolves automatically. - Arduino IDE: open the
.ino, install the libraries below from the Library Manager, pick your ESP32 board, and upload.
Compile-verified on our side (it builds clean with the pinned toolchain), but not yet run on the bench with real sensors, so it ships as source rather than a browser image. If you run it, tell the collective how it went; that’s what turns it into a flash-from-browser sketch.
Set it up.
Setup happens on the device’s own page: nothing to install, works with no internet:
- Power the node from any USB charger or your computer.
- Join its Wi-Fi network
OAT-Analog-XXXX, and the setup page opens (or visithttp://192.168.4.1). - Sign in, set your Wi-Fi, where the readings go, and the sensor details above, then save.
- Point delivery at the test endpoint and watch your first reading arrive, checked against the standard.
Settings persist across reboots; a fresh flash wipes them, on purpose, so a re-used board never carries the last owner’s Wi-Fi or endpoint.
Notes.
- A 16-bit ADC and a two-point calibration get you accuracy a raw ESP32 analog pin can’t. The live-volts table on the setup page shows the reading so you can derive m and b.
- Each channel becomes one oat-ods message, with
physical_idrecordingads1115:<ch>.
For makers & trainers.
Frequently asked questions.
How do I read a 4–20 mA sensor with an ESP32?
Put a precise sense resistor (commonly 150 ohm) across the current loop so the 4–20 mA becomes roughly 0.6–3.0 V, then read that voltage with a 16-bit ADS1115 ADC over I2C. A linear calibration (value = m × volts + b) maps the voltage back to the sensor’s engineering units.
Can an ESP32 read 0–5 V analog sensors accurately?
The ESP32’s built-in ADC is noisy and tops out around 3.3 V. An external ADS1115 gives clean 16-bit readings, and for 0–5 V you scale into range with a resistor divider or use amplified 0–2.5 V outputs. A two-point calibration then converts volts to the measurement.