Downloading Bitmap via WiFi with CircuitPython, Saving to Local File System, and Displaying on LCD using OnDiskBitmap.
In my previous post, I demonstrated basic exercises running on the Raspberry Pi Pico 2 W with CircuitPython 10.0.3, displaying graphics on a 1.28‑inch IPS module (GC9A01 + CST816S, 240×240 round, 4‑wire SPI).
In this post, I present exercises using CircuitPython 10.0.3 on the Raspberry Pi Pico 2 W to download a bitmap via WiFi, save it to the local file system, and display it on the GC9A01 LCD using OnDiskBitmap.
The BMP in my test was resized and converted from JPG to BMP(240*240 RGB888) using FFmpeg.
cpy_rpPicoW_gc9a01_OnDiskBitmap_wifi.py
cpy_rpPicoW_gc9a01_OnDiskBitmap_wifi_loop.py
In this post, I present exercises using CircuitPython 10.0.3 on the Raspberry Pi Pico 2 W to download a bitmap via WiFi, save it to the local file system, and display it on the GC9A01 LCD using OnDiskBitmap.
The BMP in my test was resized and converted from JPG to BMP(240*240 RGB888) using FFmpeg.
cpy_rpPicoW_gc9a01_OnDiskBitmap_wifi.py
"""
Raspberry Pi Pico 2 W/CircuitPython 10.0.3
with 1.28" 240x240 Round GC9A01 SPI IPS LCD
Download bmp to local file system and display it using OnDiskBitmap
~ Single bmp.
In this exercise, Pico 2 W download image from web server,
save it on CircuitPython local filesystem, named "image.bmp,
then display it on 1.28" 240x240 Round GC9A01 SPI IPS LCD using OnDiskBitmap.
https://coxxect.blogspot.com/2026/01/downloading-bitmap-via-wifi-with.html
Prepare Image Server
--------------------
The BMP in my test was resized and converted from JPG to BMP(240*240 RGB888) using FFmpeg.
https://coxxect.blogspot.com/2026/01/resize-and-convert-jpgmp4-to-bmpgif.html
A simple way to run a web server in Python is to switch to the folder containing the images and run:
> python -m http.server
Both the image server and the Pico 2 W must be connected to the same WiFi network.
You also need to provide the SSID and password in this exercise.
Prepare Libraries
-----------------
CircuitPython Libraries Bundle for Version 9.x needed:
(https://circuitpython.org/libraries)
- adafruit_gc9a01a.mpy
- adafruit_requests.mpy
- adafruit_connection_manager.mpy
To install libraries using circup, enter the command:
> circup install adafruit_gc9a01a adafruit_requests
(Install adafruit_requests will install adafruit_connection_manager also.)
For CircUp, read:
https://coxxect.blogspot.com/2024/12/install-and-using-circup-circuitpython.html
Make filesystem writable
------------------------
In order to save "image.bmp" on CircuitPython local filesystem,
have to make the filesystem writable.
Visit: https://coxxect.blogspot.com/2024/12/set-circuitpython-file-system-writable.html
Copy boot_writable.py, save it in CIRCUITPY's '/', name it boot.py.
and reset.
"""
import os, sys
import board
import time
import displayio
import busio
import adafruit_gc9a01a
from fourwire import FourWire
import wifi
import socketpool
import adafruit_requests
displayio.release_displays()
tft_blk = board.GP22
tft_cs = board.GP17
tft_dc = board.GP21
tft_res = board.GP20
tft_sda = board.GP19
tft_scl = board.GP18
# Release any resources currently in use for the displays
displayio.release_displays()
disp_spi = busio.SPI(clock=tft_scl, MOSI=tft_sda)
display_bus = FourWire(spi_bus=disp_spi,
command=tft_dc,
chip_select=tft_cs,
reset=tft_res)
display = adafruit_gc9a01a.GC9A01A(display_bus, width=240, height=240, backlight_pin=tft_blk)
#=======================================
info = os.uname()[4] + "\n" + \
sys.implementation[0] + " " + os.uname()[3] + "\n" + \
adafruit_gc9a01a.__name__ + " " + adafruit_gc9a01a.__version__ + "\n" + \
displayio.OnDiskBitmap.__name__
print("=======================================")
print(info)
print("=======================================")
print()
# Create a dummy bitmap
dummy_bitmap = displayio.Bitmap(240, 240, 1)
dummy_palette = displayio.Palette(1)
dummy_palette[0] = 0x000000
bmpTileGrid = displayio.TileGrid(dummy_bitmap, pixel_shader=dummy_palette)
group = displayio.Group()
group.append(bmpTileGrid)
display.root_group = group
# Prepare WiFi
ssid = "ssid"
password="password"
print("Connecting", ssid)
wifi.radio.connect(ssid, password)
print("wifi.radio.connected:", wifi.radio.connected)
print("wifi.radio.ipv4_address", wifi.radio.ipv4_address) # Pico 2 W IP
print("wifi.radio.ipv4_gateway", wifi.radio.ipv4_gateway) # WiFi Station IP
server_ip = str(wifi.radio.ipv4_gateway)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, wifi)
# Assume web server is setup in the WiFi station, have the same IP.
# otherwise, fill in server_ip manually.
server_url = "http://" + server_ip + ":8000/"
image_file = "image_005.bmp"
url = server_url + image_file
print(url)
# This line sometimes fail in my early try,
# response = requests.get(url, stream=True) # Enable streaming mode
# so I place it in try..except...block.
while True:
try:
print("requests.get()", end="")
response = requests.get(url, stream=True) # Enable streaming mode
print(" - success")
break
except OSError as err:
print(" - failed! retry in 1 second")
print("OSError:", err)
time.sleep(1)
save_image_file = "/image.bmp"
print("Save to", save_image_file)
start_time = time.time()
with open(save_image_file, "wb") as file:
for chunk in response.iter_content(2048): # Download in chunks of 1024 bytes
file.write(chunk)
stop_time = time.time()
print("Downloaded and Saved in", stop_time-start_time, "s")
print("Saved")
# retrieve saved save_image_file info.
file_info = os.stat(save_image_file)
print(save_image_file, "File size:", file_info[6], "bytes") # index 6 is file size
file.close()
response.close()
print("Display", save_image_file)
bitmap = displayio.OnDiskBitmap(save_image_file)
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
group = displayio.Group()
group.append(tile_grid)
display.root_group = group
print("~ finished ~")
cpy_rpPicoW_gc9a01_OnDiskBitmap_wifi_loop.py
"""
Raspberry Pi Pico 2 W/CircuitPython 10.0.3
with 1.28" 240x240 Round GC9A01 SPI IPS LCD
Download bmp to local file system and display it using OnDiskBitmap
~ Loop for multi bmp.
In this exercise, Pico 2 W download image from web server,
save it on CircuitPython local filesystem, named "image.bmp,
then display it on 1.28" 240x240 Round GC9A01 SPI IPS LCD using OnDiskBitmap.
https://coxxect.blogspot.com/2026/01/downloading-bitmap-via-wifi-with.html
Prepare Image Server
--------------------
The BMP in my test was resized and converted from JPG to BMP(240*240 RGB888) using FFmpeg.
https://coxxect.blogspot.com/2026/01/resize-and-convert-jpgmp4-to-bmpgif.html
A simple way to run a web server in Python is to switch to the folder containing the images and run:
> python -m http.server
Both the image server and the Pico 2 W must be connected to the same WiFi network.
You also need to provide the SSID and password in this exercise.
Prepare Libraries
-----------------
CircuitPython Libraries Bundle for Version 9.x needed:
(https://circuitpython.org/libraries)
- adafruit_gc9a01a.mpy
- adafruit_requests.mpy
- adafruit_connection_manager.mpy
To install libraries using circup, enter the command:
> circup install adafruit_gc9a01a adafruit_requests
(Install adafruit_requests will install adafruit_connection_manager also.)
For CircUp, read:
https://coxxect.blogspot.com/2024/12/install-and-using-circup-circuitpython.html
Make filesystem writable
------------------------
In order to save "image.bmp" on CircuitPython local filesystem,
have to make the filesystem writable.
Visit: https://coxxect.blogspot.com/2024/12/set-circuitpython-file-system-writable.html
Copy boot_writable.py, save it in CIRCUITPY's '/', name it boot.py.
and reset.
"""
import os, sys
import board
import time
import displayio
import busio
import adafruit_gc9a01a
from fourwire import FourWire
import wifi
import socketpool
import adafruit_requests
import gc
RED = "\033[31m"
RESET = "\033[0m"
displayio.release_displays()
tft_blk = board.GP22
tft_cs = board.GP17
tft_dc = board.GP21
tft_res = board.GP20
tft_sda = board.GP19
tft_scl = board.GP18
# Release any resources currently in use for the displays
displayio.release_displays()
disp_spi = busio.SPI(clock=tft_scl, MOSI=tft_sda)
display_bus = FourWire(spi_bus=disp_spi,
command=tft_dc,
chip_select=tft_cs,
reset=tft_res)
display = adafruit_gc9a01a.GC9A01A(display_bus, width=240, height=240, backlight_pin=tft_blk)
#=======================================
info = os.uname()[4] + "\n" + \
sys.implementation[0] + " " + os.uname()[3] + "\n" + \
adafruit_gc9a01a.__name__ + " " + adafruit_gc9a01a.__version__ + "\n" + \
displayio.OnDiskBitmap.__name__
print("=======================================")
print(info)
print("=======================================")
print()
# Create a dummy bitmap
dummy_bitmap = displayio.Bitmap(240, 240, 1)
dummy_palette = displayio.Palette(1)
dummy_palette[0] = 0x000000
bmpTileGrid = displayio.TileGrid(dummy_bitmap, pixel_shader=dummy_palette)
group = displayio.Group()
group.append(bmpTileGrid)
display.root_group = group
# Prepare WiFi
ssid = "ssid"
password="password"
print("Connecting", ssid)
wifi.radio.connect(ssid, password)
print("wifi.radio.connected:", wifi.radio.connected)
print("wifi.radio.ipv4_address", wifi.radio.ipv4_address) # Pico 2 W IP
print("wifi.radio.ipv4_gateway", wifi.radio.ipv4_gateway) # WiFi Station IP
server_ip = str(wifi.radio.ipv4_gateway)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, wifi)
save_image_file = "/image.bmp"
# download_image(url):
# Download and save image.
# In order to prevent out of memory, enable streaming mode and download in chunks.
#chunk_size = 1024
chunk_size = 2048
#chunk_size = 8192
# This line sometimes fail in my early try,
# response = requests.get(url, stream=True) # Enable streaming mode
# so I place it in try..except...block.
def download_image(url):
print()
print(url)
while True:
try:
print("requests.get()", end="")
response = requests.get(url, stream=True) # Enable streaming mode
print(" - success")
break
except OSError as err:
print(" - failed! retry in 1 second")
print("OSError:", err)
time.sleep(1)
print("Save to", save_image_file)
start_time = time.time()
with open(save_image_file, "wb") as file:
for chunk in response.iter_content(chunk_size): # Download in chunks
if chunk: # filter out keep-alive chunks
file.write(chunk)
stop_time = time.time()
print("Downloaded and Saved in", stop_time-start_time, "s")
# retrieve saved save_image_file info.
file_info = os.stat(save_image_file)
print(save_image_file, "File size:", file_info[6], "bytes") # index 6 is file size
file.close()
response.close()
def show_image(filename):
"""Load and display an image file, replacing any previous one."""
try:
# Create new bitmap + tilegrid
bitmap = displayio.OnDiskBitmap(save_image_file)
print(bitmap.width, "x", bitmap.height)
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
# Replace old tilegrid if exists, else append
if len(group) > 0:
group[0] = tile_grid
else:
group.append(tile_grid)
# Get memory free size, for reference only.
print("Memory Free after bitmap updated:", gc.mem_free(), "bytes")
# Force garbage collection to free old objects
gc.collect()
print("Memory Free after gc.collect(): ", gc.mem_free(), "bytes")
except ValueError as e:
# Catch invalid bmp or unsupported format, skip
print(RED, "* ValueError *", e, RESET) # print in Shell/REPL in RED
# Create one group globally
group = displayio.Group()
display.root_group = group
# Assume web server is setup in the WiFi station, have the same IP.
# otherwise, fill in server_ip manually.
server_url = "http://" + server_ip + ":8000/"
image_urls = ["image_000.bmp",
"image_001.bmp",
"invalid_image.bmp", # Invalid, no such bmp in server.
"image_002.bmp",
"image_003.bmp",
"image_004.bmp",
"image_005.bmp"
]
while True:
for u in image_urls:
download_image(server_url + u)
show_image(save_image_file)
Comments
Post a Comment