Water System Monitoring - updates
Chart on server showing pressure readings over last 2 days
Components:
- ESP32 WROOM ($4.76 CAD) - https://www.aliexpress.com/item/4000471022528.html
- 5V 1/8NPT Pressure Transducer ($6.15 CAD) - https://www.aliexpress.com/item/1005005255271180.html
- 16 Bit I2C ADS1115 Module ($2.79 CAD) - https://www.aliexpress.com/item/32817162654.html
- OLED SSD1306 ($1.53 CAD) - https://www.aliexpress.com/item/32643950109.html
3d model for case designed for free with selfcad (www.selfcad.com)
https://www.thingiverse.com/thing:6481134
Hardware setup
Pressure Transducer → ADS1115
Your “universal” 5 V sender is almost certainly ratiometric 0.5–4.5 V, 3-wire:
-
Red → 5 V (ESP32 VIN or other clean 5 V)
-
Black → GND (common ground with ESP32 + ADS1115)
-
Signal → Voltage divider → ADS1115 A0
Voltage divider (example: 10 kΩ / 10 kΩ)
-
Sensor signal → Rtop (10 kΩ) → ADS A0
-
ADS A0 → Rbottom (10 kΩ) → GND
This halves the voltage so 0.5–4.5 V becomes 0.25–2.25 V (safe for 3.3 V ADS1115).
Optional: 0.1 µF capacitor from ADS A0 to GND for noise smoothing.
ADS1115 → ESP32
-
ADS1115 VDD → ESP32 3.3 V
-
GND → GND
-
SDA → GPIO 21 (default SDA)
-
SCL → GPIO 22 (default SCL)
-
ADDR → GND (I²C address
0x48
)
SH1106G Display → ESP32 (I²C)
Adafruit SH1106G typically uses:
-
VCC → ESP32 3.3 V
-
GND → GND
-
SDA → GPIO 21
-
SCL → GPIO 22
Both OLED and ADS1115 share the I²C bus (different addresses).
ESP32 code written in Arduino IDE (https://www.arduino.cc/en/software)
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
// --- Display setup ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// --- ADS1115 setup ---
Adafruit_ADS1115 ads;
// Divider values
const float Rtop = 10000.0; // Ohms
const float Rbottom = 10000.0;
const float dividerGain = (Rbottom / (Rtop + Rbottom)); // 0.5
const float dividerInverse = 1.0 / dividerGain; // 2.0
// Sensor parameters (0.5–4.5 V = 0–100 psi)
const float sensorMinV = 0.5;
const float sensorMaxV = 4.5;
const float psiMax = 100.0;
// Smoothing
float psiFiltered = 0.0;
const float alpha = 0.2; // 0..1
void setup() {
Serial.begin(115200);
Wire.begin();
// --- Init display ---
if (!display.begin(0x3C, true)) { // 0x3C is common SH1106 address
Serial.println("SH1106G not found");
while (1);
}
display.clearDisplay();
display.setTextColor(SH110X_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Pressure Sensor Init...");
display.display();
// --- Init ADS1115 ---
if (!ads.begin(0x48)) {
Serial.println("ADS1115 not found");
while (1);
}
ads.setGain(GAIN_ONE); // ±4.096 V range
ads.setDataRate(RATE_ADS1115_128SPS);
delay(500);
}
float countsToVolts(int16_t counts) {
return ads.computeVolts(counts);
}
float voltsToPsi(float v_ads) {
// Undo divider
float v_sensor = v_ads * dividerInverse;
// Map to psi
float psi = (v_sensor - sensorMinV) * (psiMax / (sensorMaxV - sensorMinV));
// Clamp
if (psi < 0) psi = 0;
if (psi > psiMax) psi = psiMax;
return psi;
}
void loop() {
// Read ADC
int16_t raw = ads.readADC_SingleEnded(0);
float v_ads = countsToVolts(raw);
float psi = voltsToPsi(v_ads);
// Smooth
psiFiltered = alpha * psi + (1 - alpha) * psiFiltered;
// --- Serial output ---
Serial.print("Raw: "); Serial.print(raw);
Serial.print(" | Vads: "); Serial.print(v_ads, 4);
Serial.print(" V | PSI: "); Serial.print(psi, 2);
Serial.print(" | PSI Filtered: "); Serial.println(psiFiltered, 2);
// --- Display output ---
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Pressure Reading:");
display.setTextSize(2);
display.setCursor(0, 20);
display.print(psiFiltered, 1);
display.print(" PSI");
display.display();
delay(200);
}