Ground tank and Roof tank monitor with flow meter (based on ultrasonic data).Water level accurate to +/- 1 litre.Both mcu are working 24/7 no server disconnect or freeze.Also sync relay data to SinricPro Server mean Alexa and Google home support.
Requirement:
2x wemos d1 mini
1x ds18b20
2x Jsn sr04t
1x solid state relay
Code:
kayyumuddin/water-tank: Dual Water Tank Monitor System with Switch Control and Accurate Data log (github.com)
Demo:
1 Like
Roof Tank:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <Ultrasonic.h>
#include <RunningMedian.h>
#include <SimpleKalmanFilter.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "SinricPro.h"
#include "SinricProSwitch.h"
#include "MiniUpCredentials.h"
OneWire oneWire(D7);
DallasTemperature tempSensor(&oneWire);
DeviceAddress tempSensorAddr = {0x28, 0x3C, 0x58, 0x77, 0x91, 0x0B, 0x02, 0x17};
Ultrasonic pingSensor(D5, D6);
RunningMedian tempMedianFilter = RunningMedian(3);
RunningMedian pingMedianFilter = RunningMedian(5);
SimpleKalmanFilter kalmanFilter(3.0, 3.0, 0.1);
BlynkTimer timer;
float litre, flow_rate, temp;
double soundSpeed(double c)
{
double s = 331.3 + 0.606 * c;
return s / 20000.0;
}
void pingTimer()
{
float rv = pingSensor.readTiming() * soundSpeed(temp);
pingMedianFilter.add(rv);
rv = (MAX_HEIGHT - pingMedianFilter.getMedian()) / DIVIDE_RATIO;
litre = constrain(kalmanFilter.updateEstimate(rv), 0, 100) * MULTIPLY_RATIO;
}
void flowTimer()
{
static float pl;
flow_rate = litre - pl;
pl = litre;
}
void tempTimer()
{
tempSensor.requestTemperatures();
float rv = tempSensor.getTempC(tempSensorAddr);
if (!isnan(rv) && rv > -10 && rv < 70)
{
tempMedianFilter.add(rv);
}
temp = tempMedianFilter.getMedian();
Blynk.virtualWrite(V4, temp);
}
void sendLitre()
{
int v = round(litre);
Blynk.virtualWrite(V2, v);
}
void sendRate()
{
String v = String(flow_rate, 1);
Blynk.virtualWrite(V3, v);
}
void timerSetup()
{
timer.setInterval(10000L, tempTimer);
delay(40);
timer.setInterval(500L, pingTimer);
delay(40);
timer.setInterval(60000L, flowTimer);
delay(40);
timer.setInterval(30000L, sendRate);
delay(40);
timer.setTimeout(30000L, []()
{ timer.setInterval(1000L, sendLitre); });
}
BLYNK_CONNECTED()
{
Blynk.syncAll();
}
void switchSetup()
{
digitalWrite(RELAY_PIN, HIGH);
pinMode(RELAY_PIN, OUTPUT);
}
bool onPowerState(const String &deviceId, bool &state)
{
bool relay_state = state;
Blynk.virtualWrite(V10, relay_state);
digitalWrite(RELAY_PIN, relay_state ? LOW : HIGH);
return true;
}
BLYNK_WRITE(V10)
{
bool relay_state = param.asInt();
SinricProSwitch &mySwitch = SinricPro[SWITCH_ID];
mySwitch.sendPowerStateEvent(relay_state);
digitalWrite(RELAY_PIN, relay_state ? LOW : HIGH);
}
void setup()
{
switchSetup();
tempSensor.begin();
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, PASS);
ArduinoOTA.setHostname(HOSTNAME);
ArduinoOTA.begin();
Blynk.config(AUTH, SERVER_ADDRESS, 80);
Blynk.connect();
SinricProSwitch &mySwitch = SinricPro[SWITCH_ID];
mySwitch.onPowerState(onPowerState);
SinricPro.begin(APP_KEY, APP_SECRET);
timerSetup();
}
void loop()
{
ArduinoOTA.handle();
Blynk.run();
timer.run();
SinricPro.handle();
}
Ground Tank:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <Ultrasonic.h>
#include <RunningMedian.h>
#include <SimpleKalmanFilter.h>
#include "SinricPro.h"
#include "SinricProSwitch.h"
#include "MiniDownCredentials.h"
Ultrasonic pingSensor(D7, D6);
RunningMedian medianFilter = RunningMedian(5);
SimpleKalmanFilter kalmanFilter(3.0, 3.0, 0.1);
BlynkTimer timer;
float litre, flow_rate;
void pingTimer()
{
float rv = pingSensor.readTiming() / 57.0;
medianFilter.add(rv);
rv = (MAX_HEIGHT - medianFilter.getMedian()) / DIVIDE_RATIO;
litre = constrain(kalmanFilter.updateEstimate(rv), 0, 100) * MULTIPLY_RATIO;
}
void flowTimer()
{
static float pl;
flow_rate = litre - pl;
pl = litre;
}
void sendLitre()
{
int v = round(litre);
Blynk.virtualWrite(V2, v);
}
void sendRate()
{
String v = String(flow_rate, 1);
Blynk.virtualWrite(V3, v);
}
void timerSetup()
{
timer.setInterval(500L, pingTimer);
delay(40);
timer.setInterval(60000L, flowTimer);
delay(40);
timer.setInterval(30000L, sendRate);
delay(40);
timer.setTimeout(30000L, []()
{ timer.setInterval(1000L, sendLitre); });
}
BLYNK_CONNECTED()
{
Blynk.syncAll();
}
void switchSetup()
{
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
}
bool onPowerState(const String &deviceId, bool &state)
{
bool relay_state = state;
Blynk.virtualWrite(V10, relay_state);
digitalWrite(RELAY_PIN, relay_state ? HIGH : LOW);
return true;
}
BLYNK_WRITE(V10)
{
bool relay_state = param.asInt();
SinricProSwitch &mySwitch = SinricPro[SWITCH_ID];
mySwitch.sendPowerStateEvent(relay_state);
digitalWrite(RELAY_PIN, relay_state ? HIGH : LOW);
}
void setup()
{
switchSetup();
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, PASS);
ArduinoOTA.setHostname(HOSTNAME);
ArduinoOTA.begin();
Blynk.config(AUTH, SERVER_ADDRESS, 80);
Blynk.connect();
SinricProSwitch &mySwitch = SinricPro[SWITCH_ID];
mySwitch.onPowerState(onPowerState);
SinricPro.begin(APP_KEY, APP_SECRET);
timerSetup();
}
void loop()
{
ArduinoOTA.handle();
Blynk.run();
timer.run();
SinricPro.handle();
}