Medindo o volume da caixa de água

image

Este tutorial trata-se da instalação de sensor ultrassônico na caixa de água para medir o volume da mesma integrado ao home assistant e entidades de alerta para volume mínimo e máximo.

O código deste tutorial aplica-se a caixas de água com formato como o mostrado na figura a seguir:
394742_3
O cálculo do volume da caixa será aproximado para a forma de um tronco de cone.

O volume máximo calculado para a caixa será o volume útil (volume utilizável) com base nas características da mesma (principalmente a posição que a boia fecha e a posição das tubulações de saída e do extravasor/ladrão), sendo que pode ser diferente do volume nominal da caixa.

O volume morto é o volume de água que está abaixo da tubulação de saída.

1. Materiais utilizados:

2. Ligação do sensor:

A ligação do sensor ao nodemcu é bem simples:

  1. Ligar o pino 5V do sensor ao pino aos 5V da fonte ou ao pino Vin do nodemcu.
  2. Ligar o pino Trig do sensor ao pino D6 do nodemcu.
  3. Ligar o pino Echo do sensor ao pino D7 do nodemcu.
  4. Ligar o pino GND do sensor a um pino GND do nodemcu.

O sensor deve ser instalado na parte central da tampa da caixa.

3. Informações da instalação e caixa de água:

É necessário obter alguns parâmetros físicos da caixa de água para o cálculo correto do nível e volume de água, a imagem abaixo mostra cada informação necessária com a respectiva sigla da configuração no código:
MedidasCaixa
Configurando os parâmetros físicos da caixa, este código se aplica ao cálculo do volume de caixas deste formato independente do capacidade da mesma (um ponto a se observar é a distância máxima que o sensor é capaz de medir).

4. Código ESPHOME:

Confirme os pinos ligados ao sensor, altere os parâmetros físicos da caixa de água e realize as configurações de rede.

substitutions:
  #Configurações da placa:
  Plataforma: ESP8266
  TipoPlaca: d1_mini
  
  #Configurações do dispositivo:
  hostname: 'casa_caixa_agua' #Hostname do dispositivo na rede
  PrefixoNome: "Caixa Água - "
  
  #Configurações da Rede:
  RedeWifi: !secret RedeWifi_1 #Nome da rede wifi que o dispositivo irá se conectar
  SenhaWifi: !secret SenhaWifi_1 #Senha da rede wifi que o dispositivo irá se conectar
  SenhaWifiReconfig: !secret SenhaWifiReconfig #Senha do AP Wifi para reconfiguração do wifi do dispositivo (padrão: o nome do hostame)
  WifiIP: 192.168.xxx.xxx #Endereço IP
  WifiGateway: 192.168.xxx.xxx #Gateway padrão
  WifiSubNet: 255.255.255.0 #Máscara de subred
  EndConfig: 192.168.xxx.xxx #Endereço para configuração (IP que o esp está acessível atualmente na rede)
  
  #Senhas
  SenhaAPI: !secret SenhaAPI
  SenhaOTA: !secret SenhaOTA
  
  #Pinos do Sensor
  SensorTriggerPin: D6
  SensorEchoPin: D7
  
  #INFORMAÇÕES FÍSICAS DA CAIXA E DA INSTALAÇÃO DO SENSOR (medidas em metros):
  #Diametro interno da base da caixa (fundo)
  DD1: "0.95"
  #Diametro interno da borda superior sem a tampa
  DM: "1.22"
  #Distância entre o fundo da caixa e a borda sem a tampa 
  HB: "0.58"
  #Distância entre o fundo da caixa e a borda superior da tampa (onde o sensor será instalado)
  HT: "0.72"
  #Distância entre o fundo da caixa e o nível da base da tubulação de saída (altura da coluna de água do nível morto)
  HMT: "0.038"
  #Distância entre o fundo da caixa e o nível máximo normal (altura da água onde a boia é fechada)
  HM: "0.54"
  #Distância entre o sensor e o nível máximo normal (altura onde a boia é fechada até o sensor)
  HS: "0.22"
  #Distância entre o fundo da caixa e o nível de transbordamento (ou nível do extravasor/ladrão, o que o ocorrer primeiro)
  HMA: "0.55"

#Logger
  LoggerUART: UART0_SWAP
  LoggerLevel: DEBUG

esphome:
  name: $hostname
  platform: ${Plataforma}
  board: ${TipoPlaca}
  
wifi:
  ssid: ${RedeWifi}
  password: ${SenhaWifi}
  
  manual_ip:
    static_ip: ${WifiIP}
    gateway: ${WifiGateway}
    subnet: ${WifiSubNet}
    
  use_address: ${EndConfig}
  
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: WIFI
    password: ${SenhaWifiReconfig}

#Habilita um AP Wifi para reconfigurar em caso de perda de conexão com a rede configurada
captive_portal:

#Habilita a atualização de firmware por OTA
ota:
  password: ${SenhaOTA}
  
#Habilita as mensagens de logs pela porta serial e via MQTT
logger:
  hardware_uart: ${LoggerUART}
  level: ${LoggerLevel}

#Habilita a api para comunicar com o Home Assistant
api:
  password: ${SenhaAPI}

switch:
############################# SENSORES DEVICE ##################################
  #Comando reinicilizar esp remotamente
  - platform: restart
    id: ${hostname}_restart
    name: ${PrefixoNome} Reiniciar
    icon: mdi:restart

text_sensor:
############################# SENSORES DEVICE ##################################
  #Informações da conexão wifi
  - platform: wifi_info
    #Endereço IP
    ip_address:
      id: ${hostname}_IP
      name: ${PrefixoNome} Endereço IP
      icon: mdi:ip-network
    #Nome da Rede
    ssid:
      id: ${hostname}_SSID
      name: ${PrefixoNome} Rede Wifi
      icon: mdi:wifi
  #Informação da versão da compilação
  - platform: version
    id: ${hostname}_versao
    name: ${PrefixoNome} Versão
    icon: mdi:information

binary_sensor:
############################# SENSORES DEVICE ##################################
  #Status (conectado ou desconectado)
  - platform: status
    id: ${hostname}_status
    name: ${PrefixoNome} Status
    device_class: connectivity

############################# ALERTA DE NIVEIS #################################
  #Nível mínimo de alerta
  - platform: template
    id: NAMIN
    name: ${PrefixoNome} Nível Mínimo de Alerta
    ##internal: True
    lambda: |-
      if (id(VAGUAP).state <= id(AMIN).state) {
        return true;
      } else {
        return false;
      }

  #Nível máximo de alerta
  - platform: template
    id: NAMAX
    name: ${PrefixoNome} Nível Máximo de Alerta
    ##internal: True
    lambda: |-
      if (id(VAGUAP).state >= id(AMAX).state) {
        return true;
      } else {
        return false;
      }
      
  #Erro medição
  - platform: template
    id: ERRO_MED
    name: ${PrefixoNome} Erro Medição
    #internal: True
    lambda: |-
      if (((id(HMED).state>((id(HM).state+id(HS).state)))) or (id(HMED).state<id(HS).state)) {
        return true;
      } else {
        return false;
      }

sensor:
############################# SENSORES DEVICE ##################################
  #Sensor Intensidade Sinal Wifi
  - platform: wifi_signal
    id: ${hostname}_wifi_sinal
    name: ${PrefixoNome} Intensidade Wifi
    icon: mdi:signal
    update_interval: 10s

############################ IMPORT VARIAVÉIS HA ###############################
  - platform: homeassistant
    id: AMIN
    name: ${PrefixoNome} Nível Mínimo de Alerta
    internal: true #false Apenas para debug
    entity_id: input_number.caixa_agua_alerta_nivel_minimo
    accuracy_decimals: 2

  - platform: homeassistant
    id: AMAX
    name: ${PrefixoNome} Nível Máximo de Alerta
    internal: true #false Apenas para debug
    entity_id: input_number.caixa_agua_alerta_nivel_maximo
    accuracy_decimals: 2

############################ SENSOR ULTRASONICO ################################
  - platform: ultrasonic
    id: HMED
    trigger_pin: ${SensorTriggerPin}
    echo_pin: ${SensorEchoPin}
    name: ${PrefixoNome} Distância Medida Sensor
    internal: false
    accuracy_decimals: 6
    update_interval: 1s
    filters:
      - sliding_window_moving_average:
          window_size: 10
          send_every: 10
          send_first_at: 1
      
#################### INFORMAÇÕES FÍSICAS DA INSTALAÇÃO #########################
  #Diametro interno da base da caixa (fundo)
  - platform: template
    id: DD1
    name: ${PrefixoNome} Diâmentro Interno Base
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return ${DD1};
    accuracy_decimals: 4
    update_interval: 1s

  #Diametro interno da borda superior sem a tampa
  - platform: template
    id: DM
    name: ${PrefixoNome} Diâmetro Interno Superior
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return ${DM};
    accuracy_decimals: 4
    update_interval: 1s

  #Distância entre o fundo da caixa e a borda sem a tampa
  - platform: template
    id: HB
    name: ${PrefixoNome} Altura Interna até a borda 
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return ${HB};
    accuracy_decimals: 4
    update_interval: 1s

  #Distância entre o fundo da caixa e a borda superior da tampa (onde o sensor será instalado)
  - platform: template
    id: HT
    name: ${PrefixoNome} Altura com Tampa
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return ${HT};
    accuracy_decimals: 4
    update_interval: 1s
    
  #Distância entre o fundo da caixa e o nível da base da tubulação de saída (altura da coluna de água do nível morto)
  - platform: template
    id: HMT
    name: ${PrefixoNome} Coluna de Água Nível Morto
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return ${HMT};
    accuracy_decimals: 4
    update_interval: 1s
  
  #Distância entre o fundo da caixa e o nível máximo normal (altura da água onde a boia é fechada)
  - platform: template
    id: HM
    name: ${PrefixoNome} Coluna de Água Útil
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return ${HM};
    accuracy_decimals: 4
    update_interval: 1s
  
  #Distância entre o sensor e o nível máximo normal (altura onde a boia é fechada até o sensor)
  - platform: template
    id: HS
    name: ${PrefixoNome} Distância Sensor Nível Máximo
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return ${HS};
    accuracy_decimals: 4
    update_interval: 1s

  #Distância entre o fundo da caixa e o nível de transbordamento (ou nível do extravasor/ladrão, o que o ocorrer primeiro)
  - platform: template
    id: HMA
    name: ${PrefixoNome} Coluna de Água Transbordamento
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return ${HMA};
    accuracy_decimals: 4
    update_interval: 1s
    
######################### CÁLCULOS AUXILIARES ##################################
  #Coluna de água medida (descontado a distância do sensor)
  - platform: template
    id: H
    name: ${PrefixoNome} Coluna de Água Atual
    internal: false
    unit_of_measurement: m
    lambda: return (id(HM).state+id(HS).state-id(HMED).state);
    accuracy_decimals: 4
    update_interval: 1s
    
  #Raio menor do reservatório
  - platform: template
    id: R1
    name: ${PrefixoNome} Raio Menor 
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return (id(DD1).state/2);
    accuracy_decimals: 4
    update_interval: 1s
  
  #Raio maior máximo do reservatório
  - platform: template
    id: RM
    name: ${PrefixoNome} Raio Maior Máximo Físico
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return (id(DM).state/2);
    accuracy_decimals: 4
    update_interval: 1s
  
  #Raio maior máximo de acordo com o nível máximo de água
  - platform: template
    id: R2M
    name: ${PrefixoNome} Raio Maior com Nível Máximo
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return (id(R1).state+(id(HM).state*tan(atan(((id(DM).state-id(DD1).state)/2)/(id(HB).state)))));
    accuracy_decimals: 4
    update_interval: 1s
  
  #Raio maior atual do reservatório (de acordo com o nível da água)
  - platform: template
    id: R2
    name: ${PrefixoNome} Raio Maior com o Nível Atual
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return (id(R1).state+(id(H).state*tan(atan(((id(DM).state-id(DD1).state)/2)/(id(HB).state)))));
    accuracy_decimals: 4
    update_interval: 1s
  
  #Raio maior o volume morto
  - platform: template
    id: RHMT
    name: ${PrefixoNome} Raio Maior no Nível Mínimo
    internal: true #false Apenas para debug
    unit_of_measurement: m
    lambda: return (id(R1).state+(id(HMT).state*tan(atan(((id(DM).state-id(DD1).state)/2)/(id(HB).state)))));
    accuracy_decimals: 4
    update_interval: 1s
    
########################## CÁLCULOS DOS VOLUMES#################################
  #Volume com o reservatório cheio (altura da borda)
  - platform: template
    id: VTT
    name: ${PrefixoNome} Volume com o Reservatório Cheio
    internal: true
    unit_of_measurement: litros
    lambda: return ((1.047197*id(HB).state)*((id(RM).state*id(RM).state)+(id(RM).state*id(R1).state)+(id(R1).state*id(R1).state))*1000)-id(VMT).state;
    accuracy_decimals: 0
    update_interval: 1s

  #Volume de água do volume morto (abaixo da saída)
  - platform: template
    id: VMT
    name: ${PrefixoNome} Volume Morto
    internal: false
    unit_of_measurement: litros
    lambda: return ((1.047197*id(HMT).state)*((id(RHMT).state*id(RHMT).state)+(id(RHMT).state*id(R1).state)+(id(R1).state*id(R1).state))*1000);
    accuracy_decimals: 0
    update_interval: 1s

  #Volume de água com o nível máximo
  - platform: template
    id: VT
    name: ${PrefixoNome} Volume com o Nível Máximo
    internal: false
    unit_of_measurement: litros
    lambda: return ((1.047197*id(HM).state)*((id(R2M).state*id(R2M).state)+(id(R2M).state*id(R1).state)+(id(R1).state*id(R1).state))*1000)-id(VMT).state;
    accuracy_decimals: 0
    update_interval: 1s
    
  #Volume de Água
  - platform: template
    id: VAGUA
    name: ${PrefixoNome} Volume
    unit_of_measurement: litros
    lambda: |-
      if ( (((1.047197*id(H).state)*((id(R2).state*id(R2).state)+(id(R2).state*id(R1).state)+(id(R1).state*id(R1).state))*1000)-id(VMT).state) <0 ) {
        return 0;
      } else if  (  (((1.047197*id(H).state)*((id(R2).state*id(R2).state)+(id(R2).state*id(R1).state)+(id(R1).state*id(R1).state))*1000)-id(VMT).state) > id(VTT).state) {
        return id(VTT).state;
      } else {
        return (((1.047197*id(H).state)*((id(R2).state*id(R2).state)+(id(R2).state*id(R1).state)+(id(R1).state*id(R1).state))*1000)-id(VMT).state);
      }
    accuracy_decimals: 0
    update_interval: 1s

  #Volume Percentual
  - platform: template
    id: VAGUAP
    name: ${PrefixoNome} Volume Percentual
    unit_of_measurement: "%"
    lambda: return ((id(VAGUA).state / id(VT).state)*100);
    accuracy_decimals: 1
    update_interval: 1s

4. Criação dos input number:

Código para os input number de configuração do alerta de nível (os mesmos id_entity usados aqui devem ser usados no código do esphome, nos ids AMIN e AMAX):

input_number:
  caixa_agua_alerta_nivel_minimo:
    icon: mdi:percent
    name: Caixa de Água Nível  Mínimo
    min: 0
    max: 110
    step: 1
    mode: slider
    
  caixa_agua_alerta_nivel_maximo:
    icon: mdi:percent
    name: Caixa de Água Nível Máximo
    min: 0
    max: 110
    step: 1
    mode: slider

Você pode criar os input number incluindo o código acima no arquivo de configuração do home assistant ou manualmente acessando Configurações > Ajudantes > Adicionar Ajudante > Número.

5. Lovelace

Card simples para o lovelace com todas as entidades:

Código:

type: grid
columns: 1
title: Caixa de Água
cards:
  - type: entities
    entities:
      - binary_sensor.caixa_agua_erro_medicao
      - sensor.caixa_agua_volume
      - sensor.caixa_agua_volume_percentual
      - sensor.caixa_agua_volume_com_o_nivel_maximo
      - sensor.caixa_agua_volume_morto
    title: Volume
  - type: entities
    entities:
      - entity: sensor.caixa_agua_distancia_medida_sensor
      - entity: sensor.caixa_agua_coluna_de_agua_atual
    title: Sensor
  - type: entities
    entities:
      - entity: input_number.caixa_agua_alerta_nivel_maximo
      - entity: input_number.caixa_agua_alerta_nivel_minimo
      - entity: binary_sensor.caixa_agua_nivel_maximo_de_alerta
      - entity: binary_sensor.caixa_agua_nivel_minimo_de_alerta
    title: Níveis de Alerta
  - type: entities
    entities:
      - entity: binary_sensor.caixa_agua_status
      - entity: sensor.caixa_agua_rede_wifi
      - entity: sensor.caixa_agua_intensidade_wifi
      - entity: sensor.caixa_agua_endereco_ip
      - entity: switch.caixa_agua_reiniciar
      - entity: sensor.caixa_agua_versao
    title: Informações do Dispositivo
square: false

6. Erro de Medição:

A entidade erro de medição para ser verdadeira verifica uma das seguintes condições:

  • Se a distância medida pelo sensor é maior que a altura do nível máximo + a distância do sensor ao nível máximo.
  • Se a distância medida pelo sensor é menor que a distância entre o sensor e o nível máximo.
5 Likes

Cara, QUE OBRA DE ENGENHARIA, PARABÉNS MAN!!!

2 Likes