A research-grade (or any industrial) sensor speaks one of a handful of "languages" on its wires. None of them need an expensive logger, a cheap ESP32 reads all four and turns the reading into oat-ods for your endpoint or Home Assistant. Here's each one.
01First, pick the output.
You choose a sensor's output when you buy it (on Apogee, the model number's suffix says which; Atlas's EZO circuits speak I²C/UART). For a first build, a smart I²C/UART circuit or an amplified 0–2.5 V output are the friendliest.
| I²C / UART (smart circuit) | easiest | A sensor circuit (e.g. Atlas EZO) does the analog work and hands the ESP32 a finished reading over a native bus. No ADC, no resistor. |
|---|---|---|
| 0–2.5 V (amplified) | easy | A small voltage. Read it on an ESP32 ADC pin, or an ADS1115 for accuracy. |
| 0–5 V / self-powered mV | easy | 5 V needs a 2:1 divider first; a raw millivolt signal needs a precision ADC (ADS1115) with gain. |
| 4–20 mA | easy | A current loop. A precision sense resistor turns it into a voltage you can read. |
| SDI-12 | moderate | 1-wire digital, addressable, many sensors on one bus, long runs. |
| Modbus RTU | moderate | RS-485 digital, multi-drop, the industrial workhorse. |
02Smart sensor circuits (I²C / UART).
The easiest of all, and increasingly common. Instead of a raw voltage, a small circuit sits next to the probe, does the analog work and the calibration, and gives the ESP32 a finished number over I²C or UART, the two buses the chip speaks natively. No ADC, no sense resistor, no divider. Atlas Scientific's EZO circuits are the worked example: a pH, EC, dissolved-oxygen, ORP, or RTD-temperature probe plugs into an EZO circuit, and your sketch just asks it for a reading. I²C lets many circuits share two wires (each at its own address); UART is one circuit per serial port. The cleanest path for water chemistry, the readings a hydroponic or aquaponic grower lives by.
03Analog voltage.
The most accessible. A 0–2.5 V signal sits inside the ESP32's ADC range, so you can read it on a pin. But the on-chip ADC is noisy and non-linear, so for a research-grade reading pair the ESP32 with an ADS1115, a 16-bit I²C ADC that's clean, linear, and can amplify the tiny self-powered millivolt sensors too. A 0–5 V output needs a simple 2:1 resistor divider first. Convert the voltage to the measured value with the sensor's calibration factor (from its datasheet).
044–20 mA.
An industrial current loop, reliable over long cable runs and immune to voltage drop, which is why it's everywhere in the field. The trick: put a precision resistor across the loop and measure the voltage it produces. A 150 Ω resistor turns 4–20 mA into about 0.6–3.0 V, right for an ADS1115. 4 mA is the bottom of the range and 20 mA the top; map linearly to the value. (The loop usually needs 12–24 V of supply, that's the loop power, separate from the ESP32.)
05SDI-12.
A digital serial protocol built for environmental sensors: one data wire, addressable, so many sensors share a bus over long distances. The ESP32 asks the sensor to take a measurement and reads the value(s) back as text. Use the Arduino SDI-12 library; SDI-12 idles at 5 V, so add a small level interface to the 3.3 V ESP32. Best when you have several sensors or long runs. (Apogee's SQ-521 is an SDI-12 quantum sensor.)
06Modbus RTU.
The industrial workhorse, RS-485 wiring, multi-drop, very reliable over long, noisy runs. Add an RS-485 transceiver (a MAX485 or an auto-direction module) to one of the ESP32's UARTs, and a Modbus library reads the sensor's registers. Reach for it when you're tying into industrial equipment or running many devices on one long bus. (Apogee's SQ-522 is a Modbus quantum sensor.)
07Turn it into oat-ods.
However you read it, a voltage, a current, an SDI-12 string, a Modbus register, you end up with a number and a unit. Fill an oat-ods reading and send it. The device emits the same message a wireless thermometer does, so the endpoint can't tell a $600 PAR sensor from a $20 probe, it's all one stream of owned data.
oat::Reading r; r.stream_id = "canopy-par"; // the place, the primary key r.measurement = "par"; // what it is r.unit = "umol/m2/s"; // PPFD r.value = ppfd; // from the ADC + the sensor's calibration r.physical_id = "apogee-sq-512"; // the instrument (swappable) String body; oat::encodeNative(dev, r, body); // → POST, or MQTT
That's the same oat_ods module the BLE listener uses. These readers are becoming their own sketches, an analog/ADS1115 reader, an SDI-12 reader, a Modbus reader, each pouring into the one envelope. Watch for them in the Software Library.
The shortest version
Five ways in, one cheap chip. The friendliest is a smart circuit (e.g. Atlas EZO) over I²C/UART; analog volts read straight (an ADS1115 for accuracy); 4–20 mA via a sense resistor; SDI-12 and Modbus are digital buses for many or distant sensors. Convert to a number, wrap it in oat-ods, send it anywhere.
Frequently asked questions.
How do I read a 4-20 mA sensor with an ESP32?
Put a precision sense resistor across the current loop and measure the voltage it produces with an ADC. A 150 Ω resistor turns 4–20 mA into about 0.6–3.0 V, which an ADS1115 reads cleanly; map 4 mA to the bottom of the sensor's range and 20 mA to the top. The loop itself usually needs a 12–24 V supply, separate from the ESP32.
How do I read an SDI-12 sensor with an ESP32?
Use the Arduino SDI-12 library on one data pin. The ESP32 sends the sensor a measurement command and reads the value back as text. SDI-12 idles at 5 V, so add a small level interface to the 3.3 V ESP32. It's addressable, so several sensors can share one wire over long runs, ideal for spread-out field sensors.
How do I connect a Modbus (RS-485) sensor to an ESP32?
Add an RS-485 transceiver (a MAX485 or an auto-direction module) to one of the ESP32's hardware UARTs, then use a Modbus RTU library to read the sensor's holding registers. RS-485 is multi-drop and very reliable over long, electrically noisy runs, so it's the right pick for industrial gear or many devices on one bus.
Can an ESP32 read an analog sensor accurately?
For a rough reading, the ESP32's built-in ADC works, but it's noisy and non-linear. For a research-grade sensor, pair the ESP32 with an ADS1115, a 16-bit I²C ADC that reads cleanly and linearly and can amplify tiny millivolt signals. Then apply the sensor's calibration factor to turn volts into the measured value.
How do I read a pH or EC sensor with an ESP32?
The easiest way is a sensor with a smart circuit. Atlas Scientific's EZO circuits take a pH, EC, dissolved-oxygen, or ORP probe and hand your ESP32 a calibrated reading over I²C or UART, with no ADC and no calibration math in your code. Wire the EZO to the ESP32's I²C pins or a serial port, ask it for a reading, and pass the value on to wherever you store your data.