How to check if someone is in bath?

Got it. Testing trend first
By the way, should not derivatives also solve this problems?
It would show how fast humidity is changing, if I am not mistaken

P.S. I don’t really want to use custom component if default once can handle this task. That’s why I’m starting with trend

For humidity, look at the rate-of-rise or slope of the line ( derivative of FFT of data points) to get an accurate detection.

If I were to design something to check bath usage, I would use 3 temp probes and some logic. The probes would be located:

1 in the drain, 1 at the source (handle), 1 at the top of the exit (before shower nozzle)

That would allow detection if you are showering or using the bath (if you have a shower), thought it would be a lot of work since temp probes need to be placed on copper pipes

steady high temp at the top and drain = shower
constant high temp at source, then drop in drain, then drop at source = bath filled
increase temp in drain then dropoff = bath drained

You could also use a microphone to detect the sound of a bath filling or shower running, they have different acoustic profiles, volume levels in specific frequency bands are pretty obvious. My bath is adjacent to another room, an an acoustic probe placed on that rooms wall would probably work, keeping the hardware out of the bathroom and away from humidity.

Temp + acoustic + humidity triggers would make a bulletproof detection system

True, I think when I first looked at this HA did not have a derivative sensor.

If the generic hygrostats do not meet your requirements. Just use the generic_thermostat. I’ve used that for ages for my hygrostats, since there was not really any alternatives. Only you have to live with pretending your humidity is temperature.

Here is how I handle the light in bathroom using humidity and motion

id: '1596963203067'
  alias: Bathroom light ON [ON MOTION]
  - platform: state
    entity_id: binary_sensor.motion_2, binary_sensor.presence_1
    to: 'on'
  - platform: device
    type: turned_on
    device_id: d2296767263e4c6f84f7538991381d85
    entity_id: light.bathroom
    domain: light
  - service: light.turn_on
    entity_id: light.bathroom
  mode: single
- id: '1596963203063'
  alias: Bathroom light OFF [MOTION 10 min]
  - entity_id: binary_sensor.motion_2, binary_sensor.presence_1
    for: 0:05:00
    platform: state
    to: 'off'
  - condition: device
    type: is_on
    device_id: d2296767263e4c6f84f7538991381d85
    entity_id: light.bathroom
    domain: light
      hours: 0
      minutes: 0
      seconds: 0
  - wait_template: '{{float(states(''sensor.th_7_humidity'')) < float(80)}}'
    continue_on_timeout: false
  - type: turn_off
    device_id: d2296767263e4c6f84f7538991381d85
    entity_id: light.bathroom
    domain: light
  mode: single

I did a little differently.
The fan in my bathroom is connected via Sonoff TH10 with AM2301 (temperature + humidity) sensor. ESPHome-based firmware is uploaded inside it.
The system can autonomously maintain the set indoor humidity (default: 75%). In this case, the states of the sensors are broadcast to HA and through MQTT you can reconfigure the fan response threshold.
You can also temporary change the threshold for a specified time. At the end of which, the system will return to the previous state.
The second option: by pressing a button on the TH10, the fan is forced to start for 5 minutes (also works without the participation of a smart home).

The general logic is simple: remove as much primitive work from the smart home as possible. At the same time, leaving it in full control of the situation.

Regarding the main topic …
IMHO, to accurately determine the presence of people, you will need two sensors: a door opening sensor + a PIR sensor.
Let us take as X time how long the PIR sensor waits before canceling the “in motion” state.
The logic is this:

  • The door is open - the light is always on;
  • If the door is closed more than X …
    • if the PIR sensor is ON (indicates the presence of movement), then there are people in the room. We leave this state unchanged until the door is opened.
    • if the PIR sensor is OFF (indicates there is no movement), then there are no people in the room and you can turn off the light.

I already use motion + door sensor
And I have that logic
But here is the case:
You leave bathroom and immediately next person gets in. Motion is not longer detected but person is in bath, Home Assistant thinks that person left (first person did) and turns off the light while you are in bath
that’s a rear case, that’s why I am ok for more than a year now with that logic, but it can be better

If there are failures, then you have some kind of violation of logic.

Or the PIR sensor is not scanning the entire room. Or the state of the PIR sensor is not checked after the X timeout after the door is closed.

If a person left and closed the door, after time X the PIR sensor will turn off. If a new person came next, he would move at least for a few seconds. This means that in time X after the door is closed, the PIR sensor will still be turned on.

Motion sensor just can not see a person in bath

Hi, If its of any use and you don’t mind using node red I created a function for detecting the rate of rise of temperature but you could adapt it for your use. The function just really compares two values it receives in succession and calculates the difference. So for the actual rate of rise you would need to send the temp/humidity values at an interval of 1 min or more.

Node Red Flow
Screenshot 2020-11-21 at 22.17.01

[{"id":"e6994f2d.a8f94","type":"function","z":"4b74def4.25059","name":"compare","func":"// See Setup TAB for where the variables are initialised.\n//  Function to compare 2 values to send a payload based on either\n// rate of rise trigger or Max Temperature reached\n\n\n\nvar previoustemp = context.get('previoustemp'); //previous temperature value\nvar currenttemp =  context.get('currenttemp'); // current temperature value\nvar payloadtemp = msg.payload; // current temperature value\n\n// Change the RoR value for the Rate of Rise trigger \nvar RoR = 7.5;\n// Change the MAX Temperature Value \nvar maxtemp = 60;\n\n\ncontext.set('currenttemp',payloadtemp); //set the current temperature to temp2 variable\ncurrenttemp=context.get('currenttemp');\n\n//Temperature difference between 2 values\ntempdif=currenttemp-previoustemp; \n\n// set the message payload based on conditions\nif ((previoustemp == -300) && (maxtemp > payloadtemp)) {msg.payload=\"Previous temp is null can't give rate of rise yet until i receive another value\"}\nelse if (maxtemp < payloadtemp) {msg.payload={\"FireDetected\":\"true\", \"MaxTemp\":payloadtemp}}\nelse if (tempdif > RoR) {msg.payload={\"FireDetected\":\"true\", \"RateofRise\":tempdif };}\nelse if (previoustemp !== -300) {msg.payload={\"FireDetected\":\"false\", \"RateofRise\":tempdif};}\n\n// set previous temperature to the value of current temperature\ncontext.set('previoustemp',currenttemp);\n\n// Return the new message\nreturn msg;\n\n\n\n\n\n\n\n\n// if (temp3>6.7) {\n//  msg.payload= \"on \" + count + temp1 +temp2;\n//  return msg.payload;\n//}  else {\n//  return null\n//}\n","outputs":1,"noerr":0,"initialize":"//Initialise the variables \nvar previoustemp = context.get('previoustemp') || -300; //previous temperature value\nvar currenttemp =  context.get('currenttemp') || -300; // current temperature value\nvar tempdif =null;\ncontext.set('previoustemp',-300);","finalize":"","x":300,"y":640,"wires":[["f2b59f04.059708"]]},{"id":"d3f359ba.7105e8","type":"inject","z":"4b74def4.25059","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"4","payloadType":"num","x":130,"y":620,"wires":[["e6994f2d.a8f94"]]},{"id":"7f6a7349.ff7714","type":"inject","z":"4b74def4.25059","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"10","payloadType":"num","x":130,"y":660,"wires":[["e6994f2d.a8f94"]]},{"id":"ed8d44b7.85f87","type":"inject","z":"4b74def4.25059","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"20","payloadType":"num","x":130,"y":700,"wires":[["e6994f2d.a8f94"]]},{"id":"f2b59f04.059708","type":"debug","z":"4b74def4.25059","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":480,"y":640,"wires":[]},{"id":"e13159fc.392a88","type":"inject","z":"4b74def4.25059","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":130,"y":580,"wires":[["e6994f2d.a8f94"]]},{"id":"5cc2a0c5.2b13","type":"inject","z":"4b74def4.25059","name":"Max Temp 61","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"61","payloadType":"num","x":150,"y":740,"wires":[["e6994f2d.a8f94"]]}]

@nickrout , could you explain how a hygrostat would help here?

As far as I understood, the hygrostat reacts/switches when it detects changes relative to a fixed set point for (relative) humidity. As you pointed out, bath action detection needs to take changing background humidity into account. How would one accomplish this with the hygrostat integration?

@michib I would use this custom integration. GitHub - basschipper/homeassistant-generic-hygrostat: Generic Hygrostat for Home Assistant

I am surprised that no one suggested the VL53 series of “TOF Sensors”. These sensors measure the distance to an object, even through a layer of sheetrock.

From another thread:

(Why they are called “Time of Flight” is a mystery. They are simply a radar-based distance sensor).

Because they have read the first post which set out that the OP wanted to capture sharp rises in relative humidity, not presence.

1 Like

Just offering an alternative solution, like others in the thread did.

I would accomplish this the same way I already have: humidity sensor in the bathroom, and a humidity sensor not in the bathroom. Compare the humidity in the bathroom to the general humidity elsewhere in the house. If the humidity in the bathroom is a significant amount higher than that in the rest of the house, the bath/shower is being used. In my case, I use it to determine how long to run the exhaust fan for, but I see no reason it couldn’t be used in the manner OP was looking for.

IMO, this is much easier than looking for spikes in a graph.

Because they measure the time it takes for a light (photon) packet sent from the sensor to bounce back to it. Radar also uses the time of flight physical principle, but ToF sensors are not radar. They’re optical devices using an infrared laser, while radar uses RF waves. Radar can penetrate walls and bounce back from metallic structures. Tof behaves like visible light and is closer to LiDAR.

LOL Time of Foton Light?

Time of Photon Flight :slight_smile:

Jokes aside, the physics behind these things is fascinating and shows just how advanced these devices really are. Good ToF sensors actually detect, count and measure individual photons using a SPAD (single photon avalanche diode). They count ‘particles of light’, while RF radars use interference, treating RF ‘light’ as a wave. Wave particle duality in practice :slightly_smiling_face:

Okay back to bathroom humidity !