Here is what I do. This flow uses a state machine node from node-red-contrib-persistent-fsm
Upon the state change of each contact sensor it uses a change node to set the window status to true/false. That is fed into a join node, then into a function node. After that the output is run through a state machine which is then sent on to increase or decrease the open window count. There are some extra things in the payload that are passed along to get alexa to announce what window has been opened or closed and to set global variables for each one. Hopefully that helps.
[{"id":"e9f85247edc84d56","type":"group","z":"7a970dd2f2d67388","name":"Example Flow","style":{"stroke":"#000000","label":true,"fill":"#addb7b","color":"#000000"},"nodes":["9651c36a651b560d","9f850cdc54c04a82","8cdf9f495372322b","971e6d57fd26ed62","3e600fef1861556c","8485ccedb3fdc82b","14d60c274541a9e1"],"x":2308,"y":6119,"w":1664,"h":428},{"id":"9651c36a651b560d","type":"group","z":"7a970dd2f2d67388","g":"e9f85247edc84d56","name":"All Windows","style":{"stroke":"#000000","label":true,"fill":"#bfdbef","color":"#000000"},"nodes":["f9701d841c940c0d","be352481d03ca30a","772730774634f996","45283b2c9bea5fa6"],"x":3104,"y":6199,"w":212,"h":322},{"id":"f9701d841c940c0d","type":"function","z":"7a970dd2f2d67388","g":"9651c36a651b560d","name":"Build Array","func":"var DiningRoomWestWindow = msg.payload[\"DiningRoomWestWindow\"];\nvar DiningRoomEastWindow = msg.payload[\"DiningRoomEastWindow\"];\nvar LivingRoomWestWindow = msg.payload[\"LivingRoomWestWindow\"];\nvar LivingRoomEastWindow = msg.payload[\"LivingRoomEastWindow\"];\nvar BedroomWindow = msg.payload[\"BedroomWindow\"];\nvar MasterBathWindow = msg.payload[\"MasterBathWindow\"];\nvar KitchenWindow = msg.payload[\"KitchenWindow\"];\nvar GuestRoomWindow = msg.payload[\"GuestRoomWindow\"];\nvar OfficeWindow = msg.payload[\"OfficeWindow\"];\n\nmsg.payload = [DiningRoomWestWindow,DiningRoomEastWindow,LivingRoomWestWindow,LivingRoomEastWindow,BedroomWindow,MasterBathWindow,KitchenWindow,GuestRoomWindow,OfficeWindow];\n\nreturn msg;\n\n//Array is buit based on order of sensors","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":3210,"y":6320,"wires":[["772730774634f996"]]},{"id":"be352481d03ca30a","type":"join","z":"7a970dd2f2d67388","g":"9651c36a651b560d","name":"Get Values","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","useparts":true,"accumulate":true,"timeout":"","count":"9","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":3210,"y":6240,"wires":[["f9701d841c940c0d"]]},{"id":"772730774634f996","type":"change","z":"7a970dd2f2d67388","g":"9651c36a651b560d","name":"Set Payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"$string(payload[0].currentValue) & \" \" & (payload[1].currentValue) & \" \" & (payload[2].currentValue) & \" \" & (payload[3].currentValue) & \" \" & (payload[4].currentValue) & \" \" & (payload[5].currentValue) & \" \" & (payload[6].currentValue) & \" \" & (payload[7].currentValue) & \" \" & (payload[8].currentValue)","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"windows","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":3210,"y":6400,"wires":[["45283b2c9bea5fa6"]]},{"id":"45283b2c9bea5fa6","type":"state-machine","z":"7a970dd2f2d67388","g":"9651c36a651b560d","name":"All Windows","triggerProperty":"payload","triggerPropertyType":"msg","stateProperty":"payload","statePropertyType":"msg","initialDelay":"","persistOnReload":false,"outputStateChangeOnly":true,"throwException":false,"states":["Initializing...","all windows closed","all windows open"],"transitions":[{"name":"closed closed closed closed closed closed closed closed closed","from":"Initializing...","to":"all windows closed"},{"name":"open open open open open open open open open","from":"Initializing...","to":"all windows open"},{"name":"Initializing...","from":"*","to":"Initializing..."}],"x":3210,"y":6480,"wires":[["e63b61144a6805f2"]],"icon":"font-awesome/fa-gears"},{"id":"9f850cdc54c04a82","type":"group","z":"7a970dd2f2d67388","g":"e9f85247edc84d56","style":{"stroke":"#000000","label":true,"fill":"#bfdbef","color":"#000000"},"nodes":["f735a3268c649b63","e63b61144a6805f2","cbf1ad3e851d6ace","5d6a699bcb680ca5","f6ef7c59eaaea41c","695f634015dbf90b","3cf473db337992e5","b960bc8aa3886b13"],"x":3394,"y":6259,"w":552,"h":202},{"id":"f735a3268c649b63","type":"rbe","z":"7a970dd2f2d67388","g":"9f850cdc54c04a82","name":"","func":"rbe","gap":"","start":"","inout":"out","septopics":true,"property":"payload","topi":"topic","x":3835,"y":6360,"wires":[["b960bc8aa3886b13"]],"l":false},{"id":"e63b61144a6805f2","type":"switch","z":"7a970dd2f2d67388","g":"9f850cdc54c04a82","name":"Open/Closed","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"open","vt":"str"},{"t":"cont","v":"closed","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":3490,"y":6360,"wires":[["cbf1ad3e851d6ace","f6ef7c59eaaea41c"],["695f634015dbf90b","5d6a699bcb680ca5"]]},{"id":"cbf1ad3e851d6ace","type":"change","z":"7a970dd2f2d67388","g":"9f850cdc54c04a82","name":"RESET","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"},{"t":"set","p":"payload","pt":"msg","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":3665,"y":6380,"wires":[["695f634015dbf90b"]],"icon":"font-awesome/fa-refresh","l":false},{"id":"5d6a699bcb680ca5","type":"change","z":"7a970dd2f2d67388","g":"9f850cdc54c04a82","name":"RESET","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"},{"t":"set","p":"payload","pt":"msg","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":3665,"y":6340,"wires":[["f6ef7c59eaaea41c"]],"icon":"font-awesome/fa-refresh","l":false},{"id":"f6ef7c59eaaea41c","type":"trigger","z":"7a970dd2f2d67388","g":"9f850cdc54c04a82","name":"15 seconds","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"15","extend":false,"overrideDelay":false,"units":"s","reset":"","bytopic":"topic","topic":"topic","outputs":1,"x":3665,"y":6300,"wires":[["3cf473db337992e5"]],"icon":"node-red-contrib-bigtimer/timer.png","l":false},{"id":"695f634015dbf90b","type":"trigger","z":"7a970dd2f2d67388","g":"9f850cdc54c04a82","name":"15 seconds","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"15","extend":false,"overrideDelay":false,"units":"s","reset":"","bytopic":"topic","topic":"topic","outputs":1,"x":3665,"y":6420,"wires":[["3cf473db337992e5"]],"icon":"node-red-contrib-bigtimer/timer.png","l":false},{"id":"3cf473db337992e5","type":"junction","z":"7a970dd2f2d67388","g":"9f850cdc54c04a82","x":3780,"y":6360,"wires":[["f735a3268c649b63"]]},{"id":"b960bc8aa3886b13","type":"link out","z":"7a970dd2f2d67388","g":"9f850cdc54c04a82","name":"OUT - Contact Sensor Status","mode":"link","links":["a129361629c081e1"],"x":3905,"y":6360,"wires":[]},{"id":"8cdf9f495372322b","type":"comment","z":"7a970dd2f2d67388","g":"e9f85247edc84d56","name":"Nodes to create an array","info":"First, everyting is sent to the join node\nSecond, the function node buiilds the array\nThird, I use a change node to get everything \norganized the way I want\nAnd finally I send that to a state machine","x":3210,"y":6160,"wires":[]},{"id":"971e6d57fd26ed62","type":"comment","z":"7a970dd2f2d67388","g":"e9f85247edc84d56","name":"Counter","info":"Here is wehre I use the date to set the counter\nthen the reast of the data is passed along to\nother flows for alexa announcements, setting global\nvariables, etc. ","x":3660,"y":6220,"wires":[]},{"id":"3e600fef1861556c","type":"comment","z":"7a970dd2f2d67388","g":"e9f85247edc84d56","name":"Contact sensor nodes","info":"These no-op nodes are stand ins for my \nhubitat contact sensor nodes and don't actually\ndo anything. \n\nImagine nine seperate nodes (one for each window)\nthat all connect to their own change node. Then all \nof them funnel into the join node.","x":2740,"y":6220,"wires":[]},{"id":"8485ccedb3fdc82b","type":"junction","z":"7a970dd2f2d67388","g":"e9f85247edc84d56","x":3080,"y":6240,"wires":[["be352481d03ca30a"]]},{"id":"14d60c274541a9e1","type":"group","z":"7a970dd2f2d67388","g":"e9f85247edc84d56","style":{"stroke":"#000000","label":true,"fill":"#bfdbef","color":"#000000"},"nodes":["21059a69aecac317","6d5b434365411267","3374d2edad9333d4","f44172b6997788ea"],"x":2334,"y":6259,"w":712,"h":182},{"id":"21059a69aecac317","type":"change","z":"7a970dd2f2d67388","g":"14d60c274541a9e1","name":"Bedroom Window Contact State","rules":[{"t":"set","p":"topic","pt":"msg","to":"BedroomWindow","tot":"str"},{"t":"change","p":"payload.value","pt":"msg","from":"open","fromt":"str","to":"true","tot":"bool"},{"t":"change","p":"payload.value","pt":"msg","from":"closed","fromt":"str","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":2890,"y":6300,"wires":[["8485ccedb3fdc82b"]]},{"id":"6d5b434365411267","type":"no-op","z":"7a970dd2f2d67388","g":"14d60c274541a9e1","name":"Bedroom Contact Sensor Node (no-op)","x":2520,"y":6300,"wires":[["21059a69aecac317"]]},{"id":"3374d2edad9333d4","type":"change","z":"7a970dd2f2d67388","g":"14d60c274541a9e1","name":"Kitchen Window Contact State","rules":[{"t":"set","p":"topic","pt":"msg","to":"KitchenWindow","tot":"str"},{"t":"set","p":"statusReport.windows.kitchenWindow","pt":"global","to":"payload.value","tot":"msg"},{"t":"set","p":"payload.status","pt":"msg","to":"$string & \"Kitchen Window \" & (payload.currentValue)\t","tot":"jsonata"},{"t":"change","p":"payload.value","pt":"msg","from":"open","fromt":"str","to":"true","tot":"bool"},{"t":"change","p":"payload.value","pt":"msg","from":"closed","fromt":"str","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":2890,"y":6400,"wires":[["8485ccedb3fdc82b"]]},{"id":"f44172b6997788ea","type":"no-op","z":"7a970dd2f2d67388","g":"14d60c274541a9e1","name":"Kitchen Contact Sensor Node (no-op)","x":2530,"y":6400,"wires":[["3374d2edad9333d4"]]}]