Bring analog and current-loop sensors — the huge install base with no digital bus — into data you own.
| Status | Source release — build & flash it yourself |
| Interface | ADS1115 16-bit ADC (I²C) — reads 0–2.5 V / 0–5 V and 4–20 mA |
| Delivers | Webhook (HTTP POST) · MQTT — oat-ods/0.3 |
| Site page | openagriculturetechnology.com/build/sketches/analog-reader/ |
| License | Apache-2.0 |
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 (a 16-bit I²C ADC), applies a per-channel linear calibration, and emits each as oat-ods.
value = m × volts + b
That one linear map covers amplified 0–2.5 V / 0–5 V outputs and 4–20 mA
(with a sense resistor turning current into a voltage) — you just pick m and b
to match the sensor's range. The bridge for the huge install base of analog and
current-loop sensors that have no digital bus.
One line per ADS1115 channel on the setup page:
<ch> <stream_id> <measure>:<unit>:<m>:<b>
Examples:
0 canopy-par par:umol/m2/s:800:0 # Apogee SQ-512: 0-2.5V = 0-2000 umol -> m=800, b=0
1 tank level:%:41.667:-25 # 4-20mA via 150 ohm: 0.6-3.0V -> 0-100%
Each channel → one oat-ods message: stream = stream_id,
physical_id = ads1115:<ch>.
Two points (volts, value) define the line:
m = (value2 − value1) / (volts2 − volts1)
b = value1 − m × volts1
The setup page's Live volts table shows the raw voltage on each channel —
read it at two known sensor states and compute m/b.
ADS1115 is I²C (3.3 V): SDA, SCL, 3V3, GND (default addr 0x48).
Sensor output to A0–A3.
m/b.Set the gain on the setup page to the smallest full-scale that still covers your voltage — smaller full-scale = finer resolution.
Flash (see Build), join OAT-Analog-xxxx, open the setup page (admin /
oatsetup), set Wi-Fi + delivery + the I²C pins/gain + the channel map. Point
delivery at the test endpoint
to confirm.
pipx install platformio # or: pip install --user platformio
cd oat-analog-reader
./build.sh
This is a source release: it compiles against the pinned deps but hasn't
earned the bench-verified badge the live sketches carry — build it, flash it, and
prove it on your bench before you trust it in the field. Deps (pinned in
platformio.ini): Adafruit ADS1X15, PubSubClient, ArduinoJson, and the
local oat_ods module.
How do I read a 4–20 mA sensor with an ESP32? Put a precise sense resistor (commonly 150 Ω) 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 I²C. 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.
oat-cwsi-node/ and oat-sht30-node/ — the other I²C sketches; same default pins, one wiring habit.../lib/oat_ods/ — the shared oat-ods encoder + measurand vocabulary.Shared core: this sketch carries its own copy of the config / Wi-Fi / delivery scaffolding; as the shared
oat-node-corelibrary is adopted, only the acquisition layer stays sketch-specific.
Code: Apache-2.0 · Docs: CC BY 4.0 · An OAT sketch — an OpenCDC initiative.