Skip to content

Circuit Playground Bluefruit NeoPixel Controller #957

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions Circuit_Playground_Bluefruiit_NeoPixel_Controller/Controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""
Control code for Circuit Playground Bluefruit NeoPixel Animation and Color controller. To be used
with another Circuit Playground Bluefruit running the receiver code.
"""

import time

from adafruit_circuitplayground.bluefruit import cpb

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
from adafruit_bluefruit_connect.color_packet import ColorPacket
from adafruit_bluefruit_connect.button_packet import ButtonPacket


def scale(value):
"""Scale a value from acceleration value range to 0-255 (RGB range)"""
value = abs(value)
value = max(min(19.6, value), 0)
return int(value / 19.6 * 255)


def send_packet(uart_connection_name, packet):
"""Returns False if no longer connected."""
try:
uart_connection_name[UARTService].write(packet.to_bytes())
except: # pylint: disable=bare-except
try:
uart_connection_name.disconnect()
except: # pylint: disable=bare-except
pass
return False
return True


ble = BLERadio()

# Setup for preventing repeated button presses and tracking switch state
button_a_pressed = False
button_b_pressed = False
last_switch_state = None

uart_connection = None
# See if any existing connections are providing UARTService.
if ble.connected:
for connection in ble.connections:
if UARTService in connection:
uart_connection = connection
break

while True:
last_switch_state = None
if not uart_connection or not uart_connection.connected: # If not connected...
print("Scanning...")
for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=5): # Scan...
if UARTService in adv.services: # If UARTService found...
print("Found a UARTService advertisement.")
uart_connection = ble.connect(adv) # Create a UART connection...
break
# Stop scanning whether or not we are connected.
ble.stop_scan() # And stop scanning.
while uart_connection and uart_connection.connected: # If connected...
if cpb.button_a and not button_a_pressed: # If button A pressed...
print("Button A pressed.")
# Send a LEFT button packet.
if not send_packet(uart_connection,
ButtonPacket(ButtonPacket.LEFT, pressed=True)):
uart_connection = None
continue
button_a_pressed = True # Set to True.
time.sleep(0.05) # Debounce.
if not cpb.button_a and button_a_pressed: # On button release...
button_a_pressed = False # Set to False.
time.sleep(0.05) # Debounce.
if cpb.button_b and not button_b_pressed: # If button B pressed...
print("Button B pressed.")
# Send a RIGHT button packet.
if not send_packet(uart_connection,
ButtonPacket(ButtonPacket.RIGHT, pressed=True)):
uart_connection = None
continue
button_b_pressed = True # Set to True.
time.sleep(0.05) # Debounce.
if not cpb.button_b and button_b_pressed: # On button release...
button_b_pressed = False # Set to False.
time.sleep(0.05) # Debounce.
if cpb.switch is not last_switch_state: # If the switch state is changed...
last_switch_state = cpb.switch # Set state to current switch state.
print("Switch is to the", "left: LEDs off!" if cpb.switch else "right: LEDs on!")
# Send a BUTTON_1 button packet.
if not send_packet(uart_connection,
ButtonPacket(ButtonPacket.BUTTON_1, pressed=cpb.switch)):
uart_connection = None
continue
if cpb.switch: # If switch is to the left...
cpb.pixels.fill((0, 0, 0)) # Turn off the LEDs.
else: # Otherwise...
r, g, b = map(scale, cpb.acceleration) # Map acceleration values to RGB values...
color = (r, g, b) # Set color to current mapped RGB value...
print("Color:", color)
cpb.pixels.fill(color) # Fill controller LEDs with current color...
if not send_packet(uart_connection, ColorPacket(color)): # And send a color packet.
uart_connection = None
continue
time.sleep(0.1) # Delay to prevent sending packets too quickly.
114 changes: 114 additions & 0 deletions Circuit_Playground_Bluefruiit_NeoPixel_Controller/Receiver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""
Receiver code for Circuit Playground Bluefruit NeoPixel Animation and Color controller. To be used
with another Circuit Playground Bluefruit running the controller code.
"""

import board
import neopixel
from adafruit_circuitplayground.bluefruit import cpb
from adafruit_led_animation.animation import Blink, Comet, Sparkle, AnimationGroup,\
AnimationSequence
import adafruit_led_animation.color as color

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

from adafruit_bluefruit_connect.packet import Packet
from adafruit_bluefruit_connect.color_packet import ColorPacket
from adafruit_bluefruit_connect.button_packet import ButtonPacket

# The number of NeoPixels in the externally attached strip
# If using two strips connected to the same pin, count only one strip for this number!
STRIP_PIXEL_NUMBER = 30

# Setup for blink animation
BLINK_SPEED = 0.5 # Lower numbers increase the animation speed
BLINK_INITIAL_COLOR = color.RED # Color before controller is connected

# Setup for comet animation
COMET_SPEED = 0.03 # Lower numbers increase the animation speed
COMET_INITIAL_COLOR = color.MAGENTA # Color before controller is connected
CPB_COMET_TAIL_LENGTH = 5 # The length of the comet on the Circuit Playground Bluefruit
STRIP_COMET_TAIL_LENGTH = 15 # The length of the comet on the NeoPixel strip
CPB_COMET_BOUNCE = False # Set to True to make the comet "bounce" the opposite direction on CPB
STRIP_COMET_BOUNCE = True # Set to False to stop comet from "bouncing" on NeoPixel strip

# Setup for sparkle animation
SPARKLE_SPEED = 0.03 # Lower numbers increase the animation speed
SPARKLE_INITIAL_COLOR = color.PURPLE # Color before controller is connected

# Create the NeoPixel strip
strip_pixels = neopixel.NeoPixel(board.A1, STRIP_PIXEL_NUMBER, auto_write=False)

# Setup BLE connection
ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)

# Setup animations
animations = AnimationSequence(
AnimationGroup(
Blink(cpb.pixels, BLINK_SPEED, BLINK_INITIAL_COLOR),
Blink(strip_pixels, BLINK_SPEED, BLINK_INITIAL_COLOR),
sync=True
),
AnimationGroup(
Comet(cpb.pixels, COMET_SPEED, COMET_INITIAL_COLOR, tail_length=CPB_COMET_TAIL_LENGTH,
bounce=CPB_COMET_BOUNCE),
Comet(strip_pixels, COMET_SPEED, COMET_INITIAL_COLOR, tail_length=STRIP_COMET_TAIL_LENGTH,
bounce=STRIP_COMET_BOUNCE)
),
AnimationGroup(
Sparkle(cpb.pixels, SPARKLE_SPEED, SPARKLE_INITIAL_COLOR),
Sparkle(strip_pixels, SPARKLE_SPEED, SPARKLE_INITIAL_COLOR)
),
)

animation_color = None
mode = 0
blanked = False

while True:
ble.start_advertising(advertisement) # Start advertising.
was_connected = False
while not was_connected or ble.connected:
if not blanked: # If LED-off signal is not being sent...
animations.animate() # Run the animations.
if ble.connected: # If BLE is connected...
was_connected = True
if uart.in_waiting: # Check to see if any data is available from the controller.
try:
packet = Packet.from_stream(uart) # Create the packet object.
except ValueError:
continue
if isinstance(packet, ColorPacket): # If the packet is color packet...
if mode == 0: # And mode is 0...
animations.color = packet.color # Update the animation to the color.
print("Color:", packet.color)
animation_color = packet.color # Keep track of the current color...
elif mode == 1: # Because if mode is 1...
animations.color = animation_color # Freeze the animation color.
print("Color:", animation_color)
elif isinstance(packet, ButtonPacket): # If the packet is a button packet...
# Check to see if it's BUTTON_1 (which is being sent by the slide switch)
if packet.button == ButtonPacket.BUTTON_1:
if packet.pressed: # If controller switch is to the left...
print("Controller switch is to the left: LEDs off!")
else: # If the controller switch is to the right...
print("Controller switch is to the right: LEDs on!")
# If the controller switch is moved from right to left...
if packet.pressed and not blanked:
animations.fill(color.BLACK) # Turn off the LEDs.
blanked = packet.pressed # Track the state of the slide switch.
if packet.pressed: # If the buttons on the controller are pressed...
if packet.button == ButtonPacket.LEFT: # If button A is pressed...
print("A pressed: animation mode changed.")
animations.next() # Change to the next animation.
elif packet.button == ButtonPacket.RIGHT: # If button B is pressed...
mode += 1 # Increase the mode by 1.
if mode == 1: # If mode is 1, print the following:
print("B pressed: color frozen!")
if mode > 1: # If mode is > 1...
mode = 0 # Set mode to 0, and print the following:
print("B pressed: color changing!")