Hi All,
Lurking around in the forum and reddit for some time, though first post here as I am a bit stuck.
I am working on a waterflow sensor to measure a shower waterflow with the goal of telling openHAB if someone is occupying the room or not (to keep lights on/turn them off).
I recently switched, after some Reddit advice, my project to ESP-Now, as without it my 7000mah LifePo4 battery died after 15h.
My setup:
- Wemos D1 Mini (ESP8266)
- LifePo4 7000mAh battery connected directly to 3.3V and GND
- Waterflow sensor (YF-S201) connected to D7 (sensor), D2 (VCC) and GND
- RST and D0 pins for deepSleep
My issue:
While running the code (see below) I am able to gather the relevant waterflow measure (flowRate) and calculate the totalLiter value.
This also worked (without ESP-Now) reliable, though not battery efficient.
When sending them to the ESP-Now Coordinator though, the communication is only sent/or received (?) sometimes with serial printing "Delivery fail" whereas more often or not it just drops.
My code:
(1) Master/Sensor:
//Include libraries and other includes
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <espnow.h>
#include <SPI.h>
#include "network.h"
#include "waterflow.h"
//Declare GPIO variables - D7 for pulse measure; D2 for VCC
#define SENSOR D7
const int pingPin = D2;
int count = 0;
//Structure example to send data - must match coordinator
typedef struct struct_message {
float flowRate;
unsigned long totalLiters;
} struct_message;
//Init struct_messege
struct_message myData;
//Declare functions
//Count pulses
void IRAM_ATTR pulseCounter()
{
pulseCount++;
}
// Callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
Serial.print("Last Packet Send Status: ");
if (sendStatus == 0){
Serial.println("Delivery success");
}
else{
Serial.println("Delivery fail");
}
}
void setup() {
//Init Serial Monitor
Serial.begin(115200);
// Deactive build-in LED and power up GPIO D2
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, HIGH);
pinMode(SENSOR, INPUT_PULLUP);
//Set warterflow variables
pulseCount = 0;
flowRate = 0.0;
flowMilliLitres = 0;
totalMilliLitres = 0;
previousMillis = 0;
totalLiters = 0;
count = 0;
attachInterrupt(digitalPinToInterrupt(SENSOR), pulseCounter, FALLING);
//Set device WIFI Station (STA) and ensure it is NOT connected
WiFi.mode(WIFI_STA);
WiFi.disconnect();
// Init ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Once ESP- Now is successfully init, set Role, regirster onDataSent and register with Coordinator - Slave
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
esp_now_register_send_cb(OnDataSent);
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}
void loop() {
currentMillis = millis();
if (currentMillis - previousMillis > interval) {
pulse1Sec = pulseCount;
pulseCount = 0;
flowRate = ((1000.0 / (millis() - previousMillis)) * pulse1Sec) / calibrationFactor;
previousMillis = millis();
flowMilliLitres = (flowRate / 60) * 1000;
totalMilliLitres += flowMilliLitres;
totalLiters = totalMilliLitres / 1000;
if (int(flowRate) < 1) {
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(struct_message));
digitalWrite(pingPin, LOW);
Serial.println("Going into deep sleep");
delay(100);
ESP.deepSleep(15e6);
} else if (int(flowRate) >= 1) {
Serial.println(flowRate);
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(struct_message));
return;
}
}
}
(2) Slave/Coordinator:
// Include libraries and other includes
#include <Arduino.h>
#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <espnow.h>
#include "network.h"
#include "waterflow.h"
// WIFI and MQTT
WiFiClient espClient;
PubSubClient client(espClient);
// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
float flowRate;
unsigned long totalLiters;
} struct_message;
// Create a struct_message called myData
struct_message myData;
// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
//Serial.println("Message received");
memcpy(&myData, incomingData, sizeof(myData));
Serial.println(myData.flowRate);
Serial.println(myData.totalLiters);
Serial.println(len);
//Translating float to string (_str) and package for mqtt (toCharArray)
flow_str = String(myData.flowRate);
flow_str.toCharArray(flow, flow_str.length() + 1);
total_str = String(myData.totalLiters);
total_str.toCharArray(total, total_str.length() + 1);
if (int(myData.flowRate) != 0) {
Serial.print("Flowrate: ");
Serial.println(flow);
client.publish("masterbathroom/shower/flowrate", flow);
} else if (int(myData.flowRate) == 0) {
Serial.print("Total Liters: ");
Serial.println(total);
client.publish("masterbathroom/shower/totalliters", total);
client.publish("masterbathroom/shower/state", "OFF");
}
}
void setup() {
// Init Serial Monitor
Serial.begin(115200);
//Set static IP, WIFI mode, connect and loop till connected
WiFi.mode(WIFI_STA);
WiFi.config(staticIP, dns, gateway, subnet);
WiFi.begin(ssid, password, channel, bssid);
WiFi.persistent(true);
WiFi.setAutoConnect(true);
WiFi.setAutoReconnect(true);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
//Connect to MQTT - loop till connected
client.setServer(mqttServer, mqttPort);
while (!client.connected()) {
if (client.connect("WEMOS", mqttUser, mqttPassword)) {
client.subscribe("masterbathroom/shower");
} else {
delay(500);
}
}
// Init ESP-Now
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
client.publish("masterbathroom/shower/state_coordinator", "ON");
esp_now_register_recv_cb(OnDataRecv);
//Start OTA mode
ArduinoOTA.onStart([]() {
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
}
void loop() {
client.loop();
}
As I am just starting out on this journey, I understand that my code might not be the best, it seems to work though to a certain extend.
Another thing I tried was to have the code all only in the setup function with if and while loops to run the calculation so that ESP-Now is only activated once the flowRate value is above "1", whereas I had similar issues as before.
Could anyone point me into the right direction on how to fix this issue?