Maker.io main logo

PyLeap CLUE Barometer

2024-03-01 | By Adafruit Industries

License: See Original Project Bluetooth / BLE Displays

Courtesy of Adafruit

Guide by Liz Clark

Overview

In this project, you'll utilize the CLUE's onboard BMP280 sensor to ‎measure ambient temperature and air pressure. The PyLeap app will ‎wirelessly load the project onto your CLUE over BLE.‎

 

The CLUE display will show the temperature and air pressure readings ‎in either metric (Celsius and hectopascals) or imperial (Fahrenheit and ‎inches of mercury) units. The code takes into account the air pressure ‎reading and your nominal baseline pressure to adjust the servo's angle ‎to point to a weather condition.‎

display_1

Barometric Pressure and Weather

Barometric pressure, or air pressure, is the measure of the pressure ‎resulting from air pressing down on the Earth due to gravity. Since this ‎pressure varies with altitude, different locations on Earth will have ‎different nominal pressure values. However, weather can also affect ‎this pressure. Taking both of these pieces of information into ‎account, a barometer can be used to display weather conditions, ‎depending on if you have a higher or lower than nominal pressure ‎reading for your location.‎

forecast_2

https://commons.wikimedia.org/wiki/File:Day5pressureforecast.png

Parts

Connect the Servo to the CLUE

connect_3

To wire up the servo motor to the CLUE, you'll clip the servo's alligator ‎clips to the CLUE's pads located at the bottom of the board. The ‎alligator clips are color coded so that you can tell which connection ‎goes where.‎

Wiring Diagram

diagram_4

  • Servo Data to CLUE pad 0 (white wire)
  • Servo Power to CLUE 3V pad (red wire)
  • Servo Ground to CLUE GND pad (black wire)

Assembly

First, make sure that your CLUE is disconnected from power. Then, clip ‎the servo's red alligator clip to the CLUE's 3V pad. This is the ‎power input for the servo.‎

assembly_5

Next, clip the servo's black alligator clip to the CLUE's GND pad. ‎This is the ground connection for the servo.‎

assembly_6

Finally, clip the servo's white alligator clip to the CLUE's pad 0. ‎This is the data pin for the servo.

assembly_7

CircuitPython on CLUE

CircuitPython is a derivative of MicroPython designed to simplify ‎experimentation and education on low-cost microcontrollers. It makes ‎it easier than ever to get prototyping by requiring no upfront desktop ‎software downloads. Simply copy and edit files on the CIRCUITPY flash ‎drive to iterate.‎

The following instructions will show you how to install CircuitPython. If ‎you've already installed CircuitPython but are looking to update it or ‎reinstall it, the same steps work for that as well!‎

Set up CircuitPython Quick Start!‎

Follow this quick step-by-step for super-fast Python power :)‎

Download the latest version of CircuitPython for CLUE from ‎circuitpython.org

Click the link above to download the latest version of ‎CircuitPython for the CLUE.‎

Download and save it to your desktop (or wherever is handy).‎

download_8

Plug your CLUE into your computer using a known-good USB cable.‎

A lot of people end up using charge-only USB cables and it is ‎very frustrating! So, make sure you have a USB cable you know ‎is good for data sync.‎

Double-click the Reset button on the top (magenta arrow) on your ‎board, and you will see the NeoPixel RGB LED (green arrow) turn green. ‎If it turns red, check the USB cable, try another USB port, ‎etc. Note: The little red LED next to the USB connector will pulse red. ‎That's ok!‎

If double-clicking doesn't work the first time, try again. Sometimes it ‎can take a few tries to get the rhythm right!‎

board_9

You will see a new disk drive appear called CLUEBOOT.‎

Drag the adafruit-circuitpython-clue-etc.uf2 file to CLUEBOOT.‎

drive_10

drive_11

The LED will flash. Then, the CLUEBOOT drive will disappear, and a ‎new disk drive called CIRCUITPY will appear.‎

If this is the first time, you're installing CircuitPython or you're doing a ‎completely fresh install after erasing the filesystem, you will have two ‎files - boot_out.txt, and code.py, and one folder - lib on ‎your CIRCUITPY drive.‎

If CircuitPython was already installed, the files present before reloading ‎CircuitPython should still be present on your CIRCUITPY drive. Loading ‎CircuitPython will not create new files if there was already a ‎CircuitPython filesystem present.‎

That's it, you're done! :)

drive_12

Pairing

Now that you're done uploading the correct firmware, disconnect your ‎device from your computer and power it via LiPoly or AAA battery pack.‎

Pairing device to PyLeap

Once powered, press the small Reset button in the center of the board ‎‎(Circuit Playground Bluefruit) or on the top right of the board (CLUE). ‎When the blue light flashes, press the Reset button again.

circuit_playground_ezgif22

Circuit Playground Bluefruit with a small Reset button in the center of the board

button_13

Adafruit CLUE Reset Button (Highlighted on the upper right)‎

When done correctly, the LEDs will flash yellow followed by solid blue. ‎Once this occurs, the board will continuously be in discovery mode.‎

Scan & Connect

When your Circuit Playground Bluefruit or Adafruit CLUE is in ‎discovery mode, hold it very closely to your iPhone or iPadOS to pair.

circuitpython_ezgifcom-gif-maker-3

Below the spinning Blinka, you'll notice a status indicator that will let ‎you know your current pairing status.‎

Once you've found your device and received the Bluetooth Pairing ‎Request message, press Pair to pair your board to your iPhone or ‎iPadOS.‎

pyleap_14

If your Circuit Playground Bluefruit doesn't ‎appear:‎

  1. Check to see if your Circuit Playground Bluefruit is powered on. ‎Verify that the green On light is lit.‎‎
  2. Make sure your Circuit Playground Bluefruit is running the ‎correct firmware. See the CircuitPython page in this guide.
  3. Try resetting the Circuit Playground Bluefruit by pressing the ‎small Reset button near the center of the board.‎

PyLeap CLUE Barometer Code

fairdisplay_15

Download Project Bundle

Copy Code
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT

import time
import board
import simpleio
import adafruit_bmp280
import pwmio
import displayio
from adafruit_motor import servo
import terminalio
from adafruit_clue import clue
from adafruit_display_text import label

# pwm setup for servo
pwm = pwmio.PWMOut(board.D0, duty_cycle=2 ** 15, frequency=50)
gauge = servo.Servo(pwm)

# bmp280 sensor setup
i2c = board.I2C() # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c)

# change depending on your location's elevation
NOMINAL_PRESSURE = 1005.94

PRESSURE_RANGE = 40 # hPa, expected pressure range variance caused by local weather
PRESSURE_LOW_LIM = NOMINAL_PRESSURE - PRESSURE_RANGE
PRESSURE_HIGH_LIM = NOMINAL_PRESSURE + PRESSURE_RANGE

# board display
# scaling for terminalio font
display = board.DISPLAY
group = displayio.Group(scale=3)

# text elements
temp_header = "Temperature:"
press_header = "Pressure:"
temp_text = " ºC"
press_text = " hPa"
font = terminalio.FONT
blue = 0x0000FF
red = 0xFF0000

# temperature text elements
temp_label = label.Label(font, text=temp_header, color=red, x=5, y=10)
temp_data = label.Label(font, text=temp_text, color=red, x=5, y=25)

# pressure text elements
press_label = label.Label(font, text=press_header, color=blue, x=5, y=50)
press_data = label.Label(font, text=press_text, color=blue, x=5, y=65)

# adding text to display group
group.append(temp_label)
group.append(press_label)
group.append(temp_data)
group.append(press_data)

display.root_group = group

# function to convert celcius to fahrenheit
def c_to_f(temp):
temp_f = (temp * 9/5) + 32
return temp_f

# function to convert hPa to inHg
def hpa_to_inHg(hPa):
inches_mercury = hPa * 0.02953
return inches_mercury

# time.monotonic clock
clock = 0
# units state
metric_units = False

while True:
# non-blocking 2 second delay
if (clock + 2) < time.monotonic():
# map servo range to barometric pressure range
servo_value = simpleio.map_range(bmp280.pressure,
PRESSURE_LOW_LIM, PRESSURE_HIGH_LIM, 180, 0)
# set servo to pressure
gauge.angle = servo_value
# print data for debugging
print("\nTemperature: %0.1f C" % bmp280.temperature)
print("Pressure: %0.1f hPa" % bmp280.pressure)
print(servo_value)
# if metric units...
if metric_units:
# update temp & pressure text in celcius and hPa
temp_data.text = "%0.1f ºC" % bmp280.temperature
press_data.text = "%0.1f hPa" % bmp280.pressure
# if imperial units...
else:
# convert celcius to fahrenheit
temp_fahrenheit = c_to_f(bmp280.temperature)
# convert hPa to inHg
pressure_inHg = hpa_to_inHg(bmp280.pressure)
# update temp & pressure text
temp_data.text = "%0.1f ºF" % temp_fahrenheit
press_data.text = "%0.1f inHg" % pressure_inHg
# reset time.monotonic() clock
clock = time.monotonic()
# if a button is pressed, metric_units is True, show metric
if clue.button_a:
metric_units = True
# if b button is pressed, metric_units is False, show imperial units
if clue.button_b:
metric_units = False

View on GitHub

How the CircuitPython Code Works

The code begins by creating a displayio group and some text elements ‎to show on the CLUE display. ‎

Download File

Copy Code
#  board display
# scaling for terminalio font
display = board.DISPLAY
group = displayio.Group(scale=3)

# text elements
temp_header = "Temperature:"
press_header = "Pressure:"
temp_text = " ºC"
press_text = " hPa"
font = terminalio.FONT
blue = 0x0000FF
red = 0xFF0000

PWM and I2C

Then, the servo object is created with PWM and the BMP280 sensor is ‎instantiated over I2C.‎

Download File

Copy Code
#  pwm setup for servo
pwm = pwmio.PWMOut(board.D0, duty_cycle=2 ** 15, frequency=50)
gauge = servo.Servo(pwm)

# bmp280 sensor setup
i2c = board.I2C() # uses board.SCL and board.SDA
bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c)

Nominal Baseline Pressure

The deviation from the nominal baseline pressure is used to show your ‎current weather conditions with the servo. ‎The NOMINAL_PRESSURE value must be set for your location (covered later in ‎guide on the Usage page). The PRESSURE_RANGE value can be adjusted as ‎needed for typical local weather driven deviations. A lower value will ‎make the detection more sensitive.‎

Download File

Copy Code
#  change depending on your location's elevation
NOMINAL_PRESSURE = 1005.94

PRESSURE_RANGE = 40 # hPa, expected pressure range variance caused by local weather
PRESSURE_LOW_LIM = NOMINAL_PRESSURE - PRESSURE_RANGE
PRESSURE_HIGH_LIM = NOMINAL_PRESSURE + PRESSURE_RANGE

Text Labels

There are four text labels that are shown on the ‎display. temp_label and press_label are headers with the ‎text "Temperature:" and "Pressure:". temp_data and press_data are updated in the ‎loop to show the readings from the BMP280 sensor.‎

Download File

Copy Code
#  temperature text elements
temp_label = label.Label(font, text=temp_header, color=red, x=5, y=10)
temp_data = label.Label(font, text=temp_text, color=red, x=5, y=25)

# pressure text elements
press_label = label.Label(font, text=press_header, color=blue, x=5, y=50)
press_data = label.Label(font, text=press_text, color=blue, x=5, y=65)

# adding text to display group
group.append(temp_label)
group.append(press_label)
group.append(temp_data)
group.append(press_data)

display.root_group = group

Unit Conversion Functions

There are two functions to convert metric units to imperial ‎units. c_to_f() converts Celsius to Fahrenheit by passing the temperature ‎in Celsius and returning the temperature in Fahrenheit.‎

hpa_to_inHg() converts hectopascals to inches of mercury by passing the ‎barometric pressure in hectopascals and returning the pressure reading ‎in inches of mercury.‎

Two variables are declared before the loop. clock is ‎a time.monotonic() device and metric_units is used to determine which units ‎are being shown on the display and is affected by the CLUE buttons.‎

Download File

Copy Code
#  function to convert celcius to fahrenheit
def c_to_f(temp):
temp_f = (temp * 9/5) + 32
return temp_f

# function to convert hPa to inHg
def hpa_to_inHg(hPa):
inches_mercury = hPa * 0.02953
return inches_mercury

# time.monotonic clock
clock = time.monotonic()
# units state
metric_units = True

The Loop

In the loop, the BMP280 pressure reading is mapped from the ‎calculated pressure range with your nominal baseline pressure to the ‎value range of the servo motor angle. The servo motor angle is then ‎set to that mapped value.‎

Download File

Copy Code
#  non-blocking 2 second delay
if (clock + 2) < time.monotonic():
# map servo range to barometric pressure range
servo_value = simpleio.map_range(bmp280.pressure,
PRESSURE_LOW_LIM, PRESSURE_HIGH_LIM, 180, 0)
# set servo to pressure
gauge.angle = servo_value

Displaying Data

If metric_units is True, then the temperature and air pressure readings are ‎displayed on the CLUE in Celsius and hPa.‎

Download File

Copy Code
#  if metric units...
if metric_units:
# update temp & pressure text in celcius and hPa
temp_data.text = "%0.1f ºC" % bmp280.temperature
press_data.text = "%0.1f hPa" % bmp280.pressure

If metric_units is False, the readings from the BMP280 are converted to ‎imperial units with the two conversion functions and are shown on the ‎display in Fahrenheit and inHg.‎

Download File

Copy Code
#  if imperial units...
else:
# convert celcius to fahrenheit
temp_fahrenheit = c_to_f(bmp280.temperature)
# convert hPa to inHg
pressure_inHg = hpa_to_inHg(bmp280.pressure)
# update temp & pressure text
temp_data.text = "%0.1f ºF" % temp_fahrenheit
press_data.text = "%0.1f inHg" % pressure_inHg

The CLUE Buttons

If CLUE button A is pressed, then the BMP280 readings are displayed in ‎metric units. If the CLUE button B is pressed, then the BMP280 ‎readings are displayed in imperial units.‎

Download File

Copy Code
#  if a button is pressed, metric_units is True, show metric
if clue.button_a:
metric_units = True
# if b button is pressed, metric_units is False, show imperial units
if clue.button_b:
metric_units = False

File Glider App Set Up

glider_16

What is File Glider?‎

From the description in the App store, File Glider allows you to:‎

Wirelessly transfer files to and from file transfer-ready Bluetooth Low ‎Energy (BLE) firmware. You can browse and edit files from within File ‎Glider or use the Files app integration to access the files from other ‎apps. Multiple devices can be managed at once and access can be ‎shared amongst multiple apps.‎

Basically, this app allows you to transfer files from your iOS device to ‎your CPB wirelessly with a couple of taps. It also lets you add and edit ‎code on the CPB directly from the App, how neat!‎

Step 1: Download the File Glider App from ‎the App Store.‎

Using your iOS device, download the File Glider App.‎

You must have an iOS device in order to download this app. We are ‎currently rewriting our BLE Android library to provide File Glider and ‎PyLeap to Android users, but this will not be ready until later.‎

Step 2: Connect your BLE board to your iOS ‎device through the app.‎

Open the File Glider App after it finishes downloading and make sure ‎your board is connected to your computer.‎

led_pixels_click_gif

  • Click the reset button on the board.‎
  • You will see the board NeoPixels flash through a series of colors, ‎first red, then yellow then blue.‎
  • When the blue appears, click the reset button again.
  • The NeoPixels will then flash through another series of colors ‎then turn blue momentarily before turning off again.‎

search_17

  • The app should then state "Status: connected..." ‎
  • Then a Bluetooth Pairing Request will pop up, select "Pair".
  • The board is now connected to the File Glider App!‎

app_18

app_19

info_20

Troubleshooting

Problem: You try to connect your board but then you see the following ‎error on the app "Disconnected: Peer removed pairing information."‎

Solution: Go to your Bluetooth device settings on your iOS device ‎‎(Settings > Bluetooth). Scroll down to the one labeled "CIRCUITPYxxxx". ‎Then click on the info icon (a letter i with a circle). Now select "forget ‎this device". Try to connect the board again from step 2 above and you ‎should be set.‎

error_21

error_22

Prep Your Paper Plate

Begin by folding your paper plate in half.‎

prep_23

Cut the plate in half on the folded line.

prep_24

Mount the Servo

Draw a line down the center of the half plate. Line up the servo's gear ‎on the line at the bottom of the plate and trace its outline.‎

prep_25

Cut out a window for the servo at the bottom of the plate. Then, use ‎the two mounting screws to poke holes into the plate and attach the ‎servo.‎

prep_26

prep_27

Mount the CLUE

At the top of the plate, line-up the CLUE's pad 2 hole on the center ‎line. Cut a small slit on the line.‎

mount_28

Use an M3 screw and nut to attach the CLUE to the plate through pin ‎pad 2.‎

mount_29

mount_30

Make an Arrow

With the unused half of the paper plate, cut out an arrow shape.‎

arrow_31

Cut a small slit on the bottom edge of the arrow. Attach it to the servo ‎horn with the servo horn screw.‎

cut_32

Use some markers to decorate the arrow and the paper plate. You can ‎label the arch to correspond with weather conditions. From left to right:‎

  • Stormy
  • Rain
  • Change
  • Fair
  • Very Dry

This mirrors what classic barometers have been labeled with. ‎

markers_33

Usage

After loading the project onto your CLUE with PyLeap, close out of the ‎PyLeap app. This disconnects the CLUE from PyLeap to allow it to ‎connect to File Glider.‎

You need to close out of PyLeap before connecting to File Glider. The ‎CLUE can only be connected to one app at a time.‎

Find Your Nominal Baseline Pressure

Use this standard atmosphere calculator to determine your nominal ‎baseline pressure. You'll need to know your location's elevation, which ‎can be found by doing a search online with "[location] elevation".‎

Enter your elevation in the altitude input box. Then, ‎click CALCULATE. In the output section, you'll use the pressure in mb ‎as your nominal baseline pressure number.‎

pressure_34

Standard Atmosphere Calculator

Edit With File Glider

You can edit your code with your nominal baseline pressure by ‎connecting your CLUE to File Glider, select Explorer to view the file ‎directory of your CLUE. Then, select code.py to edit the code file. ‎

projects_openCode

You can edit the NOMINAL_PRESSURE variable to equal your nominal baseline ‎pressure value that you calculated with the atmosphere calculator.‎

projects_editingCode

When you’re ready to load your updated badge, select Save in the app. ‎You’ll see the CLUE reset and begin running the code.‎

projects_startUp

The servo will point to the weather condition according to deviations ‎from the nominal baseline pressure that you've entered into the code.‎

projects_changingPressure

The CLUE display will show the temperature and air pressure reading ‎from the BMP280. You can press the A button to show the information ‎in metric units (Celsius and hPa) or you can press the B button to show ‎the information in imperial units (Fahrenheit and inHg).‎

projects_buttons

制造商零件编号 4500
CLUE NRF52840 EXPRESS
Adafruit Industries LLC
¥365.90
Details
制造商零件编号 5592
MICRO SERVO WITH ALLIGATOR CLIPS
Adafruit Industries LLC
¥71.53
Details
制造商零件编号 592
CABLE A PLUG TO MCR B PLUG 3'
Adafruit Industries LLC
¥24.01
Details
制造商零件编号 3287
BATTERY HOLDER AA 3 CELL LEADS
Adafruit Industries LLC
¥26.12
Details
制造商零件编号 727
BATTERY HOLDER AAA 3 CELL LEADS
Adafruit Industries LLC
¥17.27
Details
Add all DigiKey Parts to Cart
TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum