Raspberry Pi Picow Galactic Unicorn Weather and Clock display

For the past month or so I’ve been working on a weather display that uses the amazing Galactic Unicorn LED Matrix from the Pirates at Pimoroni. This board has a Raspberry Pi Pico W onboard on the back along with a speaker, several user-controllable buttons, battery connection and some Qw/ST (Qwiic/STEMMA QT) connectors.

Around the front, you will find 583 RGB LEDs in a 53 x 11 grid. This gives ample space for scrolling messages, pictographs and more. In my use, I will be displaying a graphic depicting the current weather along with the text of the current temperature and the current time in 24-hour format.

This is an image of the Pimoroni Galactic Unicorn display showing 583 RGB LEDs in a 53 x 11 grid
On this display is a night cloud with 8 degree and showing the time of 20:05
An example of the weather display with time.

The image above shows one of the weather readings. I will be working on more code and images for this over the next few months as time allows. The most time-consuming element is creating images that are small, so I can fit them all in the limited memory of the Raspberry Pi Pico W. Making them look good at a sensible viewing distance is also time-consuming.

If you want a stab at running this yourself, the current code is on Git Hub Gists:

A Threaded weather and clock display for the #Pimoroni #GlacticUnicorn (github.com)

import urequests as requests
import json
import network
import secrets
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN as DISPLAY
from galactic import GalacticUnicorn
import jpegdec, math, ntptime, time
import _thread

blink=0
machine.freq(200000000)
rtc = machine.RTC()
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
last_second = second
blink = 0
galactic = GalacticUnicorn()
graphics = PicoGraphics(DISPLAY)
#Timer global variables
last_time_sync = time.time()
last_cheerlight_check = time.time()
utc_offset = 0

def sync_time():
    global wlan
    if not wifi_available:
        return

    if not wlan.isconnected():
        wifi_connect()

    try:
        ntptime.settime()
        #print("Time set")
    except OSError as e:
        print(e)
        pass


def sync_time_if_reqd():
    global last_time_sync
    if time.time() - last_time_sync > 86400: #Sync once per day
        #print ("Running Time Sync")
        sync_time()
        last_time_sync = time.time()


WHITE = graphics.create_pen(255, 255, 255)
BLACK = graphics.create_pen(0, 0, 0)
BACKGROUND_COLOUR = (10, 0, 96) # Blue
OUTLINE_COLOUR = (0, 0, 0)
MESSAGE_COLOUR = (255, 255, 255)

city = 'Colchester'
country_code = 'UK'
#example
#city = 'Lahore'
#country_code = 'PAK'
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT

open_weather_map_api_key = '<API_KEY>'

station = network.WLAN(network.STA_IF)

station.active(True)
station.connect(secrets.WIFI_SSID, secrets.WIFI_PASSWORD)

while station.isconnected() == False:
  pass

def outline_text(text, x, y):
    graphics.set_pen(BLACK)
    graphics.text(text, x - 1, y - 1, -1, 1)
    graphics.text(text, x, y - 1, -1, 1)
    graphics.text(text, x + 1, y - 1, -1, 1)
    graphics.text(text, x - 1, y, -1, 1)
    graphics.text(text, x + 1, y, -1, 1)
    graphics.text(text, x - 1, y + 1, -1, 1)
    graphics.text(text, x, y + 1, -1, 1)
    graphics.text(text, x + 1, y + 1, -1, 1)

    graphics.set_pen(WHITE)
    graphics.text(text, x, y, -1, 1)
    
def set_background():
   # global cheercolor
   graphics.set_pen(graphics.create_pen(10,0,96))
   for x in range(14,width):
      for y in range(0,height):
         graphics.pixel(x, y)
    
print('Connection successful')

def redraw_weather():
    while True:
        #set your unique OpenWeatherMap.org URL
        open_weather_map_url = 'http://api.openweathermap.org/data/2.5/weather?q=' + city + ',' + country_code + '&APPID=' + open_weather_map_api_key
        weather_data = requests.get(open_weather_map_url)
        # Location (City and Country code)
        location = weather_data.json().get('name')    
        # Weather Description
        description = weather_data.json().get('weather')[0].get('main')
        weather_icon = weather_data.json().get('weather')[0].get('icon')       
        print(description)
        print(weather_icon)
        icon=weather_icon+'.jpg'
        raw_temperature = weather_data.json().get('main').get('temp')-273.15
        temperature = str(round(raw_temperature)) + '°'
        print(temperature)
        graphics.set_pen(graphics.create_pen(10,0,96))
        for x in range(11,30):
            for y in range(0,height):
                graphics.pixel(x, y)
        j = jpegdec.JPEG(graphics)
        j.open_file(icon)
        j.decode(0, 0, jpegdec.JPEG_SCALE_FULL)
        graphics.set_font("bitmap8")
        #graphics.set_pen(WHITE)
        outline_text(temperature,13, 2)
        galactic.update(graphics)
        time.sleep(120)

def redraw_display_if_reqd():
    global year, month, day, wd, hour, minute, second, last_second, blink

    year, month, day, wd, hour, minute, second, _ = rtc.datetime()
    
    if second != last_second:
        hour += utc_offset
        if hour < 0:
            hour += 24
        elif hour >= 24:
            hour -= 24

        #set_background()
        graphics.set_pen(graphics.create_pen(10,0,96))
        for x in range(30,width):
            for y in range(0,height):
                graphics.pixel(x, y)
        
        if blink == 0:
            clock = "{:02}:{:02}".format(hour, minute)
            blink = 1
        else:
            clock = "{:02}|{:02}".format(hour, minute)
            blink = 0
        graphics.set_font("bitmap8")     
        outline_text(clock, 32, 2)
        last_second = second

def redraw_time():
    while True:
        redraw_display_if_reqd()
        galactic.update(graphics)
        time.sleep(0.1)
            
#while True:
galactic.set_brightness(0.5)

#set_background()
second_thread = _thread.start_new_thread(redraw_time, ())
redraw_weather()

You can now also download the icons I use for this display from (https://talktech.info/wp-content/uploads/2023/03/weather.7z). You will need to extract all the files and put them onto the device.