Detect if somebody is taking a shower

Please provide me one :slight_smile:

Try and play with this sample simulation flow

Start with setting the outside (means in the room next to the bathroom) sensor relative humidity level, assuming 30% RH

Then increase the humidity level in the shower, click a couple of times and you will see that the bathroom status changes from "vacant" to "occupied". Now end showering by reducing the shower humidity level and after a few clicks it should change back to "vacant" again

The required delta level between outside and shower is configured in the function nodes javascript code

[{"id":"4beb05f9.86c54c","type":"function","z":"8634f4e6.6557b8","name":"","func":"var hum_outside = flow.get('hum_outside')||30;\nvar hum_shower = flow.get('hum_shower')||30;\nvar sensor = msg.sensor;\nvar delta = 10; //set to the desired threshold level\n\nswitch(sensor){\n    case \"outside\":\n        flow.set(\"hum_outside\", msg.payload);\n        break\n        \n    case \"shower\":\n        flow.set(\"hum_shower\", msg.payload);\n        break\n}\n\nif (hum_shower > hum_outside + delta){\n    msg.payload = \"occupied\";\n}\nelse{\n    msg.payload = \"vacant\";\n}\n\nnode.status({\n\ttext : \"Shower RH%: \"+hum_shower.toString()+' '+\"Outside RH%: \"+hum_outside.toString()\n});\n\nreturn msg;","outputs":1,"noerr":0,"x":1030,"y":250,"wires":[["b980b462.363868"]]},{"id":"21cf8b7f.cb70a4","type":"smooth","z":"8634f4e6.6557b8","name":"","property":"payload","action":"mean","count":"5","round":"","mult":"single","x":680,"y":170,"wires":[["5a86f71c.b62ea8"]]},{"id":"2712565b.cad90a","type":"smooth","z":"8634f4e6.6557b8","name":"","property":"payload","action":"mean","count":"5","round":"","mult":"single","x":680,"y":350,"wires":[["f429a2ba.72f8"]]},{"id":"5a86f71c.b62ea8","type":"change","z":"8634f4e6.6557b8","name":"","rules":[{"t":"set","p":"sensor","pt":"msg","to":"outside","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":840,"y":170,"wires":[["4beb05f9.86c54c"]]},{"id":"f429a2ba.72f8","type":"change","z":"8634f4e6.6557b8","name":"","rules":[{"t":"set","p":"sensor","pt":"msg","to":"shower","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":840,"y":350,"wires":[["4beb05f9.86c54c"]]},{"id":"b980b462.363868","type":"debug","z":"8634f4e6.6557b8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1220,"y":250,"wires":[]},{"id":"76208144.26d0b","type":"inject","z":"8634f4e6.6557b8","name":"Outside 30","topic":"","payload":"30","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":480,"y":170,"wires":[["21cf8b7f.cb70a4"]]},{"id":"1eaeac81.dc9843","type":"inject","z":"8634f4e6.6557b8","name":"Shower 30","topic":"","payload":"30","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":480,"y":350,"wires":[["2712565b.cad90a"]]},{"id":"a6ccb4d9.53bbf8","type":"inject","z":"8634f4e6.6557b8","name":"Shower 40","topic":"","payload":"40","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":480,"y":400,"wires":[["2712565b.cad90a"]]},{"id":"b410272.681a6d8","type":"inject","z":"8634f4e6.6557b8","name":"Shower 50","topic":"","payload":"50","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":480,"y":450,"wires":[["2712565b.cad90a"]]}]
1 Like

In your function where do you set the local variables to what is in msg.payload? (hint hint)

Complicated stuff. I will try to understand this.

Another simulation flow

[{"id":"55e24072.959fb","type":"function","z":"15462191.80250e","name":"fake hum change","func":"var c = context.get(\"c\") || 15\nvar r = Math.random()\nvar d = context.get(\"d\") || \"up\"\n\nif(d === \"up\"){\n    if(c < 20){\n        c += r\n    }\n    else {\n        d = \"down\"\n        c -= r\n        \n    }\n}\nelse{\n   if(c > 10){\n        c -= r\n    }\n    else {\n        d = \"up\"\n        c += r\n        \n    } \n}\ncontext.set(\"d\",d)\ncontext.set(\"c\",c);\n\nmsg.payload = c\nreturn msg;","outputs":1,"noerr":0,"x":240,"y":160,"wires":[["142f8e0f.5b00c2"]]},{"id":"9ca2ebbb.5409f8","type":"inject","z":"15462191.80250e","name":"","topic":"","payload":"","payloadType":"date","repeat":".5","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":100,"wires":[["55e24072.959fb"]]},{"id":"2d74af35.2e8bb","type":"switch","z":"15462191.80250e","name":"","property":"payload","propertyType":"msg","rules":[{"t":"gt","v":"hum","vt":"global"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":370,"y":280,"wires":[["3ec8985b.0de778"],["9bb8b1a6.49e07"]]},{"id":"142f8e0f.5b00c2","type":"rbe","z":"15462191.80250e","name":"","func":"deadbandEq","gap":"2","start":"","inout":"out","property":"payload","x":300,"y":220,"wires":[["2d74af35.2e8bb"]]},{"id":"3ec8985b.0de778","type":"change","z":"15462191.80250e","name":"","rules":[{"t":"set","p":"humdirection","pt":"global","to":"up","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":260,"wires":[["be78dd6.ddc7e2"]]},{"id":"9bb8b1a6.49e07","type":"change","z":"15462191.80250e","name":"","rules":[{"t":"set","p":"humdirection","pt":"global","to":"down","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":300,"wires":[["be78dd6.ddc7e2"]]},{"id":"1607b36f.5088ed","type":"delay","z":"15462191.80250e","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"5","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":490,"y":360,"wires":[["12096a0f.48f676","eab37a99.dfe1c8"]]},{"id":"eab37a99.dfe1c8","type":"switch","z":"15462191.80250e","name":"","property":"humdirection","propertyType":"global","rules":[{"t":"cont","v":"up","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":430,"y":440,"wires":[["e92d5fc3.3c26f"],["9d971bed.3b56a8"]]},{"id":"e92d5fc3.3c26f","type":"change","z":"15462191.80250e","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"Probably somebody is in bathroom and taking shower","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":620,"y":420,"wires":[["fc82cff1.aa417"]]},{"id":"9d971bed.3b56a8","type":"change","z":"15462191.80250e","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"Bathroom is free to use","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":620,"y":460,"wires":[["fc82cff1.aa417"]]},{"id":"9ff1bc82.60f9b","type":"debug","z":"15462191.80250e","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":850,"y":540,"wires":[]},{"id":"fc82cff1.aa417","type":"rbe","z":"15462191.80250e","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":790,"y":480,"wires":[["9ff1bc82.60f9b"]]},{"id":"12096a0f.48f676","type":"debug","z":"15462191.80250e","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":710,"y":360,"wires":[]},{"id":"be78dd6.ddc7e2","type":"change","z":"15462191.80250e","name":"","rules":[{"t":"set","p":"hum","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":280,"wires":[["1607b36f.5088ed"]]}]

This looks like the way to go. Let's see if I can change it, so it processes my msg.payload.humidity.

I get this: "TypeError: msg.payload.humidity is not a function"

[{"id":"9ec7fa1e.00bc38","type":"function","z":"d11dfeaa.8b609","name":"fake hum change","func":"var c = context.get(\"c\") || 15\nvar r = msg.payload.humidity()\nvar d = context.get(\"d\") || \"up\"\n\nif(d === \"up\"){\n    if(c < 20){\n        c += r\n    }\n    else {\n        d = \"down\"\n        c -= r\n        \n    }\n}\nelse{\n   if(c > 10){\n        c -= r\n    }\n    else {\n        d = \"up\"\n        c += r\n        \n    } \n}\ncontext.set(\"d\",d)\ncontext.set(\"c\",c);\n\nmsg.payload = c\nreturn msg;","outputs":1,"noerr":0,"x":2630,"y":1280,"wires":[["53b09b2b.403954"]]},{"id":"fb44e2b0.82099","type":"switch","z":"d11dfeaa.8b609","name":"","property":"payload","propertyType":"msg","rules":[{"t":"gt","v":"hum","vt":"global"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":2760,"y":1400,"wires":[["814bd053.feaf7"],["efe0587a.471458"]]},{"id":"53b09b2b.403954","type":"rbe","z":"d11dfeaa.8b609","name":"","func":"deadbandEq","gap":"2","start":"","inout":"out","property":"payload","x":2690,"y":1340,"wires":[["fb44e2b0.82099"]]},{"id":"814bd053.feaf7","type":"change","z":"d11dfeaa.8b609","name":"","rules":[{"t":"set","p":"humdirection","pt":"global","to":"up","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":2930,"y":1380,"wires":[["b69ca636.4d7318"]]},{"id":"efe0587a.471458","type":"change","z":"d11dfeaa.8b609","name":"","rules":[{"t":"set","p":"humdirection","pt":"global","to":"down","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":2930,"y":1420,"wires":[["b69ca636.4d7318"]]},{"id":"5bd1a26b.9868ac","type":"delay","z":"d11dfeaa.8b609","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"5","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":2880,"y":1480,"wires":[["a7eb1dc2.66546","f8f97499.98af88"]]},{"id":"f8f97499.98af88","type":"switch","z":"d11dfeaa.8b609","name":"","property":"humdirection","propertyType":"global","rules":[{"t":"cont","v":"up","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":2820,"y":1560,"wires":[["b0473627.2f1bb8"],["3d3196eb.e2aeaa"]]},{"id":"b0473627.2f1bb8","type":"change","z":"d11dfeaa.8b609","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"Probably somebody is in bathroom and taking shower","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":3010,"y":1540,"wires":[["a75eaf8.b0a8c5"]]},{"id":"3d3196eb.e2aeaa","type":"change","z":"d11dfeaa.8b609","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"Bathroom is free to use","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":3010,"y":1580,"wires":[["a75eaf8.b0a8c5"]]},{"id":"4c99cb84.91c224","type":"debug","z":"d11dfeaa.8b609","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":3240,"y":1660,"wires":[]},{"id":"a75eaf8.b0a8c5","type":"rbe","z":"d11dfeaa.8b609","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":3180,"y":1600,"wires":[["4c99cb84.91c224"]]},{"id":"a7eb1dc2.66546","type":"debug","z":"d11dfeaa.8b609","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":3100,"y":1480,"wires":[]},{"id":"b69ca636.4d7318","type":"change","z":"d11dfeaa.8b609","name":"","rules":[{"t":"set","p":"hum","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":3140,"y":1400,"wires":[["5bd1a26b.9868ac"]]},{"id":"89e3d052.09eec","type":"mqtt in","z":"d11dfeaa.8b609","name":"","topic":"zigbee2mqtt/Temperatuur_badkamer","qos":"2","datatype":"json","broker":"7a291092.162ac","x":1860,"y":480,"wires":[["47b9e919.17f118","19cbe94e.c0bf17","9ec7fa1e.00bc38"]]},{"id":"7a291092.162ac","type":"mqtt-broker","z":"","name":"MQTT","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

@hotNipi
I do not see that your flow compensates for normal changes in humidity levels (that will naturally happen). Even if nobody is showering, a common, even slow, increase in RH% will indicate bathroom occupied once the threshold for "up" in deadband is reached. This is the reason why I used the outside sensor as baseline reference, it will automatically adjust the baseline reference
Or have I misunderstood your flow?

@krambriwWalter, have you discovered the 'bug' in your code yet?? Has the 'hint' helped?

1 Like

Hello, yes
It will work but everything is delayed until "next "time sensor values arrives, Actually the switch should look like this

Thank you & best regards
Walter

switch(sensor){
    case "outside":
        flow.set("hum_outside", msg.payload);
        hum_outside = msg.payload;
        break
        
    case "shower":
        flow.set("hum_shower", msg.payload);
        hum_shower = msg.payload;
        break
}

This is wrong javascript syntax

var r = msg.payload.humidity()

It should be

var r = msg.payload.humidity;

Could you add a debug node to your mqtt nodes showing the complete msg? Also for the mqtt node getting the sensor data from the room outside? And paste the result here

image

I did the flow to get things going in direction the original issue asked for. It is far from being the solution for the problem.

The number 74.4 and 15.400000000000006 are from the first debug node from your flow.

I don't use a sensor outside the bathroom.

This worked. Now data is coming through. I notice that it adds 15 to the payload, right?

You said so earlier!???

Well, if you do not have a reference (an additional sensor) that is automatically adjusting the reference to normal humidity conditions, I think you will get problems as I mentioned. But it is up to you, my case is now closed, it was based on the statement that you had two sensors

I guess we misunderstood eachother.
But I have the temperature/humidity/pressure sensor installed against the outside (tiles) wall of the shower (but still inside the bathroom) and I also have a motion sensor placed somewhere in the bathroom to detect motion and lux. The motion part is already done, but it doesn't detect motion when someone is in the shower. That's why I need to detect the humidity to detect if someone is in the shower.

And about the reference conditions. I could use a value from early morning as a reference? I also have a sensor in the living room, but those values are worlds apart. At his moment it is 46% in the living room and 59% in the bathroom. Bathroom hasn't been used for 6 hours now. But you think that can be linked?

OK, understood

The value in the living room I think can be used as a reference value. Both this sensor and the one in the bathroom will be influenced by outdoor weather conditions due to ventilation of the house even if delayed. Is it the same type of zigbee sensor?

But first a question about the behavior of the sensor in the bathroom. How fast is it reacting to changes, I mean, approximately

  • when you start the shower, how long time does it take until the value changes?
  • what is a typical humidity value during shower?
  • how long does it take for the value to go down after shower?

I used the flow of @hotNipi, because it made more sense to me. With a quick test shower (no real person inside :slight_smile: ) it already gave me decent results. It took a while before the flow reacted on the humidity going up. It acted quickly when it went down. So that looks promising.To give you an idea of what happened:
At 15.16 turned on shower, humidity was: 56
At 15.19 humidity 64, few seconds later humidity 71. Half a minute later I turned the shower off.
At 15.22 humidity 65. So big drop after the 71
At 15.23 humidity 59
At 15.52 humidity 55

So that was a very quick shower, usually it will take longer. So humidity will be higher. We have mechanical ventilation, a window and a door.
The typical humidity value is not really definable. It can be above 80, or it go just above 60. Depending on length of the shower, door/window open or closed. Mechanical ventilation speed. But significant changes can be detected within seconds.

The sensor in the living room is exactly the same.
As a test, I installed them both in the same spot, right next to eachother. The results are quite different. 2 degrees Celcius and 8 humidity difference. So they are not really accurate. Maybe I need to let them settle a bit longer.

Fine, then keep that flow running. It will be interesting to see how it works for a longer period. Maybe my fear regarding the reference is not needed to care about, as long as it gives the result you are looking for

In the mean time I built a similar setup (using my flow with 2 sensors, one as a reference) but with other type of sensors, just simple temp/hum sensors for rf 433. It seems also to work, I get status change from the flow when filling hot water into the sink (with the sensor placed next to it) and it changes back a while later when the hot water is emptied. My sensors are cheaper and not that fast in reacting, they are updating the readings approx once per minut and I took away the smoothing to make things react quicker

Do you switch this ventilator manually or is it somehow smart thing?

It is manual. But I would like to make it smarter if that was possible.