102 lines
3.5 KiB
Python
102 lines
3.5 KiB
Python
# Standalone MicroPython Voice Animation: Network Retry
|
|
# Exposes run(text="", frames=...) and runs automatically if executed directly.
|
|
import time
|
|
import math
|
|
|
|
try:
|
|
import board_config
|
|
display = getattr(board_config, 'display_instance', None)
|
|
except Exception:
|
|
board_config = None
|
|
display = None
|
|
|
|
def draw_center_text(d, msg, y, w, scale=1, c=1):
|
|
char_w = 8 * scale
|
|
x = max(0, (w - len(msg) * char_w) // 2)
|
|
if hasattr(d, 'text_large') and scale > 1:
|
|
try:
|
|
d.text_large(msg, x, y, scale, c)
|
|
return
|
|
except Exception:
|
|
pass
|
|
d.text(msg, x, y, c)
|
|
|
|
def run(text="", frames=100):
|
|
if not display:
|
|
print("board_config.display_instance is not available. Skipping animation.")
|
|
return
|
|
|
|
width = getattr(display, 'width', 400)
|
|
height = getattr(display, 'height', 300)
|
|
cx, cy = width // 2, height // 2
|
|
|
|
label = text if text else "CONNECTING..."
|
|
frame = 0
|
|
|
|
try:
|
|
while True:
|
|
if frames is not None and frames > 0 and frame >= frames:
|
|
break
|
|
|
|
display.clear(0)
|
|
|
|
# Wi-Fi Dot base at bottom of logo
|
|
dot_y = cy + 20
|
|
display.fill_rect(cx - 4, dot_y - 4, 8, 8, 1)
|
|
|
|
# Determine Wi-Fi wave stage (0 to 3) for sequential scanning
|
|
stage = (frame // 3) % 4
|
|
|
|
# Wave 1 (inner arc)
|
|
if stage >= 1:
|
|
display.line(cx - 15, dot_y - 12, cx, dot_y - 20, 1)
|
|
display.line(cx, dot_y - 20, cx + 15, dot_y - 12, 1)
|
|
|
|
# Wave 2 (middle arc)
|
|
if stage >= 2:
|
|
display.line(cx - 30, dot_y - 25, cx, dot_y - 36, 1)
|
|
display.line(cx, dot_y - 36, cx + 30, dot_y - 25, 1)
|
|
|
|
# Wave 3 (outer arc)
|
|
if stage >= 3:
|
|
display.line(cx - 45, dot_y - 38, cx, dot_y - 52, 1)
|
|
display.line(cx, dot_y - 52, cx + 45, dot_y - 38, 1)
|
|
|
|
# Draw a rotating retry circle (dashed arrow indicator) around the Wi-Fi icon
|
|
r = 68
|
|
# Compute 2 rotating arrow segments based on frame
|
|
rot_offset = frame * 0.12
|
|
for side in (0, math.pi):
|
|
for a_deg in range(0, 120, 15):
|
|
angle = side + rot_offset + math.radians(a_deg)
|
|
px = cx + int(r * math.cos(angle))
|
|
py = cy - 10 + int(r * math.sin(angle))
|
|
display.fill_rect(px - 2, py - 2, 4, 4, 1)
|
|
|
|
# Draw arrowheads at the leading edge of each segment
|
|
lead_angle = side + rot_offset + math.radians(120)
|
|
lx = cx + int(r * math.cos(lead_angle))
|
|
ly = cy - 10 + int(r * math.sin(lead_angle))
|
|
|
|
# Arrowhead wings
|
|
w1 = lead_angle - math.pi * 0.75
|
|
w2 = lead_angle + math.pi * 0.75
|
|
display.line(lx, ly, lx + int(8 * math.cos(w1)), ly + int(8 * math.sin(w1)), 1)
|
|
display.line(lx, ly, lx + int(8 * math.cos(w2)), ly + int(8 * math.sin(w2)), 1)
|
|
|
|
# Draw centered text label at the bottom
|
|
draw_center_text(display, label, height - 30, width, scale=1, c=1)
|
|
|
|
display.show()
|
|
frame += 1
|
|
|
|
try:
|
|
time.sleep_ms(55)
|
|
except AttributeError:
|
|
time.sleep(0.055)
|
|
except KeyboardInterrupt:
|
|
print("Animation interrupted by user.")
|
|
|
|
if __name__ in ('__main__', '__name__'):
|
|
run()
|