I've stripped the NR flow down and de-coupled it from my home automation system, so I hope it still 'sort of works' for you.
There should be an init node connected to the input of the FSM to ensure it starts in state S0.


I've also included the animation as this was a bit of fun - no real use but it looks nice on the Dashboard.
Here's the NR flow for the above.
[{"id":"245264d194646520","type":"tab","label":"Garage Door - minimum","disabled":false,"info":"","env":[]},{"id":"a6150293cc61b97e","type":"group","z":"245264d194646520","name":"","style":{"fill":"#e3f3d3","label":true},"nodes":["29b8dabd0ee4dd3f","f2ea5ec81b09adf3","ef9e541e16f87173","1320a76202f9d9f5","1a11a41cd38305a9","7da8cd3152e38825","4766fefe5a6f3a3f","fbef7d799d2b627a","f6fc4c0af5aa9a0d"],"x":54,"y":479,"w":692,"h":302},{"id":"d14994cc7338bd14","type":"mqtt in","z":"245264d194646520","name":"","topic":"garagedoor/sensors/#","qos":"0","datatype":"json","broker":"b80c36f2.044588","nl":false,"rap":true,"rh":0,"inputs":0,"x":160,"y":280,"wires":[["3f46f2e52466b22f","caf57d0535fc9e7d","ae24791fb5773807"]]},{"id":"f8f320894fb1ee54","type":"comment","z":"245264d194646520","name":"Inputs from microswitches","info":"","x":170,"y":240,"wires":[]},{"id":"3f46f2e52466b22f","type":"function","z":"245264d194646520","name":"Detect tms","func":"if ( (msg.payload.sensor == \"top\") && (msg.payload.level == 1) ) {\n msg.topic=\"tms\";\n return msg;\n}\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":280,"wires":[["5a2ac52663ff9f78","4e662086e45c3691"]]},{"id":"caf57d0535fc9e7d","type":"function","z":"245264d194646520","name":"Detect bms","func":"if ( (msg.payload.sensor == \"bottom\") && (msg.payload.level == 1) ) {\n msg.topic=\"bms\";\n return msg;\n}\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":340,"wires":[["5a2ac52663ff9f78","2f824be589f71d19"]]},{"id":"5a2ac52663ff9f78","type":"link out","z":"245264d194646520","name":"Detect tms or bms","mode":"link","links":["c752bd8364c93b03"],"x":555,"y":400,"wires":[]},{"id":"ae24791fb5773807","type":"debug","z":"245264d194646520","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":390,"y":220,"wires":[]},{"id":"bfacad9b04486fda","type":"function","z":"245264d194646520","name":"FSM - State Transition Table","func":"// states\n// S0 closed << default state\n// S1 opening\n// S2 open\n// S3 closing\n// S4 closing_stopped\n// S5 opening_stopped\n\n// inputs\n// tms top_microswitch\n// bms bottom_microswitch\n\n\nif ( (msg.topic == \"reset\") || (msg.topic == \"bms\") ) {\n flow.set(\"state_register\", \"S0\");\n flow.set(\"roller_pos\",0);\n node.send( [{payload: \"S0\"}, null] );\n}\n\nif (msg.topic == \"tms\") {\n flow.set(\"state_register\", \"S2\");\n flow.set(\"roller_pos\",100);\n node.send( [{payload: \"S2\"}, null] );\n}\n\nvar fsm_state = flow.get(\"state_register\") || \"S0\";\n\nswitch (fsm_state) \n {\n case \"S0\":\n if (msg.topic == \"ogd\") {\n fsm_state = \"S1\";\n node.send( [{payload: \"S1\"}, {payload:1}] );\n }\n break;\n \n case \"S1\":\n if (msg.topic == \"sgd\") {\n fsm_state = \"S5\";\n node.send( [{payload: \"S5\"}, {payload:1}] );\n }\n break;\n \n case \"S2\":\n if (msg.topic == \"ogd\") {\n fsm_state = \"S3\";\n node.send( [{payload: \"S3\"}, {payload:1}] );\n }\n break;\n \n case \"S3\":\n if (msg.topic == \"sgd\") {\n fsm_state = \"S4\";\n node.send( [{payload: \"S4\"}, {payload:1}] );\n }\n break;\n \n case \"S4\":\n if (msg.topic == \"ogd\") {\n fsm_state = \"S1\";\n node.send( [{payload: \"S1\"}, {payload:1}] );\n }\n break;\n \n case \"S5\":\n if (msg.topic == \"ogd\") {\n fsm_state = \"S3\";\n node.send( [{payload: \"S3\"}, {payload:1}] );\n }\n break;\n }\n\nflow.set(\"state_register\", fsm_state);\nnode.status({text:\"State register = \" + fsm_state});\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1180,"y":240,"wires":[[],[]]},{"id":"f250df6c08e0a893","type":"alexa-remote-routine","z":"245264d194646520","name":"","account":"65fc5fb4b8d06bdd","routineNode":{"type":"speak","payload":{"type":"regular","text":{"type":"msg","value":"payload"},"devices":{"type":"msg","value":"device_name"}}},"x":1140,"y":420,"wires":[[]]},{"id":"bf6312cfb075291f","type":"mqtt out","z":"245264d194646520","name":"","topic":"garagedoor/command/cmd","qos":"2","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"b80c36f2.044588","x":1180,"y":340,"wires":[]},{"id":"c752bd8364c93b03","type":"link in","z":"245264d194646520","name":"FSM_IN","links":["0c414d4b211b399f","ac59d671dd2f857a","e4fbf5c0b4c1dec6","5a2ac52663ff9f78","f2ab3cd4c844fdf0","9ad85296ad697bcc"],"x":995,"y":240,"wires":[["bfacad9b04486fda"]]},{"id":"62359648ac744616","type":"link in","z":"245264d194646520","name":"Alexa_IN","links":["2b448505509f131e"],"x":995,"y":420,"wires":[["f250df6c08e0a893"]]},{"id":"c12523c640553967","type":"link in","z":"245264d194646520","name":"MQTT_IN","links":["880f3dfdd1b2c3c5","93efc9dbbc73a141","c9df95ee3ee40829","7bc49c695ec66d03"],"x":995,"y":340,"wires":[["bf6312cfb075291f"]]},{"id":"2b448505509f131e","type":"link out","z":"245264d194646520","name":"To_Alexa","mode":"link","links":["62359648ac744616"],"x":875,"y":420,"wires":[]},{"id":"f2ab3cd4c844fdf0","type":"link out","z":"245264d194646520","name":"To_FSM","mode":"link","links":["c752bd8364c93b03"],"x":875,"y":240,"wires":[]},{"id":"7bc49c695ec66d03","type":"link out","z":"245264d194646520","name":"To_MQTT","mode":"link","links":["c12523c640553967"],"x":875,"y":340,"wires":[]},{"id":"4e662086e45c3691","type":"function","z":"245264d194646520","name":"top_microswitch detected","func":"var alexa_device_name = flow.get(\"alexa_device_name\") || \"Study\";\n\n\n\n// FSM command, Alexa details, MQTT details\n\nif (msg.topic == \"tms\") {\n // flow.set(\"roller_pos\",0);\n node.send([null, {device_name: alexa_device_name, payload: \"Door is fully open\"}, {payload: \"event,ledcode=4\"}]);\n}\n\nreturn null;","outputs":3,"noerr":0,"initialize":"","finalize":"","libs":[],"x":650,"y":280,"wires":[["f2ab3cd4c844fdf0"],["2b448505509f131e"],["7bc49c695ec66d03"]],"outputLabels":["To FSM","To Alexa","To controller via MQTT"]},{"id":"2f824be589f71d19","type":"function","z":"245264d194646520","name":"bottom_microswitch detected","func":"var alexa_device_name = flow.get(\"alexa_device_name\") || \"Study\";\n\n\n\n// FSM command, Alexa details, MQTT details\n\nif (msg.topic == \"bms\") {\n // flow.set(\"roller_pos\",0);\n node.send([null, {device_name: alexa_device_name, payload: \"Door is fully closed\"}, {payload: \"event,ledcode=1\"}]);\n}\n\nreturn null;","outputs":3,"noerr":0,"initialize":"","finalize":"","libs":[],"x":660,"y":340,"wires":[["f2ab3cd4c844fdf0"],["2b448505509f131e"],["7bc49c695ec66d03"]],"outputLabels":["To FSM","To Alexa","To controller via MQTT"]},{"id":"29b8dabd0ee4dd3f","type":"ui_template","z":"245264d194646520","g":"a6150293cc61b97e","group":"273505a6.34ddaa","name":"Roller door simulation","order":1,"width":"0","height":"0","format":"<style>\n :root {\n --rollade-color: #097479;\n --rollade-width: 90px;\n }\n .rollade__container {\n width: var(--rollade-width);\n overflow: hidden;\n position: relative;\n }\n .rollade__fenster {\n position: relative;\n overflow: hidden;\n z-index: 1;\n }\n .rollade__fenster path {\n stroke: var(--rollade-color);\n fill:none!important;\n stroke-width:6px;\n }\n .rollade__rollade {\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0px;\n z-index: 10;\n transition: all 1s;\n }\n .rollade__rollade path.line {\n stroke: white;\n fill: none;\n stroke-width: 1.5px;\n }\n .rollade__rollade path.bg {\n fill: var(--rollade-color);\n }\n \n </style>\n\n <h3>Door position</h3>\n <div class=\"rollade__container\">\n <svg class=\"rollade__fenster\" width=\"100%\" height=\"100%\" viewBox=\"0 0 170 188\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:space=\"preserve\" xmlns:serif=\"http://www.serif.com/\" style=\"fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;\">\n <g transform=\"matrix(1,0,0,1,-15.909,-45.6212)\">\n <g transform=\"matrix(0.989904,0,0,0.992491,4.03539,0.837446)\">\n <path d=\"M180.329,56.389C180.329,51.839 176.626,48.145 172.064,48.145L23.291,48.145C18.729,48.145 15.025,51.839 15.025,56.389L15.025,222.454C15.025,227.004 18.729,230.698 23.291,230.698L172.064,230.698C176.626,230.698 180.329,227.004 180.329,222.454L180.329,56.389Z\" />\n </g>\n <g transform=\"matrix(1,0,0,1.38253,3.04599,-37.9811)\">\n <path d=\"M97.589,64.432L97.589,191.286\" />\n </g>\n <g transform=\"matrix(1,0,0,1,2.84135,56.1777)\">\n <path d=\"M18.74,83.189L177.463,84.189\" />\n </g>\n </g>\n </svg>\n <svg class=\"rollade__rollade\" style=\"top: calc((-1) * {{msg.payload}}%);\" width=\"100%\" height=\"100%\" viewBox=\"0 0 181 190\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:space=\"preserve\" xmlns:serif=\"http://www.serif.com/\" style=\"fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;\">\n <g transform=\"matrix(1.35281,0,0,1.35281,-45.3041,-102.109)\">\n <path class=\"bg\" d=\"M167.134,82.161C167.134,78.473 164.14,75.479 160.452,75.479L40.171,75.479C36.483,75.479 33.489,78.473 33.489,82.161L33.489,208.93C33.489,212.618 36.483,215.612 40.171,215.612L160.452,215.612C164.14,215.612 167.134,212.618 167.134,208.93L167.134,82.161Z\"/>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,-9)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,1)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,11)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,21)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,31)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,41)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,51)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,61)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,71)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,81)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,91)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,101)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n <g transform=\"matrix(1.69574,0,0,1,18.3547,111)\">\n <path class=\"line\" d=\"M13.383,95.652L84.46,95.652\" />\n </g>\n </g>\n </svg>\n </div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","className":"","x":600,"y":660,"wires":[[]]},{"id":"f2ea5ec81b09adf3","type":"inject","z":"245264d194646520","g":"a6150293cc61b97e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payloadType":"date","x":170,"y":600,"wires":[["ef9e541e16f87173"]]},{"id":"ef9e541e16f87173","type":"trigger","z":"245264d194646520","g":"a6150293cc61b97e","name":"","op1":"1","op2":"0","op1type":"str","op2type":"str","duration":"250","extend":false,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":180,"y":660,"wires":[["1320a76202f9d9f5","7da8cd3152e38825"]]},{"id":"1320a76202f9d9f5","type":"debug","z":"245264d194646520","g":"a6150293cc61b97e","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":390,"y":720,"wires":[]},{"id":"1a11a41cd38305a9","type":"link in","z":"245264d194646520","g":"a6150293cc61b97e","name":"","links":["5d29e00c2db9c541"],"x":115,"y":740,"wires":[["ef9e541e16f87173"]]},{"id":"7da8cd3152e38825","type":"function","z":"245264d194646520","g":"a6150293cc61b97e","name":"","func":"var roller_pos = flow.get(\"roller_pos\");\n\nvar state_register = flow.get(\"state_register\") || \"S0\";\n\nif (state_register == \"S0\") {\n flow.set(\"roller_pos\",0);\n node.send( [{payload: 0}] );\n}\nelse if (state_register == \"S1\") {\n if (roller_pos < 100){\n roller_pos++;\n flow.set(\"roller_pos\", roller_pos);\n }\n node.send( [{payload: roller_pos}] );\n}\n\nelse if (state_register == \"S2\") {\n flow.set(\"roller_pos\", 100);\n node.send( [{payload: 100}] );\n }\n\nelse if (state_register == \"S3\") {\n if (roller_pos > 1){\n roller_pos--;\n flow.set(\"roller_pos\", roller_pos);\n }\n node.send( [{payload: roller_pos}] );\n}\n\nreturn null;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":660,"wires":[["29b8dabd0ee4dd3f"]]},{"id":"4766fefe5a6f3a3f","type":"comment","z":"245264d194646520","g":"a6150293cc61b97e","name":"Roller door simulation - nothing to do with controlling the door","info":"","x":300,"y":520,"wires":[]},{"id":"fbef7d799d2b627a","type":"comment","z":"245264d194646520","g":"a6150293cc61b97e","name":"Roller door simulation has 100 steps, so each step is 250ms","info":"","x":500,"y":600,"wires":[]},{"id":"f6fc4c0af5aa9a0d","type":"comment","z":"245264d194646520","g":"a6150293cc61b97e","name":"Dave's garage door takes 25-second to open or close","info":"","x":280,"y":560,"wires":[]},{"id":"b80c36f2.044588","type":"mqtt-broker","name":"Broker_156","broker":"192.168.1.156","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"120","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"65fc5fb4b8d06bdd","type":"alexa-remote-account","name":"Amazon acct","authMethod":"proxy","proxyOwnIp":"192.168.1.156","proxyPort":"3456","cookieFile":"/home/pi/amazon_alexa.txt","refreshInterval":"3","alexaServiceHost":"alexa.amazon.co.uk","amazonPage":"amazon.co.uk","acceptLanguage":"en-GB","onKeywordInLanguage":"","userAgent":"","useWsMqtt":"on","autoInit":"on"},{"id":"273505a6.34ddaa","type":"ui_group","name":"Garage roller door","tab":"fc0f45ae.d6066","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"fc0f45ae.d6066","type":"ui_tab","name":"Garage roller door","icon":"dashboard","order":45,"disabled":false,"hidden":false}]
I need to explain a few things...
The state of my microswitches (top and bottom) are sensed by a Wemos D1 Mini which sends any changes via MQTT to Node-RED. These changes are fed into the FSM. To operate my garage door I send an MQTT message which is picked-up by an ESP-01S that has a relay to which my broken key-fob is attached. I also send messages to Alexa to inform me what is happening - you might want to delete these.
Hope you can adapt this for your situation. Let me know if you need any extra info.