Water meter monitoring

Using a ESP32 with QMC5883L compass module. TBD

Quite accurate, each interval (max to min to max) from the water meter appears to be 32.5ml, this was confirmed over the course of a few days and about 1.6 m³ of water (about 49 thousand intervals).

This is still a work in progress, and will need some customization for your specific installation (such as defining which magnetic axis to monitor and thresholds).

watermeter.yaml
esphome:
  name: WaterMeter
  friendly_name: water
  project:
    name: "photonicsguy.Water Meter Sensor"
    version: "0.1.2"
  on_boot:
    priority: 300
    then:
      - lambda: |-
          id(sample)=id(total_pulses);

esp32:
  board: esp32dev
  framework:
    type: arduino
    version: recommended
 
# Don't use VERBOSE or DEBUG logging when Hall sensor has fast updates
logger:
  level: WARN
 
# Enable Home Assistant API
api:
  encryption:
    key: !secret ha_key

ota:
  password: !secret ota_passwd

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

i2c:
  - id: bus_a
    sda: 4
    scl: 15
    frequency: 800kHz
    scan: true

text_sensor:
  - platform: wifi_info
    ip_address:
      name: IP Address
      entity_category: "diagnostic"

switch:
  - platform: restart
    name: "Reboot"
  - platform: template
    name: "Reset usage"
    id: resetusage
    optimistic: false
    icon: mdi:water-sync
    restore_mode: ALWAYS_OFF
    turn_on_action:
      then:
        - lambda: |-
            id(sample)=id(total_pulses);
            id(wateruse).publish_state((id(total_pulses)-id(sample)) * 0.01 * id(offset));
 

number:
  - platform: template
    name: "Threshold Minimum"
    id: minVal
    optimistic: true
    restore_value: true
    entity_category: config
    initial_value: 70
    min_value: -200
    max_value: 200
    step: 5
    unit_of_measurement: "µT"
    set_action:
      - lambda: id(pulse).set_lower_threshold(x);
  - platform: template
    name: "Threshold Maximum"
    id: maxVal
    optimistic: true
    restore_value: true
    entity_category: config
    initial_value: 90
    min_value: -200
    max_value: 200
    unit_of_measurement: "µT"
    step: 5
    set_action:
      - lambda: id(pulse).set_upper_threshold(x);
  - platform: template
    name: "Threshold Minimum alt"
    id: minVal2
    optimistic: true
    restore_value: true
    entity_category: config
    initial_value: 40
    min_value: -200
    max_value: 200
    step: 5
    unit_of_measurement: "µT"
    set_action:
      - lambda: id(pulse2).set_lower_threshold(x);
  - platform: template
    name: "Threshold Maximum alt"
    id: maxVal2
    optimistic: true
    restore_value: true
    entity_category: config
    initial_value: 60
    min_value: -200
    max_value: 200
    unit_of_measurement: "µT"
    step: 5
    set_action:
      - lambda: id(pulse2).set_upper_threshold(x);
 

globals:
  - id: total_pulses
    type: int
    restore_value: True
    initial_value: '0'
  - id: sample
    type: int
    restore_value: False
    initial_value: '0'
  - id: offset
    type: float
    restore_value: False
    initial_value: '3.25'

sensor:
  - platform: wifi_signal
    name: "RSSI"
    id: rssi_db
    filters:
      - delta: 2
      - throttle: 300s
    entity_category: "diagnostic"
  - platform: qmc5883l
    i2c_id: bus_a
    address: 0x0D
    field_strength_x:
      name: "Field Strength X"
      id: fsx
      internal: true
    range: 200uT
    oversampling: 64x
    update_interval: 0.005s
  - platform: template
    name: "Water Consumption new"
    id: waterconsumption3
    device_class: water
    unit_of_measurement: "m³"
    state_class: "total_increasing"
    icon: "mdi:water"
    accuracy_decimals: 4
    lambda: |-
        return id(total_pulses) * 0.00001 * id(offset);
  - platform: template
    name: "Water usage"
    id: wateruse
    device_class: water
    unit_of_measurement: "L"
    state_class: "measurement"
    icon: "mdi:hand-water"
    accuracy_decimals: 2
    lambda: |-
        return (id(total_pulses)-id(sample)) * 0.01 * id(offset);
  - platform: template
    name: "Counter"
    unit_of_measurement: pulses
    id: watercounter
    lambda: |-
        return id(total_pulses);

binary_sensor:
  - platform: analog_threshold
    name: "Pulse" # Cover closed
    id: pulse
    #internal: True
    sensor_id: fsx
    threshold:
      upper: 90
      lower: 80
    on_state:
      then:
        - lambda: |-
            id(total_pulses) += 1;
            id(waterconsumption3).publish_state(id(total_pulses) * 0.00001 * id(offset));
            id(wateruse).publish_state((id(total_pulses)-id(sample)) * 0.01 * id(offset));
            id(watercounter).publish_state(id(total_pulses));
  - platform: analog_threshold
    name: "Pulse2"  #Cover open
    id: pulse2
    sensor_id: fsx
    threshold:
      upper: 60
      lower: 40
    on_state:
      then:
        - lambda: |-
            id(total_pulses) += 1;
            id(waterconsumption3).publish_state(id(total_pulses) * 0.00001 * id(offset));
            id(wateruse).publish_state((id(total_pulses)-id(sample)) * 0.01 * id(offset));
            id(watercounter).publish_state(id(total_pulses));
  • esphome/watermeter.txt
  • Last modified: 2023/12/20 07:30
  • by photonicsguy