ESP rain detector

The sensor has labels on each pin. Its pretty self explanatory.

1 Like

Those are great questions.

In the sample YAML, I am updating the sensor every 5 seconds. you should see - interval: 5s under interval:. You can change it to a value that suits you. For my case, I found setting it to 60s to be good enough.

I did not think of a weather based integration. But now you say it, it seems to me that would add unnecessary point of failure and dependency on internet connectivity for the benefit we will get from it.

Also note the delays before and after the sensor update. These help sensor warm-up and reading time. For simple sensor as rain sensor that uses resistance, a short delay is fine. However, for other sensors, based on the manufacturer, you may need longer delays.

Regarding the wiring, I used the same as in the YAML file. Pins from left to right with the back of the board facing you.

  VCC on sensor -> D7 on esp32
  GND on sensor -> GND on sp32
  A0 on sensor -> A0 on esp32
  D0 on sensor -> D2 on esp32

PS: I updated the original code to add substitutions on top to control interval, warmup and cooldown.

Hello,
I am also trying to build a weather station and have the same rain sensor and a few other sensors (BMP280, DHT22) which I have already got working.
Unfortunately I am having problems with the rain sensor.
To solve the problem, I created a YAML that only contains the rain sensor with the code from “Shamasis”.
When uploading to my ESP32 (board: az-delivery-devkit-v4) I get the following error message
error: ‘GPIO33’ was not declared in this scope
GPIO pin 33 is assigned as pin_rs_digital.
I have already tried different GPIO pins.
If I comment out these lines

  • lambda: |-
    bool rain_state = !digitalRead(${pin_rs_digital});
    id(rain_sensor).publish_state(rain_state);

the code can be installed on the ESP32
But, I don’t get any changes in the values when I apply a drop of water to the sensor
‘water_resistance’: Sending state 109.88889 V with 2 decimals of accuracy
‘Raindrop Coverage Sensor’: Sending state 0.00000 % with 1 decimals of accuracy

I would be happy if someone could help me, as I am a real beginner in the lambda functions.

Thank you very much

substitutions:
  name: esp32-weatherstation
  friendly_name: ESP32_WeatherStation
  board: az-delivery-devkit-v4
  pin_power: GPIO32
  pin_rs_analog: GPIO36
  pin_rs_digital: GPIO33
  sensor_update_interval: 5s
  sensor_warmup: 10ms
  sensor_cooldown: 10ms
  
esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  name_add_mac_suffix: false
  project:
    name: esphome.web
    version: '1.0'

esp32:
  board: ${board}
  framework:
    type: arduino
    version: 2.0.0

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "XXXX"

ota:
  password: "XXXX"

globals:
  - id: rain_state
    type: bool
    restore_value: no
    initial_value: 'false'

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp32-Weatherstation"
    password: "XXXX"

dashboard_import:
  package_import_url: github://esphome/example-configs/esphome-web/esp8266.yaml@main
  import_full_config: true

# --------------------------------------------------------------------------------------------

sensor:
  - platform: adc
    pin: ${pin_rs_analog}
    id: water_resistance
    internal: true
    filters:
      - calibrate_linear: # trim erroneous 5% edges
          - 0.05 -> 0.0
          - 0.95 -> 100.0
  
  - platform: template
    name: "Raindrop Coverage Sensor"
    id: raindrop_coverage_sensor
    accuracy_decimals: 1
    unit_of_measurement: "%"
    icon: "mdi:water-percent"

binary_sensor:
  - platform: template
    name: "Rain Sensor"
    id: rain_sensor
    device_class: moisture
    icon: "mdi:umbrella"

# we read data every 5 seconds and update the sensors
interval:
  - interval: ${sensor_update_interval}
    then:
      - output.turn_on: sensor_power
      - delay: ${sensor_warmup}
      - component.update: water_resistance
      - sensor.template.publish:
          id: raindrop_coverage_sensor
          state: !lambda |-
            return std::max(0.0, std::min(100.0, 100.0 - id(water_resistance).state));
      #- lambda: |-
      #    bool rain_state = !digitalRead(${pin_rs_digital});
      #    id(rain_sensor).publish_state(rain_state);
      - delay: ${sensor_cooldown}
      - output.turn_off: sensor_power
      

# This Pin provides power to the sensor. We use one of the pins so that
# we can power on the sensor right before reading data and power back off.
# This reduces power consumption, but more importantly, being exposed to
# water, it reduces the side effects of sensor's physical corrosion.
output:
  - platform: gpio
    pin: ${pin_power}
    id: sensor_power

Hi @Slein.

Does anything around the water sensor work? I mean, at a quick glance I could not spot any issue with your lambda. (I am not an expert either.) I was thinking of taking your code and flashing it to try. But before I do that, if you don’t mind, can you confirm if you have checked some of the basics with your setup?

  1. Can you log the value of digital read? Using something like. (Temporarily remove other lambdas to be more confident.)
      - lambda: |-
         int digital_value = digitalRead(${pin_rs_digital});
         ESP_LOGD("main", "Digital Read Value: %d", digital_value);
  1. I am not familiar with the variant of your board can you ensure that GPIO33 (used as pin_rs_digital) is a valid pin for digital read operations on your specific ESP32 board. GPIO33 should be usable, but it’s always good to confirm with the ESP32 pinout for the az-delivery-devkit-v4.

  2. Does the sensor work? Using a simple 3v3,GND,GPIO33GPIO36 connection and an update_interval: 10s on the sensor and logging it, do you see values?

Update: Also check with return std::max(0.0, std::min(100.0, 100.0 - id(water_resistance).state()));. (called the .state() function instead of .state prop)

I have set everything up according to these instructions, but apparently there are some problems with the configuration. There is also an issue about this on GitHub. Basically, the idea is great, but I think the code needs to be revised. I don’t understand the code completely, so I’m a bit helpless.

When flashing, you get the message that the attenuation of 11dB is outdated and you should use 12dB. In the ESPhome documentation it also says that the adc behaves differently since 2021.11. Does the code have to be adapted in this respect?

The status “rain” is only ever displayed briefly in Home Assistant and then “watching” is displayed. When it stops raining, “drying” is displayed. I have never seen “dry” displayed, for example.

I think ist is due to the following code:

Test for dry

  # We assume sensor is dry when current resistance == max resistance
  - if:
      condition:
        lambda: "return id(resistance_sensor).state == $max_resistance;"
      then:
        - script.execute: its_dry

  - script.execute: end_measure
  - script.wait: end_measure

If the max_resistance ist defined here:

Skip the value not in the range

min_resistance: “1000”
max_resistance: “500000”

but the

[D][sensor:094]: ‘Rain Detector resistance’: Sending state 42138.82031 Ω with 1 decimals of accuracy

the condition will never be true and therefore the status never changes to “dry”. But as i said i don’t understand the code completely. Maybe i’m completely wrong.

I think it would be great and certainly help many people if someone who understands the code could update it so that there is a good, working guide for a simple and cheap rain detector. :grinning:

Ok… i think we need to clarify which rain sensor exactly you’re using. Got a model number? Link?, picture? Are you 100% sure its even analog? Does it have analog and digital pins? This is important details you need to always add or else how are we supposed to know if the problem is the code or the sensor?

I had the same problem with various pins I tried to my NodeMCU v.3 board.
Finally the solution was to declare only the pin number in quotes.

pin_rs_digital: '16'  # instead D0 or GPIO16 on my board or
pin_rs_digital: '33'  # instead GPIO33 as in your example