Skip to content

Instantly share code, notes, and snippets.

@Tugzrida
Last active January 1, 2024 16:46
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Tugzrida/2c9fcf52571909cf60cbafc32413daf0 to your computer and use it in GitHub Desktop.
Save Tugzrida/2c9fcf52571909cf60cbafc32413daf0 to your computer and use it in GitHub Desktop.
Prometheus Smart Water Meter project for the ESP32

Prometheus Water Meter

This is a fairly involved process as it seems that no one currently makes a pre-made product that measures water usage from a household meter.

It took quite a while to set up due to WiFi issues and the flow rate code still needs some work as the output is semi-random at the moment.

If you get stuck anywhere I'm happy to answer questions provided this doesn't go viral 😂

Components:

Hardware:

Basically all that needs to happen is that the output of the pulse probe is connected between A GND and D7 on the ESP32.

I did this by cutting off the probe wire from the plug as supplied by Aquatrip, then soldering on an extension wire and sealing the joint in heatshrink.

The wire can then be run from the water meter to inside and into the ESP32.

Software:

The attached Arduino sketch can be uploaded to the board with the Arduino IDE, after following the DFRobot instructions to install the Beetle board.

Before uploading the sketch, you'll need to substitute your WiFi details, and also the timezone if you aren't in Sydney. The required format for the timezone is a bit convoluted, but there's a reference here.

Upon powering up, the board will briefly turn on the green led, then turn it back off until a WiFi connection is made. This specific board seems to have fairly poor reception so close proximity to an access point is necessary.

Once working, the board will be waiting for http connections on port 80 and will serve the litres used today and current flowrate in Prometheus text exposition format, along with a couple of debug headers.

Depending on how your water meter sends pulses, you may also need to change the volPerPulse variable to ensure an accurate reading. You can do this by checking the change in the reported water usage before and after filling up a bucket with a known capacity.

Once it's working, you can add a job to prometheus with something like this:

scrape_configs:
  - job_name: 'water'
    scrape_interval: 30s
    static_configs:
      - targets: ['ESP32_IP_ADDRESS']

Then onto Grafana dashboard design.

#include <WiFi.h>
const int pulseDebounce = 250; //50
const int flowRateTimeout = 20000;
const float volPerPulse = 0.5;
const float flowRatePerMs = 60000;
volatile unsigned int pulses = 0;
volatile unsigned long secondLastPulse = 0;
volatile unsigned long lastPulse = 0;
int lastResetDate = 0;
int newLineCount = 0;
WiFiServer promSrv(80);
void setup() {
pinMode(D9, OUTPUT);
digitalWrite(D9, LOW);
Serial.begin(9600);
Serial.print("Connecting to WiFi");
WiFi.begin("WIFI_SSID", "WIFI_PASSWORD");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("Connected as ");
Serial.println(WiFi.localIP());
configTzTime("AEST-10:00:00AEDT-11:00:00,M10.1.0/02:00:00,M4.1.0/03:00:00", "au.pool.ntp.org");
struct tm localTime;
getLocalTime(&localTime);
lastResetDate = localTime.tm_mday;
Serial.println(&localTime, "It's currently %A %d %B %Y %H:%M:%S %Z");
promSrv.begin();
pinMode(D7, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(D7), pulse, RISING);
Serial.println("Ready!");
digitalWrite(D9, HIGH);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Reconnecting to WiFi");
WiFi.begin();
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("Connected as ");
Serial.println(WiFi.localIP());
}
WiFiClient client = promSrv.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n') {
newLineCount++;
if (newLineCount == 2) {
// Client has finished request, send response
struct tm localTime;
getLocalTime(&localTime);
if (localTime.tm_mday != lastResetDate) {
pulses = 0;
lastResetDate = localTime.tm_mday;
}
client.print("HTTP/1.1 200 OK\n");
client.print("Content-Type: text/plain; charset=UTF-8; version=0.0.4\n");
client.print("Access-Control-Allow-Origin: *\n");
client.print(&localTime, "X-DateTime: %A %d %B %Y %H:%M:%S %Z\n");
client.print("X-WiFi: ");
client.print(WiFi.SSID());
client.print(" (");
client.print(WiFi.BSSIDstr());
client.print(") at ");
client.print(WiFi.RSSI());
client.print("dBm\n");
client.print("Connection: close\n\n");
client.print("# HELP water_today_litres Total litres of water used since midnight.\n");
client.print("# TYPE water_today_litres counter\n");
client.print("water_today_litres ");
client.print(pulses * volPerPulse);
client.print("\n\n");
client.print("# HELP water_flowrate_lpm Current flowrate in litres per minute.\n");
client.print("# TYPE water_flowrate_lpm gauge\n");
client.print("water_flowrate_lpm ");
if ((millis() - lastPulse < flowRateTimeout) && secondLastPulse != lastPulse) {
client.print(volPerPulse / ((lastPulse - secondLastPulse) / flowRatePerMs));
} else {
client.print(0.0);
}
client.print("\n");
client.stop();
}
} else if (c != '\r') {
newLineCount = 0;
}
}
}
}
}
void pulse() {
if (millis() - lastPulse > pulseDebounce) {
pulses++;
secondLastPulse = lastPulse;
lastPulse = millis();
}
}
@tumharaashish
Copy link

Hi bro i need your help regarding my final years project,iam building an indoor air quality using bme280,esp32 DFRobot,c02 sensor DFRobot monitoring every thing is completed only help needed is in the Prometheus and grafana part i am unable to see any data of Prometheus data source in grafana no metrics found
Help is really needed 🙏🙏🙏
I am just a beginner to contact me pls refer my email ashishthakurt15@gmail.com

@tumharaashish
Copy link

Pls bro help me

@tumharaashish
Copy link

We can connect with an online meet i will share my screen to show the trouble
For more details you can email me
🙏🙏🙏

@Tugzrida
Copy link
Author

Hi @tumharaashish, I'm not available for direct support via screen share, but I'll point you to the following Grafana documentation. It sounds like you have Grafana and Prometheus working, and just need to add Prometheus as a data source in the Grafana config.

@tumharaashish
Copy link

I have added Prometheus data source in grafana and updated config.h using https://github.com/grafana/diy-iot
Main problem is iam unable to see any data⬇️⬇️
Screenshot (6)

@Tugzrida
Copy link
Author

@tumharaashish I'm not familiar with Grafana cloud so all I can suggest is looking in the prometheus interface to see if the series are present there, or maybe doing a packet capture on your device to ensure it's pushing the metrics correctly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment