Adding Libraries

Installing Project Code

To use with CircuitPython, you need to first install a few libraries, into the lib folder on your CIRCUITPY drive. Then you need to update code.py with the example script.

Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, open the directory BLE_Buzzy_Box/ and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your CIRCUITPY drive.

Your CIRCUITPY drive should now look similar to the following image:

CIRCUITPY
# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import time
import board
import busio
import neopixel
import adafruit_drv2605
import adafruit_ble
from adafruit_ble.advertising.standard import SolicitServicesAdvertisement
from adafruit_ble.services.standard import CurrentTimeService
from adafruit_ble_apple_notification_center import AppleNotificationCenterService
from digitalio import DigitalInOut, Direction

#  setup for onboard NeoPixel
pixel_pin = board.NEOPIXEL
num_pixels = 1

pixel = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False)

#  setup for haptic motor driver
i2c = busio.I2C(board.SCL, board.SDA)
drv = adafruit_drv2605.DRV2605(i2c)

#  onboard blue LED
blue_led = DigitalInOut(board.BLUE_LED)
blue_led.direction = Direction.OUTPUT

#  setup for BLE
ble = adafruit_ble.BLERadio()
if ble.connected:
    for c in ble.connections:
        c.disconnect()

advertisement = SolicitServicesAdvertisement()

#  adds ANCS and current time services for BLE to advertise
advertisement.solicited_services.append(AppleNotificationCenterService)
advertisement.solicited_services.append(CurrentTimeService)

#  state machines
current_notification = None #  tracks the current notification from ANCS
current_notifications = {} #  array to hold all current notifications from ANCS
cleared = False #  state to track if notifications have been cleared from ANCS
notification_service = None #  holds the array of active notifications from ANCS
all_ids = [] #  array to hold all of the ids from ANCS
hour = 0 #  used to track when it is on the hour for the mindfulness reminder
mindful = False #  state used to track if it is time for mindfulness
vibration = 16 #  vibration effect being used for the haptic motor
blue = (0, 0, 255) #  color blue for the NeoPixel
purple = (255, 0, 255) #  color purple for the NeoPixel
red = (255, 0, 0) #  color red for the NeoPixel
clear = (0, 0, 0) #  allows for NeoPixel to be turned 'off'

#  function for blinking NeoPixel
#  blinks: # of blinks
#  speed: how fast/slow blinks
#  color1: first color
#  color2: second color
def blink_pixel(blinks, speed, color1, color2):
    for _ in range(0, blinks):
        pixel.fill(color1)
        pixel.show()
        time.sleep(speed)
        pixel.fill(color2)
        pixel.show()
        time.sleep(speed)

#  function for haptic motor vibration
#  num_zzz: # of times vibrates
#  effect: type of vibration
#  delay: time between vibrations
def vibe(num_zzz, effect, delay):
    drv.sequence[0] = adafruit_drv2605.Effect(effect)
    for _ in range(0, num_zzz):
        drv.play()  # play the effect
        time.sleep(delay)  # for 0.5 seconds
        drv.stop()

#  start BLE
ble.start_advertising(advertisement)

while True:

    blue_led.value = False
    print("Waiting for connection")

    #  NeoPixel is red when not connected to BLE
    while not ble.connected:
        blue_led.value = False
        pixel.fill(red)
        pixel.show()

    print("Connected")

    while ble.connected:
        blue_led.value = True #  blue LED is on when connected
        all_ids.clear()
        for connection in ble.connections:
            if not connection.paired:
                #  pairs to phone
                connection.pair()
                print("paired")
            #  allows connection to CurrentTimeService
            cts = connection[CurrentTimeService]
            notification_service = connection[AppleNotificationCenterService]
        #  grabs notifications from ANCS
        current_notifications = notification_service.active_notifications

        for notif_id in current_notifications:
            #  adds notifications into array
            notification = current_notifications[notif_id]
            all_ids.append(notif_id)

        if current_notification and current_notification.removed:
            # Stop showing the latest and show that there are no new notifications.
            current_notification = None
            pixel.fill(clear)
            pixel.show()

        if not current_notification and not all_ids and not cleared:
            #  updates cleared state for notification
            cleared = True
            #  turns off NeoPixel when notifications are clear
            pixel.fill(clear)
            pixel.show()

        elif all_ids:
            cleared = False
            if current_notification and current_notification.id in all_ids:
                index = all_ids.index(current_notification.id)
            else:
                index = len(all_ids) - 1
                notif_id = all_ids[index]
            #  if there is a notification:
            if not current_notification or current_notification.id != notif_id:
                current_notification = current_notifications[notif_id]
                #  parses notification info into a string
                category = str(notification).split(" ", 1)[0]
                #  haptic motor vibrates
                vibe(2, vibration, 0.5)
                #  all info for notification is printed to REPL
                print('-'*36)
                print("Msg #%d - Category %s" % (notification.id, category))
                print("From app:", notification.app_id)
                if notification.title:
                    print("Title:", notification.title)
                if notification.subtitle:
                    print("Subtitle:", notification.subtitle)
                if notification.message:
                    print("Message:", notification.message)
                #  NeoPixel blinks and then stays on until cleared
                blink_pixel(2, 0.5, purple, clear)
                pixel.fill(purple)
                pixel.show()
        #  if it's on the hour:
        if cts.current_time[4] == hour and not mindful:
            print(cts.current_time[4])
            print("mindful time")
            #  haptic motor vibrates
            vibe(5, vibration, 1)
            #  NeoPixel blinks and then stays on
            blink_pixel(5, 1, blue, clear)
            mindful = True
            pixel.fill(blue)
            pixel.show()
            print("hour = ", hour)
        #  if it's no longer on the hour:
        if cts.current_time[4] == (hour + 1) and mindful:
            #  NeoPixel turns off
            mindful = False
            pixel.fill(clear)
            pixel.show()
            print("mindful time over")

    #  if BLE becomes disconnected then blue LED turns off
    #  and BLE begins advertising again to reconnect
    print("Disconnected")
    blue_led.value = False
    print()
    ble.start_advertising(advertisement)
    notification_service = None

This guide was first published on May 13, 2020. It was last updated on May 13, 2020.

This page (Coding the Buzzy Box) was last updated on Sep 25, 2023.

Text editor powered by tinymce.