Hi Pete:
It’s been a while since we chatted. I hope you had a good winter. It’s spring and I’m planning on going up to the cabin. The program you helped my with (December 2021 above) worked really well last summer and actually saved us from a water break - so thanks. At the end of last year I mentioned that I thought I’d like to add a sensor to measure the voltage of the battery at the tank - as it began to fail towards the end of the season. I took your advice and learned about voltage dividers. I created one and attached it to the transmitter at the well head. The transmitter sketch works okay and displays the water depth and voltage. The problem is on the receiving end. I’ve tried to add code to receive, parse and display the voltage. But it doesn’t work I just get a reading of “0”. I have avoided having to rewrite the code to send and receive the data as an array or structure as I’m not quite comfortable with them - so I thought I’d try a simple solution. Obviously it didn’t work. Is there a way of getting the voltage to display along with the water depth and send it along to Blynk2? I’ll attach the transmitter sketch followed by the receiver sketch.
TRANSMITTER SKETCH
/*
* Credits to VDEngineering video for the Kalman filter algorithm:
* https://www.youtube.com/watch?v=ruB917YmtgE
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <LoRa.h>
#include <SPI.h>
LiquidCrystal_I2C lcd(0x3F, 16, 2);
const int echo = 8;
const int trig = 7;
const int maxdist = 450;
const float mindist = 2.5;
//const int R1 = 30000;
//const int R2 = 7500;
double kalman(double U);
double kalman(double U) {
static const double R = 60;
static const double H = 1.00;
static double Q = 10;
static double P = 0;
static double U_hat = 0;
static double K = 0;
K = P * H / (H * P * H + R);
U_hat += +K * (U - H * U_hat);
P = (1 - K * H) * P + Q;
return U_hat;
}
double distance, duration, voltage;
void setup() {
lcd.begin();
lcd.backlight();
delay(1000);
pinMode(trig, OUTPUT);
pinMode(echo, INPUT);
pinMode(A0, INPUT);
while (!Serial)
;
Serial.println("LoRa Receiver");
if (!LoRa.begin(433E6)) {
Serial.println("Starting LoRa failed!");
while (1)
;
}
LoRa.setSpreadingFactor(10);
LoRa.setSignalBandwidth(62.5E3);
LoRa.crc();
}
void loop() {
digitalWrite(trig, LOW);
delayMicroseconds(2);
digitalWrite(trig, HIGH);
delayMicroseconds(10);
digitalWrite(trig, LOW);
duration = pulseIn(echo, HIGH);
distance = (duration * .0133) / 2;
// Define voltage divider resistors
int value = 0;
float R1 = 30000.0;
float R2 = 7500.0;
//Read voltate - may have to adjust 5.00 to input voltage on Vin
value = analogRead(A0);
voltage = value * (5.10 / 1024) * ((R1 + R2) / R2); // should be 5 volts, but adjusted for voltage reading at nano 5v pin
// Kalman filter for distance measurement
double fildist = kalman(distance);
Serial.print("Water is down: ");
Serial.print(fildist);
Serial.print(" inches, Voltage is: ");
Serial.print(voltage);
Serial.println(" V");
delay(500);
// Send packet
LoRa.beginPacket();
LoRa.print(fildist);
LoRa.print(",");
LoRa.print(voltage);
LoRa.endPacket();
delay(200);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Water:");
lcd.print(fildist);
lcd.print(" in");
lcd.setCursor(0, 1);
lcd.print("Voltage:");
lcd.print(voltage);
lcd.print(" V");
if (fildist <= 25) {
digitalWrite(5, LOW);
} else {
digitalWrite(5, HIGH);
}
}
RECEIVER SKETCH
/*
For this example you'll need the following library:
* *
1) Arduino-LiquidCrystal-I2C-library: https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
2) Blynk Library 0.6.1 (if usimg Legacy or latest if using IoT): https://github.com/blynkkk/blynk-library
Conncetions:
D0 (GPIO16) -> RST Pin on LoRa Rx module
D1 (GPIO5) -> LED on U3 connector?
D2 (GPIO4) -> DIO0 Pin on LoRa Rx Module
D3 (GPIO0) -> SDA Pin on OLED Display
D4 (GPIO2) -> SCL Pin on OLED Display
D5 (GPIO14) -> SCK pin on LoRA Rx module
D6 (GPIO12) -> MISO pin on LoRA Rx module
D7 (GPIO13) -> MOSI pin on LoRA Rx module
D8 (GPIO15) -> nSS pin on LoRA Rx module
*/
#include <LoRa.h>
#define BLYNK_PRINT Serial
#include <SPI.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define I2C_SDA 0 // GPIO0 = D3 - redefining I2C pins as D1 is needed by LoRa unit
#define I2C_SCL 2 // GPIO2 = D4
#define ss 15 // GPIO15 = D1
#define rst 16 // GPIO16 = D0
#define dio0 4 // GPIO4 = D2
int LEDPin=5; //Relay and LED pin
int adjustment;
int adjusted_reading;
int tank_to_read;
int voltage;
const int ledPin = 5; // GPIO5 = D1 - warning light that water has dropped beyond preset level
char auth[] = "ZFiawkv0a-UnC_tXeO3Ir0n_FRhEXy1v"; //Enter the Auth code which was send by Blink
char ssid[] = "XXXXXXXXXXXXX"; //Enter your WIFI Name kuggle's_condo_2
char pass[] = "XXXXXXXXXXXXXX"; //Enter your WIFI Password
int wifi_connect_count = 0; // Keep track of how many times we've tried to connect to the WiFi
int wifi_connect_max_retries = 20; // Specify how many attempts we will have at connecting to the WiFi
bool sync_completed = false; // Flag to track when BLYNK_WRITE(V1) has completed
BlynkTimer timer;
void setup()
{
pinMode(ledPin, OUTPUT);
Wire.begin(I2C_SDA, I2C_SCL); // Updated from deprecated wire.pins(sda,scl) command
Serial.begin(9600); // Native baud rate for the NodemCU
lcd.begin(); // iInit the LCD for 16 chars 2 lines
lcd.backlight(); // Turn on the backligt (try lcd.noBaklight() to turn it off)
delay (1000);
Serial.println("LoRa Receiver ");
LoRa.setPins(ss, rst, dio0);
if (!LoRa.begin(433E6))
{
Serial.println("Starting LoRa failed!");
delay(2000);
Serial.println("Restarting ESP...");
ESP.restart(); // Restart the ESP
}
Serial.println("LoRa Started");
lcd.clear();
lcd.print("Waiting");
LoRa.setSpreadingFactor(10);
LoRa.setSignalBandwidth(62.5E3);
LoRa.crc();
WiFi_Connect();
Blynk.config(auth);
send_to_blynk(); // Connect to Blynk then sync the segmented switch at startup
timer.setInterval( 1 * 1000L, take_a_reading); // Existing timer
timer.setInterval(1 * 60 * 1000L, check_connections); // Check that we have a WiFi connection every 1 minute
timer.setInterval(2 * 60 * 1000L, send_to_blynk); // send data to Blynk every 2 minutes (180,000 m/s)
}
void loop()
{
timer.run();
}
void take_a_reading()
{
int packetSize = LoRa.parsePacket();
int reading = LoRa.parseInt();
if (packetSize)
{
adjusted_reading = (reading - adjustment);
Serial.print("Selected tank = ");
Serial.println(tank_to_read);
Serial.print("Actual reading = ");
Serial.println(reading);
Serial.print("Adjustment factor = ");
Serial.println(adjustment);
Serial.print("Adjusted reading = ");
Serial.println(adjusted_reading);
Serial.print("Voltage = ");
Serial.println(voltage);
lcd.setCursor(0, 0); //First line
lcd.print(adjusted_reading);
lcd.print(" inches");
lcd.setCursor(0, 1); //Second line
lcd.print(voltage);
}
if (adjusted_reading >=28 ) //ALARM
{
digitalWrite(LEDPin,HIGH); //ALARM
if(adjusted_reading >=28)
{
Blynk.notify("water level has dropped below 28 inches");
}
timer.setTimeout(1600L, [](){
// Blynk.email("jgroberm@shaw.ca", "water level has dropped below 28 inches");
});
}
else {
digitalWrite(LEDPin,LOW); // play tone of 400Hz for 500 ms
}
}
void send_to_blynk()
{
if (WiFi.status() == WL_CONNECTED)
{
Serial.println ("Connecting to Blynk");
Blynk.connect();
if (Blynk.connected())
{
Serial.println ("Connected");
sync_completed = false;
Blynk.syncVirtual(V1); // force the server to send the latest value for the segmented switch
while (!sync_completed) // Wait until BLYNK_WRITE(V1) has completed
{
Blynk.run();
}
take_a_reading(); // take a reading from the tank indicated by the segmented switch
Blynk.virtualWrite(V0, adjusted_reading); // To Display Widget
Blynk.virtualWrite(V1, voltage); // send voltage to Blynk
Blynk.run();
Blynk.disconnect();
Serial.println ("Blynk Disconnected");
}
else
{
Serial.println (">>>>>>>>>>>> Unable to connect to Blynk <<<<<<<<<<<<");
}
}
else
{
// we get here if we there is no WiFi connection
Serial.println (">>>>>>>>>>>> No WiFi Connection, so Blynk connection not attempted <<<<<<<<<<<<");
}
}
BLYNK_WRITE(V1) // Segmented switch to select tank
{
Serial.println("BLYNK_WRITE(V1) Executed");
tank_to_read = param.asInt();
switch (tank_to_read)
{
case 1:
{
adjustment = 0;
sync_completed = true;
break;
}
case 2:
{
adjustment = 13;
sync_completed = true;
break;
}
case 3:
{
adjustment = 15;
sync_completed = true;
break;
}
case 4:
{
adjustment = 12;
sync_completed = true;
break;
}
}
}
void check_connections()
{
if (WiFi.status() != WL_CONNECTED)
{
WiFi_Connect();
}
else
{
Serial.println(F(">>>> WiFi checked - all good <<<<"));
}
}
void WiFi_Connect() // New functon to handle the connectuon to the WiFi network
{
wifi_connect_count=0; // reset the counter
Serial.println(F("Connecting to WiFi"));
if (WiFi.status() != WL_CONNECTED)
{
WiFi.begin(ssid, pass); // connect to the network
}
while (WiFi.status() != WL_CONNECTED && wifi_connect_count < wifi_connect_max_retries) // Loop until we've connected, or reached the maximum number of attemps allowed
{
delay(500);
wifi_connect_count++;
Serial.print(F("WiFi connection - attempt number "));
Serial.println(wifi_connect_count);
}
if (WiFi.status() == WL_CONNECTED)
{
WiFi.mode(WIFI_STA);
Serial.println(F("Wi-Fi CONNECTED"));
Serial.println();
}
else
{
Serial.println(F(">>>>>>>>>>>> Unable to connect to WiFi <<<<<<<<<<<<"));
}
}