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:
2025-10-04 10:02:47 +13:00
parent 763a2053ad
commit 9cf1855b51

View File

@@ -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."""