fix: Stop LED flash when tag is removed (v1.2.2)

- Add per-pad stop event system (_flash_stop_events dictionary)
- Add stop_flash(pad) method to cancel active flash animations
- flash_pad now checks stop events at multiple points in loop
- Tag removal handler calls stop_flash before setting pad to OFF
- Fixes issue where LED flash continued indefinitely after figure removed
This commit is contained in:
2026-02-20 23:12:03 +11:00
parent 62a61b2d36
commit 3bcf573160

View File

@@ -74,7 +74,7 @@ VENDOR_ID = 0x0e6f
PRODUCT_ID = 0x0241 PRODUCT_ID = 0x0241
# Module version # Module version
__version__ = "1.2.1" __version__ = "1.2.2"
def get_usb_backend(): def get_usb_backend():
@@ -183,6 +183,9 @@ class LegoDimensionsReader:
# Active tags currently on pads (pad_num -> TagInfo) # Active tags currently on pads (pad_num -> TagInfo)
self._active_tags: Dict[int, TagInfo] = {} self._active_tags: Dict[int, TagInfo] = {}
# Flash stop events per pad (for cancelling software flash)
self._flash_stop_events: Dict[int, threading.Event] = {}
# Callbacks # Callbacks
self.on_tag_insert: Optional[Callable[[TagInfo], None]] = None self.on_tag_insert: Optional[Callable[[TagInfo], None]] = None
self.on_tag_remove: Optional[Callable[[TagInfo], None]] = None self.on_tag_remove: Optional[Callable[[TagInfo], None]] = None
@@ -590,6 +593,22 @@ class LegoDimensionsReader:
command = [0x55, 0x06, 0xc0, 0x02, pad.value, color[0], color[1], color[2]] command = [0x55, 0x06, 0xc0, 0x02, pad.value, color[0], color[1], color[2]]
self._send_command(command) self._send_command(command)
def stop_flash(self, pad: Pad):
"""
Stop any active flash animation on a pad.
Args:
pad: Which pad to stop flashing (Pad.ALL stops all pads)
"""
if pad == Pad.ALL:
pads_to_stop = [Pad.CENTER, Pad.LEFT, Pad.RIGHT]
else:
pads_to_stop = [pad]
for p in pads_to_stop:
if p.value in self._flash_stop_events:
self._flash_stop_events[p.value].set()
def flash_pad(self, pad: Pad, color: list, on_time: int = 10, def flash_pad(self, pad: Pad, color: list, on_time: int = 10,
off_time: int = 10, count: int = 5): off_time: int = 10, count: int = 5):
""" """
@@ -618,19 +637,44 @@ class LegoDimensionsReader:
else: else:
pads_to_flash = [pad] pads_to_flash = [pad]
# Stop any existing flash on these pads
for p in pads_to_flash:
if p.value in self._flash_stop_events:
self._flash_stop_events[p.value].set()
# Create new stop events for this flash
stop_events = {}
for p in pads_to_flash:
stop_events[p.value] = threading.Event()
self._flash_stop_events[p.value] = stop_events[p.value]
def _flash_thread(): def _flash_thread():
for _ in range(actual_count): for _ in range(actual_count):
# Check if we should stop (device disconnected or stop requested)
if not self._running and not self.dev: if not self._running and not self.dev:
break break
# Check if stop was requested for any of our pads
if any(stop_events[p.value].is_set() for p in pads_to_flash):
break
# ON # ON
for p in pads_to_flash: for p in pads_to_flash:
if not stop_events[p.value].is_set():
self.set_pad_color(p, color) self.set_pad_color(p, color)
time.sleep(on_secs) time.sleep(on_secs)
# Check again before OFF
if any(stop_events[p.value].is_set() for p in pads_to_flash):
break
# OFF # OFF
for p in pads_to_flash: for p in pads_to_flash:
if not stop_events[p.value].is_set():
self.set_pad_color(p, COLORS['OFF']) self.set_pad_color(p, COLORS['OFF'])
time.sleep(off_secs) time.sleep(off_secs)
# Cleanup stop events when done
for p in pads_to_flash:
if p.value in self._flash_stop_events and self._flash_stop_events[p.value] == stop_events[p.value]:
del self._flash_stop_events[p.value]
# Run flash in background thread so it doesn't block # Run flash in background thread so it doesn't block
flash_thread = threading.Thread(target=_flash_thread, daemon=True) flash_thread = threading.Thread(target=_flash_thread, daemon=True)
flash_thread.start() flash_thread.start()
@@ -720,7 +764,8 @@ class LegoDimensionsReader:
if pad_num in self._active_tags: if pad_num in self._active_tags:
del self._active_tags[pad_num] del self._active_tags[pad_num]
# Turn off pad LED # Stop any active flash and turn off pad LED
self.stop_flash(pad)
self.set_pad_color(pad, COLORS['OFF']) self.set_pad_color(pad, COLORS['OFF'])
if self.on_tag_remove: if self.on_tag_remove: