From d715af43449dd82488ec34f8c8bee4c3b1811496 Mon Sep 17 00:00:00 2001 From: jimmy Date: Fri, 19 Sep 2025 00:22:25 +1200 Subject: [PATCH] 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 --- src/main.py | 64 ++++++++++++++++++++++++------------------------- src/patterns.py | 18 ++++++++++---- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/main.py b/src/main.py index d24a311..23e02f4 100644 --- a/src/main.py +++ b/src/main.py @@ -47,39 +47,39 @@ def main(): last_msg = msg if last_msg: - # try: - data = json.loads(last_msg) - defaults = data.get("d", {}) - bar = data.get(settings.get("name"), {}) - - # Check message type - message_type = defaults.get("t", "b") # Default to beat if not specified - - # Always update parameters from message - patterns.brightness = bar.get("br", defaults.get("br", patterns.brightness)) - patterns.delay = bar.get("dl", defaults.get("dl", patterns.delay)) - patterns.colors = bar.get("cl", defaults.get("cl", patterns.colors)) - patterns.n1 = bar.get("n1", defaults.get("n1", patterns.n1)) - patterns.n2 = bar.get("n2", defaults.get("n2", patterns.n2)) - patterns.n3 = bar.get("n3", defaults.get("n3", patterns.n3)) - patterns.step = bar.get("pattern_step", defaults.get("step", patterns.step)) - - # Only execute pattern if it's a beat message - if message_type == "b": # Beat message - selected_pattern = bar.get("pt", defaults.get("pt", "off")) - if selected_pattern in patterns.patterns: - # Run the selected pattern ONCE in response to this beat message - patterns.patterns[selected_pattern]() + try: + data = json.loads(last_msg) + defaults = data.get("d", {}) + bar = data.get(settings.get("name"), {}) + + # Check message type + message_type = defaults.get("t", "b") # Default to beat if not specified + + # Always update parameters from message + patterns.brightness = bar.get("br", defaults.get("br", patterns.brightness)) + patterns.delay = bar.get("dl", defaults.get("dl", patterns.delay)) + patterns.colors = bar.get("cl", defaults.get("cl", patterns.colors)) + patterns.n1 = bar.get("n1", defaults.get("n1", patterns.n1)) + patterns.n2 = bar.get("n2", defaults.get("n2", patterns.n2)) + patterns.n3 = bar.get("n3", defaults.get("n3", patterns.n3)) + patterns.step = bar.get("s", defaults.get("s", patterns.step)) + + # Only execute pattern if it's a beat message + if message_type == "b": # Beat message + selected_pattern = bar.get("pt", defaults.get("pt", "off")) + if selected_pattern in patterns.patterns: + # Run the selected pattern ONCE in response to this beat message + 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: - 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: - print(f"Unknown message type: {message_type}") - # except Exception as ex: - # print(f"Failed to load espnow data {last_msg}: {ex}") - # continue + print(f"Unknown message type: {message_type}") + except Exception as ex: + print(f"Failed to load espnow data {last_msg}: {ex}") + continue main() diff --git a/src/patterns.py b/src/patterns.py index 866c713..d36383c 100644 --- a/src/patterns.py +++ b/src/patterns.py @@ -89,13 +89,21 @@ class Patterns(PatternBase): # Inherit from PatternBase self.last_update = current_time 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): - 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]) else: self.n[i] = (0, 0, 0) 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 return self.delay @@ -129,7 +137,7 @@ class Patterns(PatternBase): # Inherit from PatternBase self.n[i] = active_color 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)) @@ -189,10 +197,10 @@ class Patterns(PatternBase): # Inherit from PatternBase step_rate = max(1, int(self.n3)) 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.write() - self.pattern_step = (self.pattern_step + step_rate) % 256 + self.step = (self.step + step_rate) % 256 return max(1, int(self.delay // 5)) def specto(self):