192 lines
6.2 KiB
Python
Executable file
192 lines
6.2 KiB
Python
Executable file
# SPDX-FileCopyrightText: 2020 Carter Nelson for Adafruit Industries
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
import time
|
|
import struct
|
|
import displayio
|
|
import terminalio
|
|
from microcontroller import nvm
|
|
from adafruit_display_text import label
|
|
import adafruit_imageload
|
|
from adafruit_clue import clue
|
|
|
|
# ==| USER CONFIG |=====================
|
|
USE_METRIC = False
|
|
DISPLAY_UPDATE = 1
|
|
HOLD_TO_SET = 1
|
|
FONT = terminalio.FONT
|
|
BLUE = 0x53E4FF
|
|
ORANGE = 0xFCDF03
|
|
RED = 0xFA0000
|
|
DEBOUNCE = 0.05
|
|
SAMPLES = 10
|
|
DELAY = 0.05
|
|
STD_SLP = 1013.25
|
|
# ==| USER CONFIG |=====================
|
|
|
|
# configure pressure sensor (see Table 15 in datasheet)
|
|
clue._pressure.mode = 0x03 # normal
|
|
clue._pressure.overscan_pressure = 0x05 # x16
|
|
clue._pressure.overscan_temperature = 0x02 # x2
|
|
clue._pressure.iir_filter = 0x02 # 4
|
|
clue._pressure.standby_period = 0x01 # 62.5 ms
|
|
|
|
# restore saved sea level pressure from NVM
|
|
slp = struct.unpack("f", nvm[0:4])[0]
|
|
clue.sea_level_pressure = slp if 0 < slp < 2000 else STD_SLP
|
|
|
|
# --------------------------------------------------------------------
|
|
# D I S P L A Y S E T U P
|
|
# --------------------------------------------------------------------
|
|
|
|
# create main display group
|
|
splash = displayio.Group()
|
|
clue.display.show(splash)
|
|
|
|
# background
|
|
bg_bmp, bg_pal = adafruit_imageload.load(
|
|
"/network23.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette
|
|
)
|
|
for i, color in enumerate(bg_pal):
|
|
if color == 0xFF0000:
|
|
bg_pal.make_transparent(i)
|
|
break
|
|
background = displayio.TileGrid(bg_bmp, pixel_shader=bg_pal)
|
|
|
|
# a group for both altitude readouts
|
|
alti_readouts = displayio.Group(scale=6)
|
|
|
|
# altitude (corrected)
|
|
alti_disp = label.Label(FONT, text="12345", color=ORANGE)
|
|
alti_disp.anchor_point = (0, 0)
|
|
alti_disp.anchored_position = (7, 2)
|
|
|
|
# altitude (uncorrected)
|
|
alt2_disp = label.Label(FONT, text="12345", color=ORANGE)
|
|
alt2_disp.anchor_point = (0, 0)
|
|
alt2_disp.anchored_position = (7, 15)
|
|
|
|
# add both alti's to group
|
|
alti_readouts.append(alti_disp)
|
|
alti_readouts.append(alt2_disp)
|
|
|
|
# barometric pressure and temperature
|
|
aux_data = label.Label(FONT, text="P: 1234.56 T: 123.4", color=BLUE)
|
|
aux_data.anchor_point = (0, 0)
|
|
aux_data.anchored_position = (16, 212)
|
|
|
|
# calibration mode indicator
|
|
cal_mode = label.Label(FONT, text=" ", color=RED, scale=4, x=150, y=200)
|
|
|
|
# add everything to splash
|
|
splash.append(background)
|
|
splash.append(alti_readouts)
|
|
splash.append(aux_data)
|
|
splash.append(cal_mode)
|
|
|
|
# --------------------------------------------------------------------
|
|
# H E L P E R F U N C T I O N S
|
|
# --------------------------------------------------------------------
|
|
def compute_altitude(barometric_pressure, sea_level_pressure):
|
|
"""Compute altitude (m) from barometric pressure (hPa) and sea level pressure (hPa)."""
|
|
# https://www.weather.gov/media/epz/wxcalc/pressureAltitude.pdf
|
|
return 44307.69396 * (1 - pow((barometric_pressure / sea_level_pressure), 0.190284))
|
|
|
|
|
|
def compute_sea_level_pressure(barometric_pressure, altitude):
|
|
"""Compute sea level pressure (hPa) from barometric pressure (hPa) and altitude (m)."""
|
|
return barometric_pressure * pow((1 - (altitude / 44307.69396)), -5.2553)
|
|
|
|
|
|
def average_readings(samples=10, delay=0.05):
|
|
"""Return averaged readings for pressure and temperature."""
|
|
pressure = 0
|
|
temperature = 0
|
|
for _ in range(samples):
|
|
pressure += clue.pressure
|
|
temperature += clue.temperature
|
|
time.sleep(delay)
|
|
return pressure / samples, temperature / samples
|
|
|
|
|
|
def recalibrate(current_sea_level_pressure=None):
|
|
"""Enter current altitude."""
|
|
cal_mode.text = "CAL"
|
|
alt2_disp.text = "-----"
|
|
# wait for release if still being held
|
|
while clue.button_a and clue.button_b:
|
|
pass
|
|
# get current value
|
|
altitude = int(alti_disp.text)
|
|
done = False
|
|
while not done:
|
|
now = time.monotonic()
|
|
# increase
|
|
if clue.button_a and not clue.button_b:
|
|
altitude -= 1
|
|
time.sleep(DEBOUNCE)
|
|
# decrease
|
|
elif clue.button_b and not clue.button_a:
|
|
altitude += 1
|
|
time.sleep(DEBOUNCE)
|
|
# hold both to set
|
|
elif clue.button_a and clue.button_b:
|
|
while clue.button_a and clue.button_b:
|
|
if time.monotonic() - now > HOLD_TO_SET:
|
|
print("done")
|
|
done = True
|
|
break
|
|
alti_disp.text = "{:5d}".format(altitude)
|
|
cal_mode.text = " "
|
|
# change clue settings
|
|
if not USE_METRIC:
|
|
altitude *= 0.3048
|
|
# get current local pressure
|
|
barometric_pressure, _ = average_readings(SAMPLES, DELAY)
|
|
# compute sea level pressure and set
|
|
clue.sea_level_pressure = compute_sea_level_pressure(barometric_pressure, altitude)
|
|
# store in NVM for later use
|
|
nvm[0:4] = struct.pack("f", clue.sea_level_pressure)
|
|
|
|
|
|
def update_display():
|
|
"""Update the display with latest info."""
|
|
barometric_pressure, temperature = average_readings(SAMPLES, DELAY)
|
|
altitude = compute_altitude(barometric_pressure, clue.sea_level_pressure)
|
|
alt2tude = compute_altitude(barometric_pressure, STD_SLP)
|
|
if not USE_METRIC:
|
|
altitude *= 3.28084 # ft
|
|
alt2tude *= 3.28084
|
|
# barometric_pressure *= 0.0145038 # psi
|
|
temperature = 32 + 1.8 * temperature # deg F
|
|
alti_disp.text = "{:5d}".format(int(altitude))
|
|
alt2_disp.text = "{:5d}".format(int(alt2tude))
|
|
aux_data.text = "P: {:7.2f} T: {:5.1f}".format(barometric_pressure, temperature)
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# M A I N L O O P
|
|
# --------------------------------------------------------------------
|
|
last_update = time.monotonic()
|
|
|
|
while True:
|
|
|
|
now = time.monotonic()
|
|
|
|
# update display with latest info
|
|
if now - last_update > DISPLAY_UPDATE:
|
|
update_display()
|
|
last_update = now
|
|
|
|
# hold both to recalibrate
|
|
if clue.button_a and clue.button_b:
|
|
# accumulate hold time
|
|
while clue.button_a and clue.button_b:
|
|
if time.monotonic() - now > HOLD_TO_SET:
|
|
print("set")
|
|
recalibrate(clue.sea_level_pressure)
|
|
break
|
|
# wait for release if still being held
|
|
while clue.button_a and clue.button_b:
|
|
pass
|