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 signal
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
import time
|
||||||
|
|
||||||
# Single instance locker to prevent multiple UI processes
|
# Single instance locker to prevent multiple UI processes
|
||||||
class SingleInstanceLocker:
|
class SingleInstanceLocker:
|
||||||
@@ -169,6 +170,10 @@ class MidiController:
|
|||||||
self.knob7 = 0
|
self.knob7 = 0
|
||||||
self.knob8 = 0
|
self.knob8 = 0
|
||||||
self.beat_sending_enabled = True
|
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)
|
# Color palette selection state (two selected indices, alternating target)
|
||||||
self.selected_indices = [0, 1]
|
self.selected_indices = [0, 1]
|
||||||
self.next_selected_target = 0 # 0 selects color1 next, 1 selects color2 next
|
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}")
|
logging.info(f"MIDI CC {control}: {value}")
|
||||||
|
|
||||||
if control == 33: # Brightness (0-100)
|
if control == 33: # Brightness (0-100)
|
||||||
self.brightness = round((value / 127) * 100)
|
current_time = time.time()
|
||||||
if callable(self.on_parameters_change):
|
new_brightness = round((value / 127) * 100)
|
||||||
self.on_parameters_change({"brightness": self.brightness})
|
|
||||||
|
# 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)
|
elif control == 34: # n1 (0-255)
|
||||||
self.n1 = int(value)
|
self.n1 = int(value)
|
||||||
if callable(self.on_parameters_change):
|
if callable(self.on_parameters_change):
|
||||||
@@ -1027,12 +1043,15 @@ class UIClient:
|
|||||||
async def persist_parameters(self, params: dict):
|
async def persist_parameters(self, params: dict):
|
||||||
"""POST parameter changes via REST to /api/parameters."""
|
"""POST parameter changes via REST to /api/parameters."""
|
||||||
try:
|
try:
|
||||||
|
print(f"Sending parameters to backend: {params}")
|
||||||
data = json.dumps(params).encode('utf-8')
|
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'})
|
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:
|
with urllib.request.urlopen(req, timeout=2.0) as resp:
|
||||||
_ = resp.read()
|
_ = resp.read()
|
||||||
|
print(f"Successfully sent parameters: {params}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.debug(f"Failed to persist parameters (REST): {e}")
|
logging.debug(f"Failed to persist parameters (REST): {e}")
|
||||||
|
print(f"Failed to send parameters: {e}")
|
||||||
|
|
||||||
def on_closing(self):
|
def on_closing(self):
|
||||||
"""Handle application closing."""
|
"""Handle application closing."""
|
||||||
|
Reference in New Issue
Block a user