Skip to content

Commit 16db087

Browse files
authored
Merge pull request #995 from jedgarpark/master
first commit CPB Volume BLE, added .python-version to .gitignore
2 parents 8979902 + f73354a commit 16db087

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ Hue_Controller/secrets.h
33
.idea
44
*.DS_Store
55
CircuitPython_Logger/secrets\.py
6+
.python-version

CPB_Volume_BLE/cpb_volume_ble.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
"""
2+
A CircuitPython 'multimedia' dial demo
3+
Uses a Circuit Playground Bluefruit + Rotary Encoder -> BLE out
4+
Knob controls volume, push encoder for mute, CPB button A for Play/Pause
5+
Once paired, bonding will auto re-connect devices
6+
"""
7+
8+
import time
9+
import digitalio
10+
import board
11+
import rotaryio
12+
import neopixel
13+
from adafruit_hid.consumer_control import ConsumerControl
14+
from adafruit_hid.consumer_control_code import ConsumerControlCode
15+
16+
import adafruit_ble
17+
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
18+
from adafruit_ble.services.standard.hid import HIDService
19+
from adafruit_ble.services.standard.device_info import DeviceInfoService
20+
21+
22+
ble = adafruit_ble.BLERadio()
23+
ble.name = "Bluefruit-Volume-Control"
24+
# Using default HID Descriptor.
25+
hid = HIDService()
26+
device_info = DeviceInfoService(software_revision=adafruit_ble.__version__,
27+
manufacturer="Adafruit Industries")
28+
advertisement = ProvideServicesAdvertisement(hid)
29+
cc = ConsumerControl(hid.devices)
30+
31+
FILL_COLOR = (0, 32, 32)
32+
UNMUTED_COLOR = (0, 128, 128)
33+
MUTED_COLOR = (128, 0, 0)
34+
DISCONNECTED_COLOR = (40, 40, 0)
35+
36+
# NeoPixel LED ring
37+
# Ring code will auto-adjust if not 16 so change to any value!
38+
ring = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=0.05, auto_write = False)
39+
ring.fill(DISCONNECTED_COLOR)
40+
ring.show()
41+
dot_location = 0 # what dot is currently lit
42+
43+
# CPB button for Play/Pause
44+
button_A = digitalio.DigitalInOut(board.BUTTON_A)
45+
button_A.switch_to_input(pull=digitalio.Pull.DOWN)
46+
47+
button_a_pressed = False # for debounce state
48+
49+
# Encoder button is a digital input with pullup on A1
50+
# so button.value == False means pressed.
51+
button = digitalio.DigitalInOut(board.A1)
52+
button.pull = digitalio.Pull.UP
53+
54+
encoder = rotaryio.IncrementalEncoder(board.A2, board.A3)
55+
56+
last_pos = encoder.position
57+
muted = False
58+
command = None
59+
# Disconnect if already connected, so that we pair properly.
60+
if ble.connected:
61+
for connection in ble.connections:
62+
connection.disconnect()
63+
64+
65+
def draw():
66+
if not muted:
67+
ring.fill(FILL_COLOR)
68+
ring[dot_location] = UNMUTED_COLOR
69+
else:
70+
ring.fill(MUTED_COLOR)
71+
ring.show()
72+
73+
74+
advertising = False
75+
connection_made = False
76+
print("let's go!")
77+
while True:
78+
if not ble.connected:
79+
ring.fill(DISCONNECTED_COLOR)
80+
ring.show()
81+
connection_made = False
82+
if not advertising:
83+
ble.start_advertising(advertisement)
84+
advertising = True
85+
continue
86+
else:
87+
if connection_made:
88+
pass
89+
else:
90+
ring.fill(FILL_COLOR)
91+
ring.show()
92+
connection_made = True
93+
94+
advertising = False
95+
96+
pos = encoder.position
97+
delta = pos - last_pos
98+
last_pos = pos
99+
direction = 0
100+
101+
if delta > 0:
102+
command = ConsumerControlCode.VOLUME_INCREMENT
103+
direction = -1
104+
elif delta < 0:
105+
command = ConsumerControlCode.VOLUME_DECREMENT
106+
direction = 1
107+
108+
if direction:
109+
muted = False
110+
for _ in range(abs(delta)):
111+
cc.send(command)
112+
# spin neopixel LED around in the correct direction!
113+
dot_location = (dot_location + direction) % len(ring)
114+
draw()
115+
116+
if not button.value:
117+
if not muted:
118+
print("Muting")
119+
cc.send(ConsumerControlCode.MUTE)
120+
muted = True
121+
else:
122+
print("Unmuting")
123+
cc.send(ConsumerControlCode.MUTE)
124+
muted = False
125+
draw()
126+
while not button.value: # debounce
127+
time.sleep(0.1)
128+
129+
if button_A.value and not button_a_pressed: # button is pushed
130+
cc.send(ConsumerControlCode.PLAY_PAUSE)
131+
print("Play/Pause")
132+
button_a_pressed = True # state for debouncing
133+
time.sleep(0.05)
134+
135+
if not button_A.value and button_a_pressed:
136+
button_a_pressed = False
137+
time.sleep(0.05)

0 commit comments

Comments
 (0)