Hi Arduino Forum,
I have frequently visited but never posted before. I have a water tank and I want to know when it's not filling or the water level is getting low. Board of choice nano 33 IOT, a non contact level sensor, US sensor, a hall effect flow sensor, 3 LEDs and a connection to MQTT broker. It's grown from a more simple but not working system over the last 3+ years. I have divided the code into functions. I have had an interesting learning experience and am grateful to loads of instructional info out there. I now have something that all but works. Only I have two (known) sticking points: Void LEDs() stalls after all LEDs are HIGH after a number of loops, When there is no stall here it stalls in void mqtt() after Serial.println of the error code if it is -1. In advance thank you.
#include <Arduino_ConnectionHandler.h> //connection handeler library is used to check WiFi connection and reconnect
#include "arduino_secrets.h" //loads the arduino_secrets.h file (note "" v <>)
#include <ArduinoMqttClient.h>
WiFiConnectionHandler conn(SECRET_SSID, SECRET_PASS); //Arduino_ConnectionHandler.h declaring the login info.
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
//Mqtt setup
const char broker[] = "192.168.0.50"; //my raspberry pi Zero W with mosqitto broker
int port = 1883; //brokers port
const char topicflow[] = "flow"; //publishes to topic "tank/flow"
const char topiclevel[] = "level"; //publishes to topic "tank\level"
unsigned long mqttMillis = 0; //mqtt - store for curent mqttMillis
unsigned long mqttPrevMillis = 0; //mqtt - store for prior mqttMillis value
const unsigned long mqttPeriod = 60000; //mqtt - period between mqtt broadcasts
//Hall effect flow sensor
int flowPin = 2; //Sets pin 2 to be 'int & flowPin' (which is an intrrupt pin)
double flowRate = 0; //flow - calculated flow value
volatile int count = 0; //flow - counts number of hall effect occurences (needs to be volatile as it is used in the intrrupt)
int flowDelay = 10000; //flow - period of intrupt and count
//non contact level sensor
int levelPin = 3; //Sets pin 3 to be 'int & levelPin'
int fullLevel = 0; //level status 1 = full / 0 = not full sets fullLevel to 0
unsigned long levelMillis = 0; //level - store for curent levelMillis
unsigned long levelPrevMillis = 0; //level - store for prior levelMillis value
const unsigned long levelPeriod = 3000; //level - period between FullLevel readings
//ultrasound
int trigPin = 8; //sets pin 8 to be 'int & trigPin'
int echoPin = 9; //sets pin 8 to be 'int & echoPin'
int remaining = 0; //sets variable for the remaining water
unsigned long usMillis = 0; //us - store for curent usMillis
unsigned long usPrevMillis = 0; //us - store for prior usMillis value
const unsigned long usPeriod = 3000; //us - period between TOF readings
int duration = 0; //us - TOF
int distance = 0; //distance calculated from TOF
//LED
int ledhi = 4; //sets pin 4 to be 'int & ledhi' the green LED
int ledmed = 5; //sets pin 5 to be 'int & ledmed' the yellow LDE
int ledlow = 6; //sets pin 6 to be 'int & ledlow' red LDE
//unsigned long LEDMillis = 0; //LED - store for curent LDEMillis
//unsigned long LEDPrevMillis = 0; //LED - store for prior LDEMillis value
//const unsigned long = 3000; //LED - period between LED update
const unsigned long flashPeriod = 100000;//LED - period between the red (ledlow) will flash when flow <= 10 l/h
void setup() {
//serial setup
Serial.begin(9600);
while (!Serial) {
; //waits for the USB serial to connect only needed for debugging
}
//connects to the WiFi
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(SECRET_SSID);
while (WiFi.begin(SECRET_SSID, SECRET_PASS) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
//hall effect flow sensor setup
pinMode(flowPin, INPUT); //sets flowPin to input
attachInterrupt(digitalPinToInterrupt(2), Flow, RISING); //configurees inerrupt 0 (apparently pin 2 on nano / uno?) to run funcion 'Flow', the counter
//non contact level sensor setup
pinMode(levelPin,INPUT); //sets levelPin (pin 3) to input
//ultrasound
pinMode(trigPin, OUTPUT); //sets trigPin (pin 8) to output
pinMode(echoPin, INPUT_PULLUP); //sets echoPin (pin 9) to input
//LEDs
pinMode(ledhi, OUTPUT); //sets ledhi (pin 4) to output
pinMode(ledmed, OUTPUT); //sets ledmed (pin 5) to output
pinMode(ledlow, OUTPUT); //sets ledlow (pin 6) to output
}
void loop() {
//checkWiFi();
flowCal();
Full();
Ultrasound();
mqtt();
LEDs();
}
void LEDs() {
Serial.println(fullLevel, DEC);
//check LEDs
digitalWrite(ledhi, HIGH);
digitalWrite(ledmed, HIGH);
digitalWrite(ledlow, HIGH);
delay(10000); //****why is this shorter than expected 10000 millis is 10 s****
//****the codeappears to stall here. The last serial monitor text is the Serial.println above and the LEDs all remain HIGH****
digitalWrite(ledhi, LOW);
digitalWrite(ledmed, LOW);
digitalWrite(ledlow, LOW);
Serial.print("This is the flowRate value used to set the LEDs flashing, or not = ");
Serial.println(flowRate);
//set the flow status (flashing red if <= 10 l/h)
if (flowRate < 10) {
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
digitalWrite(ledlow, LOW);
delay(flashPeriod);
digitalWrite(ledlow, HIGH);
delay(flashPeriod);
delay(flashPeriod);
}
//set the RAG level status LEDs
if (fullLevel == 1) {
remaining = 100;
} else { //this else will need amending to read the US sensor reading in
remaining = 0;
}
Serial.print("This is the value for fullLevel used to set the RAG = ");
Serial.println(fullLevel);
Serial.print("This is the value for remaining used to set the RAG = ");
Serial.println(remaining);
if (remaining == 100) {
digitalWrite(ledhi, HIGH);
digitalWrite(ledmed, LOW);
digitalWrite(ledlow, LOW);
}
if (remaining < 100) {
digitalWrite(ledhi, LOW);
digitalWrite(ledmed, HIGH);
digitalWrite(ledlow, LOW);
}
if (remaining < 50) {
digitalWrite(ledhi, LOW);
digitalWrite(ledmed, LOW);
digitalWrite(ledlow, HIGH);
}
}
void mqtt() {
mqttClient.poll(); // call poll() regularly to allow the library to send MQTT keep alives which avoids being disconnected by the broker
mqttMillis = millis(); //takes Millis and stores it
if ((mqttMillis - mqttPrevMillis) >= mqttPeriod) { //time check for the mqtt message broadcast
mqttPrevMillis = mqttMillis; // save the time a message is sent
conn.check(); //This runs a WiFi connection check reconnecting if connection is lost -Arduino_ConnectionHandler.h
Serial.print("Checking WiFi connection ");
Serial.println();
//is there a need for a pause while the WiFi is checked and connection is up? Would need to look in the libarary and see if that is possible
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError()); //****I think this stalls the loop if code is -1 ****
//could add and LED alarm state here if the MQTT broker fails to connect
while (1)
;
}
Serial.println("You're connected to the MQTT broker!");
Serial.print("Sending message to topic: ");
Serial.println("tank/flow");
Serial.println(flowRate);
// send message, the Print interface can be used to set the message contents
mqttClient.beginMessage(topicflow);
mqttClient.print(flowRate);
mqttClient.endMessage();
Serial.print("Sending message to topic: ");
Serial.println("tank/level");
Serial.print(fullLevel, DEC);
// send message, the Print interface can be used to set the message contents
mqttClient.beginMessage(topiclevel);
mqttClient.print(fullLevel, DEC);
mqttClient.endMessage();
Serial.println();
}
}
//this counts once the itrrupt is called
void Flow() {
count++; //counts pulses during the intrupt
}
//the flowCal function
void flowCal() {
count = 0; //resets the counter
interrupts(); //enable interrupts on the arduino
delay(flowDelay); //waits for time = "flowDelay"
noInterrupts(); //Disables the inturrupts on arduino
//calculation
flowRate = (23 * count / flowDelay); //l/min (23 the conversion factor on the sensor) I don't know if this is the correct formular for this sensor
flowRate = (flowRate * 60); //l/h
Serial.print("Water flow rate = ");
Serial.print(flowRate);
Serial.println(" l/h");
}
void Full() {
levelMillis = millis(); //takes Millis and stores it
if ((levelMillis - levelPrevMillis) >= levelPeriod) {
levelPrevMillis = levelMillis; //updates levelPrevMillis
fullLevel = digitalRead(3); //updates fullLevel variable with sensor reading
Serial.print("water level = ");
Serial.println(fullLevel, DEC);
}
}
void Ultrasound() {
usMillis = millis();
if (fullLevel == 0) {
if ((usMillis - usPrevMillis) >= usPeriod) {
usPrevMillis = usMillis; //updates usPrevMillis
digitalWrite(trigPin, LOW); //sets trigger pin is LOW double check
delayMicroseconds(5); //waits
digitalWrite(trigPin, HIGH); //sets trigger pin HIGH starts US ping
delayMicroseconds(10); //waits, there is some question as to how long
digitalWrite(trigPin, LOW); //sets triver pin LOW
duration = pulseIn(echoPin, HIGH); //sets duration as TOF
distance = duration * 0.034 / 2; //calculates distance from TOF, ****check this
}
}
}