Strategy for counting door/window events

What is the best way to count number of opening/closing doors and windows?

Mainly it must survive HA restart.
I would also like to avoid creating as many sensors as door/window ones. Initially I thought I can count events and store totals in attributes. But I don’t know if attributes are stored in history therefore might be restored after system restart

Any ideas?
If it does matter I prefer NodeRed
Thanx in advance

How many events are you counting?

  • Record openings/closings of all door and windows is just one counter.
  • If you separate doors and windows, that’s two counters.
  • Many counters if you want stats for each individual door and window.

Have you considered using the History Stats integration?

I use input_number “helpers” for counting. They do survive a restart (although the input_boolean ones don’t) and you can have them shown in lovelace dashboards (as badges, for example). Increments appear in the logbook.

thank you gus for suggestions. I did’t knew about options you mentioned.

I want to track each door or window separately. It seems that using history integration or input_number means creating tents of additional sensors. Do you think I could use attributes of single input_sensor?

A Template Sensor allows you to define custom attributes (one for each window and door). Each attribute will have its own template that monitors the state of a binary_sensor. However, I have never created a self-incrementing template so I can’t say how feasible that might be. For example, initially the value will be unknown so the template’s algorithm can’t simply be “add 1 to my current value”.

yep got the idea and actually have it ready in NodeRed. I wasn’t if attributes survive ha restart.

thank you

Finally I did that following way, using NodeRed

  1. Set up State trigger to react on sensor changes which provides open/close state. I used regexp pattern matching for that.
  2. wrote a function creates collection of counters stored in flow variable. This variable is stored to disk (this feature must be configured in NodeRed, it’s not by default)
  3. create sensor by NodeRed and store colection of counters in its attributes. It could be a payload too (in case of using input_text sensor), but payload is limited to 255 characters. in my case I used sensor state to handle total sum of all events.

My example contain one another sensor fed by true/false injectors for testing purposes.

[{"id":"f41f5513.814be8","type":"function","z":"4c9dd282.42faf4","name":"Update Data","func":"var newMsg = {};\nnewMsg.payload = 0;\nnewMsg.attributes = {};\n\nvar arrdata = flow.get('shellies_data', 'inFile');\nif (arrdata === undefined) arrdata = {};\n\n// remove sensor type from identifier\nvar sensorname = msg.data.entity_id.replace('binary_sensor.', '');\n\nif (sensorname in arrdata) arrdata[sensorname]++;\nelse arrdata[sensorname] = 1;\n\n// count total\nObject.keys(arrdata).forEach(key =>\n{\n    newMsg.payload += arrdata[key];\n});\n\nflow.set('shellies_data', arrdata, 'inFile');\n\nnewMsg.attributes = arrdata\nreturn newMsg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":390,"y":300,"wires":[["fb0d03e4.e95fe"]]},{"id":"b991efd0.ab63a8","type":"inject","z":"4c9dd282.42faf4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":150,"y":200,"wires":[["480cc098.5bb99"]]},{"id":"5b22c7ea.427ae8","type":"inject","z":"4c9dd282.42faf4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"false","payloadType":"bool","x":150,"y":240,"wires":[["480cc098.5bb99"]]},{"id":"fb0d03e4.e95fe","type":"ha-entity","z":"4c9dd282.42faf4","name":"doorwindow_counter","server":"6cdd0bc8.b8e434","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"doorwindow_counter"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:counter"},{"property":"unit_of_measurement","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"counters","value":"attributes","valueType":"msg"}],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"block","x":640,"y":300,"wires":[["6745e560.e00b94"]]},{"id":"cfd5f2e5.736f38","type":"trigger-state","z":"4c9dd282.42faf4","name":"Collect events","server":"6cdd0bc8.b8e434","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"^binary_sensor\\..*?(door|window)+.*?state$","entityidfiltertype":"regex","debugenabled":false,"constraints":[{"id":"ir0oav99mvr","targetType":"this_entity","targetValue":"","propertyType":"property","propertyValue":"new_state.original_state","comparatorType":"is_not","comparatorValueDatatype":"str","comparatorValue":"undefined"}],"constraintsmustmatch":"all","outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"habool","x":160,"y":300,"wires":[["f41f5513.814be8"],[]]},{"id":"6745e560.e00b94","type":"debug","z":"4c9dd282.42faf4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":870,"y":300,"wires":[]},{"id":"480cc098.5bb99","type":"ha-entity","z":"4c9dd282.42faf4","name":"test_door_counter_state","server":"6cdd0bc8.b8e434","version":1,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"test_door_counter_state"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":410,"y":220,"wires":[[]]},{"id":"6cdd0bc8.b8e434","type":"server","z":"","name":"Home Assistant"}]

Since I need to use template sensors anyway, I fill count attribute of such sensor by related value from counters collection:

  - platform: template
    sensors:
      child_room_window:
        friendly_name: "Child Room Window"
        device_class: "window"
        value_template: >-
          {{ is_state("binary_sensor.child_room_window_state", "on") }}
        icon_template: >-
          {% if is_state("binary_sensor.child_room_window_state", "off") %}
            mdi:window-closed-variant
          {% elif states('sensor.child_room_window_tilt')|float > 2 %}
            mdi:angle-acute
          {% else %}
            mdi:window-open-variant
          {% endif %}
        attribute_templates:
          battery: >-
            {{ state_attr('binary_sensor.child_room_window_battery','battery') }}
          tilt: >-
            {{ state_attr('binary_sensor.child_room_window_tilt','tilt') }}
          count: >-
            {{ state_attr('sensor.doorwindow_counter','counters')['child_room_window_state'] }}

How does what you created meet this requirement?

my solution doesn’t create count sensor for each input one. history stats or input_numbers would end up with a lot them.
All counters are handled by single sensor: doorwindow_counter

Just curious if the end goal is to use the #cycles as a trugger for automations, or is this just for personal records? If the latter, you can do that easily with influxdb and grafana, with no need for any additional sensors. I have several such dial indicators that show how often doors/windows were opened/closed throughout the day, hour, month, year, or whatever arbitrary time range I select from drop down boxes. It is super easy to use, and you get the added benefit of influxdb which makes storing years worth of data doable, and fast! …now I know why my garage entry spring hinge fails after just 5years… gets opened 100’s of times a day lol! Also know when my garage door (cover) springs get near their eol (I designed/installed myself, so know the mtbf for the springs). Many other neat uses for such info. :wink:

Yes you are right, From architecture POV counters shouldn’t be done this way. there are more efficient tools to achieve what I did.

I mocked this up this way mainly because I’m still running HA from SD card. And it was quicker to finish. Once I switch to SSD I’ll do that right way for sure.

The reason I needed counters is potentially short lifetime of Shelly battery powered devices. Especially door/window sensors.