Your soil sensor is
lying to you.
pH reads 6.8 no matter what. NPK values jump randomly. It's not the sensor. It's your code. FarmSense fixes that.
Three lines. Done.
Supply your read function. Let FarmSense handle the filtering and calibration mapping.
#include <FarmSense.h> // Transport-agnostic: wrap your Modbus/I2C/ADC call float readPH() { return modbus.readRegister(0x0006) / 100.0; } FarmSenseChannel ph(PARAM_PH, readPH); void setup() { ph.begin(); } void loop() { float val = ph.read(); // Filtered & Calibrated delay(500); }
read() runs the full pipeline: raw fetch โ Adaptive Kalman Filter โ segmented calibration interpolation โ clamp/OOR check.
Pass-through reading is not enough.
Noisy RS485 lines. Non-linear pH responses. Extrapolation errors. Here's what this library does about it.
Adaptive Kalman Filter
Locks onto stable readings. Only reacts to real changes in soil conditions, suppressing RS485 noise via innovation gating.
Multi-Point Calibration
Segmented linear interpolation (up to 10 points). Your sensor's pH curve isn't linear and we don't pretend it is.
Persistent Storage
EEPROM on AVR, Preferences (NVS) on ESP32. Calibration survives power cycles automatically.
Dual Calibration Methods
Calibrate live in the field via serial, or load offline batch data (CSV) from previous lab tests.
CLAMP by Default
Extrapolating saturated pH sensors is dangerous. FarmSense clamps at known boundaries and flags out-of-range.
Transport Agnostic
Modbus RTU? I2C? Plain ADC? Just pass a function pointer. The processing pipeline doesn't care how you get the data.
See the difference.
| Feature | Raw Pass-through | Other Libraries | FarmSense |
|---|---|---|---|
| Noise filtering | โ | Simple averaging | โ Adaptive Kalman |
| Out-of-range safety | โ | โ Extrapolates blindly | โ CLAMP + Flag |
| Calibration saved | โ Lost on reboot | โ Manual EEPROM | โ Auto NVS/EEPROM |
| Non-linear correction | โ | โ Linear only | โ 10-point segmented |
| Offline batch calibration | โ | โ | โ Array / CSV / File |
| Transport mechanism | โ Yes | โ Hardware specific | โ Agnostic (Func ptr) |
| Cross-platform | โ | ESP32 or AVR only | โ Both + fallback |
8-in-1 Ready.
Each channel manages its own Kalman state, calibration map, and storage namespace independently.
| Enum | Parameter | Typical Unit |
|---|---|---|
PARAM_TEMPERATURE | Temperature | ยฐC |
PARAM_MOISTURE | Moisture | % |
PARAM_CONDUCTIVITY | Conductivity (EC) | ยตS/cm |
PARAM_PH | pH | pH |
PARAM_NITROGEN | Nitrogen (N) | mg/kg |
PARAM_PHOSPHORUS | Phosphorus (P) | mg/kg |
PARAM_KALIUM | Kalium (K) | mg/kg |
PARAM_FERTILITY | Fertility Index | โ |
Calibrate via Serial.
Place the probe in a buffer solution and send commands. Changes persist automatically.
// In your loop(), pass commands to channels: if (Serial.available()) { String cmd = Serial.readStringUntil('\n'); ph.processCommand(cmd); temp.processCommand(cmd); }
API.
true if โฅ2 calibration points exist.true if the last reading was outside the calibrated boundaries.channel,raw,ref) and loads matching rows.OOR_CLAMP (default), OOR_FLAG_ONLY, OOR_EXTRAPOLATE.cal:pH:4.01). Returns true if it matches this channel.What you actually get.
Ship faster
Stop rewriting smoothing filters and calibration math. Install and focus on your product.
Deploy and forget
Persistent calibration survives reboots. Setup once in the field, runs for years.
Scale without rewriting
Because it's transport-agnostic, you can swap Modbus libraries or change hardware without touching the calibration logic.