Pico RSS News Feed Reader

I wanted to make a little news feed reader for the Raspberry Pi Pico W, a cheap microcontroller with wifi capabilities, and display the results on a Pimoroni Pico Inky Pack e-ink display using Micropython.

I flashed the Pico with the Pimoroni Micropython bundle. Unfortunately the Micropython libraries do not appear to include an XML parser, so I had to use regex calls to extract the headlines and the dates from the RSS feed. The regex functions are a subset of those available in Python 3.7+ and I was only able to grab three items with a single pattern before running out of memory.

The reader uses the three buttons (A, B, C) on the Inky display to select between the three items and display each. It gets the RSS feed every ten minutes and checks to see if the title of the first item has changed from the previous fetch, refreshing the display if this is true.

I’m using the ABC Australia latest news RSS feed as the source: https://www.abc.net.au/news/feed/51120/rss.xml

Three files are used.

WIFI_CONFIG.py

SSID = 'your-network-ssid'
PSK = 'your-network-password'

network_connect.py

import time
import network
import WIFI_CONFIG

wlan = network.WLAN(network.STA_IF)

def connect_to_network():
    wlan.active(True)
    wlan.config(pm = 0xa11140) # Disable power-save mode
    wlan.connect(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK)
    
    max_wait = 10
    while max_wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        max_wait  -= 1
        print('waiting for connection...')
        time.sleep(1)
        
    if wlan.status() !=3:
        raise RuntimeError('network connection failed')
    else:
        print('connected')
        status = wlan.ifconfig()
        print('ip = ' + status[0])

main.py

# Get the ABC Australia news feed and display on Pimoroni Inky
import network_connect
import time
import urequests
import re
from pimoroni import Button
from picographics import PicoGraphics, DISPLAY_INKY_PACK, PEN_1BIT

network_connect.connect_to_network()


# ABC News Feed
feed_address = "http://www.abc.net.au/news/feed/51120/rss.xml"
feed_title = "ABC News"
feed_instructions = "Press A, B or C to display the 3 latest items."
feed_items = {}
old_title = ""

# Function to get feed
def get_feed():
    titles = {}
    dates = {}
    r = urequests.get(feed_address)
    item_pattern = '<item>\s*<title>(.*?)</title>.*?</description>\s*<pubDate>(.*?)\+'
    pattern = item_pattern + '.*?' + item_pattern + '.*?' + item_pattern
    items = re.search(pattern, r.content)
    j = 1
    for i in range(3):
        titles[i] = items.group(j).decode('utf-8')
        dates[i] = items.group(j+1).decode('utf-8')
        j = j + 2       
    r.close()
    return titles, dates

# We're only using a few colours so we can use a 4 bit/16 colour palette and save RAM!
display = PicoGraphics(display=DISPLAY_INKY_PACK, pen_type=PEN_1BIT, rotate=0)

display.set_backlight(0.5)
display.set_font("bitmap8")

button_a = Button(12)
button_b = Button(13)
button_c = Button(14)

WHITE = 15
BLACK = 0


# sets up a handy function we can call to clear the screen
def clear():
    display.set_pen(WHITE)
    display.clear()
    display.update()

# Display feed item
def display_item(i = 0):
    clear()                                           # clear to black
    display.set_pen(BLACK)                            # change the pen colour
    display.text(feed_title, 10, 5, 240, 3)
    display.line(10, 30, 286, 30)                     # draw a line beneath the title
    display.text('Item ' + str(i + 1) + ': ' + feed_items[1][i], 10, 35, 240, 1)    # display the date and item nunber
    display.text(feed_items[0][i], 10, 45, 240, 2)    # display the title
    display.line(10, 115, 286, 115)                   # draw a line above the instructions
    display.text(feed_instructions, 10, 118, 240, 1)  # display feed instructions
    display.update()

# set up
clear()
feed_items = get_feed()
old_title = feed_items[0][0]
display_item(0)
ftimer = 0

while True:
    if ftimer > 600:                                      # update every 10 minutes
        feed_items = get_feed()
        if feed_items[0][0] != old_title:                 # feed contains updated items
            old_title = feed_items[0][0]
            display_item(0) 
        ftimer = 0
        
    if button_a.read():                                   # if a button press is detected then...
        display_item(0)                                      
    elif button_b.read():
        display_item(1)
    elif button_c.read():
        display_item(2)
        
    time.sleep(0.1)  # this number is how frequently the Pico checks for button presses
    ftimer = ftimer + 1

I’m just learning Python and the Pico, so there are probably better ways of doing some of the above.

It does appear to run out of memory or crash when independently powered, so I’m looking into that. Use the above code at your own risk.

Future Enhancements

Instead of getting three items from a single news feed I’m thinking of using the buttons to switch between three different feeds. More error checking is also required.

Submit a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s