How To Get The News With Raspberry Pi Pico W and CircuitPython
The Raspberry Pi Pico certainly made the cat among the doves in 2021, but it was missing a key feature, Wi-Fi. Sure, we can hack our own solution, but we had to wait until mid-2022, when Raspberry Pi announced the Raspberry Pi Pico W, to get official support.
The Raspberry Pi Pico W was released with robust MicroPython firmware, but unfortunately CircuitPython, our favorite microcontroller Python version, lacked support. It may have taken a few months but on the hard work of @jeffler We now have CircuitPython 8 Beta 2, which brings Wi-Fi support to the Pico W while maintaining the familiar CircuitPython ecosystem.
To celebrate this milestone, we put together a project to highlight CircuitPython on the Raspberry Pi Pico W. We will be working with live data from an RSS news feed, converted to JSON and then displayed on a tiny OLED screen.
construction of the circuit
For this project you will need
The circuit is essentially just the OLED screen connected to the Raspberry Pi Pico via an I2C connection. The only addition to the circuit are two 4.7K ohm resistors connected to the + rail and the Pico’s SDA and SCL pins. This rail is connected to 3.3V and the resistors are used to pull up the pins ready to send and receive data.
The connections are as follows
wire color | Raspberry Pi Pico W | breadboard | OLED display |
Green | GP0 (SDA) | N / A | SDA |
Yellow | GP1 (SCL) | N / A | SCL |
Red | 3V3 off | + | VIN |
Black | Dimensions | N / A | Dimensions |
Configure CircuitPython
1. Go to the official CircuitPython page for the Raspberry Pi Pico W and Download the latest UF2 firmware image. At the time of writing this was CircuitPython 8 Beta 2.
2. While holding the BOOTSEL button, connect the Raspberry Pi Pico W to your computer. A new drive, RPI-RP2, will appear
3. Copy the downloaded CircuitPython UF2 file to RPI-RP2. This will write CircuitPython to the Pico W’s internal flash memory. A new drive, CIRCUITPY, will appear.
We need a bunch of CircuitPython libraries before we can continue. These libraries of pre-built code add additional functionality to a project.
1. Download the bundle of libraries for the same version of CircuitPython as installed on the Pico W. We have CircuitPython 8 installed, so downloaded the bundle for version 8.x.
2. Extract the bundle to your desktop and Then open the lib folder included in it.
3. Copy the following files/folders from this lib folder to the lib folder on the CIRCUITPY drive.
adafruit_bitmap_font
adafruit_display_text
adafruit_displayio_ssd1306.mpy
adafruit_requests.mpy
Working with CircuitPython
1. Download and install Thonny if you don’t already have it. Thonny is a Python editor covering Python 3, MicroPython and CircuitPython.
2. Open Thonny and go to Tools >> Options.
3. Select Interpreter, then set the Interpreter to CircuitPython, the Port to Automatic, and click OK. Thonny will now connect to the Pico W running CircuitPython.
Our project code consists of two files, secrets.py and code.py. The secrets.py file is essentially a Python module with two variables containing our Wi-Fi access point’s SSID and password. It’s a good idea to store your WiFi details in a separate file called secrets.py to reduce the risk of accidentally sharing your credentials. This process works for CircuitPython and MicroPython.
1. Create a new file and in there Create two objects, ssid and password.
2. Assign the name of your WLAN access point/router to the ssid object.
ssid = “YOUR WI-FI AP NAME HERE”
3. Assign the WiFi password as the password.
password = “YOUR SECRET PASSWORD”
4. Save the file as secrets.py on the CIRCUITPY drive.
Secrets.py Code List
ssid = "YOUR WI-FI AP NAME HERE"
password = "YOUR SECRET PASSWORD"
The code for this project is contained in a file called code.py. This file runs automatically when the Pico W is powered on, this is a feature of CircuitPython. In MicroPython, we would name the file main.py to achieve the same result. We’ll now start writing the code that makes up our project.
1. Click File >> Open and Select the CircuitPython device. Open code.py on the CIRCUITPY drive. Delete any code in the file.
2. Import modules from ready-made code to pause (time) our code, set an IP address, use the Pico W’s Wi-Fi chip, and create web sockets.
import time
import ipaddress
import wifi
import socketpool
3. Import four more modules for secure connections to make web requests, a module with our WiFi credentials and a module to interact with the GPIO.
import ssl
import adafruit_requests
import secrets
import board
4. Import the last module group for accelerated bus access, a display library, a terminal-style text module, scrolling text, and a driver for the OLED display.
import busio
import displayio
import terminalio
from adafruit_display_text.scrolling_label import ScrollingLabel
import adafruit_displayio_ssd1306
5. Share the display with CircuitPython to use it and then Specify the GPIO pins used for I2C.
displayio.release_displays()
i2c = busio.I2C(board.GP1, board.GP0)
6. Provide the I2C interface and I2C address for the OLED screen on the display bus and then Use this to create a display object. Don’t forget to set the width and height to match your OLED display. To find the I2C address of the OLED display, consult its datasheet or use an I2C scanner to look for it.
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
7. Connect to WiFi with the ssid and password stored in the secrets module.
wifi.radio.connect(ssid=secrets.ssid,password=secrets.password)
8. Create a socket pool which we can use for connections and Then create a new HTTP session to be used when making web requests.
pool = socketpool.SocketPool(wifi.radio)
request = adafruit_requests.Session(pool, ssl.create_default_context())
9. Create a while true loop to run the main project code. This loop will continue as long as the Pico W is powered on.
while True:
10. Create a banner and store it in the Toms object.The banner consists of a series of * followed by “Tom’s Hardware News” then another 10 more *.
toms = "*"*10+" Tom's Hardware News"+"*"*10
11. Create an object to scroll the text stored in the toms object. Animation time controls scrolling speed, scaling is used to increase text size, with 3 being the largest available for our 128×32 screen.
my_scrolling_label = ScrollingLabel(terminalio.FONT, text=toms, max_characters=20, animate_time=0.1, scale=3)
12. Specify the position of the text (horizontal, x and vertical, y).
my_scrolling_label.x = 10
my_scrolling_label.y = 10
13. View the text on the OLED display.
display.show(my_scrolling_label)
14. Use a for loop to scroll the banner over the screen. We use the length of the text stored in the Toms object minus six to create a pleasing scroll. This needs to be customized to match your banner text.
for i in range(len(toms)-6):
my_scrolling_label.update()
time.sleep(0.1)
15. Create an object, feed to Store the URL of the JSON feed that contains the news headlines. We used rss2json.com to convert Tom’s Hardware RSS feed to JSON that’s easy to work with in CircuitPython.
feed =
request.get("https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fwww.tomshardware.com%2Ffeeds%2Fall")
16. Use a for loop to get the first five stories from the feed.
for story in range(5):
17. Print the headline of the story to the Python shell.
print(feed.json()['items'][story]['title'])
18. Update the scrolling text to scroll the headlinewith a buffer of 20 spaces before the text and a scaling (text size) of 2.
my_scrolling_label = ScrollingLabel(terminalio.FONT, text=" "*20+str(feed.json()['items'][story]['title']), max_characters=20, animate_time=0.1, scale=2)
19. Specify the position of the text (horizontal, x and vertical, y).
my_scrolling_label.x = 10
my_scrolling_label.y = 10
20. View the text on the OLED display.
display.show(my_scrolling_label)
21. Use another for loop to scroll the heading text. The iterations in the loop are determined by the length of the heading plus 21 characters to create a buffer.
for i in range(len(feed.json()['items'][story]['title'])+21):
my_scrolling_label.update()
time.sleep(0.1)
22. Finally add a sleep of 30 minutes (1800 seconds) to set the Pico W to check for new headlines every half hour.
time.sleep(1800)
23. Save the project as code.py Go to CIRCUITPY and click Run to test the code.
You should see the OLED screen come to life and a banner scroll, then the headlines. Since we saved the project in the code.py file, this code will run automatically when the Pico W is powered on.
Complete code list
import time
import ipaddress
import wifi
import socketpool
import ssl
import adafruit_requests
import secrets
import board
import busio
import displayio
import terminalio
from adafruit_display_text.scrolling_label import ScrollingLabel
import adafruit_displayio_ssd1306
# Setup the display
displayio.release_displays()
i2c = busio.I2C(board.GP1, board.GP0)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
wifi.radio.connect(ssid=secrets.ssid,password=secrets.password)
pool = socketpool.SocketPool(wifi.radio)
request = adafruit_requests.Session(pool, ssl.create_default_context())
while True:
toms = "*"*10+" Tom's Hardware News"+"*"*10
my_scrolling_label = ScrollingLabel(terminalio.FONT, text=toms, max_characters=20, animate_time=0.1, scale=3)
my_scrolling_label.x = 10
my_scrolling_label.y = 10
display.show(my_scrolling_label)
for i in range(len(toms)-6):
my_scrolling_label.update()
time.sleep(0.1)
feed = request.get("https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fwww.tomshardware.com%2Ffeeds%2Fall")
for story in range(5):
print(feed.json()['items'][story]['title'])
my_scrolling_label = ScrollingLabel(terminalio.FONT, text=" "*20+str(feed.json()['items'][story]['title']), max_characters=20, animate_time=0.1, scale=2)
my_scrolling_label.x = 10
my_scrolling_label.y = 10
display.show(my_scrolling_label)
for i in range(len(feed.json()['items'][story]['title'])+21):
my_scrolling_label.update()
time.sleep(0.1)
time.sleep(1800)