UI: Add rate limiting to brightness control
- Add 100ms minimum interval between brightness updates to backend - Keep UI responsive with immediate local brightness updates - Prevent backend overload from rapid MIDI CC33 changes - Add time import for rate limiting functionality - Add debug output to show when updates are sent vs rate limited - Improve smoothness and reduce network traffic - Protect lighting controller from too many rapid parameter changes
This commit is contained in:
@@ -18,6 +18,7 @@ import atexit
|
||||
import signal
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import time
|
||||
|
||||
# Single instance locker to prevent multiple UI processes
|
||||
class SingleInstanceLocker:
|
||||
@@ -169,6 +170,10 @@ class MidiController:
|
||||
self.knob7 = 0
|
||||
self.knob8 = 0
|
||||
self.beat_sending_enabled = True
|
||||
|
||||
# Rate limiting for brightness control
|
||||
self.last_brightness_update = 0
|
||||
self.brightness_update_interval = 0.1 # 100ms minimum between updates
|
||||
# Color palette selection state (two selected indices, alternating target)
|
||||
self.selected_indices = [0, 1]
|
||||
self.next_selected_target = 0 # 0 selects color1 next, 1 selects color2 next
|
||||
@@ -313,9 +318,20 @@ class MidiController:
|
||||
logging.info(f"MIDI CC {control}: {value}")
|
||||
|
||||
if control == 33: # Brightness (0-100)
|
||||
self.brightness = round((value / 127) * 100)
|
||||
if callable(self.on_parameters_change):
|
||||
self.on_parameters_change({"brightness": self.brightness})
|
||||
current_time = time.time()
|
||||
new_brightness = round((value / 127) * 100)
|
||||
|
||||
# Rate limiting: only update if enough time has passed
|
||||
if current_time - self.last_brightness_update >= self.brightness_update_interval:
|
||||
self.brightness = new_brightness
|
||||
self.last_brightness_update = current_time
|
||||
print(f"Brightness changed to: {self.brightness}")
|
||||
if callable(self.on_parameters_change):
|
||||
self.on_parameters_change({"brightness": self.brightness})
|
||||
else:
|
||||
# Still update the local value for UI display, but don't send to backend
|
||||
self.brightness = new_brightness
|
||||
print(f"Brightness updated locally to: {self.brightness} (rate limited)")
|
||||
elif control == 34: # n1 (0-255)
|
||||
self.n1 = int(value)
|
||||
if callable(self.on_parameters_change):
|
||||
@@ -1027,12 +1043,15 @@ class UIClient:
|
||||
async def persist_parameters(self, params: dict):
|
||||
"""POST parameter changes via REST to /api/parameters."""
|
||||
try:
|
||||
print(f"Sending parameters to backend: {params}")
|
||||
data = json.dumps(params).encode('utf-8')
|
||||
req = urllib.request.Request(f"{HTTP_BASE}/api/parameters", data=data, method='POST', headers={'Content-Type': 'application/json'})
|
||||
with urllib.request.urlopen(req, timeout=2.0) as resp:
|
||||
_ = resp.read()
|
||||
print(f"Successfully sent parameters: {params}")
|
||||
except Exception as e:
|
||||
logging.debug(f"Failed to persist parameters (REST): {e}")
|
||||
print(f"Failed to send parameters: {e}")
|
||||
|
||||
def on_closing(self):
|
||||
"""Handle application closing."""
|
||||
|
Reference in New Issue
Block a user