toblum / McLighting

The ESP8266 based multi-client lighting gadget
MIT License
1.05k stars 291 forks source link

Noticeable latency when changing the brightness from 0. #166

Open flagstone78 opened 6 years ago

flagstone78 commented 6 years ago

For example, when on the static effect, changing the brightness from 1 to 255 will instantly change every time. Changing the brightness from 0 to 255 sometimes delays. The delay varies from insignificant to almost a full second (I estimate).

The issue is dependent on the effect being rendered. On the static effect, it only delays by a second. On the breathe effect, the delay was almost 5 seconds and I had to refresh the web interface to be able to control it again. The color wipe effects seem to have no issue. Random Color has a small and constant delay. I have not testest the other effects yet.

I updated my code to the latest version to make sure that was not the issue.

The issue occurs both with the web interface and by calling strip.setBrightness in the code (I modified what the button function did). I am still investigating the cause of the delay. I checked the WS2812fx GitHub for a similar issue; Nothing similar was reported.

flagstone78 commented 6 years ago

It looks like the breathe function in the WS2812fx library divides by the brightness, which causes a divide by zero error. The fade function also does this.

That explains why those effects crash the web interface when you set the brightness to zero, but the delay for the other functions is still unaccounted for.

debsahu commented 6 years ago

@flagstone78 no matter what you do to strip.setBrightness(), until you call strip.service() or strip.show() it will not update the strip. During a web/websocket/mqtt callback strip.show() can be called immediately, but from my experience it is a bit CPU intensive (or blocking) and can crash your esp8266. Usually it is recommended that in callbacks, one should just flip/change variables and do the actual changing in the main loop(). In McLighting, we use global variables that are set/changed/flipped in callbacks and strip.service() is present in the main loop(). They delay you mention are from two sources,

  1. Delay used by WS2812FX where there is no update done to the animation until the delay has exceeded the time for next update
  2. The webserver/websocket server/DNS server/TCP server/UDP server/pubsubclient are not asynchronous and the CPU does spend some time in the main loop() checking if there are callbacks/serving the HTTP server. This can be mitigated by using Async versions of everything. I have this in sight for v3, but if you want to try it out check this and remove all taskscheduler and mesh stuff.
kitesurfer1404 commented 6 years ago

Hi there. Harm from WS2812FX here. :)

On the delay: You might try to call trigger() and service() immediately after changing any FX values or brightness. That should result in a re-rendering of the strip.

I think we will take care of the divide by zero over at the WS2812FX lib.

debsahu commented 6 years ago

Thank you @kitesurfer1404, excellent idea of adding strip.trigger() during set brightness/speed/color/mode calls.

flagstone78 commented 6 years ago

Thanks for the replies, but I think that there is more to this issue because the dealy only occurs around a brightness level of 0. If it was an issue with not calling strip.show() quickly enough, I would expect this delay to happen any time that I change the brightness.

A bit more about my project: I am trying to replace the button logic with a rotary encoder that changes the brightness of the strip when it is rotated. I am only replacing the logic of the button() function in the main loop. I have modeled my code after the existing code and update the brightness in the same the same way as setModeByStateString()

I change the global brightness level when the rotary encoder changes (which has a separate issue: The main loop is not looping fast enough to catch all of the rotations. I tried using a library that used interrupts, but it causes wdt resets.) I let the rest of the code update the display for me. I expect a small delay from the time I change the value to the time the display is updated.

No delay is noticed except when the previous brightness value was 0. I have worked around this issue by setting the mode to OFF and the brightness value to 1 when the rotation of the encoder would have set the brightness to 0. By avoiding a brightness value of 0, everything works as I expect.