[Automation] Shower detection: trigger when humidity increases in 10 minutes?

Can anyone help me to set up an automation trigger when humidity increases (say 10%) within 10 minutes?

My goal is to switch on a bathroom fan when this happens (shower detection).

Iā€™ve got Xiaomi humidity sensors that I use to detect shower occupancy in two bathrooms. I use the trend sensor to detect the rate of change, and the rate of humidity change tells me if the shower is occupied or not. I use the trend sensors to switch on the bathroom fan, plus Iā€™ve got the lights tied to motion detectors, and I donā€™t want those lights going off if somebody is in the shower.

Here are the docs for how the trend sensor works:

Youā€™ll probably need to tweak the sample duration and the min_gradient to get things dialed in for your particular instance. Iā€™ve included my trend sensor configuration below, so you can see an example for your use case. The code below lives in my configuration.yaml file.

binary_sensor:
  # Tracks 3 humidity readings over 10 minutes. If the change is greater than 10%, evals to true. (10/(60*10))
  - platform: trend
    sensors:
      master_bath_shower_occupancy:
        max_samples: 3
        entity_id: sensor.xiaomi_master_bath_humidity
        sample_duration: 600
        min_gradient: 0.01666
  # Tracks 2 humidity readings over 5 minutes. If the change decrease is greater than 5%, evals to true. (-5/(60*5))
  # Bumped samples down from 4 to 2, because it was staying on way too long.
  - platform: trend
    sensors:
      master_bath_shower_occupancy_off:
        max_samples: 2
        entity_id: sensor.xiaomi_master_bath_humidity
        sample_duration: 300
        min_gradient: -0.016666
        
  # Tracks 4 humidity readings over 5 minutes. If the change is greater than 10%, evals to true. (10/(60*5))
  # Guest bath trends spike faster because it's a smaller room.
  - platform: trend
    sensors:
      guest_bath_shower_occupancy:
        max_samples: 4
        entity_id: sensor.guest_bathroom_humidity
        sample_duration: 300
        min_gradient: 0.033333
  # Tracks 4 humidity readings over 5 minutes. If the change decrease is greater than 5%, evals to true. (-5/(60*5))
  - platform: trend
    sensors:
      guest_bath_shower_occupancy_off:
        max_samples: 4
        entity_id: sensor.guest_bathroom_humidity
        sample_duration: 300
        min_gradient: -0.016666
16 Likes

I went back and looked at my automation, and Iā€™m only using that trend sensor for the lights.
It turns out I handled fan automation a different way, but either method should work.

For kicking on the bathroom fan, I measured humidity in the bathroom, and in the room adjacent to the bathroom, and when the difference between those two rooms is greater than 5%, I kick on the fan. (I initially tried to tie the fan to a single humidity sensor, but since i live in a rainforest, the humidity hits 100% on occassion)
You can create a template sensor that compares the two humidity readings. Hereā€™s the sensor creation from my sensors.yaml

  - platform: template
    sensors:
      bath_humidity_change:
        friendly_name: "Bathroom Humidity Change"
        value_template: "{{ (states.sensor.xiaomi_master_bath_humidity.state | int ) - (states.sensor.zb_bedroom_humidity.state | int)}}"
        device_class: "humidity"
        unit_of_measurement: '%'

Hereā€™s the automation that actually kicks on the fan from my automations.yaml

  alias: Bathroom fan kicks on above 10% humidity difference
  trigger:
  - above: '10'
    entity_id: sensor.bath_humidity_change
    platform: numeric_state
  condition:
  - condition: state
    entity_id: switch.zw_bathroom_fan
    state: 'off'
  - after: 06:00:00
    before: '21:00:00'
    condition: time
  action:
  - data:
      entity_id: switch.zw_bathroom_fan
    service: switch.turn_on```
8 Likes

@RyanRayNeff Thank you for responding and providing me with enough info to get things done!

Appreciated! :+1:

1 Like

Anyone knows how to add this as a MQTT-binary sensor?

I get an error message saying the MQTT device: extra keys not allowed @ data['sensors']

I use Node Red trying to the sensor included with a function node with this payload:

var _payload = {
    "name": "Mqtt ShowerDectectIncrease",
    "unique_id": "mqtt_showerdectincr",
    "state_topic": _topic + "/state",
    "platform": "trend",
    "sensors": {
        "bath_humidity_increase": {
            "max_samples": 3,
            // My Bathroom Humidity sensor
            "entity_id": "sensor.badkamer_badk_sens_vocht",
            "sample_duration": 600,
            // Calculation formula:
            // (INCREASE_IN_%(60*MINUTES))
            "min_gradient": 0.0166
        }
    },
    "device": {
        "name": "Mqtt ShowerDectectIncrease",
        "manufacturer": "MQTT Hass.io",
        "model": "Custom",
        "identifiers": ["Mqtt ShowerDectectIncrease"],
        "sw_version": "20200112"
        }
    };

Anyone have a clue how to get this done? Do I do something wrong in my configured payload?

EDIT: Made a separate topic to achieve this:

For the ones that still looking for an answer with just 1 humidity sensor. I have the following that is working consistently for the past weeks.

In configuration:

sensor:
  - platform: statistics
    name: Bathroom Humidity Stats
    entity_id: sensor.your_bathroom_humidity_sensor
    sampling_size: 40
    max_age:
      hours: 1

binary_sensor:
  - platform: template
    sensors:
      showering:
        value_template: ā€œ{{ states(ā€˜sensor.your_bathroom_humidity_sensorā€™) | int > states(ā€˜sensor.bathroom_humidity_statsā€™) | int and states(ā€˜sensor.bathroom_humidity_statsā€™) != ā€˜unknownā€™ }}ā€
        friendly_name: Showering
        device_class: occupancy

Now we can know if someone is showering by checking if the current humidity percentage is higher than the average of the past hour, if so, youā€™re probably showering. Only thing we need to do now, is turn the ventilator on/off when showering is on/off:

  - alias: '[Ventilator] Turn on/off ventilator if someone is taking a shower'
    trigger:
      - platform: state
        entity_id: binary_sensor.showering
    action:
      - choose:
        - conditions:
          - condition: state
            entity_id: binary_sensor.showering
            state: 'on'
          sequence:
            - service: switch.turn_on
              data:
                entity_id:
                  - switch.your_bathroom_ventilator
        - conditions:
          - condition: state
            entity_id: binary_sensor.showering
            state: 'off'
          sequence:
            - service: switch.turn_off
              data:
                entity_id:
                  - switch.your_bathroom_ventilator

Edit: updated with better coding standards.

10 Likes

Hi Peter, thanks for that, itā€™s just what I was looking for. Iā€™m having a problem with the binary sensor not detecting when the shower is running. My humidity sensor is sensor.ensuite_ble_humidity and the stats sensor is sensor.ensuite_bathroom_humidity_stats, which is generating correct values. This is my binary sensor:

    ensuite_showering:
        value_template: '{{ sensor.ensuite_ble_humidity.state | int > states.sensor.ensuite_bathroom_humidity_stats.state | int and states.sensor.ensuite_bathroom_humidity_stats.state != "unknown" }}'
        friendly_name: EnSuite Shower 
        device_class: occupancy

Iā€™m still getting to grips with templating, so itā€™s probably something obvious. The binary sensor stays off even when the humidity is greater than the stats value. Iā€™ve tried changing the comparison to less than (<) but it still stays off. Any ideas?

Seems that youā€™re missing ā€˜states.ā€™ in your first sensor.

Can you try this:

    ensuite_showering:
        value_template: '{{ states.sensor.ensuite_ble_humidity.state | int > states.sensor.ensuite_bathroom_humidity_stats.state | int and states.sensor.ensuite_bathroom_humidity_stats.state != "unknown" }}'
        friendly_name: EnSuite Shower 
        device_class: occupancy

I thoght I had compared them, but obviously all those states confused my brain!

Itā€™s working now, many thanks.

Pat

Wow thank you for this great sensor! this helped me a lot to do some advanced bathroom automation.

I now play a random Spotify playlist on my bathroomspeaker when iā€™m showering, turn on the bathroom dehumidifier and fan when iā€™m showering. Also the bathroom lights (that turn on with opening the door, and until now go off after 15 minutes) are prevented to go off when still showering.

And everything goes off when i leave the bathroom or Humidity is down a acceptable level.

Hi @petergerdes,
Looks like a great solution, but Iā€™m curious about the false-positive rate of this sensor. I mean - we take the average humidity of the last hour and compare it with the current humidity.
Assuming that we calculate the average with one hour window due to the fact that a single sample is not enough (the humidity isnā€™t a constant through the day), so 2 samples are not equal to each other, if the latter sample is bigger than the previous - we will get a false-positive, right?

1 Like

For my house these variables work best (after a trial and error period with a significant other who got annoyed :joy:), but it might indeed not work for every bathroom. I donā€™t get false-positives anymore, but I would suggest to play with the variables until you have something that works perfectly for your bathroom :slight_smile:

1 Like

thank you for pointing me in the right direction in getting my fan to turn on when humidity is detected!
Iā€™ve got a problem with false triggers though. just a question about the bathroom humidity stat- if i increase the max age of the sample to say 2 hours, do i need to double the sample size?

I would double the sample size as well.

1 Like

I have just started using these sensors and automations to control some bathroom ventilation as well. Its working pretty well but want to see if I can get the fans to run a bit less.

Is it possible, in the binary sensor value template to add some maths so that it turns on at 5-10% above average humidity level? My templating skills are non existent, any help would be much appreciated.

Would it just be:

        value_template: '{{ sensor.your_bathroom_humidity_sensor.state | int > states.sensor.bathroom_humidity_stats.state | int +5 and states.sensor.bathroom_humidity_stats.state != "unknown" }}'

or is that too easy?

Thatā€™s the way it should work indeed!

Maybe this is a bit more safe:

        value_template: '{{ sensor.your_bathroom_humidity_sensor.state | int > (states.sensor.bathroom_humidity_stats.state | int + 5) and states.sensor.bathroom_humidity_stats.state != "unknown" }}'

See the warning box here:

Use states("sensor.your_bathroom_humidity_sensor"). So:

    value_template: >-
      {{ states("sensor.your_bathroom_humidity_sensor")|int >
         states("sensor.bathroom_humidity_stats")|int + 5 and
         states("sensor.bathroom_humidity_stats") != "unknown" }}

Note that this looks for a 5 percentage point increase, so if the average is 95%+, itā€™ll never trigger.

To throw another way to accomplish this out there. I use the Average Sensor (available via HACS [also here: GitHub - Limych/ha-average: Average Sensor for Home Assistant]).

- platform: average
  name: Master Bathroom Humidity Average
  duration:
    days: 1
  entities:
    - sensor.master_bathroom_sensor_relative_humidity_measurement

I then created an input_number which saves a threshold. This is used so I can easily update this threshold without having to restart HA.

master_bath_humidity_threshold:
  name: Master Bath Humidity Threshold
  min: 0
  max: 20
  initial: 9
  mode: box
  step: 1

I use a binary_sensor to check if the current humidity minus the average humidity is greater than the input_number threshold.

    master_bath_fan_sb:
      friendly_name: Master Fan S/B Status
      value_template: "{{ (states('sensor.master_bathroom_sensor_relative_humidity_measurement')|int - states('sensor.master_bathroom_humidity_average')|int) > states('input_number.master_bath_humidity_threshold')|int }}"

This automation then works to turn the fan on/off based on the value of the binary_sensor changing.

- id: '1555779101294'
  alias: Master Bath Fan - TOGGLE
  trigger:
  - entity_id: binary_sensor.master_bath_fan_sb
    for: 00:00:30
    platform: state
  condition: []
  action:
  - data:
      entity_id: switch.master_bath_fan
    service_template: switch.turn_{{trigger.to_state.state}}

Really all you need is the average sensor and the automation - I just use the input_number to allow me to change the ā€˜testā€™ without restarting / editing the automation. Same with the binary_sensor - this could be done in the automation itself with a trigger template and/or by breaking into two automations. Anyhow, more than one way to skin a cat, as always, with HA.

5 Likes

trying to follow along and the binary sensor is throwing errors in the confog. Would you be able to share more of your config around the binary sensor?

You most likely have incorrect formatting. Just post the error instead.