Maker.io main logo

PyLeap CLUE Barometer

11

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

Mfr Part # 4500
CLUE NRF52840 EXPRESS
Adafruit Industries LLC
287,68 kr.
View More Details
Mfr Part # 5592
MICRO SERVO WITH ALLIGATOR CLIPS
Adafruit Industries LLC
50,88 kr.
View More Details
Mfr Part # 592
CABLE A PLUG TO MCR B PLUG 3'
Adafruit Industries LLC
18,88 kr.
View More Details
Mfr Part # 3287
BATTERY HOLDER AA 3 CELL LEADS
Adafruit Industries LLC
18,88 kr.
View More Details
Mfr Part # EN91
BATTERY ALKALINE 1.5V AA
Energizer Battery Company
3,68 kr.
View More Details
Mfr Part # 727
BATTERY HOLDER AAA 3 CELL LEADS
Adafruit Industries LLC
12,48 kr.
View More Details
Add all DigiKey Parts to Cart
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.