Single button ZigBee2MQTT dimmer
This flow uses the "brightness_move" Zigbee2MQTT commands (just like directly paired bulbs and remotes) for perfectly smooth dimming.
The flow is designed to be used with buttons that sends pressed/released commands or on/off, true/false, 0/1, etc. It does not have to be input from Home Assistant nodes.
Long press (hold): increase or decrease brightness. If the light is off, when the button is held, the light will start from minimum brightness and slowly increase. If the light is on, it will be decreased or increased to the minimum or maximum without turning off.
Short press: toggles the light on and off (select resume brightness level or full brightness by double clicking the subflow - see below)
I also made a similar flow to be used with deCONZ which can be found here
[{"id":"e3301957976476f0","type":"subflow","name":"Binary input Z2M dimmer","info":"","category":"","in":[{"x":70,"y":200,"wires":[{"id":"9f87f8f5a0a6f362"}]}],"out":[{"x":980,"y":270,"wires":[{"id":"4d5ab2bb2776a25f","port":0},{"id":"623c940912dc705c","port":0},{"id":"f2d8a00ea9de27c5","port":0},{"id":"7cb765110229bd5e","port":0},{"id":"dba4815f0d6f50bd","port":0},{"id":"a1f7a8de202bbf49","port":0},{"id":"158601ea01c03c26","port":0}]}],"env":[{"name":"ButtonPressed","type":"str","value":"on","ui":{"label":{"en-US":"Button pressed"}}},{"name":"ButtonReleased","type":"str","value":"off","ui":{"label":{"en-US":"Button released"}}},{"name":"TransitionTime","type":"num","value":"60","ui":{"label":{"en-US":"Dimming speed (1-254)"},"type":"input","opts":{"types":["num"]}}},{"name":"On state","type":"str","value":"Resume","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"Resume"},"v":"Resume"},{"l":{"en-US":"Full brightness"},"v":"Full brightness"}]}}}],"meta":{},"color":"#E6E0F8","inputLabels":["from trigger"],"outputLabels":["to mqtt node"],"icon":"node-red/light.svg","status":{"x":770,"y":480,"wires":[{"id":"a983c5eb8f9b55ae","port":0}]}},{"id":"29435ea77589dea0","type":"comment","z":"e3301957976476f0","name":"instructions + link to latest version of this subflow","info":"Latest version of this flow can be found at https://flows.nodered.org/flow/b3aa835c9ead60b8ec96b63ae2e80595 \n\n\nto the input add:\n1) button sending different pressed/released commands","x":410,"y":40,"wires":[]},{"id":"9f87f8f5a0a6f362","type":"switch","z":"e3301957976476f0","name":"Input filter","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"ButtonPressed","vt":"env"},{"t":"eq","v":"ButtonReleased","vt":"env"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":170,"y":200,"wires":[["fd1f289113a203c2","dfef76a89df6753e"],["1112f60123c3443c","8c6813e5601aa5b1","b8f03edc064421f7"],["df800b5afbd00c08"]]},{"id":"fd1f289113a203c2","type":"trigger","z":"e3301957976476f0","name":"Button held?","op1":"","op2":"true","op1type":"nul","op2type":"bool","duration":"500","extend":false,"units":"ms","reset":"","bytopic":"all","outputs":1,"x":390,"y":320,"wires":[["45f6f56b676ac14f"]]},{"id":"eaf04f8417ecd7a2","type":"switch","z":"e3301957976476f0","name":"Last increased?","property":"increased","propertyType":"flow","rules":[{"t":"true"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":400,"y":380,"wires":[["a1f7a8de202bbf49"],["7cb765110229bd5e"]]},{"id":"10ef55d27dc868c0","type":"switch","z":"e3301957976476f0","name":"toggle","property":"LightTurnedOn","propertyType":"flow","rules":[{"t":"eq","v":"ON","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":530,"y":230,"wires":[["4d5ab2bb2776a25f"],["9fef249d888268f7"]]},{"id":"4d5ab2bb2776a25f","type":"change","z":"e3301957976476f0","name":"Off","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"state\":\"OFF\"}","tot":"json"},{"t":"set","p":"LightTurnedOn","pt":"flow","to":"OFF","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":690,"y":220,"wires":[[]]},{"id":"623c940912dc705c","type":"change","z":"e3301957976476f0","name":"Full brightness","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"brightness\":254, \"state\":\"ON\", \"transition\": 0.2}","tot":"json"},{"t":"set","p":"LightTurnedOn","pt":"msg","to":"ON","tot":"str"},{"t":"set","p":"increased","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":720,"y":260,"wires":[[]]},{"id":"45f6f56b676ac14f","type":"switch","z":"e3301957976476f0","name":"LightTurnedOn?","property":"LightTurnedOn","propertyType":"flow","rules":[{"t":"eq","v":"ON","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":160,"y":400,"wires":[["eaf04f8417ecd7a2"],["158601ea01c03c26"]]},{"id":"dfef76a89df6753e","type":"change","z":"e3301957976476f0","name":"","rules":[{"t":"set","p":"PressedTime","pt":"flow","to":"","tot":"date"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":100,"wires":[[]]},{"id":"1112f60123c3443c","type":"change","z":"e3301957976476f0","name":"","rules":[{"t":"set","p":"ReleasedTime","pt":"flow","to":"","tot":"date"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":180,"wires":[["c35256d3cf376244"]]},{"id":"c35256d3cf376244","type":"function","z":"e3301957976476f0","name":"Short press?","func":"if (flow.get(\"ReleasedTime\") - flow.get(\"PressedTime\") < 500)\n{\n msg.payload = \"Short press\";\n return msg;\n}","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":230,"wires":[["10ef55d27dc868c0"]]},{"id":"9fef249d888268f7","type":"switch","z":"e3301957976476f0","name":"Resume or full brightness?","property":"On state","propertyType":"env","rules":[{"t":"eq","v":"Full brightness","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":440,"y":280,"wires":[["623c940912dc705c"],["f2d8a00ea9de27c5"]]},{"id":"f2d8a00ea9de27c5","type":"change","z":"e3301957976476f0","name":"Resume","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"state\":\"ON\"}","tot":"json"},{"t":"set","p":"LightTurnedOn","pt":"flow","to":"ON","tot":"str"},{"t":"set","p":"increased","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":300,"wires":[[]]},{"id":"7cb765110229bd5e","type":"function","z":"e3301957976476f0","name":"start increasing brightness","func":"flow.set(\"dimming\",true);\nflow.set(\"increased\",true);\nvar TransitionTime = env.get(\"TransitionTime\")||60;\nmsg.payload = {\"brightness_move\": TransitionTime}\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":380,"wires":[[]]},{"id":"a1f7a8de202bbf49","type":"function","z":"e3301957976476f0","name":"start decreasing brightness","func":"flow.set(\"dimming\",true);\nflow.set(\"increased\",false);\nvar TransitionTime = env.get(\"TransitionTime\")|| 60;\nmsg.payload = {\"brightness_move\": -TransitionTime}\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":340,"wires":[[]]},{"id":"a983c5eb8f9b55ae","type":"function","z":"e3301957976476f0","name":"share status","func":"msg.payload = { state:flow.get(\"LightTurnedOn\"), bri: flow.get(\"oldBrightness\")}\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":480,"wires":[[]]},{"id":"8c6813e5601aa5b1","type":"change","z":"e3301957976476f0","name":"Button not held","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":150,"y":320,"wires":[["fd1f289113a203c2"]]},{"id":"dba4815f0d6f50bd","type":"change","z":"e3301957976476f0","name":"Stop increasing/decreasing brightness","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"brightness_move\": 0}","tot":"json"},{"t":"set","p":"dimming","pt":"flow","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":670,"y":140,"wires":[[]]},{"id":"158601ea01c03c26","type":"change","z":"e3301957976476f0","name":"start from 0","rules":[{"t":"set","p":"payload","pt":"msg","to":"{ \"state\": \"ON\", \"brightness\": 1, \"transition\": 1}","tot":"json"},{"t":"set","p":"LightTurnedOn","pt":"flow","to":"ON","tot":"str"},{"t":"set","p":"increased","pt":"flow","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":430,"wires":[["db0f892e33285c76"]]},{"id":"db0f892e33285c76","type":"delay","z":"e3301957976476f0","name":"","pauseType":"delay","timeout":"0.1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":620,"y":430,"wires":[["7cb765110229bd5e"]]},{"id":"b8f03edc064421f7","type":"switch","z":"e3301957976476f0","name":"currently dimming?","property":"dimming","propertyType":"flow","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":410,"y":140,"wires":[["dba4815f0d6f50bd"]]},{"id":"6f306ce75f97b326","type":"change","z":"e3301957976476f0","name":"save current state","rules":[{"t":"set","p":"LightTurnedOn","pt":"flow","to":"payload.state","tot":"msg"},{"t":"set","p":"oldBrightness","pt":"flow","to":"payload.brightness","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":480,"wires":[["a983c5eb8f9b55ae"]]},{"id":"df800b5afbd00c08","type":"switch","z":"e3301957976476f0","name":"","property":"payload.state","propertyType":"msg","rules":[{"t":"nempty"}],"checkall":"true","repair":false,"outputs":1,"x":210,"y":480,"wires":[["6f306ce75f97b326"]]},{"id":"9c579514c5adf19e","type":"tab","label":"Binary input Z2M dimmer","disabled":false,"info":"","env":[]},{"id":"09675c8646d05309","type":"mqtt in","z":"9c579514c5adf19e","name":"","topic":"zigbee2mqtt/FRIENDLY_NAME","qos":"2","datatype":"auto-detect","broker":"","nl":false,"rap":true,"rh":0,"inputs":0,"x":160,"y":140,"wires":[["415bef9f3e44a85e"]]},{"id":"415bef9f3e44a85e","type":"subflow:e3301957976476f0","z":"9c579514c5adf19e","name":"","env":[{"name":"On state","value":"Full brightness","type":"str"}],"x":430,"y":140,"wires":[["fc77f0db2fdd2fe0"]]},{"id":"fc77f0db2fdd2fe0","type":"mqtt out","z":"9c579514c5adf19e","name":"","topic":"zigbee2mqtt/FRIENDLY_NAME/set","qos":"2","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"","x":720,"y":140,"wires":[]},{"id":"5952f1c9345522b5","type":"server-state-changed","z":"9c579514c5adf19e","name":"Binary input [on/off, true/false, 0/1, pressed/released]","server":"","version":5,"outputs":1,"exposeAsEntityConfig":"","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":true,"ignoreCurrentStateUnavailable":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":230,"y":70,"wires":[["415bef9f3e44a85e"]]},{"id":"456ed6141e473eda","type":"comment","z":"9c579514c5adf19e","name":"instructions + link to latest version of this flow","info":"Latest version of this flow can be found at https://flows.nodered.org/flow/b3aa835c9ead60b8ec96b63ae2e80595 \n\n 1. Edit or replace the Home Assistant node to send binary output (pressed/released) to the input of the subflow\n 2. select your MQTT broker used for Zigbee2MQTT in the MQTT nodes and replace \"FRIENDLY_NAME\" with the name of your light in Zigbee2MQTT.\n 3. double click the subflow and set the button pressed and released values (could be on/off, true/false, button_1_pressed/button_1_released, etc.)","x":200,"y":30,"wires":[]}]