Thursday, February 18, 2021

RPi Pico/CircuitPython x AHT20+BMP280 (Temperature, Humidity and Pressure Sensor Module), display on ssd1306 I2C OLED

It's a exercise for Raspberry Pi Pico running CircuitPython 6.2.0-beta.2, to read AHT20+BMP280 Temperature, Humidity and Pressure Sensor Module, and display on SSD1306 I2C OLED.

AHT20+BMP280 Digital Temperature, Humidity and Pressure Sensor Module

It's a module adopts the digital temperature and humidity sensor AHT20 and Bosch BPM280 composed of Aosong, I2C mainstream output,




Connection:

In this exercise, both the I2C from AHT20+BMP280 module and from SSD1306 OLED connect to one common I2C port of Raspberry Pi Pico.

Driver libraries:

Visit https://circuitpython.org/libraries, download the appropriate bundle for your version of CircuitPython. Unzip the file, and copy the needed file/directory to /lib directory of your Raspberry Pi Pico CIRCUITPY driver.


If you looking for read the sensor module only, only adafruit_ahtx0.mpy and adafruit_bmp280.mpy are needed. adafruit_displayio_ssd1306.mpy, adafruit_display_shapes and adafruit_display_text directories are needed for ssd1306 I2C OLED.

For more on using ssd1306 with adafruit_displayio_ssd1306.mpy (framebuffer), refer last post "Raspberry Pi Pico/CircuitPython + ssd1306 I2C OLED using adafruit_displayio_ssd1306 driver".

Example code:

cpyPico_bmp280_simpletest.py,  read BMP280 sensor. Basically it is modifed from the bmp280_simpletest.py example come with the downloaed Adafruit CircuitPython Library, with change of GPIO for I2C only.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""Simpletest Example that shows how to get temperature,
   pressure, and altitude readings from a BMP280"""
import time
import board

# import digitalio # For use with SPI
import busio
import adafruit_bmp280

# Create library object using our Bus I2C port
#i2c = busio.I2C(board.SCL, board.SDA)
SDA = board.GP8
SCL = board.GP9
i2c = busio.I2C(SCL, SDA)
bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c)

# OR create library object using our Bus SPI port
# spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
# bmp_cs = digitalio.DigitalInOut(board.D10)
# bmp280 = adafruit_bmp280.Adafruit_BMP280_SPI(spi, bmp_cs)

# change this to match the location's pressure (hPa) at sea level
bmp280.sea_level_pressure = 1013.25

while True:
    print("\nTemperature: %0.1f C" % bmp280.temperature)
    print("Pressure: %0.1f hPa" % bmp280.pressure)
    print("Altitude = %0.2f meters" % bmp280.altitude)
    time.sleep(2)
cpyPico_ahtx0_simpletest.py, read AHT20 sensor, modify from ahtx0_simpletest.py example.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

import time
import board
import adafruit_ahtx0
import busio

# Create the sensor object using I2C
SDA = board.GP8
SCL = board.GP9
i2c = busio.I2C(SCL, SDA)
sensor = adafruit_ahtx0.AHTx0(i2c)
#sensor = adafruit_ahtx0.AHTx0(board.I2C())

while True:
    print("\nTemperature: %0.1f C" % sensor.temperature)
    print("Humidity: %0.1f %%" % sensor.relative_humidity)
    time.sleep(2)

cpyPico_bmp280_ssd1306.py, read BMP280 sensor, display on ssd1306 I2C OLED.
"""
Raspberry Pi Pico/CircuitPython exercise
to read BMP280 using adafruit_bmp280,
display on ssd1306 I2C OLED using adafruit_displayio_ssd1306
"""
import os
import time
import board
import busio
import adafruit_bmp280
import displayio
import terminalio
import adafruit_displayio_ssd1306
from adafruit_display_text import label

displayio.release_displays()

print()
print("Machine: \t\t\t" + os.uname()[4])
print("CircuitPython: \t\t\t" + os.uname()[3])

print(adafruit_bmp280.__name__ + " : \t\t" + adafruit_bmp280.__version__)
print(adafruit_displayio_ssd1306.__name__ + " : \t" + adafruit_displayio_ssd1306.__version__)
print()

# I2C common used by AHT20/BMP280 module and ssd1306 I2C OLED
SDA = board.GP8
SCL = board.GP9
i2c = busio.I2C(SCL, SDA)

#display connected I2C devices address
if(i2c.try_lock()):
    print("i2c.scan(): " + str(i2c.scan()))
    i2c.unlock()
print()

bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c)
# change this to match the location's pressure (hPa) at sea level
bmp280.sea_level_pressure = 1013.25

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
NUM_OF_COLOR = 2
display_bus = displayio.I2CDisplay(i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=display_width, height=display_height)

#================================================
# Make the display context
group = displayio.Group(max_size=10)


bitmap = displayio.Bitmap(display_width, display_height, NUM_OF_COLOR)
bitmap_palette = displayio.Palette(NUM_OF_COLOR)
bitmap_palette[0] = 0x000000
bitmap_palette[1] = 0xFFFFFF

tileGrid = displayio.TileGrid(bitmap,
                              pixel_shader=bitmap_palette,
                              x=0, y=0)
group.append(tileGrid)

# Draw a label
text_group = displayio.Group(max_size=10, scale=2)

text_temp = label.Label(terminalio.FONT, text="temperature:", color=0xFFFFFF)
text_temp.anchor_point = (0.0, 0.0)
text_temp.anchored_position = (0, 0)

text_pres = label.Label(terminalio.FONT, text="pressure:", color=0xFFFFFF)
text_pres.anchor_point = (0.0, 0.0)
text_pres.anchored_position = (0, 10)

text_alti = label.Label(terminalio.FONT, text="altitude:", color=0xFFFFFF)
text_alti.anchor_point = (0.0, 0.0)
text_alti.anchored_position = (0, 20)

text_group.append(text_temp)
text_group.append(text_pres)
text_group.append(text_alti)
group.append(text_group)

display.show(group)
#================================================

time.sleep(0.5)
text_temp.text = "%0.1f C" % bmp280.temperature
text_pres.text = "%0.1f hPa" % bmp280.pressure
text_alti.text = "%0.2f m" % bmp280.altitude

print("\nTemperature: %0.1f C" % bmp280.temperature)
print("Pressure: %0.1f hPa" % bmp280.pressure)
print("Altitude = %0.2f meters" % bmp280.altitude)


while True:
    temp = bmp280.temperature
    pres = bmp280.pressure
    alti = bmp280.altitude
    
    text_temp.text = "%0.1f C" % temp
    text_pres.text = "%0.1f hPa" % pres
    text_alti.text = "%0.2f m" % alti

    print("\nTemperature: %0.1f C" % temp)
    print("Pressure: %0.1f hPa" % pres)
    print("Altitude = %0.2f meters" % alti)
    time.sleep(2)


#print("- bye -")
while True:
    pass
cpyPico_ahtx0_ssd1306.py, read AHT20 sensor, display on ssd1306 I2C OLED with animation effect.
"""
Raspberry Pi Pico/CircuitPython exercise
to read AHT20 using adafruit_ahtx0,
display on ssd1306 I2C OLED using adafruit_displayio_ssd1306
"""
import os
import time
import board
import adafruit_ahtx0
import busio
import displayio
import terminalio
import adafruit_displayio_ssd1306
from adafruit_display_text import label
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.rect import Rect

displayio.release_displays()

print()
print("Machine: \t\t\t" + os.uname()[4])
print("CircuitPython: \t\t\t" + os.uname()[3])

print(adafruit_ahtx0.__name__ + " : \t\t" +
      adafruit_ahtx0.__version__)
print(adafruit_displayio_ssd1306.__name__ + " : \t" +
      adafruit_displayio_ssd1306.__version__)
print()

# I2C common used by AHT20/BMP280 module and ssd1306 I2C OLED
SDA = board.GP8
SCL = board.GP9
i2c = busio.I2C(SCL, SDA)

#display connected I2C devices address
if(i2c.try_lock()):
    print("i2c.scan(): " + str(i2c.scan()))
    i2c.unlock()
print()

ath20 = adafruit_ahtx0.AHTx0(i2c)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
NUM_OF_COLOR = 2
display_bus = displayio.I2CDisplay(i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=display_width, height=display_height)

"""
ref:
Adafruit Display_Text Library
~ https://circuitpython.readthedocs.io/projects/display_text/en/latest/index.html
Adafruit Display_Shapes Library
~ https://circuitpython.readthedocs.io/projects/display-shapes/en/latest/index.html
"""
#================================================
# Make the display context
group = displayio.Group(max_size=10)


bitmap = displayio.Bitmap(display_width, display_height, NUM_OF_COLOR)
bitmap_palette = displayio.Palette(NUM_OF_COLOR)
bitmap_palette[0] = 0x000000
bitmap_palette[1] = 0xFFFFFF

tileGrid = displayio.TileGrid(bitmap,
                              pixel_shader=bitmap_palette,
                              x=0, y=0)
group.append(tileGrid)
#---------------------------
group_temp = displayio.Group(max_size=10, scale=1)
group_temp.x = 0
group_temp.y = 0
label_temp = label.Label(terminalio.FONT, text="temperature", color=0xFFFFFF)
label_temp.anchor_point = (0.0, 0.0)
label_temp.anchored_position = (0, 0)
label_temp_width = label_temp.bounding_box[2]
label_temp_height = label_temp.bounding_box[3]
shape_temp = RoundRect(x=0, y=0,
                       width=label_temp_width,
                       height=label_temp_height,
                       r=6,
                       fill=0x000000,
                       outline=0xFFFFFF, stroke=1)

group_temp.append(shape_temp)
group_temp.append(label_temp)
#---------------------------
group_humi = displayio.Group(max_size=10, scale=1)
group_humi.x = 40
group_humi.y = 30
label_humi = label.Label(terminalio.FONT, text="humidity", color=0xFFFFFF)
label_humi.anchor_point = (0.0, 0.0)
label_humi.anchored_position = (0, 0)
label_humi_width = label_humi.bounding_box[2]
label_humi_height = label_humi.bounding_box[3]
shape_humi = Rect(x=0, y=0,
                  width=label_humi_width,
                  height=label_humi_height,
                  fill=0x000000,
                  outline=0xFFFFFF, stroke=1)

group_humi.append(shape_humi)
group_humi.append(label_humi)
#---------------------------
group.append(group_humi)
group.append(group_temp)
display.show(group)

#================================================
#prepare for moving
tempXMove = +1
tempYMove = +1
tempXLim = display_width - 1 - label_temp_width
tempYLim = display_height - 1 - label_temp_height

humiXMove = -1
humiYMove = +1
humiXLim = display_width - 1 - label_humi_width
humiYLim = display_height - 1 - label_humi_height

NxMeasureMs = time.monotonic() + 3

while True:
    time.sleep(0.05)
    
    if time.monotonic() > NxMeasureMs:
        NxMeasureMs = time.monotonic() + 1
        
        temp = ath20.temperature
        humi = ath20.relative_humidity
        label_temp.text = "  %0.1f C" % temp
        label_humi.text = " %0.1f %% " % humi
        print("\nTemperature: %0.1f C" % temp)
        print("Humidity: %0.1f %%" % humi)
            
    #Move Temperate group
    x = group_temp.x + tempXMove
    group_temp.x = x
    if tempXMove > 0:
        if x >= tempXLim:
            tempXMove = -1
    else:
        if x <= 0:
            tempXMove = +1
            
    y = group_temp.y + tempYMove
    group_temp.y = y
    if tempYMove > 0:
        if y > tempYLim:
            tempYMove = -1
    else:
        if y <= 0:
            tempYMove = +1
            

    #Move Humidity group
    x = group_humi.x + humiXMove
    group_humi.x = x
    if humiXMove > 0:
        if x >= humiXLim:
            humiXMove = -1
    else:
        if x <= 0:
            humiXMove = +1
            
    y = group_humi.y + humiYMove
    group_humi.y = y
    if humiYMove > 0:
        if y > humiYLim:
            humiYMove = -1
    else:
        if y <= 0:
            humiYMove = +1


No comments: