# SPDX-FileCopyrightText: 2023 Trevor Beaton for Adafruit Industries # # SPDX-License-Identifier: MIT import os import time import ssl import math import board import microcontroller import wifi import socketpool import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_io.adafruit_io import IO_MQTT from adafruit_adxl34x import ADXL345 from adafruit_lc709203f import LC709203F, PackSize aio_username = os.getenv('aio_username') aio_key = os.getenv('aio_key') # Wi-Fi try: print("Connecting to %s" % os.getenv('CIRCUITPY_WIFI_SSID')) wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) print("Connected to %s!" % os.getenv('CIRCUITPY_WIFI_SSID')) # Wi-Fi connectivity fails with error messages, not specific errors, so this except is broad. except Exception as e: # pylint: disable=broad-except print("Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset() # Create a socket pool pool = socketpool.SocketPool(wifi.radio) # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", username= aio_username, password= aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) # Initialize Adafruit IO MQTT "helper" io = IO_MQTT(mqtt_client) try: if not io.is_connected: # Connect the client to the MQTT broker. print("Connecting to Adafruit IO...") io.connect() print("Connected to Adafruit IO!") except Exception as e: # pylint: disable=broad-except print("Failed to get or send data, or connect. Error:", e, "\nBoard will hard reset in 30 seconds./n") time.sleep(30) microcontroller.reset() threshold = 20 # set threshold value here time_interval = 0.5 # set the time interval in seconds # create the I2C bus object i2c = board.STEMMA_I2C() # For ADXL345 accelerometer = ADXL345(i2c) # To monitor the battery battery_monitor = LC709203F(i2c) battery_monitor.pack_size = PackSize.MAH400 t0 = time.monotonic() while True: x, y, z = accelerometer.acceleration t1 = time.monotonic() dt = t1 - t0 total_acceleration = math.sqrt(x**2 + y**2 + z**2) if total_acceleration >= threshold: print("Battery Percent: {:.2f} %".format(battery_monitor.cell_percent)) print("Collision strength: %.2f" % total_acceleration) io.publish("punch-strength", total_acceleration) # add code here to trigger an event or alert the user t0 = t1 time.sleep(time_interval)
This code is doing several things:
- Connecting to the internet
- Connecting to Adafruit IO
- Gathering accelerometer data and battery percentage data
- Displaying accelerometer and battery data on the TFT
- Sending accelerometer data to a feed in Adafruit IO
Acquiring WiFi credentials
These few lines of code extract the values for the Adafruit IO username and Adafruit IO API key from the settings.toml file mentioned here.
The values for aio_username
and aio_key
are in the settings.toml file.
aio_username = os.getenv('aio_username') aio_key = os.getenv('aio_key')
Connecting to WiFi
This code block connects to a WiFi network using the wifi.radio.connect
function and passes in the network’s SSID and password as arguments. The values of the SSID and password are read from environment variables CIRCUITPY_WIFI_SSID
and CIRCUITPY_WIFI_PASSWORD
.
# Wi-Fi try: print("Connecting to %s" % os.getenv('CIRCUITPY_WIFI_SSID')) wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) print("Connected to %s!" % os.getenv('CIRCUITPY_WIFI_SSID')) # Wi-Fi connectivity fails with error messages, not specific errors, so this except is broad. except Exception as e: # pylint: disable=broad-except print("Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset()
Creating a Socket Pool
Next, the code initializes a socket pool and an MQTT client for communicating with the Adafruit IO cloud service.
The socketpool.SocketPool
function creates a pool of sockets for management of network connections. It takes the wifi.radio
object as an argument to allow for network communication over the WiFi connection.
pool = socketpool.SocketPool(wifi.radio)
Initializing a MQTT Client
The MQTT.MQTT
function is then used to initialize a new MQTT client object, which will be used to send and receive messages with the Adafruit IO cloud service. This function takes several arguments:
-
broker
: the hostname of the MQTT broker (Adafruit IO in this case). -
username
andpassword
: the credentials for authenticating with the Adafruit IO service are stored in the settings.toml file. -
socket_pool
: the socket pool created in the previous step. -
ssl_context
: an SSL context created using thecreate_default_context
method from thessl
module. This provides secure communication between the device and the Adafruit IO service.
Finally, the IO_MQTT
function is used to initialize an "Adafruit IO MQTT helper", a convenient wrapper around the MQTT client that provides a simple API for working with Adafruit IO.
mqtt_client = MQTT.MQTT( broker="io.adafruit.com", username= aio_username, password= aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) # Initialize Adafruit IO MQTT "helper" io = IO_MQTT(mqtt_client)
Connecting to Adafruit IO
Now to check the connection status of Adafruit IO, and if it is not connected, it is trying to connect to the MQTT broker using the io.connect()
method.
If the connection to Adafruit IO fails, an error message is printed, and the board will hard reset after 30 seconds.
The except
block is broad to catch all exceptions and the broad-except
.
try: # If Adafruit IO is not connected... if not io.is_connected: # Connect the client to the MQTT broker. print("Connecting to Adafruit IO...") io.connect() print("Connected to Adafruit IO!") except Exception as e: # pylint: disable=broad-except print("Failed to get or send data, or connect. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset()
Adding a threshold
These lines of code set two variables, threshold
and time_interval
.
threshold
is set to 20; this value filters out movement that might trigger punch detection.
time_interval
is set to 0.5, which is the time interval in seconds; I added this to limit the amount of data points created. You can change this to cater to your Adafruit IO plan.
threshold = 20 # set threshold value here time_interval = 0.5 # set the time interval in seconds
Accessing the Accelerometer
Now to create an I2C bus object using the board.STEMMA_I2C()
method, and then create an instance of an ADXL345 accelerometer using that I2C bus object.
The ADXL345
class is imported from an external library and represents an ADXL345 3-axis accelerometer, which can measure acceleration along the X, Y, and Z axes.
The accelerometer is being initialized using the I2C bus object so that the accelerometer can communicate with the microcontroller board over the I2C bus.
# create the I2C bus object i2c = board.STEMMA_I2C() # For ADXL345 accelerometer = ADXL345(i2c)
Accessing the built-in battery monitor
Next to create an instance of the LC709203F class named battery_monitor
and set the pack_size
attribute of the battery_monitor
object to PackSize.MAH400
.
The pack_size
attribute is used to set the capacity of the battery being monitored by the LC709203F. In this case, PackSize.MAH400
is used to specify a battery capacity of 400 milliampere-hours (mAh).
battery_monitor = LC709203F(i2c) battery_monitor.pack_size = PackSize.MAH400
Setting the Current Time
This line t0 = time.monotonic()
sets the variable t0
to the current time as returned by the monotonic
method of the time
module. The monotonic
method returns the number of seconds that have passed since an unspecified time in the past, guaranteed never to go back even if the system time is changed.
t0 = time.monotonic()
Storing Acceleration Data
These few lines use a while
loop to read the x
, y
, and z
components of the accelerometer’s acceleration and then store the variables.
while True: x, y, z = accelerometer.acceleration t1 = time.monotonic() dt = t1 - t0 total_acceleration = math.sqrt(x**2 + y**2 + z**2)
The sleep interval between two acceleration readings is determined by the time_interval
variable. The code runs in a continuous loop until manually stopped.
if total_acceleration >= threshold: print("Battery Percent: {:.2f} %".format(battery_monitor.cell_percent)) print("Collision strength: %.2f" % total_acceleration) io.publish("punch-strength", total_acceleration) # add code here to trigger an event or alert the user t0 = t1 time.sleep(time_interval)
Displaying Collision Strength Data in Adafruit IO
In this if
-statement, if the total acceleration is greater than or equal to the threshold, the battery percent and total acceleration will be displayed on the TFT, and the total acceleration value will be published to a feed named "punch-strength" in Adafruit IO.
Great! Let's attach components to the glove!
Text editor powered by tinymce.