WiFi Water Flow Meter Design
Table
| Function | GPIO | Schematic Net | Connected To | Direction | Notes |
|---|---|---|---|---|---|
| USB D- | 19 | USB_D_N | J1 USB-C D- via D1 ESD | USB | Native USB serial/JTAG |
| USB D+ | 20 | USB_D_P | J1 USB-C D+ via D1 ESD | USB | Native USB serial/JTAG |
| Flow pulse input | 4 | FLOW_PULSE | J2 pin 3 through R10 100R; R6 100k pulldown | Input interrupt | Generic pulse-output flow sensor input |
| Sensor UART TX | 17 | SENSOR_UART_TX | J2 pin 4 | Output | Optional external sensor serial TX |
| Sensor UART RX | 18 | SENSOR_UART_RX | J2 pin 5 | Input | Optional external sensor serial RX |
| Sensor aux GPIO | 5 | SENSOR_AUX_GPIO | J2 pin 6 | Configurable | Optional enable/interrupt/config line |
| WiFi LED | 6 | LED_WIFI_DRV | R8 to D3 | Output | HIGH turns LED on |
| Flow LED | 7 | LED_FLOW_DRV | R9 to D4 | Output | HIGH turns LED on |
| Boot button | 0 | ESP_BOOT | R4 pull-up, S2 to GND | Strap/input | Hold BOOT while resetting to enter download mode |
| Reset button | EN | ESP_EN | R3 pull-up, C6 delay, S1 to GND | Reset | Pull low to reset module |
| UART0 TX | TXD0/GPIO43 | UART_TXD0 | J3 pin 3 | Output | Debug/programming UART TX |
| UART0 RX | RXD0/GPIO44 | UART_RXD0 | J3 pin 4 | Input | Debug/programming UART RX |
platformio.iniIni
[env:esp32-s3-devkitc-1] platform = espressif32 board = esp32-s3-devkitc-1 framework = arduino monitor_speed = 115200 upload_speed = 921600 build_flags = -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1
src/main.cpp)Cpp
#include <Arduino.h> #include <WiFi.h> // ---------------- Pin definitions from schematic ---------------- #define FLOW_PULSE_PIN 4 // U1 IO4 -> R10 -> J2 pin 3, with 100k pulldown #define SENSOR_UART_TX_PIN 17 // U1 IO17 -> J2 pin 4 #define SENSOR_UART_RX_PIN 18 // U1 IO18 -> J2 pin 5 #define SENSOR_AUX_GPIO_PIN 5 // U1 IO5 -> J2 pin 6 #define LED_WIFI_PIN 6 // U1 IO6 -> R8 -> D3 #define LED_FLOW_PIN 7 // U1 IO7 -> R9 -> D4 // USB native serial uses IO19/IO20 internally on ESP32-S3. // UART0 debug is also available on J3: TXD0/GPIO43 and RXD0/GPIO44. // ---------------- User configuration ---------------- const char* WIFI_SSID = "YOUR_WIFI_SSID"; const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"; const char* HTTP_HOST = "192.168.1.100"; // Replace with your server const uint16_t HTTP_PORT = 8080; // Calibration: pulses per liter depends on the selected external ultrasonic sensor module. // Replace this with the sensor manufacturer's K-factor after selecting the sensor. volatile uint32_t flowPulseCount = 0; const float PULSES_PER_LITER = 450.0f; // placeholder calibration constant unsigned long lastReportMs = 0; uint32_t lastPulseSnapshot = 0; float totalLiters = 0.0f; HardwareSerial SensorSerial(1); void IRAM_ATTR onFlowPulse() { flowPulseCount++; } void setWiFiLed(bool on) { digitalWrite(LED_WIFI_PIN, on ? HIGH : LOW); } void setFlowLed(bool on) { digitalWrite(LED_FLOW_PIN, on ? HIGH : LOW); } void connectWiFi() { WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); Serial.print("Connecting to WiFi"); uint8_t tries = 0; while (WiFi.status() != WL_CONNECTED && tries < 30) { setWiFiLed((tries & 1) != 0); delay(250); Serial.print('.'); tries++; } if (WiFi.status() == WL_CONNECTED) { setWiFiLed(true); Serial.printf("\nWiFi connected, IP=%s\n", WiFi.localIP().toString().c_str()); } else { setWiFiLed(false); Serial.println("\nWiFi not connected; continuing offline."); } } void initSensorInterface() { pinMode(FLOW_PULSE_PIN, INPUT); // external R6 provides pulldown attachInterrupt(digitalPinToInterrupt(FLOW_PULSE_PIN), onFlowPulse, RISING); pinMode(SENSOR_AUX_GPIO_PIN, OUTPUT); digitalWrite(SENSOR_AUX_GPIO_PIN, HIGH); // available as sensor enable/config line SensorSerial.begin(9600, SERIAL_8N1, SENSOR_UART_RX_PIN, SENSOR_UART_TX_PIN); Serial.println("Sensor interface initialized: pulse input + optional UART."); } bool sendHttpReport(float flowLpm, float totalL) { if (WiFi.status() != WL_CONNECTED) return false; WiFiClient client; if (!client.connect(HTTP_HOST, HTTP_PORT)) { Serial.println("HTTP connect failed"); return false; } String body = String("{\"flow_lpm\":") + String(flowLpm, 3) + String(",\"total_l\":") + String(totalL, 3) + String("}"); client.printf("POST /flow HTTP/1.1\r\n"); client.printf("Host: %s\r\n", HTTP_HOST); client.printf("Content-Type: application/json\r\n"); client.printf("Content-Length: %u\r\n", body.length()); client.printf("Connection: close\r\n\r\n"); client.print(body); client.stop(); return true; } void setup() { pinMode(LED_WIFI_PIN, OUTPUT); pinMode(LED_FLOW_PIN, OUTPUT); setWiFiLed(false); setFlowLed(false); Serial.begin(115200); delay(1000); Serial.println("ESP32-S3 ultrasonic water flow meter starting..."); initSensorInterface(); connectWiFi(); } void loop() { const unsigned long now = millis(); if (WiFi.status() != WL_CONNECTED) { setWiFiLed(false); connectWiFi(); } if (now - lastReportMs >= 1000) { noInterrupts(); uint32_t pulseSnapshot = flowPulseCount; interrupts(); uint32_t deltaPulses = pulseSnapshot - lastPulseSnapshot; lastPulseSnapshot = pulseSnapshot; float litersThisSecond = deltaPulses / PULSES_PER_LITER; totalLiters += litersThisSecond; float flowLpm = litersThisSecond * 60.0f; setFlowLed(deltaPulses > 0); Serial.printf("Pulses=%lu, Flow=%.3f L/min, Total=%.3f L\n", (unsigned long)deltaPulses, flowLpm, totalLiters); sendHttpReport(flowLpm, totalLiters); lastReportMs = now; } }
Bash
pio run pio run -t upload pio device monitor -b 115200
PULSES_PER_LITER or replace the pulse code with the sensor vendor's serial protocol once a specific sensor module is selected.Welcome 👋
Flux helps you build PCBs faster with an AI teammate!
Create your account to collaborate, stay updated, fork your own version, and get instant answers from our AI agent.