Skip to content

Commit e31f3f0

Browse files
authored
Merge branch 'master' into master
2 parents 24074a4 + 29bcd74 commit e31f3f0

30 files changed

+1058
-13
lines changed

CPB_ANCS/ancs_basecamp.bmp

113 KB
Binary file not shown.

CPB_ANCS/ancs_connect.bmp

113 KB
Binary file not shown.

CPB_ANCS/ancs_discord.bmp

113 KB
Binary file not shown.

CPB_ANCS/ancs_ical.bmp

113 KB
Binary file not shown.

CPB_ANCS/ancs_none.bmp

113 KB
Binary file not shown.

CPB_ANCS/ancs_phone.bmp

113 KB
Binary file not shown.

CPB_ANCS/ancs_slack.bmp

113 KB
Binary file not shown.

CPB_ANCS/ancs_sms.bmp

113 KB
Binary file not shown.

CPB_ANCS/code.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
"""
2+
This demo shows the latest icons from a connected Apple device on a TFT Gizmo screen.
3+
4+
The A and B buttons on the CircuitPlayground Bluefruit can be used to scroll through all active
5+
notifications. The screen's backlight will turn off after a certain number of seconds to save power.
6+
New notifications or pressing the buttons should turn it back on.
7+
"""
8+
9+
import time
10+
import board
11+
import digitalio
12+
import displayio
13+
import adafruit_ble
14+
from adafruit_ble.advertising.standard import SolicitServicesAdvertisement
15+
from adafruit_ble.services.apple import AppleNotificationService
16+
from adafruit_gizmo import tft_gizmo
17+
from audiocore import WaveFile
18+
from audiopwmio import PWMAudioOut as AudioOut
19+
20+
# Enable the speaker
21+
speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
22+
speaker_enable.direction = digitalio.Direction.OUTPUT
23+
speaker_enable.value = True
24+
25+
audio = AudioOut(board.SPEAKER)
26+
27+
# This is a whitelist of apps to show notifications from.
28+
APP_ICONS = {
29+
"com.tinyspeck.chatlyio": "/ancs_slack.bmp",
30+
"com.basecamp.bc3-ios": "/ancs_basecamp.bmp",
31+
"com.apple.MobileSMS": "/ancs_sms.bmp",
32+
"com.hammerandchisel.discord": "/ancs_discord.bmp",
33+
"com.apple.mobilecal": "/ancs_ical.bmp",
34+
"com.apple.mobilephone": "/ancs_phone.bmp"
35+
}
36+
37+
BLACKLIST = []
38+
DELAY_AFTER_PRESS = 15
39+
DEBOUNCE = 0.1
40+
DIM_TIMEOUT = 20 # Amount of timeout to turn off backlight
41+
DIM_LEVEL = 0.05
42+
43+
a = digitalio.DigitalInOut(board.BUTTON_A)
44+
a.switch_to_input(pull=digitalio.Pull.DOWN)
45+
b = digitalio.DigitalInOut(board.BUTTON_B)
46+
b.switch_to_input(pull=digitalio.Pull.DOWN)
47+
48+
file = open("/triode_rise.wav", "rb")
49+
wave = WaveFile(file)
50+
51+
def play_sound():
52+
audio.play(wave)
53+
time.sleep(1)
54+
55+
def find_connection():
56+
for connection in radio.connections:
57+
if AppleNotificationService not in connection:
58+
continue
59+
if not connection.paired:
60+
connection.pair()
61+
return connection, connection[AppleNotificationService]
62+
return None, None
63+
64+
class Dimmer:
65+
def __init__(self):
66+
self._update_time = time.monotonic()
67+
self._level = DIM_LEVEL
68+
self._timeout = DIM_TIMEOUT
69+
70+
def update(self):
71+
self._update_time = time.monotonic()
72+
73+
def check_timeout(self):
74+
if a.value or b.value:
75+
self._update_time = time.monotonic()
76+
if time.monotonic() - self._update_time > self._timeout:
77+
if display.brightness > self._level:
78+
display.brightness = self._level
79+
else:
80+
if display.brightness == self._level:
81+
display.brightness = 1.0
82+
83+
dimmer = Dimmer()
84+
85+
# Start advertising before messing with the display so that we can connect immediately.
86+
radio = adafruit_ble.BLERadio()
87+
advertisement = SolicitServicesAdvertisement()
88+
advertisement.complete_name = "CIRCUITPY"
89+
advertisement.solicited_services.append(AppleNotificationService)
90+
91+
def wrap_in_tilegrid(open_file):
92+
odb = displayio.OnDiskBitmap(open_file)
93+
return displayio.TileGrid(odb, pixel_shader=displayio.ColorConverter())
94+
95+
display = tft_gizmo.TFT_Gizmo()
96+
group = displayio.Group(max_size=3)
97+
group.append(wrap_in_tilegrid(open("/ancs_connect.bmp", "rb")))
98+
display.show(group)
99+
100+
current_notification = None
101+
current_notifications = {}
102+
all_ids = []
103+
last_press = time.monotonic()
104+
active_connection, notification_service = find_connection()
105+
cleared = False
106+
107+
while True:
108+
if not active_connection:
109+
radio.start_advertising(advertisement)
110+
111+
while not active_connection:
112+
active_connection, notification_service = find_connection()
113+
dimmer.check_timeout()
114+
115+
# Connected
116+
dimmer.update()
117+
play_sound()
118+
119+
with open("/ancs_none.bmp", "rb") as no_notifications:
120+
group.append(wrap_in_tilegrid(no_notifications))
121+
while active_connection.connected:
122+
all_ids.clear()
123+
current_notifications = notification_service.active_notifications
124+
for notif_id in current_notifications:
125+
notification = current_notifications[notif_id]
126+
if notification.app_id not in APP_ICONS or notification.app_id in BLACKLIST:
127+
continue
128+
all_ids.append(notif_id)
129+
130+
# pylint: disable=protected-access
131+
all_ids.sort(key=lambda x: current_notifications[x]._raw_date)
132+
# pylint: enable=protected-access
133+
134+
if current_notification and current_notification.removed:
135+
# Stop showing the latest and show that there are no new notifications.
136+
current_notification = None
137+
138+
if not current_notification and not all_ids and not cleared:
139+
cleared = True
140+
dimmer.update()
141+
group[1] = wrap_in_tilegrid(no_notifications)
142+
elif all_ids:
143+
cleared = False
144+
now = time.monotonic()
145+
if current_notification and current_notification.id in all_ids and \
146+
now - last_press < DELAY_AFTER_PRESS:
147+
index = all_ids.index(current_notification.id)
148+
else:
149+
index = len(all_ids) - 1
150+
if now - last_press >= DEBOUNCE:
151+
if b.value and index > 0:
152+
last_press = now
153+
index += -1
154+
if a.value and index < len(all_ids) - 1:
155+
last_press = now
156+
index += 1
157+
notif_id = all_ids[index]
158+
if not current_notification or current_notification.id != notif_id:
159+
dimmer.update()
160+
current_notification = current_notifications[notif_id]
161+
# pylint: disable=protected-access
162+
print(current_notification._raw_date, current_notification)
163+
# pylint: enable=protected-access
164+
app_icon_file = open(APP_ICONS[current_notification.app_id], "rb")
165+
group[1] = wrap_in_tilegrid(app_icon_file)
166+
167+
dimmer.check_timeout()
168+
169+
# Bluetooth Disconnected
170+
group.pop()
171+
dimmer.update()
172+
active_connection = None
173+
notification_service = None

CPB_ANCS/triode_rise.wav

25.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)