Savior Faire

Zigbee waterflow meter for Clack valve using ESP32-C6

This is a personal project, based on this tutorial and Ai aid.

I am using this ESP32-C6 Development Kit and Arduino IDE.

Arduino IDE settings:

USB CDC On Boot: "Enabled"
CPU Frequency: "160MHz (WiFi)"
Core Debug Level: "None"
Erase All Flash Before Sketch Upload: "Disabled"
Flash Frequency: "80MHz"
Flash Mode: "QIO"
Flash Size: "4MB (32Mb)"
JTAG Adapter: "Disabled"
Partition Scheme: "Zigbee 4MB with spiffs"
Upload Speed: "115200"
Zigbee Mode: "Zigbee ED (end device)"

It will do the following:


Code

#include <Preferences.h>
#include "Zigbee.h"

#define WATER_PIN 10
#define PULSES_PER_LITER 17
#define FLOW_SENSOR_ENDPOINT_NUMBER 10
#define SAVE_INTERVAL 1800000  // 30 minutes in milliseconds
#define RGB_BRIGHTNESS 50  // LED brightness

Preferences preferences;
int pulseCount = 0;
float totalLiters = 0.0;
bool isLowVoltage = true;
bool isConnected = false;
uint32_t lastReportTime = 0;
uint32_t lastSaveTime = 0;

ZigbeeFlowSensor zbFlowSensor = ZigbeeFlowSensor(FLOW_SENSOR_ENDPOINT_NUMBER);

void setLEDColor(uint8_t red, uint8_t green, uint8_t blue) {
#ifdef RGB_BUILTIN
    rgbLedWrite(RGB_BUILTIN, red, green, blue);
#endif
}

void saveToNVS() {
    preferences.putFloat("totalLiters", totalLiters);
    Serial.println("Saved to NVS");
}

void loadFromNVS() {
    totalLiters = preferences.getFloat("totalLiters", 0.0);
    Serial.printf("Loaded from NVS: %.3f L\n", totalLiters);
}

void setup() {
    Serial.begin(115200);
    pinMode(WATER_PIN, INPUT_PULLUP);

    preferences.begin("water_meter", false);
    loadFromNVS();

    setLEDColor(RGB_BRIGHTNESS, 0, 0);  // Red at start

    zbFlowSensor.setManufacturerAndModel("Espressif", "ZigbeeWaterMeter");
    Zigbee.addEndpoint(&zbFlowSensor);

    Serial.println("Starting Zigbee...");
    if (!Zigbee.begin()) {
        Serial.println("Zigbee failed to start! Rebooting...");
        ESP.restart();
    }

    while (!Zigbee.connected()) {
        delay(100);
    }
    isConnected = true;
    setLEDColor(0, RGB_BRIGHTNESS, 0);  // Green when connected
    zbFlowSensor.setReporting(0, 60, 1.0);
}

void loop() {
    int waterValue = digitalRead(WATER_PIN);
    if (waterValue == LOW) {
        if (isLowVoltage) {
            pulseCount++;
            isLowVoltage = false;
            totalLiters += 1.0 / PULSES_PER_LITER;
            zbFlowSensor.setFlow(totalLiters);
            Serial.printf("Total Water Usage: %.3f L\n", totalLiters);
            
            // Blink LED to indicate water flow
            if (isConnected) {
                setLEDColor(0, 0, 0);  // Off
                delay(100);
                setLEDColor(0, RGB_BRIGHTNESS, 0);  // Back to green
            }
        }
    } else {
        isLowVoltage = true;
    }

    if (millis() - lastReportTime >= 60000) {  // Report to HA every 60s
        zbFlowSensor.report();
        lastReportTime = millis();
    }

    if (millis() - lastSaveTime >= SAVE_INTERVAL) {  // Save to NVS every 30 minutes
        saveToNVS();
        lastSaveTime = millis();
    }
}

Add a sensor on configuration.yaml on Home Assistant:

- sensor:
      - name: "Total Water Usage"
        unique_id: total_water_usage
        state: "{{ states('sensor.espressif_zigbeewatermeter') | float(0) }}"
        unit_of_measurement: "L"
        device_class: water
        state_class: total_increasing

#Tutorials