The client code requires the following libraries from the CircuitPython Bundle:
- adafruit_ble
- adafruit_bluefruit_connect
- adafruit_debouncer
- adafruit_fancyled
- neopixel
The latest version can be obtained from the Adafruit CircuitPython BLE repo.
Plug in one Feather nRF52840 to your computer via a known good USB data + power cable. The board should show up as a disk drive named CIRCUITPY. Use this guide to update CircuitPython - you will want the latest version 5.0 or above.
Copy the 5 libraries to the lib folder on the Feather.
Here's the client code for the BLE peripheral. Click the download link and save to your computer. Then copy the client.py file to code.py on the Feather.
# SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries # # SPDX-License-Identifier: MIT from time import sleep from adafruit_ble.uart_client import UARTClient from adafruit_ble.scanner import Scanner from adafruit_bluefruit_connect.packet import Packet from adafruit_bluefruit_connect.button_packet import ButtonPacket from adafruit_bluefruit_connect.color_packet import ColorPacket from neopixel import NeoPixel from board import NEOPIXEL, SWITCH from adafruit_debouncer import Debouncer from digitalio import DigitalInOut, Direction, Pull import adafruit_fancyled.adafruit_fancyled as fancy pin = DigitalInOut(SWITCH) # Set up built-in pushbutton switch pin.direction = Direction.INPUT pin.pull = Pull.UP switch = Debouncer(pin) pixels = NeoPixel(NEOPIXEL, 1) # Set up built-in NeoPixel AQUA = 0x00FFFF # (0, 255, 255) GREEN = 0x00FF00 # (0, 255, 0) ORANGE = 0xFF8000 # (255, 128, 0) RED = 0xFF0000 # (255, 0, 0) BLUE = 0x0000FF # (0, 0, 255) gradients = {'Off': [(0.0, RED), (0.75, ORANGE)], 'On': [(0.0, GREEN), (1.0, AQUA)]} palette = fancy.expand_gradient(gradients['Off'], 30) gamma_levels = (0.25, 0.3, 0.15) color_index = 1 fade_direction = 1 TARGET = 'a0:b4:c2:d0:e7:f2' # CHANGE TO YOUR BLE ADDRESS button_packet = ButtonPacket("1", True) # Transmits pressed button 1 scanner = Scanner() # BLE Scanner uart_client = UARTClient() # BLE Client while True: uart_addresses = [] pixels[0] = BLUE # Blue LED indicates disconnected status pixels.show() # Keep trying to find target UART peripheral while not uart_addresses: uart_addresses = uart_client.scan(scanner) for address in uart_addresses: if TARGET in str(address): uart_client.connect(address, 5) # Connect to target while uart_client.connected: # Connected switch.update() if switch.fell: # Check for button press try: uart_client.write(button_packet.to_bytes()) # Transmit press except OSError: pass # Check for LED status receipt if uart_client.in_waiting: packet = Packet.from_stream(uart_client) if isinstance(packet, ColorPacket): if fancy.CRGB(*packet.color).pack() == GREEN: # Color match # Green indicates on state palette = fancy.expand_gradient(gradients['On'], 30) else: # Otherwise red indicates off palette = fancy.expand_gradient(gradients['Off'], 30) # NeoPixel color fading routing color = fancy.palette_lookup(palette, color_index / 29) color = fancy.gamma_adjust(color, brightness=gamma_levels) c = color.pack() pixels[0] = c pixels.show() if color_index in (0, 28): fade_direction *= -1 # Change direction color_index += fade_direction sleep(0.02)
The program scans for BLE peripherals and connects once the target is located.
The user switch is debounced. Generally speaking, when a mechanical switch is pressed, it doesn’t just change from open to closed. The metal contacts oscillate for a few milliseconds. This can trick a microcontroller into reading multiple presses. The debouncer suppresses these erroneous readings. When the switch is pressed a button packet is sent to the server to activate the solenoid.
Next, the code monitors the UART buffer for color packets and uses FancyLED to generate smooth LED color fading for the corresponding color palette. The remote control fades green/aqua if the server is on. Otherwise, it fades red/orange.