Greetings, Iβve been using Blynk for years, soon after the Kickstarter, quietly lurking, making dozens of projects without much problem even though I still consider myself quite a noob.
But this one has me stumped and I donβt even know where to look to find the problem. This project is trying to log water consumption from 2 separate water systems in our Overland Truck. Our water tanks are pressurized stainless steel kegs and thus we canβt easily see our remaining water supply. One system is for our purified drinking water, it has 2 stainless float switches that trip at 10L and 20L of water remaining and now also a flow meter. And the second set of tanks is for wash water that we get from random taps along the way, this also has a separate flow meter.
I have the flow meters calibrated perfectly - They measure to the mL as close as I can verify with a measuring cup or filling several 1l bottles etc - itβs spot on and works perfectlyβ¦ Until it glitches.
The problem Iβm having is that once or twice a day it will just drop 2 or 3 liters from the count, and oddly itβs usually in the middle of the night, and itβs usually on both water systems. In the screenshot below you can see this at 1:30am and again at 3:30am.
In an attempt to track it down, I disconnected one of the flow meters and tied the signal pin to ground and it still glitches in the same way in time with the other. For this reason, I donβt think itβs hardware.
Because it often happens when weβre sleeping I started logging the serail data showing the flow rate and consumption, but as shown below there is no flow being detected between 17:23 and 08:41, but yet the consumption jumped by ~2 liters in the middle of the night. (the event isnβt logged because it only writes debugs when there is flow)
[17:23:06:405] Flowing: 2.6L/minββ
[17:23:06:405] Flowing: 43mL/Secββ
[17:23:06:438] Drinking Water Remaining: 15.59Lββ
[17:23:07:406] Flowing: 1.0L/minββ
[17:23:07:406] Flowing: 18mL/Secββ
[17:23:07:439] Drinking Water Remaining: 15.57Lββ
[08:41:19:931] Flowing: 0.1L/minββ
[08:41:19:931] Flowing: 1mL/Secββ
[08:41:19:965] Drinking Water Remaining: 13.71Lββ <β{ Here the water remaining jumps by ~2 liters}
The code below is taken from Pkarunβs GitHub and was nearly perfect for my needs, I only duplicated everything to track two separate flow meters and added my float switches.
β’ Hardware Details: Wemos D1 mini, 2 Flow Meters, 2 Float Switches
β’ Smartphone OS is Android 10
β’ Currently using the Blynk server
/*
Using Code modified from:
Blynk Flow Sensor Water Meter- Calculates Total Water Consumption.
Source: https://github.com/pkarun/Blynk-Flow-Sensor-Water-Meter
*/
//#define BLYNK_PRINT Serial // Uncomment for debugging
#include "settings.h"
#include "secret.h" // <<--- UNCOMMENT this before you use and change values on config.h tab
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
//#include <ESP8266mDNS.h> // For OTA with ESP8266
#include <WiFiUdp.h> // For OTA
#include <ArduinoOTA.h> // For OTA
BlynkTimer timer;
int BLYNKneedsZero = 0;
int BLYNKneedsUpdate = 0;
int topFloatTripped = 0;
int bottomFloatTripped = 0;
volatile long DRINKpulseCount = 0;
volatile long WASHpulseCount = 0;
float DRINKflowRate;
float WASHflowRate;
unsigned int DRINKflowMilliLitres;
unsigned int WASHflowMilliLitres;
unsigned long DRINKtotalMilliLitres;
unsigned long WASHtotalMilliLitres;
float DRINKtotalLitres;
float WASHtotalLitres;
float DRINKtotalLitresold;
float WASHtotalLitresold;
unsigned long DRINKoldTime;
unsigned long WASHoldTime;
BLYNK_CONNECTED() { // runs once at device startup, once connected to server.
Blynk.syncVirtual(VPIN_TOTAL_LITERS_DRINK); //gets last know value of virtual pin
Blynk.syncVirtual(VPIN_TOTAL_LITERS_WASH); //gets last know value of virtual pin
}
// Restores last known liter count values from the virtual pin on the Blynk server
BLYNK_WRITE(VPIN_TOTAL_LITERS_DRINK)
{
DRINKtotalLitresold = param.asFloat();
}
BLYNK_WRITE(VPIN_TOTAL_LITERS_WASH)
{
WASHtotalLitresold = param.asFloat();
}
BLYNK_WRITE(VPIN_SET_DRINK) { // Set Water Level in PUSH mode on virtual pin V24
int setLitersDrink = param.asInt();
Serial.println("Setting Drinking Water Level");
Blynk.virtualWrite(VPIN_TOTAL_LITERS_DRINK, setLitersDrink);
Blynk.virtualWrite(VPIN_FLOW_RATE_DRINK, 0);
DRINKflowRate = 0;
DRINKflowMilliLitres = 0;
DRINKtotalMilliLitres = 0;
DRINKtotalLitres = setLitersDrink;
DRINKtotalLitresold = setLitersDrink;
Blynk.virtualWrite(VPIN_SET_DRINK, " ");
topFloatTripped = 0;
bottomFloatTripped = 0;
Blynk.virtualWrite(VPIN_TOP_FLOAT, 0);
Blynk.virtualWrite(VPIN_BOTTOM_FLOAT, 0);
Blynk.setProperty(VPIN_TOTAL_LITERS_DRINK, "color", BLYNK_BLUE);
}
BLYNK_WRITE(VPIN_SET_WASH) { // Set Water Level in PUSH mode on virtual pin V24
int setLitersWASH = param.asInt();
Serial.println("Setting WASHing Water Level");
Blynk.virtualWrite(VPIN_TOTAL_LITERS_WASH, setLitersWASH);
Blynk.virtualWrite(VPIN_FLOW_RATE_WASH, 0);
WASHflowRate = 0;
WASHflowMilliLitres = 0;
WASHtotalMilliLitres = 0;
WASHtotalLitres = setLitersWASH;
WASHtotalLitresold = setLitersWASH;
Blynk.virtualWrite(VPIN_SET_WASH, " ");
//Blynk.setProperty(VPIN_TOTAL_LITERS_WASH, "color", BLYNK_YELLOW);
}
void DRINKpulseCounter()
{
DRINKpulseCount++;
}
void WASHpulseCounter()
{
WASHpulseCount++;
}
void flow()
{
if ((millis() - DRINKoldTime) > 1000) // Only process counters once per second
{
detachInterrupt(PULSE_PIN_DRINK);
DRINKflowRate = ((1000.0 / (millis() - DRINKoldTime)) * DRINKpulseCount) / FLOW_CALIBRATION;
DRINKoldTime = millis();
DRINKflowMilliLitres = (DRINKflowRate / 60) * 1000;
DRINKtotalMilliLitres += DRINKflowMilliLitres;
DRINKtotalLitres = DRINKtotalLitresold - DRINKtotalMilliLitres * 0.001; // CHANGED THIS TO SUBTRACT AS WE WANT TO COUNT DOWN
unsigned int frac;
if (DRINKflowRate > 0) {
// Print the flow rate for this second in liters / minute
Serial.print("Flowing: ");
Serial.print(int(DRINKflowRate)); // Print the integer part of the variable
Serial.print("."); // Print the decimal point
frac = (DRINKflowRate - int(DRINKflowRate)) * 10; // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
Serial.print(frac, DEC) ; // Print the fractional part of the variable
Serial.println("L/min");
Serial.print("Flowing: "); // Print the number of liters flowed in this second
Serial.print(DRINKflowMilliLitres);
Serial.println("mL/Sec");
Serial.print("Drinking Water Remaining: "); // Print the cumulative total of liters flowed since starting
Serial.print(DRINKtotalLitres);
Serial.println("L");
BLYNKneedsUpdate = 1;
BLYNKneedsZero = 1;
}
if (DRINKflowRate == 0 & BLYNKneedsZero == 1) {
BLYNKneedsUpdate = 1;
BLYNKneedsZero = 0;
}
DRINKpulseCount = 0; // Reset the pulse counter so we can start incrementing again
attachInterrupt(PULSE_PIN_DRINK, DRINKpulseCounter, FALLING); // Enable the interrupt again now that we've finished sending output
detachInterrupt(PULSE_PIN_WASH);
WASHflowRate = ((1000.0 / (millis() - WASHoldTime)) * WASHpulseCount) / FLOW_CALIBRATION;
WASHoldTime = millis();
WASHflowMilliLitres = (WASHflowRate / 60) * 1000;
WASHtotalMilliLitres += WASHflowMilliLitres;
WASHtotalLitres = WASHtotalLitresold - WASHtotalMilliLitres * 0.001; // CHANGED THIS TO SUBTRACT AS WE WANT TO COUNT DOWN
//unsigned int frac; //Don't need this twice
if (WASHflowRate > 0) {
// Print the flow rate for this second in liters/minute
Serial.print("Flowing: ");
Serial.print(int(WASHflowRate)); // Print the integer part of the variable
Serial.print("."); // Print the decimal point
frac = (WASHflowRate - int(WASHflowRate)) * 10; // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
Serial.print(frac, DEC) ; // Print the fractional part of the variable
Serial.println("L/min");
Serial.print("Flowing: "); // Print the number of liters flowed in this second
Serial.print(WASHflowMilliLitres);
Serial.println("mL/Sec");
Serial.print("Washing Water Remaining: "); // Print the cumulative total of liters flowed since starting
Serial.print(WASHtotalLitres);
Serial.println("L");
BLYNKneedsUpdate = 1;
BLYNKneedsZero = 1;
}
if (WASHflowRate == 0 & BLYNKneedsZero == 1) {
BLYNKneedsUpdate = 1;
BLYNKneedsZero = 0;
}
WASHpulseCount = 0; // Reset the pulse counter so we can start incrementing again
attachInterrupt(PULSE_PIN_WASH, WASHpulseCounter, FALLING); // Enable the interrupt again now that we've finished sending output
}
}
void sendtoBlynk() // In this function we are sending values to blynk server
{
if (digitalRead(PIN_TOP_FLOAT) == 0 && (topFloatTripped) == 0) //When the Top float trips for the first time.
{
Blynk.virtualWrite(VPIN_TOP_FLOAT, 255);
Blynk.setProperty(VPIN_TOTAL_LITERS_DRINK, "color", BLYNK_YELLOW);
// DRINKtotalLitres = 30;
// DRINKtotalMilliLitres = 30000;
topFloatTripped = 1;
Blynk.notify("30% Water Level Float Tripped");
Serial.print("30% Water Level Float Tripped at "); // Print the cumulative total of liters flowed since starting
Serial.print(DRINKtotalLitres);
}
else if (digitalRead(PIN_TOP_FLOAT) == 1 && (topFloatTripped) == 1) // When it Un-Trips, ie; goes back up or sloshes
{
Blynk.virtualWrite(VPIN_TOP_FLOAT, 0);
}
else if (digitalRead(PIN_TOP_FLOAT) == 0 && (topFloatTripped) == 1) // Then It goes down again...
{
Blynk.virtualWrite(VPIN_TOP_FLOAT, 255);
}
if (digitalRead(PIN_BOTTOM_FLOAT) == 0 && (bottomFloatTripped) == 0)
{
Blynk.virtualWrite(VPIN_BOTTOM_FLOAT, 255);
digitalWrite(BLUE_LED, LOW); // LED On - Stupid LED is inverted
Blynk.setProperty(VPIN_TOTAL_LITERS_DRINK, "color", BLYNK_RED);
// DRINKtotalLitres = 15;
// DRINKtotalMilliLitres = 15000;
bottomFloatTripped = 1;
Blynk.notify("15% Water Level Float Tripped");
Serial.print("15% Water Level Float Tripped at "); // Print the cumulative total of liters flowed since starting
Serial.print(DRINKtotalLitres);
}
else if (digitalRead(PIN_BOTTOM_FLOAT) == 1 && (bottomFloatTripped) == 1)
{
Blynk.virtualWrite(VPIN_BOTTOM_FLOAT, 0);
digitalWrite(BLUE_LED, HIGH); // LED Off - Stupid LED is inverted
}
else if (digitalRead(PIN_BOTTOM_FLOAT) == 0 && (bottomFloatTripped) == 1)
{
Blynk.virtualWrite(VPIN_BOTTOM_FLOAT, 255);
digitalWrite(BLUE_LED, LOW); // LED On - Stupid LED is inverted
}
if (BLYNKneedsUpdate = 1) {
Blynk.virtualWrite(VPIN_TOTAL_LITERS_DRINK, DRINKtotalLitres); // Total water consumption in liters (L)
Blynk.virtualWrite(VPIN_FLOW_RATE_DRINK, DRINKflowRate); // Displays the flow rate for this second in liters / minute (L/min)
Blynk.virtualWrite(VPIN_TOTAL_LITERS_WASH, WASHtotalLitres); // Total water consumption in liters (L)
Blynk.virtualWrite(VPIN_FLOW_RATE_WASH, WASHflowRate); // Displays the flow rate for this second in liters / minute (L/min)
BLYNKneedsUpdate = 0;
}
}
void batteryBlynk()
{
float BatteryVoltage = (analogRead(PIN_CHASSIS_VOLTAGE)) * 0.01554955;
Blynk.virtualWrite(V10, BatteryVoltage);
// if (BatteryVoltage < 12); {
// //Blynk.notify("Chassis Battery Below 12 Volts");
// Blynk.notify(BatteryVoltage);
// }
}
void setup()
{
Serial.begin(9600);
Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS);
ArduinoOTA.setHostname(OTA_HOSTNAME); // For OTA - Use your own device identifying name
ArduinoOTA.begin(); // For OTA
DRINKpulseCount = 0;
WASHpulseCount = 0;
DRINKflowRate = 0.0;
WASHflowRate = 0.0;
DRINKflowMilliLitres = 0;
WASHflowMilliLitres = 0;
DRINKtotalMilliLitres = 0;
WASHtotalMilliLitres = 0;
DRINKoldTime = 0;
WASHoldTime = 0;
DRINKtotalLitresold = 0;
WASHtotalLitresold = 0;
BLYNKneedsUpdate = 0;
pinMode(BLUE_LED, OUTPUT);
digitalWrite(BLUE_LED, HIGH); // LED Off - Stupid LED is inverted
pinMode(PULSE_PIN_DRINK, INPUT_PULLUP); // Initialization of the variable "PULSE_PIN_DRINK" as INPUT
pinMode(PULSE_PIN_WASH, INPUT_PULLUP); // Initialization of the variable "PULSE_PIN_DRINK" as INPUT
pinMode(PIN_TOP_FLOAT, INPUT_PULLUP); // Initialization of the variable "PIN_TOP_FLOAT" as INPUT
pinMode(PIN_BOTTOM_FLOAT, INPUT_PULLUP); // Initialization of the variable "PIN_BOTTOM_FLOAT" as INPUT
attachInterrupt(PULSE_PIN_DRINK, DRINKpulseCounter, FALLING);
attachInterrupt(PULSE_PIN_WASH, WASHpulseCounter, FALLING);
timer.setInterval(1000L, sendtoBlynk); // send values blynk server every sec (if it needs updating)
timer.setInterval(60000L, batteryBlynk); // send values blynk server every 60 sec
}
void loop()
{
Blynk.run();
ArduinoOTA.handle(); // For OTA
timer.run();
flow();
}
I would be very grateful for any advice and would be more than willing to commission some assistance to get this going, I also have several other projects on the go that have stalled out because Iβm running into problems, and would be happy to have someone on retainer to help squash bugsβ¦
Thanks in advance,
Jason