I built a “smart” water meter with ESPHome and Home Assistant, based on the project by Pieter Brinkman.

Hardware

The project uses a 5V LJ18A3-8Z/BX Proximity sensor from AliExpress. Since I already had some ESP32 boards, that’s what I used.

The ESP32 runs on 3.3 Volt. The sensor needs 5 Volts, so in theory a level shifter is required. Even though the Espressif CEO claims that the chip is 5V tolerant, I still added a protection circuit to the proximity sensor, limiting the input voltage to safe values.

Smart Watermeter schematic

Test-installation

For testing, I mounted the components on a breadboard:

Smart Watermeter prototype on breadboard

And 3D-printed a sensor mount:

Smart Watermeter sensor with 3D-mount

Software

The ESPHome configuration YAML looks like this:

substitutions:
  devicename: "esp32-watermeter"
  long_devicename: "Smart Watermeter"
  pcb_version: "2023-02-11"

esphome:
  name: "${devicename}"
  name_add_mac_suffix: false ## if 'false' use different names/hostnames for each device!
  comment: "${long_devicename} ${pcb_version}"

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
# Set pulse counter total from home assistant using this service call:
api:
  services:
    - service: set_pulse_total
      variables:
        new_pulse_total: int
      then:
        - pulse_counter.set_total_pulses:
            id: water_consumption
            value: !lambda 'return new_pulse_total;'

ota:

wifi:
  ssid: !secret esphome_wifi_iot_ssid
  password: !secret esphome_wifi_iot_password
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "${long_devicename} hotspot"
    password: !secret watermeter_ap_password

captive_portal:

# Water flow meter using LJ18A3-8-Z/BX sensor (5V, 8mm distance)
# Generic sensor config:
#   https://esphome.io/components/sensor/index.html#config-sensor
# Pulse counter config:
#   https://esphome.io/components/sensor/pulse_counter.html
# Example project:
#   https://www.pieterbrinkman.com/2022/02/02/build-a-cheap-water-usage-sensor-using-esphome-home-assistant-and-a-proximity-sensor/
#
sensor:
  # Uptime in seconds
  - platform: uptime
    name: "${long_devicename} uptime"
    id: uptime_seconds
    update_interval: 10s
  # Pulse COUNTER reports water usage in absolute liters
  - platform: pulse_counter
    pin:
      number: GPIO34
      inverted: true    # Active LOW input, does not really matter since we're counting pulses
      mode:
        input: true
    id: water_consumption
    name: "Water consumption"
    unit_of_measurement: 'liter'
    device_class: water
    state_class: total_increasing
    #last_reset: None
    #
    icon: "mdi:water"
    update_interval: 6s
    #
    total:
      id: water_consumption_total
      name: "Water consumption total"
      unit_of_measurement: "m³"
      icon: "mdi:water"
      #
      accuracy_decimals: 3
      device_class: water
      state_class: total_increasing
      #last_reset: None
      filters:
        - multiply: 0.001

Software backlog

  • The water meter does not yet integrate nicely with the Energy Dashboard in HomeAssistant. Probably needs a specific data format / unit to be added.
  • Total water consumption resets to zero when rebooting the board - this leads to hilarious water consumption rates, for example 800.000 liters in one minute. I assumed that “total_increasing” would detect and solve this.
  • Initially I enabled the “Bluetooth Proxy” functionality on the water meter, but I encountered frequent reboots so I disabled it for now. That seems to have helped, not sure what causes this.

Updated: