Support for halting a fade in progress.
## Description:
As @s-hadinger sta…ted in [#10382](https://github.com/arendst/Tasmota/issues/10382#issuecomment-753589723), in response to a request to support changing the `Fade` command's value during a fade:
> Changing Fade during a fade is not supported and behavior is unpredictable.
> Fade code is complex enough and code will not be added for corner cases that are not supposed to happen. Unless you have a use case that interests multiple users.
The issue's author, @plamenko, was looking for a way to halt a fade in progress, and thought that disabling fades altogether might do that. I agree that halting a fade by disabling the feature altogether is probably not the best way to provide that functionality, but I do believe the ability to stop fades in progress should be a standard part of a lighting control API.
The main use case is remote touch-and-hold dimming adjustment. On my remote, I press and hold down the "increase dimming" button. The behavior I expect from the remotely-controlled light would be for the dimming level to begin increasing. When the light reaches the dimming level I desire, I release the "increase dimming" button. The light then halts the dimming process and leaves the light at the dimming level it was at when I released the button.
I am aware of three different interaction modalities for setting the dimming level of a light, and the Zigbee Cluster Library specification<sup id="a1">[[1]](#f1)</sup> for the Level cluster supports all three of them. It supports the "Move to Level" command, where you specify a target dimming level and a transition time. It supports the "Step" command, where you specify an adjustment up or down in the level from the current level by a given step size over a given transition time. Both of these dimming modalities are already supported by Tasmota, but there is a third modality which it does not support: the "Move" and "Stop" commands. The "Move" command tells the light to begin adjusting the dimming level up or down at a particular rate. The light then increases or decreases dimming continuously until it reaches the minimum or maximum dimming level, OR it receives a "Stop" command, halting the dimming at the current level. Tasmota does not at present have a command to halt dimming, per #10382.
I have done a brief survey of publicly-available lighting control APIs to determine how widespread support for this use case is. In the area of well-known home automation standards, besides Zigbee, the Z-Wave Application Command Class Specification<sup name="a2">[[2]](#f2)</sup> also supports it. I reviewed several manufacturer-specific APIs, and while many do not support this use case, such as [Tuya](https://developer.tuya.com/en/docs/iot/open-api/standard-function/electrician-category/categorytgkg/f?id=K9t2a5li5awj8) and [Lifx](https://lan.developer.lifx.com/docs/light-messages), some do, such as Insteon,<sup name="a3">[[3]](#f3)</sup> Phillips Hue<sup name="a4">[[4]](#f4)</sup> and Yeelight<sup name="a5">[[5]](#f5)</sup>. In short, there is good precedent to explicitly support this use case.
Further, I have found this use case for dimming is supported not just in software by APIs but implemented in actual physical remote control devices. For example, I have an [IKEA TRÅDFRI Remote control](https://www.ikea.com/us/en/p/tradfri-remote-control-00443130/), and when you press and hold the increase dimming and decrease dimming buttons, it produces the Zigbee "Move" command and when you release them, it produces the "Stop" command.
I have a mixture of Tasmota-powered and Zigbee devices in my home, and I'd like to be able to use the same interaction modalities for dimming lights, regardless of whether the light is Zigbee or Tasmota. With a simple Zigbee-to-MQTT translation layer (in e.g. Node-RED), I can do this—but Tasmota does not really support the "stop" command. As a workaround, I have the translation layer track how long I've held the button down for, then calculate what the dimming value *should* be when I release the button, and send an updated `Dimmer` command to the Tasmota device. Unfortunately, due to latencies in the system, the fade in progress on the Tasmota device often overshoots and then flashes back to the correct level. It would be a better user experience if there were a command for the fade to simply halt.
To that end, the required changes to Tasmota are not very large, as we already can get an equivalent of the Move command by setting `Speed` to the desired level change rate, ensuring `Fade` is on, and issuing a `Dimmer` command for the maximum or minimum dimmer level. All that is needed is a new command or a new argument to an existing command to halt a fade in progress.
As the `Dimmer` command already supports the special arguments `+` and `-` for incremental changes to the dimmer level, I propose three new special arguments to support "stop," "move up," and "move down:" `!` for "stop," `>` for "move up," and `<` for "move down." However, as support for "move up" and "move down" already exists by simply calling `Dimmer 100` or `Dimmer 1`, these would just be for convenience.
This PR constitutes a small patch to implement the above, but I am happy to change the interface to any set of commands/arguments desired.
### Caveats
This code only halts fades due to dimming. Color fades are not affected by the `Dimmer !` command.
**Related issue (if applicable):** fixes #10382
## Checklist:
- [x] The pull request is done against the latest development branch
- [x] Only relevant files were touched
- [x] Only one feature/fix was added per PR and the code change compiles without warnings
- [x] The code change is tested and works on Tasmota core ESP8266 V.2.7.4.9
- [x] The code change is tested and works with core ESP32 V.1.0.5
- [x] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla).
_NOTE: The code change must pass CI tests. **Your PR cannot be merged unless tests pass**_
---
<b id="f1"><sup>1</sup></b> The [Zigbee Cluster Library specification](https://zigbeealliance.org/wp-content/uploads/2019/12/07-5123-06-zigbee-cluster-library-specification.pdf) has a Level cluster (3.10) with "Move" and "Stop" commands that support this type of behavior.[↩](#a1)
<b id="f2"><sup>2</sup></b> The [Z-Wave Application Command Class Specification](https://www.silabs.com/documents/login/miscellaneous/SDS13781-Z-Wave-Application-Command-Class-Specification.pdf) has a Multilevel Switch Command Class (4.69—4.72) that supports a "Start Level Change Command" and a "Stop Level Change Command."[↩](#a2)
<b id="f3"><sup>3</sup></b>The [Insteon API](https://insteon.docs.apiary.io/#reference/commands/commands-collection) has a commands collection that supports `start_dim_up`, `start_dim_down`, and `stop_dim` commands.[↩](#a3)
<b id="f4"><sup>4</sup></b>The [Hue Lights API](https://developers.meethue.com/develop/hue-api/lights-api/#set-light-state) has a "set light state" command which doesn't have separate commands for move/stop, but does explicitly state that specifying a value of 0 for the `bri_inc` argument will halt a brightness transition: "Any ongoing bri transition is stopped. Setting a value of 0 also stops any ongoing transition."[↩](#a4)
<b id="f5"><sup>5</sup></b>The [Yeelight WiFi Light Inter-Operation Specification](https://www.yeelight.com/download/Yeelight_Inter-Operation_Spec.pdf) supports `start_cf` and `stop_cf` commands to start and stop "color flow," including brightness adjustment.[↩](#a5)