hugokernel / esphome-water-meter

Measurement of water consumption directly from your water meter with a TCRT5000 like sensor and ESPHome.
MIT License
64 stars 10 forks source link

Counter increment at boot #7

Closed acca84 closed 7 months ago

acca84 commented 7 months ago

I have modified your code and implemented my two counters, it seams to work well, thank for your work.

But i have noticed something : if i reboot the esp8266, the main counters (i have two, one for cold water, one for hot water) are incremented by 1.

I'd like them not to be incremented I don't use the same kind of sensor, I use reed sensors (only two wires, dry contact), so i declare their pins input pull-up, could that be the cause ?

I mean because pin goes high when declared, so it increments the counter. But I would imagine nothing happens before pin definition are finished (as in Arduino void setup() ) Thanks again

nliaudat commented 7 months ago

Hi, 1) Can you share the code you use ? It's difficult to have a look at the pin you are using without it.

2) Are your reed switch connected between GPIO and GND or GPIO and +3.3V

3) Have a look at https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/ to see which pin are safe to use (not used during boot and not high at BOOT)

acca84 commented 7 months ago

Hi, i moved to esp32 miniS2 since i had rebbots each 45minutes with Lolin D1 mini and since i red that esp32 was best for pulse counting. I still have the same problem. both sensor have one wire to ground, the other to pin 16 for sensor 1 and 17 for sensor 2.

My code is the following (sorry i don't manage to show it as code) :

substitutions:
  name: Compteur eau froide
  friendly_name: "Froide"
  friendly_nameC: "Chaude"

esphome:
  name: esp-compteur-eau
  friendly_name: Cpt eau
  platform: ESP32
  board: lolin_s2_mini
  #variant: esp32s2
  on_boot:
    priority: -10
    then:
      - script.execute: 
          publish_states
      - script.execute:
          publish_states_chaud

ota:
  password: "PASSOTA"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp-Compteur-Eau"
    password: "PASSS"

captive_portal:

# Enable Home Assistant API
api:
  encryption:
    key: "BwlakwbxY2t2BF1+713lxiWUaGJe7jPXYlANIOsyjHg="
  services:
    - service: reset_main_counter
      then:
        - script.execute: reset_main_counter
    - service: reset_secondary_counter
      then:
        - script.execute: reset_secondary_counter
    - service: reset_main_counter_chaud
      then:
        - script.execute: reset_main_counter_chaud
    - service: reset_secondary_counter_chaud
      then:
        - script.execute: reset_secondary_counter_chaud

logger:
  level: INFO # Flashing effect generate too many debug log

# Documentations:
# https://github.com/esphome/issues/issues/664
# https://esphome.io/components/sensor/integration.html
# https://community.home-assistant.io/t/using-esphome-to-build-a-water-flow-rate-meter/119380/64

globals:
 - id: main_counter_pulses
   type: int
   restore_value: yes
   initial_value: '0'
 - id: secondary_counter_pulses
   type: int
   restore_value: yes
   initial_value: '0'
 - id: daily_counter_pulses
   type: int
   restore_value: yes
   initial_value: '0'
 - id: weekly_counter_pulses
   type: int
   restore_value: yes
   initial_value: '0'
 - id: monthly_counter_pulses
   type: int
   restore_value: yes
   initial_value: '0'
 - id: yearly_counter_pulses
   type: int
   restore_value: yes
   initial_value: '0'

 - id: event_quantity
   type: int
   restore_value: no
   initial_value: '0'
 - id: last_event_quantity
   type: int
   restore_value: no
   initial_value: '0'
 - id: event_counter
   type: int
   restore_value: no
   initial_value: '0'
 - id: current_event_quantity
   type: int
   restore_value: no
   initial_value: '0'

 - id: main_counter_pulses_chaud
   type: int
   restore_value: yes
   initial_value: '0'
 - id: secondary_counter_pulses_chaud
   type: int
   restore_value: yes
   initial_value: '0'
 - id: daily_counter_pulses_chaud
   type: int
   restore_value: yes
   initial_value: '0'
 - id: weekly_counter_pulses_chaud
   type: int
   restore_value: yes
   initial_value: '0'
 - id: monthly_counter_pulses_chaud
   type: int
   restore_value: yes
   initial_value: '0'
 - id: yearly_counter_pulses_chaud
   type: int
   restore_value: yes
   initial_value: '0'

 - id: event_quantity_chaud
   type: int
   restore_value: no
   initial_value: '0'
 - id: last_event_quantity_chaud
   type: int
   restore_value: no
   initial_value: '0'
 - id: event_counter_chaud
   type: int
   restore_value: no
   initial_value: '0'
 - id: current_event_quantity_chaud
   type: int
   restore_value: no
   initial_value: '0'

script:

  - id: reset_main_counter
    then:
      - lambda: |-
          id(main_counter_pulses) = 0;
          id(water_main_consumption).publish_state(id(main_counter_pulses));

  - id: reset_secondary_counter
    then:
      - lambda: |-
          id(secondary_counter_pulses) = 0;
          id(water_secondary_consumption).publish_state(id(secondary_counter_pulses));

  - id: reset_main_counter_chaud
    then:
      - lambda: |-
          id(main_counter_pulses_chaud) = 0;
          id(water_main_consumption_chaud).publish_state(id(main_counter_pulses_chaud));

  - id: reset_secondary_counter_chaud
    then:
      - lambda: |-
          id(secondary_counter_pulses_chaud) = 0;
          id(water_secondary_consumption_chaud).publish_state(id(secondary_counter_pulses_chaud));

  - id: publish_states
    then:
      - lambda: |-
          id(water_main_consumption).publish_state(id(main_counter_pulses));
          id(water_secondary_consumption).publish_state(id(secondary_counter_pulses));
          id(water_daily_consumption).publish_state(id(daily_counter_pulses));
          id(water_weekly_consumption).publish_state(id(weekly_counter_pulses));
          id(water_monthly_consumption).publish_state(id(monthly_counter_pulses));
          id(water_yearly_consumption).publish_state(id(yearly_counter_pulses));
          id(current_water_consumption).publish_state(id(event_quantity));

  - id: publish_states_chaud
    then:
      - lambda: |-
          id(water_main_consumption_chaud).publish_state(id(main_counter_pulses_chaud));
          id(water_secondary_consumption_chaud).publish_state(id(secondary_counter_pulses_chaud));
          id(water_daily_consumption_chaud).publish_state(id(daily_counter_pulses_chaud));
          id(water_weekly_consumption_chaud).publish_state(id(weekly_counter_pulses_chaud));
          id(water_monthly_consumption_chaud).publish_state(id(monthly_counter_pulses_chaud));
          id(water_yearly_consumption_chaud).publish_state(id(yearly_counter_pulses_chaud));
          id(current_water_consumption_chaud).publish_state(id(event_quantity_chaud));

sensor:
  - platform: uptime
    name: "Compteur eau uptime"

  - platform: wifi_signal
    name: "Compteur eau WiFi signal"

  # TCRT5000 pulse counter
  # IO16 / GPIO16
  - platform: pulse_counter
    id: water_pulse_counter
    name: "${friendly_name} debit"
    pin: 
      number : 16
      allow_other_uses: true
      mode:
        input: true
        pullup: true
    update_interval: 2sec
    internal_filter: 10us
    unit_of_measurement: "L/min"
    accuracy_decimals: 0
    icon: "mdi:water"
    filters:
      # Divide by 60
      #- multiply: 0.0167
      - lambda: return abs(x);

  # Value calculated are not consistent
  #- platform: integration
  #  id: water_integration_sensor
  #  name: "${friendly_name} integrated water consumption"
  #  sensor: water_pulse_counter
  #  time_unit: min
  #  unit_of_measurement: "L"
  #  accuracy_decimals: 0
  #  icon: "mdi:water"

  - platform: template
    id: water_main_consumption
    name: "${friendly_name} consommation principale"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_secondary_consumption
    name: "${friendly_name} consommation secondaire"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_daily_consumption
    name: "${friendly_name} consommation journaliere"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_weekly_consumption
    name: "${friendly_name} consommation hebdomadaire"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_monthly_consumption
    name: "${friendly_name} consommation mensuelle"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_yearly_consumption
    name: "${friendly_name} consommation annuelle"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: current_water_consumption
    name: "${friendly_name} consommation actuelle"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: last_water_consumption
    name: "${friendly_name} consommation precedente"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

# TCRT5000 pulse counter CHAUD
  # IO18 / GPIO16
  - platform: pulse_counter
    id: water_pulse_counter_chaud
    name: "${friendly_nameC} debit"
    pin: 
      number : GPIO17
      allow_other_uses: true
      mode:
        input: true
        pullup: true
    update_interval: 2sec
    internal_filter: 10us
    unit_of_measurement: "L/min"
    accuracy_decimals: 0
    icon: "mdi:water"
    filters:
      # Divide by 60
      #- multiply: 0.0167
      - lambda: return abs(x*10);

  # Value calculated are not consistent
  #- platform: integration
  #  id: water_integration_sensor
  #  name: "${friendly_name} integrated water consumption"
  #  sensor: water_pulse_counter
  #  time_unit: min
  #  unit_of_measurement: "L"
  #  accuracy_decimals: 0
  #  icon: "mdi:water"

  - platform: template
    id: water_main_consumption_chaud
    name: "${friendly_nameC} consommation principale"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_secondary_consumption_chaud
    name: "${friendly_nameC} secondary water consumption"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_daily_consumption_chaud
    name: "${friendly_nameC} consommation journaliere"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_weekly_consumption_chaud
    name: "${friendly_nameC} consommation hebdomadaire"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_monthly_consumption_chaud
    name: "${friendly_nameC} consommation mensuelle"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: water_yearly_consumption_chaud
    name: "${friendly_nameC} consommation annuelle"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: current_water_consumption_chaud
    name: "${friendly_nameC} consommation actuelle"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

  - platform: template
    id: last_water_consumption_chaud
    name: "${friendly_nameC} consommation precedente"
    unit_of_measurement: "L"
    accuracy_decimals: 0
    icon: "mdi:water"

binary_sensor:
  # TCRT5000 pulse counter
  # IO18 / GPIO16
  - platform: gpio
    id: water_pulse
    pin: 
      number : 16
      allow_other_uses: true
      mode:
        input: true
        pullup: true
    internal: true
    filters:
       - delayed_on_off: 50ms
       - lambda: |-
          id(main_counter_pulses) += x;
          id(secondary_counter_pulses) += x;
          id(daily_counter_pulses) += x;
          id(weekly_counter_pulses) += x;
          id(monthly_counter_pulses) += x;
          id(yearly_counter_pulses) += x;
          id(event_quantity) += x;
          return x;
    on_state:
       - script.execute: publish_states
  # TCRT5000 pulse counter CHAUD
  # IO18 / GPIO16
  - platform: gpio
    id: water_pulse_chaud
    pin: 
      number : GPIO17
      allow_other_uses: true
      mode:
        input: true
        pullup: true
    internal: true
    filters:
       - delayed_on_off: 50ms
       - lambda: |-
          id(main_counter_pulses_chaud) += 10*x;
          id(secondary_counter_pulses_chaud) += 10*x;
          id(daily_counter_pulses_chaud) += 10*x;
          id(weekly_counter_pulses_chaud) += 10*x;
          id(monthly_counter_pulses_chaud) += 10*x;
          id(yearly_counter_pulses_chaud) += 10*x;
          id(event_quantity_chaud) +=10*x;
          return x;
    on_state:
       - script.execute: publish_states_chaud

switch:
  - platform: template
    name: "${friendly_name} reset main counter button"
    icon: "mdi:restart"
    turn_on_action:
      - script.execute: reset_main_counter

  - platform: template
    name: "${friendly_name} reset secondary counter button"
    icon: "mdi:restart"
    turn_on_action:
      - script.execute: reset_secondary_counter

  - platform: template
    name: "${friendly_nameC} reset main counter button"
    icon: "mdi:restart"
    turn_on_action:
      - script.execute: reset_main_counter_chaud

  - platform: template
    name: "${friendly_nameC} reset secondary counter button"
    icon: "mdi:restart"
    turn_on_action:
      - script.execute: reset_secondary_counter_chaud
  - platform: restart
    name: "Compteur eau restart"

time:
  - platform: sntp
    on_time:
      - seconds: 0
        minutes: 0
        hours: 0
        then:
          - globals.set: 
              id: daily_counter_pulses
              value: '0'
          - globals.set:
              id: daily_counter_pulses_chaud
              value: '0'
          - lambda: |-
              id(water_daily_consumption).publish_state(id(daily_counter_pulses));
              id(water_daily_consumption_chaud).publish_state(id(daily_counter_pulses_chaud));
      - seconds: 0
        minutes: 0
        hours: 0
        days_of_week: MON
        then:
          - globals.set: 
              id: weekly_counter_pulses
              value: '0'
          - globals.set:
              id: weekly_counter_pulses_chaud
              value: '0'
          - lambda: |-
              id(water_weekly_consumption).publish_state(id(weekly_counter_pulses));
              id(water_weekly_consumption_chaud).publish_state(id(weekly_counter_pulses_chaud));
      - seconds: 0
        minutes: 0
        hours: 0
        days_of_month: 1
        then:
          - globals.set: 
              id: monthly_counter_pulses
              value: '0'
          - globals.set:
              id: monthly_counter_pulses_chaud
              value: '0'
          - lambda: |-
              id(water_monthly_consumption).publish_state(id(monthly_counter_pulses));
              id(water_monthly_consumption_chaud).publish_state(id(monthly_counter_pulses_chaud));
      - seconds: 0
        minutes: 0
        hours: 0
        days_of_month: 1
        months: JAN
        then:
          - globals.set:
              id: yearly_counter_pulses
              value: '0'
          - globals.set:
              id: yearly_counter_pulses_chaud
              value: '0'
          - lambda: |-
              id(water_yearly_consumption).publish_state(id(yearly_counter_pulses));
              id(water_yearly_consumption_chaud).publish_state(id(yearly_counter_pulses_chaud));

interval:
  # Save the last consumption
  #
  # An event is published when a water flow (>= 1L / 15 seconds) is
  # detected and followed by a stop of consumption for a defined time.
  - interval: 15sec
    then:
      - lambda: |-
          if (id(event_quantity) != id(last_event_quantity)) {
            // Water continues to flow

            // Reset event counter
            id(event_counter) = 0;
          } else {
            // Water no longer flows

            if (id(event_quantity)) {
              // 4 * 15 * 5 = 5min
              if (id(event_counter) < 4 * 5) {
                // Timeout is not reaches
                id(event_counter)++;
              } else {
                  // Timeout is reaches
                  id(last_water_consumption).publish_state(id(event_quantity));

                  // Send event to Home Assistant
                  api::HomeAssistantServiceCallAction<> *api;
                  api = new api::HomeAssistantServiceCallAction<>(api_apiserver, true);
                  // Event id length limit is 32 characters
                  api->set_service("esphome.last_consumption_changes");
                  api->play();

                  id(event_quantity) = 0;
              }
            }
          }

          id(last_event_quantity) = id(event_quantity);

          if (id(event_quantity_chaud) != id(last_event_quantity_chaud)) {
            // Water continues to flow

            // Reset event counter
            id(event_counter_chaud) = 0;
          } else {
            // Water no longer flows

            if (id(event_quantity_chaud)) {
              // 4 * 15 * 5 = 5min
              if (id(event_counter_chaud) < 4 * 5) {
                // Timeout is not reaches
                id(event_counter_chaud)++;
              } else {
                  // Timeout is reaches
                  id(last_water_consumption_chaud).publish_state(id(event_quantity_chaud));

                  // Send event to Home Assistant
                  api::HomeAssistantServiceCallAction<> *api;
                  api = new api::HomeAssistantServiceCallAction<>(api_apiserver, true);
                  // Event id length limit is 32 characters
                  api->set_service("esphome.last_consumption_changes_chaud");
                  api->play();

                  id(event_quantity_chaud) = 0;
              }
            }
          }

          id(last_event_quantity_chaud) = id(event_quantity_chaud);

  # Track the current consumption
  - interval: 2sec
    then:
      - lambda: |-
          if (id(event_quantity) != id(current_event_quantity)) {
            id(current_water_consumption).publish_state(id(event_quantity));
          }
          id(current_event_quantity) = id(event_quantity);

          if (id(event_quantity_chaud) != id(current_event_quantity_chaud)) {
            id(current_water_consumption_chaud).publish_state(id(event_quantity_chaud));
          }
          id(current_event_quantity_chaud) = id(event_quantity_chaud);
nliaudat commented 7 months ago

Do not publish any passwords !!

To share code you can use the <> icon

image

acca84 commented 7 months ago

Thanks, that's what i was doing, but i had to paste my code then to click <>

Concerning pins high at boot, it seams that those pins are safe : https://www.studiopieters.nl/esp32-s2-pinout/

acca84 commented 7 months ago

I'm sorry, I didn't check correctly, I have no more problem with esp32s2. So i think I used wrong pins with esp8266