code.py
  1  # SPDX-FileCopyrightText: 2020 Anne Barela for Adafruit Industries
  2  #
  3  # SPDX-License-Identifier: MIT
  4  
  5  """Bluetooth Key Tracker."""
  6  from adafruit_ble import BLERadio
  7  from adafruit_led_animation.animation import Pulse, Solid
  8  import adafruit_led_animation.color as color
  9  from analogio import AnalogIn
 10  from array import array
 11  from audiobusio import I2SOut
 12  from audiocore import RawSample, WaveFile
 13  from board import BATTERY, D5, D6, D9, NEOPIXEL, RX, TX
 14  from digitalio import DigitalInOut, Direction, Pull
 15  from math import pi, sin
 16  from neopixel import NeoPixel
 17  from time import sleep
 18  
 19  battery = AnalogIn(BATTERY)
 20  
 21  ble = BLERadio()
 22  hit_status = [color.RED, color.ORANGE, color.AMBER, color.GREEN]
 23  
 24  pixel = NeoPixel(NEOPIXEL, 1)
 25  pulse = Pulse(pixel,
 26                speed=0.01,
 27                color=color.PURPLE,  # Use CYAN for Male Key
 28                period=3,
 29                min_intensity=0.0,
 30                max_intensity=0.5)
 31  
 32  solid = Solid(pixel, color.GREEN)
 33  
 34  reed_switch = DigitalInOut(D5)
 35  reed_switch.direction = Direction.INPUT
 36  reed_switch.pull = Pull.UP
 37  
 38  amp_enable = DigitalInOut(D6)
 39  amp_enable.direction = Direction.OUTPUT
 40  amp_enable.value = False
 41  
 42  
 43  def play_tone():
 44      """Generate tone and transmit to I2S amp."""
 45      length = 4000 // 440
 46      sine_wave = array("H", [0] * length)
 47      for i in range(length):
 48          sine_wave[i] = int(sin(pi * 2 * i / 18) * (2 ** 15) + 2 ** 15)
 49  
 50      sample = RawSample(sine_wave, sample_rate=8000)
 51      i2s = I2SOut(TX, RX, D9)
 52      i2s.play(sample, loop=True)
 53      sleep(1)
 54      i2s.stop()
 55      sample.deinit()
 56      i2s.deinit()
 57  
 58  
 59  def play_message():
 60      """Play recorded WAV message and transmit to I2S amp."""
 61      with open("d1.wav", "rb") as file:
 62          wave = WaveFile(file)
 63          i2s = I2SOut(TX, RX, D9)
 64          i2s.play(wave)
 65          while i2s.playing:
 66              pass
 67          wave.deinit()
 68          i2s.deinit()
 69  
 70  
 71  boundary_violations = 0
 72  
 73  while True:
 74      if reed_switch.value:  # Not Docked
 75          hits = 0
 76          try:
 77              advertisements = ble.start_scan(timeout=3)
 78              for advertisement in advertisements:
 79                  addr = advertisement.address
 80                  if (advertisement.scan_response and
 81                     addr.type == addr.RANDOM_STATIC):
 82                      if advertisement.complete_name == '<Your 1st beacon name here>':
 83                          hits |= 0b001
 84                      elif advertisement.complete_name == '<Your 2nd beacon name here>':
 85                          hits |= 0b010
 86                      elif advertisement.complete_name == '<Your 3rd beacon name here>':
 87                          hits |= 0b100
 88          except Exception as e:
 89              print(repr(e))
 90          hit_count = len([ones for ones in bin(hits) if ones == '1'])
 91          solid.color = hit_status[hit_count]
 92          solid.animate()
 93          sleep(1)
 94          if hit_count == 0:
 95              if boundary_violations % 60 == 0:  # Play message every 60 cycles
 96                  amp_enable.value = True
 97                  sleep(1)
 98                  play_tone()
 99                  sleep(1)
100                  play_message()
101                  sleep(1)
102                  amp_enable.value = False
103              boundary_violations += 1
104          else:
105              boundary_violations = 0
106  
107      else:  # Docked
108          boundary_violations = 0
109          voltage = battery.value * 3.3 / 65535 * 2
110          if voltage < 3.7:
111              pulse.period = 1  # Speed up LED pulse for low battery
112          else:
113              pulse.period = 3
114          pulse.animate()