-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathleds.py
More file actions
100 lines (88 loc) · 3.23 KB
/
Copy pathleds.py
File metadata and controls
100 lines (88 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import math
import time
NUM = 7
class Leds:
def __init__(self, presto):
self.p = presto
self._state = None
self._t0 = time.ticks_ms()
self.mode = "state"
# 0..1 global dimmer applied on top of per-state animation values.
# Used by the app's screen-off logic to dim the ring together with
# the display.
self._brightness = 1.0
self._suspended = False
def _off(self):
for i in range(NUM):
self.p.set_led_rgb(i, 0, 0, 0)
def _hsv(self, i, h, s, v):
self.p.set_led_hsv(i, h, s, v * self._brightness)
def _rgb(self, i, r, g, b):
b_factor = self._brightness
self.p.set_led_rgb(i, int(r * b_factor), int(g * b_factor), int(b * b_factor))
def set_mode(self, mode):
if mode not in ("state", "ambient", "off") or mode == self.mode:
return
if mode == "ambient":
self.p.auto_ambient_leds(True)
elif self.mode == "ambient":
self.p.auto_ambient_leds(False)
self.mode = mode
if mode == "off":
self._off()
def set_brightness(self, factor):
self._brightness = max(0.0, min(1.0, factor))
if self._brightness <= 0.01 and self.mode == "state":
self._off()
def suspend(self, on):
"""Temporarily blank the ring without changing `mode`. Used by the
screen-off path so `persist.led_mode` is restored on wake."""
if on and not self._suspended:
self._suspended = True
if self.mode == "ambient":
self.p.auto_ambient_leds(False)
self._off()
elif not on and self._suspended:
self._suspended = False
if self.mode == "ambient":
self.p.auto_ambient_leds(True)
def step(self, state):
if self._suspended or self.mode != "state":
return
if self._brightness <= 0.01:
return
if state != self._state:
self._state = state
self._t0 = time.ticks_ms()
self._off()
dt = time.ticks_diff(time.ticks_ms(), self._t0)
if state == "sleep":
self._off()
elif state == "idle":
# Slow Claude-orange breathing.
v = 0.08 + 0.10 * (0.5 + 0.5 * math.sin(dt * 0.003))
for i in range(NUM):
self._hsv(i, 0.06, 0.7, v)
elif state == "busy":
# Amber chase around the ring.
pos = (dt // 120) % NUM
for i in range(NUM):
v = 0.7 if i == pos else 0.05
self._hsv(i, 0.08, 1.0, v)
elif state == "attention":
# Hard red blink — should be unmissable.
on = (dt // 350) % 2 == 0
for i in range(NUM):
self._rgb(i, 220 if on else 0, 0, 0)
elif state == "celebrate":
# Rainbow sweep.
base = (dt / 2000.0) % 1.0
for i in range(NUM):
self._hsv(i, (base + i / NUM) % 1.0, 1.0, 0.65)
elif state == "heart":
# Green pulse.
v = 0.1 + 0.25 * (0.5 + 0.5 * math.sin(dt * 0.008))
for i in range(NUM):
self._hsv(i, 0.35, 0.9, v)
else:
self._off()