Code for pulse output from water meter

Hello everyone.
I'm working on a project where I want to remotely monitor the output of a water filtration system. My hardware setup includes:

I'm pretty new to Arduino, so my code is unrefined, and I'm having trouble with:

  • recording what time a pulse was counted (I've installed the RTC library but don't know how to use it )
  • logging the total volume and total pulse count at the end of a day
  • how to reset the pulse counter & total volume every 24 hours

I'm still working out the data transmission bit, but I'd appreciate some help with the above points !!

  • water meter has two wires: one is connected to GND and the other to pin 2 on the board.


#include <diskio.h>
#include <ff.h>
#include <ffconf.h>


// Global variables
const int pulsePin = 2;       // input pin on board connected to pulse output on meter
volatile unsigned long pulseCount = 0;      // initial pulse counter -- volatile bc it changes inside an interrupt
volatile unsigned long lastPulseTime = 0;  // records last time a pulse was counted -- for debouncing
volatile bool newPulseFlag = false; // tells main loop that a new pulse(s) has come in
volatile unsigned long lastPulseTimestamp = 0;  // stores the time of the last pulse


const unsigned long debounceDelay = 10; // milliseconds -- avoid counting false signals when switch bounces
unsigned long totalGallons = 0; // total volume
unsigned long pulseTimestamp = 0;       // for printing the timestamp in loop()


// Below function runs automatically each time a pulse is detected
void countPulse() {
 unsigned long now = millis();
 if (now - lastPulseTime >= debounceDelay) {
   pulseCount++;
   lastPulseTime = now;
   lastPulseTimestamp = now;   // stores timestamp of pulse
   newPulseFlag = true;
 }
}


void setup() {
 Serial.begin(9600);
 while (!Serial);


 pinMode(pulsePin, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(pulsePin), countPulse, RISING);


 Serial.println("DAE MJ-75 Gallon Pulse Counter Ready");
}


void loop() {
 if (newPulseFlag) {
   noInterrupts();
   unsigned long newPulses = pulseCount;
   pulseCount = 0;
   pulseTimestamp = lastPulseTimestamp;  // Copy timestamp safely
   newPulseFlag = false;
   interrupts();


   totalGallons += newPulses;


   Serial.print("New pulse(s): ");
   Serial.print(newPulses);
   Serial.print(" | Total Gallons: ");
   Serial.println(totalGallons);
   Serial.print(" | Last Pulse Time (ms since start): ");
   Serial.println(pulseTimestamp);
 }
}










hi @aacuil, welcome to the forum. THX for posting code correctly first time! A low bar many seem to trip over.

Are you having no trouble with a simpler sketch that just shows you another gallon has past through the meter? Are you getting the printing? BTW it's 2025, you can safely bump up the baud rate to modern "fast" at 115200. Set the serial monitor to match.

I read it is one pulse per gallon. It looks like you are correctly using the dry contact reed switch output.

What is to be done with the time stamps, one for every gallon?

RTCs are very easy to use, I suggest you find an unrelated project or example and develop the ability to set and read an RTC.

Here's one and it will also introduce you to the wokwi simulator. The RTC used is an older model, but the code should work with the DS3231 work at the basic level of HH:MM:SS.

The other things you are having trouble with seem like trivial matters compared to the sketch you present, which makes me ask if you wrote it or found it or commissioned it or what.

A missing item of possible interest is the length of the pulse coming from the meter. I did not look beyond the end of my nose for that, but it might mean you could ditch the interrupt approach to monitoring the meter.

a7

Where's one?

A good learning source for things like an RTC is to load up a library and look at the examples that come with it. Here are two good libraries with lot's of examples.

1 Like

Hi! Thanks for responding! I'll look through the links you provided!

I'm trying to get a time stamp for every gallon/pulse counted so i can have something like a time log of the data collected throughout the day.

I started off by writing code for a simple pulse counter with debouncing; then cobbled the rest from posts I found on timestamping. Once I started adding these bits of code, I got lost quickly.
I apologise if the points I brought up seem simple; the pulse counter/volume reset and the total volume&pulse count require RTC stuff (since I'll be collecting this data at a specific time every day) so I'm struggling to code these parts accurately. I don't know how to do these bits. I hope this explains things better.

thanks!

Is this something specific to Uno R4? Like a software RTC that gets time from NTP servers through it's WiFi connection?

The reason I ask is because this seems strange:

What's the mysterious "cellular device" for? Is there no WiFi with internet connectivity where the circuit will be? If there is no WiFi, why did you choose an Uno R4 WiFi instead of the regular Uno R4 ("minima")?

quote="evanmars, post:3, topic:1375436"]
Where's one?
[/quote]

Oops. Copy no paste. THX.

a7

1 Like

FYI, the DS1307 is ancient and far less efficient and accurate. I always choose the DS3231 or DS3232.

1 Like

i think it is specific to the UNO R4 -- I installed the following library:

  • NTPClient library (GitHub - arduino-libraries/NTPClient: Connect to a NTP server)
    Its documentation includes an example that shows how to set the RTC (Real Time Clock) on the Portenta C33 / UNO R4 WiFi to the current date and time retrieved from an NTP server on the Internet (pool.ntp.org)., and then the current time from the RTC is printed to the Serial port.
    I used this example and was able to upload it to my board with no issues.

The project was initially a simple remote water system deployed in a specific space (with WiFi connection) so the Uno R4 WiFi was perfect for the task. Its scope expanded to creating a system that could be deployed in a remote area (without WiFi ) -- but still using the same board.
So i'm now trying to set up a system where:

  • the board sends data via Bluetooth to a nearby phone with a sim card
  • the phone sends this data via cell network to a specific phone number/phone
    It's a bit convoluted but it's what I'm working with at the moment

@aacuil Good points. From what the OP has added, it sounds like NTP is what he needs, not an RTC. But the RTC is cheap and easy to code, so either will work. Normally, the battery backup is a deal maker, but it sounds like he has to have internet, therefore, power up in any case, so that makes the NTP case. Either solution is a minor amount of code.

Does Uno R4 have Bluetooth?

No matter, it definitely has WiFi. The phone can create a WiFi hot-spot which the R4 can connect to, to allow it's NTP-based software RTC to work.

If there is WiFi where the project will be installed, it's easy to configure it without the phone. It's just a different WiFi access point (SSID/password).

The R4 does have Bluetooth.

This is a really good point, I feel silly that I had not considered it at all. Thank you!

How about a situation where I may only have a basic cellular connection? Wouldn't this make time logging impossible ? In which case, maybe I should forego that part (timestamping each pulse counted) and simply have the total pulse count/volume of water be the data point sent?

It's your party. It shouldn't be too hard to get all your goals met here. So maybe don't forego anything, or say "postpone", as in leave the part that seems the hardest for last. If you are reasonably careful and keep in mind where you want to land up, you wont code yourself into a corner where adding more cowbell logging or reporting is harder.

The code currently does, or tries, time stamps in millis(). Time since reset or power up.

With an RTC or accurate time available, you can use a time that relates to the clock time. A handy thing is Unix time, the number of seconds since the beginning of time (00:00 1 January 1970).

A good RTC library or adding another or two will let you think about time in that way, back and forth. It makes times convenient integers, so the recording is just the same as if you were dealing with millis();

Try to think about the various pieces separately. I'm sure you can add to accumulate, and reset to zero to, um, reset using simple code.

Figure out the RTC or however you get time without worrying about anything else.

Those are problems to solve before you get to combining an ability to produce the time number, and the accumulation, which seems already to be in your sketch with miilis(); logically you can use any number same as millis() gave you - why I thought it would be simple.

Once it is easy, you'll wonder why you thought it was hard. Welcome to programming. :expressionless:

a7

Yeth. I don't use a library, and the code I wrote works perfectly on both DS1307 and DS3231 RTCs. If all you want is HH:MM:SS, the code works. The DS3231, genuine units anyway, is very accurate.

The wokwi example, which I have just taken the trouble to test with an UNO and a DS3231 works perfectly, as I mentioned it might.

I added to the setup() a bit of code so you can at least edit in a time that is more like now. @aacuil will want to get the time from somewhere, that's another little detail to be handled when the mood is right.

void setup () {
  Serial.begin(115200);

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }

  // Set the time manually here (year, month, day, hour, minute, second)
  // Example: April 21, 2025 at 15:30:00
  rtc.adjust(DateTime(2025, 4, 21, 15, 30, 0));

  Serial.println("RTC time set!");
}

HTH

a7

I used to have (may still have somewhere in the few hundred sketches I have) a routine for entering a starting date/time from the serial input. After that it's good for more than 5 years.

I'll take your advice and just work on figuring out this part of the project for now.

i hope i can get to the easy bit soon; sounds much more enjoyable :expressionless:

this might be trivial to ask but i think it's part of why I'm struggling with the RTC stuff: I downloaded an NTP-RTC library and uploaded a sketch that set the time and date to my board. Do I have to upload this sketch to the board every single time I turn it on? or once it's set, there's an internal clock that'll keep time even when the board isn't powered on?

this is very helpful thanks! It'll work as a solid contingency if the RTC stuff isn't available ... I've asked this below also but: I downloaded an NTP-RTC library and uploaded a sketch that set the time and date to my board. Do I have to upload this sketch to the board every single time I turn it on? or once it's set, there's an internal clock that'll keep time even when the board isn't powered on?

Do you mean 0.5 years until DST (daylight savings).
Leo..

1 Like