Problem with time/temp display, Galactic Unicorn LED Pico W

I’m trying to modify the example clock.py code to left-align the time, then right-align the current temp in F from a weather underground PWS. I have the wifi connected and the appropriate info in secrets.py with my api key and stationID. I keep getting this error:

waiting for connection…
Connected
Time set
Error fetching temperature: -2

The time is correct, but the temp fails.

But I verified the api key, url, etc. Any pointers?
(I am VERY new to this thing and programming)

import time
import math
import machine
import network
import ntptime
import urequests as requests
import ujson as json
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN as DISPLAY

try:
    from secrets import WIFI_SSID, WIFI_PASSWORD, WUNDERGROUNDAPIKEY, WUNDERGROUNDSTATION
    wifi_available = True
except ImportError:
    print("Create secrets.py with your WiFi credentials to get time from NTP")
    wifi_available = False

MIDDAY_HUE = 1.1
MIDNIGHT_HUE = 0.8
HUE_OFFSET = -0.1

MIDDAY_SATURATION = 1.0
MIDNIGHT_SATURATION = 1.0

MIDDAY_VALUE = 0.8
MIDNIGHT_VALUE = 0.3

gu = GalacticUnicorn()
graphics = PicoGraphics(DISPLAY)
rtc = machine.RTC()

width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT

WHITE = graphics.create_pen(255, 255, 255)
BLACK = graphics.create_pen(0, 0, 0)

def from_hsv(h, s, v):
    i = math.floor(h * 6.0)
    f = h * 6.0 - i
    v *= 255.0
    p = v * (1.0 - s)
    q = v * (1.0 - f * s)
    t = v * (1.0 - (1.0 - f) * s)

    i = int(i) % 6
    if i == 0:
        return int(v), int(t), int(p)
    if i == 1:
        return int(q), int(v), int(p)
    if i == 2:
        return int(p), int(v), int(t)
    if i == 3:
        return int(p), int(q), int(v)
    if i == 4:
        return int(t), int(p), int(v)
    if i == 5:
        return int(v), int(p), int(q)

def gradient_background(start_hue, start_sat, start_val, end_hue, end_sat, end_val):
    half_width = width // 2
    for x in range(0, half_width):
        hue = ((end_hue - start_hue) * (x / half_width)) + start_hue
        sat = ((end_sat - start_sat) * (x / half_width)) + start_sat
        val = ((end_val - start_val) * (x / half_width)) + start_val
        colour = from_hsv(hue, sat, val)
        graphics.set_pen(graphics.create_pen(int(colour[0]), int(colour[1]), int(colour[2])))
        for y in range(0, height):
            graphics.pixel(x, y)
            graphics.pixel(width - x - 1, y)
    colour = from_hsv(end_hue, end_sat, end_val)
    graphics.set_pen(graphics.create_pen(int(colour[0]), int(colour[1]), int(colour[2])))
    for y in range(0, height):
        graphics.pixel(half_width, y)

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 sync_time():
    if not wifi_available:
        return
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.config(pm=0xa11140)
    wlan.connect(WIFI_SSID, WIFI_PASSWORD)
    max_wait = 100
    while max_wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        max_wait -= 1
        print('waiting for connection...')
        time.sleep(0.2)
        gu.update(graphics)
    if max_wait > 0:
        print("Connected")
        try:
            ntptime.settime()
            print("Time set")
        except OSError:
            pass
    wlan.disconnect()
    wlan.active(False)

utc_offset = -8

up_button = machine.Pin(GalacticUnicorn.SWITCH_VOLUME_UP, machine.Pin.IN, machine.Pin.PULL_UP)
down_button = machine.Pin(GalacticUnicorn.SWITCH_VOLUME_DOWN, machine.Pin.IN, machine.Pin.PULL_UP)

def adjust_utc_offset(pin):
    global utc_offset, last_second
    if pin == up_button:
        utc_offset += 1
        last_second = None
    if pin == down_button:
        utc_offset -= 1
        last_second = None

up_button.irq(trigger=machine.Pin.IRQ_FALLING, handler=adjust_utc_offset)
down_button.irq(trigger=machine.Pin.IRQ_FALLING, handler=adjust_utc_offset)

year, month, day, wd, hour, minute, second, _ = rtc.datetime()
last_second = second

def get_temperature():
    api_key = WUNDERGROUNDAPIKEY
    station_id = WUNDERGROUNDSTATION
    url = f"http://api.weather.com/v2/pws/observations/current?stationId={station_id}&format=json&units=e&apiKey={api_key}"
    
    try:
        response = requests.get(url)
        weather_data = response.json()
        temp = weather_data['observations'][0]['imperial']['temp']
        return f"{temp}°"
    except Exception as e:
        print("Error fetching temperature:", e)
        return "N/A°"

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

    year, month, day, wd, hour, minute, second, _ = rtc.datetime()
    if second != last_second:
        hour = (hour + utc_offset) % 24
        time_through_day = (((hour * 60) + minute) * 60) + second
        percent_through_day = time_through_day / 86400
        percent_to_midday = 1.0 - ((math.cos(percent_through_day * math.pi * 2) + 1) / 2)

        hue = ((MIDDAY_HUE - MIDNIGHT_HUE) * percent_to_midday) + MIDNIGHT_HUE
        sat = ((MIDDAY_SATURATION - MIDNIGHT_SATURATION) * percent_to_midday) + MIDNIGHT_SATURATION
        val = ((MIDDAY_VALUE - MIDNIGHT_VALUE) * percent_to_midday) + MIDNIGHT_VALUE

        gradient_background(hue, sat, val, hue + HUE_OFFSET, sat, val)

        clock = "{:02}:{:02}".format(hour, minute)
        w = graphics.measure_text(clock, 1)
        x = 2
        y = 2

        outline_text(clock, x, y)

        temperature = get_temperature()
        temp_width = graphics.measure_text(temperature, 1)
        temp_x = width - temp_width - 2
        temp_y = height - 9

        outline_text(temperature, temp_x, temp_y)

        last_second = second

graphics.set_font("bitmap8")
gu.set_brightness(0.5)

sync_time()

while True:
    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
        gu.adjust_brightness(+0.01)
        last_second = None

    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
        gu.adjust_brightness(-0.01)
        last_second = None

    if gu.is_pressed(GalacticUnicorn.SWITCH_A):
        sync_time()

    redraw_display_if_reqd()
    gu.update(graphics)
    time.sleep(0.01)


As a first step, try to find out more about your exception. So replace

except Exception as e:
        print("Error fetching temperature:", e)
        return "N/A°"

with

except Exception as e:
        raise
        print("Error fetching temperature:", e)
        return "N/A°"

The raise will make your program fail but will usually give a complete stack-trace and so it will probably help to track down the root cause.

1 Like

Thank you!
Everything kept pointing to network issues. Well, duh! I was disconnecting the wlan in my sync_time function.

This is working for me now!

import time
import math
import machine
import network
import ntptime
import urequests as requests
import ujson as json
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN as DISPLAY

try:
    from secrets import WIFI_SSID, WIFI_PASSWORD, WUNDERGROUNDAPIKEY, WUNDERGROUNDSTATION
    wifi_available = True
except ImportError:
    print("Create secrets.py with your WiFi credentials to get time from NTP")
    wifi_available = False

MIDDAY_HUE = 1.1
MIDNIGHT_HUE = 0.8
HUE_OFFSET = -0.1

MIDDAY_SATURATION = 1.0
MIDNIGHT_SATURATION = 1.0

MIDDAY_VALUE = 0.8
MIDNIGHT_VALUE = 0.3

gu = GalacticUnicorn()
graphics = PicoGraphics(DISPLAY)
rtc = machine.RTC()

width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT

WHITE = graphics.create_pen(255, 255, 255)
BLACK = graphics.create_pen(0, 0, 0)

def from_hsv(h, s, v):
    i = math.floor(h * 6.0)
    f = h * 6.0 - i
    v *= 255.0
    p = v * (1.0 - s)
    q = v * (1.0 - f * s)
    t = v * (1.0 - (1.0 - f) * s)

    i = int(i) % 6
    if i == 0:
        return int(v), int(t), int(p)
    if i == 1:
        return int(q), int(v), int(p)
    if i == 2:
        return int(p), int(v), int(t)
    if i == 3:
        return int(p), int(q), int(v)
    if i == 4:
        return int(t), int(p), int(v)
    if i == 5:
        return int(v), int(p), int(q)

def gradient_background(start_hue, start_sat, start_val, end_hue, end_sat, end_val):
    half_width = width // 2
    for x in range(0, half_width):
        hue = ((end_hue - start_hue) * (x / half_width)) + start_hue
        sat = ((end_sat - start_sat) * (x / half_width)) + start_sat
        val = ((end_val - start_val) * (x / half_width)) + start_val
        colour = from_hsv(hue, sat, val)
        graphics.set_pen(graphics.create_pen(int(colour[0]), int(colour[1]), int(colour[2])))
        for y in range(0, height):
            graphics.pixel(x, y)
            graphics.pixel(width - x - 1, y)
    colour = from_hsv(end_hue, end_sat, end_val)
    graphics.set_pen(graphics.create_pen(int(colour[0]), int(colour[1]), int(colour[2])))
    for y in range(0, height):
        graphics.pixel(half_width, y)

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 sync_time():
    if not wifi_available:
        return
    wlan = network.WLAN(network.STA_IF)
    if not wlan.isconnected():
        wlan.active(True)
        wlan.config(pm=0xa11140)
        wlan.connect(WIFI_SSID, WIFI_PASSWORD)
        max_wait = 100
        while max_wait > 0:
            if wlan.status() < 0 or wlan.status() >= 3:
                break
            max_wait -= 1
            print('waiting for connection...')
            time.sleep(0.2)
            gu.update(graphics)
        if max_wait > 0:
            print("Connected")
        else:
            print("Connection failed")
            return
    try:
        ntptime.settime()
        print("Time set")
    except Exception as e:
        print("Failed to set time:", str(e))

utc_offset = -8

up_button = machine.Pin(GalacticUnicorn.SWITCH_VOLUME_UP, machine.Pin.IN, machine.Pin.PULL_UP)
down_button = machine.Pin(GalacticUnicorn.SWITCH_VOLUME_DOWN, machine.Pin.IN, machine.Pin.PULL_UP)

def adjust_utc_offset(pin):
    global utc_offset, last_second
    if pin == up_button:
        utc_offset += 1
        last_second = None
    if pin == down_button:
        utc_offset -= 1
        last_second = None

up_button.irq(trigger=machine.Pin.IRQ_FALLING, handler=adjust_utc_offset)
down_button.irq(trigger=machine.Pin.IRQ_FALLING, handler=adjust_utc_offset)

year, month, day, wd, hour, minute, second, _ = rtc.datetime()
last_second = second

def get_temperature():
    api_key = WUNDERGROUNDAPIKEY
    station_id = WUNDERGROUNDSTATION
    url = f"https://api.weather.com/v2/pws/observations/current?stationId={station_id}&format=json&units=e&apiKey={api_key}"
    print("Constructed URL:", url)
    try:
        response = requests.get(url)
        weather_data = response.json()
        temp = weather_data['observations'][0]['imperial']['temp']
        return f"{temp}°"
    except Exception as e:
        print("Error fetching temperature:", type(e).__name__, e)
        if hasattr(e, 'errno') and e.errno is not None:
            print("Error number:", e.errno)
        if hasattr(e, 'strerror') and e.strerror is not None:
            print("Error string:", e.strerror)
        return "N/A°"

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

    year, month, day, wd, hour, minute, second, _ = rtc.datetime()
    if second != last_second:
        hour = (hour + utc_offset) % 24
        time_through_day = (((hour * 60) + minute) * 60) + second
        percent_through_day = time_through_day / 86400
        percent_to_midday = 1.0 - ((math.cos(percent_through_day * math.pi * 2) + 1) / 2)

        hue = ((MIDDAY_HUE - MIDNIGHT_HUE) * percent_to_midday) + MIDNIGHT_HUE
        sat = ((MIDDAY_SATURATION - MIDNIGHT_SATURATION) * percent_to_midday) + MIDNIGHT_SATURATION
        val = ((MIDDAY_VALUE - MIDNIGHT_VALUE) * percent_to_midday) + MIDNIGHT_VALUE

        gradient_background(hue, sat, val, hue + HUE_OFFSET, sat, val)

        clock = "{:02}:{:02}".format(hour, minute)
        w = graphics.measure_text(clock, 1)
        x = 2
        y = 2

        outline_text(clock, x, y)

        temperature = get_temperature()
        temp_width = graphics.measure_text(temperature, 1)
        temp_x = width - temp_width - 2
        temp_y = height - 9

        outline_text(temperature, temp_x, temp_y)

        last_second = second

graphics.set_font("bitmap8")
gu.set_brightness(0.5)

sync_time()

while True:
    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
        gu.adjust_brightness(+0.01)
        last_second = None

    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
        gu.adjust_brightness(-0.01)
        last_second = None

    if gu.is_pressed(GalacticUnicorn.SWITCH_A):
        sync_time()

    redraw_display_if_reqd()
    gu.update(graphics)
    time.sleep(0.01)