Fix n_chase pattern to properly chase through all LED positions

- Replace oscillating behavior with proper chasing movement
- Use pattern_step for internal tracking instead of controller's step
- Calculate position relative to chase head: (i - pattern_step) % num_leds
- Chase head moves through all LED positions with n3 step multiplier
- n1 controls width of lit chase segment
This commit is contained in:
2025-09-19 00:22:25 +12:00
parent 67c4a1a6f6
commit d715af4344
2 changed files with 45 additions and 37 deletions

View File

@@ -47,39 +47,39 @@ def main():
last_msg = msg last_msg = msg
if last_msg: if last_msg:
# try: try:
data = json.loads(last_msg) data = json.loads(last_msg)
defaults = data.get("d", {}) defaults = data.get("d", {})
bar = data.get(settings.get("name"), {}) bar = data.get(settings.get("name"), {})
# Check message type # Check message type
message_type = defaults.get("t", "b") # Default to beat if not specified message_type = defaults.get("t", "b") # Default to beat if not specified
# Always update parameters from message # Always update parameters from message
patterns.brightness = bar.get("br", defaults.get("br", patterns.brightness)) patterns.brightness = bar.get("br", defaults.get("br", patterns.brightness))
patterns.delay = bar.get("dl", defaults.get("dl", patterns.delay)) patterns.delay = bar.get("dl", defaults.get("dl", patterns.delay))
patterns.colors = bar.get("cl", defaults.get("cl", patterns.colors)) patterns.colors = bar.get("cl", defaults.get("cl", patterns.colors))
patterns.n1 = bar.get("n1", defaults.get("n1", patterns.n1)) patterns.n1 = bar.get("n1", defaults.get("n1", patterns.n1))
patterns.n2 = bar.get("n2", defaults.get("n2", patterns.n2)) patterns.n2 = bar.get("n2", defaults.get("n2", patterns.n2))
patterns.n3 = bar.get("n3", defaults.get("n3", patterns.n3)) patterns.n3 = bar.get("n3", defaults.get("n3", patterns.n3))
patterns.step = bar.get("pattern_step", defaults.get("step", patterns.step)) patterns.step = bar.get("s", defaults.get("s", patterns.step))
# Only execute pattern if it's a beat message # Only execute pattern if it's a beat message
if message_type == "b": # Beat message if message_type == "b": # Beat message
selected_pattern = bar.get("pt", defaults.get("pt", "off")) selected_pattern = bar.get("pt", defaults.get("pt", "off"))
if selected_pattern in patterns.patterns: if selected_pattern in patterns.patterns:
# Run the selected pattern ONCE in response to this beat message # Run the selected pattern ONCE in response to this beat message
patterns.patterns[selected_pattern]() patterns.patterns[selected_pattern]()
else:
print(f"Pattern {selected_pattern} not found")
elif message_type == "u": # Update message
# Just update parameters, don't execute pattern
print(f"Parameters updated: brightness={patterns.brightness}, delay={patterns.delay}")
else: else:
print(f"Pattern {selected_pattern} not found") print(f"Unknown message type: {message_type}")
elif message_type == "u": # Update message except Exception as ex:
# Just update parameters, don't execute pattern print(f"Failed to load espnow data {last_msg}: {ex}")
print(f"Parameters updated: brightness={patterns.brightness}, delay={patterns.delay}") continue
else:
print(f"Unknown message type: {message_type}")
# except Exception as ex:
# print(f"Failed to load espnow data {last_msg}: {ex}")
# continue
main() main()

View File

@@ -89,13 +89,21 @@ class Patterns(PatternBase): # Inherit from PatternBase
self.last_update = current_time self.last_update = current_time
return self.delay return self.delay
# Use pattern_step for internal chasing, not the controller's step
if not hasattr(self, 'pattern_step'):
self.pattern_step = 0
for i in range(self.num_leds): for i in range(self.num_leds):
if (i + self.pattern_step) % segment_length < self.n1: # Calculate position relative to the chase head
pos_from_head = (i - self.pattern_step) % self.num_leds
if pos_from_head < self.n1:
self.n[i] = self.apply_brightness(self.colors[0]) self.n[i] = self.apply_brightness(self.colors[0])
else: else:
self.n[i] = (0, 0, 0) self.n[i] = (0, 0, 0)
self.n.write() self.n.write()
self.pattern_step = (self.pattern_step + step_rate) % segment_length
# Update internal pattern step for chasing
self.pattern_step = (self.pattern_step + step_rate) % self.num_leds
self.last_update = current_time self.last_update = current_time
return self.delay return self.delay
@@ -129,7 +137,7 @@ class Patterns(PatternBase): # Inherit from PatternBase
self.n[i] = active_color self.n[i] = active_color
self.n.write() self.n.write()
self.step = (self.step + 1) % 2 # Don't update step - use the step value sent from controller for synchronization
return max(1, int(self.delay // 2)) return max(1, int(self.delay // 2))
@@ -189,10 +197,10 @@ class Patterns(PatternBase): # Inherit from PatternBase
step_rate = max(1, int(self.n3)) step_rate = max(1, int(self.n3))
for i in range(self.num_leds): for i in range(self.num_leds):
rc_index = (i * 256 // max(1, self.num_leds)) + self.pattern_step rc_index = (i * 256 // max(1, self.num_leds)) + self.step
self.n[i] = self.apply_brightness(wheel(rc_index & 255)) self.n[i] = self.apply_brightness(wheel(rc_index & 255))
self.n.write() self.n.write()
self.pattern_step = (self.pattern_step + step_rate) % 256 self.step = (self.step + step_rate) % 256
return max(1, int(self.delay // 5)) return max(1, int(self.delay // 5))
def specto(self): def specto(self):