Na das kann Zufall sein. Denn Du gibst ja keine Messwerte aus, sondern schon errechnete. Und da ist Dein Problem.
Du benutzt einen Calibrierfaktor, der angepasst an Deine Situation ist.
Ich sehe mehrere Schwachstellen und hab die mal reinkommentiert:
if ((millis() - oldTime) > 1000) // hier ist millis()-oldTime mindestens 1001
{
detachInterrupt(WATERFLOWPIN);
flowRate = ((1000.0 / (millis() - oldTime)) * waterPulseCount) / calibrationFactor; // rechnest aber mit 1000 und hier ist noch mehr Zeit vergangen
oldTime = millis(); // hier merkst Du Dir die Zeit
flowGardenLiters = (flowRate / 60) * 1000; // was ist das für eine 1000?
waterPulseCount = 0;
attachInterrupt(digitalPinToInterrupt(WATERFLOWPIN), waterConsumption_ISR, FALLING); // aber erst ab hier misst Du wieder
}
Baue Deinen code blockadefrei und ohne delay().
Alles was Du an Zeit verbratest, und auch wenn nicht genau auf Deine 1000ms kommst, kannst Du mit rechnen lassen!
Grundsätzlich schon mal als Ansatz:
tikTime = millis();
lastCount = 0;
intervall = 1000;
if (tikTime - oldTime >= intervall)
{
detachInterrupt(WATERFLOWPIN);
lastCount = waterPulseCount;
waterPulseCount = 0;
oldTime = millis();
attachInterrupt(digitalPinToInterrupt(WATERFLOWPIN), waterConsumption_ISR, FALLING);
flowRate = (float)((intervall / (tikTime - oldTime)) * lastCount) / calibrationFactor;
flowGardenLiters = (flowRate / 60) * 1000;
}
Du musst, so wie in der ISR, auch hier schnellst möglich Deinen Wert loswerden und den Interrupt wieder aktivieren.
Versuchs mal mit.