Skip to main content

Water System Monitoring - updates

20240119-114555-2.jpg

For this project I needed a way to confirm the water pump at a remote location was functioning properly over time. The goal was to ensure the pressure is kept at a consistent 40 psi. 

 

The solution was relatively inexpensive ($15 in parts) for an easily assembled unit using an automotive pressure sensor. The pressure sensor is wired to a ADS1115 module which then converts to voltage back to a pressure reading. The pressure reading is sent every 5 minutes to a remote server which logs the data and makes the readings available through a web page with line charts.

 

The server is an HP Elitedesk Pro mini pc with linux running through cloudflare (also free). 

 

Chart on server showing pressure readings over last 2 days

22.03.2024_11.29.30_REC.png

Components:

pressure_sensor.pngcircuit_image.png

3d model for case designed for free with selfcad (www.selfcad.com)

2024-02-11_23-02.png

https://www.thingiverse.com/thing:6481134

20240212_085531.jpg

20240218_154524.jpg


 

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);
}