WiFi Water Flow Meter Design

6:35

Thought for 9 sec

Thought for 8 sec

Thought for 6 sec

Thought for 15 sec

Thought for 9 sec

Thought for 5 sec

Thought for 2 sec

Read schematic.

Thought for 5 sec

Thought for 5 sec

Thought for 8 sec

6/7 Create firmware starter project file with real ESP32 RS485/Modbus code

Thought for 55 sec

Thought for 7 sec

7/7 Run review, fix violations, and document remaining assumptions

Thought for 5 sec

Completed design checks — found 108 issues.

Read schematic.

Thought for 20 sec

Thought for 8 sec

7/7 tasks completed.

Thought for a moment

Complete: I created and wired the full schematic for the USB-C powered ESP32-S3 WiFi water flow meter, including 3.3 V buck regulation, 12 V boost sensor power, MAX3485 RS485 interface, USB-C protection/CC resistors, reset/boot circuitry, UART header, and status LEDs. Review returned no ERROR/WARNING/OPEN ERC issues.
I also created Design Notes with the architecture, power budget, assumptions, and pin map, plus Firmware Starter with PlatformIO/Arduino Modbus RS485 starter code. The main remaining assumption is the exact ultrasonic sensor’s Modbus register map; update the firmware once the sensor datasheet is chosen.
Schematic is ready for layout. Want me to proceed with board sizing and component placement?
Size the board and perform placement

0:25

Thought for 20 sec

Thought for a moment

I’ll size the PCB first, set an appropriate stackup, then place components by functional block with the ESP32 antenna at an edge, USB and sensor connectors on board edges, and decoupling/power passives near their ICs. After placement I’ll run a DRC review and adjust if needed.

7:48

Thought for 2 sec

1/4 Inspect current PCB layout state and dimensions

Thought for 3 sec

Completed 3 design checks — found 108 issues.

Read schematic.

Read layout.

Thought for 5 sec

2/4 Set board size and stackup before placement

Thought for 5 sec

Editing board size.

Thought for 8 sec

3/4 Place components with ESP32 antenna and connector constraints

Thought for 10 sec

Thought for 1 sec

Thought for 7 sec

Thought for 3 sec

Thought for 4 sec

Thought for a moment

Thought for 8 sec

Thought for 9 sec

Thought for 3 sec

Thought for 16 sec

Thought for 34 sec

Thought for 21 sec

Thought for a moment

Thought for 13 sec

Thought for a moment

Thought for 1 min 7 sec

Thought for 11 sec

Thought for 28 sec

Thought for 8 sec

Thought for a moment

Thought for 24 sec

Thought for 11 sec

Thought for 8 sec

Thought for a moment

Thought for 7 sec

Thought for a moment

Thought for 5 sec

Thought for a moment

Thought for 4 sec

Thought for 8 sec

Thought for 4 sec

4/4 Run post-placement DRC and fix placement issues

Thought for 6 sec

Completed design checks — found 95 issues.

Read layout.

Thought for 5 sec

4/4 tasks completed.

Thought for a moment

Done. I resized the PCB to 100 × 80 mm with rounded corners and a 4-layer stackup, then placed all components by functional block.
Placement is clean: ESP32 is at the top edge with antenna overhang, USB-C is on the left edge, the sensor terminal is on the right edge, power stages are grouped, and user-facing LEDs/buttons/header are accessible. The only review errors now are expected unrouted connections because routing has not been performed yet.
Ready for routing when you are.
Yes route board
Set routing rules
Check antenna keepout
Review placement details
Add mounting holes

Waiting for input

Refine this doc
Ask about this doc
Firmware Starter — ESP32-S3 WiFi Water Flow Meter
Platform & Toolchain
  • MCU/module: ESP32-S3-WROOM-1-N16R8
  • Framework: Arduino on PlatformIO
  • Sensor interface: RS485 Modbus RTU over UART
  • USB: ESP32-S3 native USB on IO19/IO20 for programming/debug if configured by board support package

Pin Mapping


FunctionGPIOSchematic NetDirectionNotes
RS485 TX17RS485_TXDOutputESP32 to MAX3485 DI
RS485 RX18RS485_RXDInputMAX3485 RO to ESP32
RS485 direction16RS485_DE_REOutputHIGH transmit, LOW receive
12 V sensor enable15BOOST_ENOutputDrives LM27313 SHDN net; external pull-up also enables by default
WiFi LED4LED_WIFI_GPIOOutputHIGH turns LED on
Flow LED5LED_FLOW_GPIOOutputHIGH turns LED on
BOOT button0ESP_BOOTInputPull low during reset for bootloader
ResetENESP_ENInputReset button pulls EN low
UART0 TX headerTXD0UART0_TXDOutputDebug/programming header
UART0 RX headerRXD0UART0_RXDInputDebug/programming header
platformio.ini

Ini


[env:esp32-s3-devkitc-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps =
    4-20ma/ModbusMaster@^2.0.1
Complete Starter Firmware

Cpp


#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ModbusMaster.h>
#include <string.h>

// Pin definitions from schematic
#define RS485_TX_PIN       17
#define RS485_RX_PIN       18
#define RS485_DE_RE_PIN    16
#define SENSOR_12V_EN_PIN  15
#define LED_WIFI_PIN        4
#define LED_FLOW_PIN        5

// Configuration placeholders
static const char* WIFI_SSID = "YOUR_SSID";
static const char* WIFI_PASSWORD = "YOUR_PASSWORD";
static const char* POST_URL = "http://192.168.1.100:8080/flow";

#define MODBUS_BAUD             9600
#define MODBUS_SLAVE_ADDR       1
#define SENSOR_READ_INTERVAL_MS 1000

// Example Modbus register assumptions. Update these to the actual sensor manual.
#define REG_FLOW_RATE_START     0x0000  // assumed float32, L/min, 2 holding registers
#define REG_TOTAL_VOLUME_START  0x0002  // assumed float32, L, 2 holding registers

ModbusMaster modbus;
unsigned long lastSensorReadMs = 0;

void rs485PreTransmission() {
  digitalWrite(RS485_DE_RE_PIN, HIGH);
  delayMicroseconds(50);
}

void rs485PostTransmission() {
  delayMicroseconds(50);
  digitalWrite(RS485_DE_RE_PIN, LOW);
}

float registersToFloat(uint16_t hi, uint16_t lo) {
  uint32_t raw = ((uint32_t)hi << 16) | lo;
  float value;
  memcpy(&value, &raw, sizeof(value));
  return value;
}

bool readFloat32Holding(uint16_t startReg, float& value) {
  uint8_t result = modbus.readHoldingRegisters(startReg, 2);
  if (result != modbus.ku8MBSuccess) {
    Serial.printf("Modbus read failed at 0x%04X: 0x%02X\n", startReg, result);
    return false;
  }
  value = registersToFloat(modbus.getResponseBuffer(0), modbus.getResponseBuffer(1));
  return true;
}

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  Serial.print("Connecting to WiFi");
  for (int i = 0; i < 30 && WiFi.status() != WL_CONNECTED; ++i) {
    digitalWrite(LED_WIFI_PIN, !digitalRead(LED_WIFI_PIN));
    delay(500);
    Serial.print('.');
  }

  if (WiFi.status() == WL_CONNECTED) {
    digitalWrite(LED_WIFI_PIN, HIGH);
    Serial.printf("\nWiFi connected, IP: %s\n", WiFi.localIP().toString().c_str());
  } else {
    digitalWrite(LED_WIFI_PIN, LOW);
    Serial.println("\nWiFi not connected; continuing offline.");
  }
}

void postFlowReading(float flowLpm, float totalLiters) {
  if (WiFi.status() != WL_CONNECTED) return;

  HTTPClient http;
  http.begin(POST_URL);
  http.addHeader("Content-Type", "application/json");

  String payload = "{\"flow_lpm\":" + String(flowLpm, 3) +
                   ",\"total_liters\":" + String(totalLiters, 3) + "}";
  int code = http.POST(payload);
  Serial.printf("HTTP POST %d: %s\n", code, payload.c_str());
  http.end();
}

void setup() {
  Serial.begin(115200);
  delay(250);
  Serial.println("ESP32-S3 WiFi Water Flow Meter starting...");

  pinMode(LED_WIFI_PIN, OUTPUT);
  pinMode(LED_FLOW_PIN, OUTPUT);
  pinMode(SENSOR_12V_EN_PIN, OUTPUT);
  pinMode(RS485_DE_RE_PIN, OUTPUT);

  digitalWrite(LED_WIFI_PIN, LOW);
  digitalWrite(LED_FLOW_PIN, LOW);
  digitalWrite(RS485_DE_RE_PIN, LOW);     // receive by default
  digitalWrite(SENSOR_12V_EN_PIN, HIGH);  // enable 12V sensor rail

  Serial2.begin(MODBUS_BAUD, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN);
  modbus.begin(MODBUS_SLAVE_ADDR, Serial2);
  modbus.preTransmission(rs485PreTransmission);
  modbus.postTransmission(rs485PostTransmission);

  initWiFi();
  Serial.println("Initialization complete.");
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    digitalWrite(LED_WIFI_PIN, LOW);
    static unsigned long lastReconnect = 0;
    if (millis() - lastReconnect > 10000) {
      lastReconnect = millis();
      initWiFi();
    }
  }

  if (millis() - lastSensorReadMs >= SENSOR_READ_INTERVAL_MS) {
    lastSensorReadMs = millis();

    float flowLpm = 0.0f;
    float totalLiters = 0.0f;
    bool okFlow = readFloat32Holding(REG_FLOW_RATE_START, flowLpm);
    bool okTotal = readFloat32Holding(REG_TOTAL_VOLUME_START, totalLiters);

    if (okFlow) {
      digitalWrite(LED_FLOW_PIN, flowLpm > 0.01f ? HIGH : LOW);
      Serial.printf("Flow: %.3f L/min", flowLpm);
      if (okTotal) Serial.printf(", Total: %.3f L", totalLiters);
      Serial.println();
      if (okTotal) postFlowReading(flowLpm, totalLiters);
    } else {
      digitalWrite(LED_FLOW_PIN, LOW);
    }
  }
}
Build & Flash

Bash


pio run
pio run -t upload
pio device monitor
To enter bootloader manually, hold BOOT, tap RESET, then release BOOT.
Sensor Register Note
The Modbus register addresses and float byte order are placeholders because the exact ultrasonic flow sensor model was not specified. Update REG_FLOW_RATE_START, REG_TOTAL_VOLUME_START, baud rate, slave address, and word order according to the sensor manual.

    Platform & Toolchain

    Pin Mapping

    `platformio.ini`

    Complete Starter Firmware

    Build & Flash

    Sensor Register Note

Documents

    Project Specification

    Design Notes — ESP32 WiFi Water Flow Meter

    Firmware Starter — ESP32-S3 WiFi Water Flow Meter

Assets

No assets added.

ESP32 WiFi Water Flow Meter

ESP32 WiFi Water Flow Meter thumbnail
USB-C powered ESP32 WiFi water flow meter for a 3/4 inch PVC pipe using an external 12V RS485 ultrasonic flow sensor, protected power input, 3.3V logic, status LEDs, and programming/reset support.

Properties

Properties describe core aspects of the project.

Pricing & Availability

Distributor

Qty 1

Arrow

$6.78–$9.00

Digi-Key

$13.75–$15.54

HQonline

$1.39–$1.43

LCSC

$12.63–$12.73

Mouser

$20.76–$20.96

TME

$1.18–$1.31

Verical

$7.56–$10.20

Controls