Kelly Sprayberry
Published © GPL3+

Scrolling Weather Forecast on Adafruit RGB Matrix Portal

This is an Eight day Scrolling Weather Forecast.

IntermediateShowcase (no instructions)2 hours1,232
Scrolling Weather Forecast on Adafruit RGB Matrix Portal

Things used in this project

Hardware components

Adafruit Matrix Portal Starter kit
×1

Software apps and online services

Openweathermap.org

Story

Read more

Code

Matrix Portal Scrolling weather forecast

MicroPython
Load the Circuitpython code on your circuitpython equipped microcontroller. This is used in conjunction with the Secrets.py file.
import time
from random import randrange
import board
import math
import terminalio
from adafruit_bitmap_font import bitmap_font
from adafruit_matrixportal.matrixportal import MatrixPortal

ICON_MAP = ("01", "02", "03", "04", "09", "10", "11", "13", "50")
DAYS = ("Mon", "Tues", "Wed", "Thurs", "Fri", "Sat", "Sun")
MONTHS = (
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "June",
    "July",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
)


try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise


# --- Data Setup --- #
# Number of guides to fetch and display from the Adafruit Learning System
# Data source URL
URL = "https://api.openweathermap.org/data/2.5/onecall?exclude=minutely,hourly,alerts"
URL += "&lat={}".format(34.876999) 
URL += "&lon={}".format(-83.959030)
URL += "&units=imperial"
URL += "&appid=" + secrets["openweather_token"]
print(URL)
DISPLAY_NUM_DAYS = 5
DATA_SOURCE = URL
FORECAST_TYPE = ["daily"]

matrixportal = MatrixPortal(
    url=DATA_SOURCE,
    json_path=FORECAST_TYPE,
    status_neopixel=board.NEOPIXEL,
)

# --- Display Setup --- #

# Colors for guide name
colors = [0xFFA500, 0xFFFF00, 0x008000, 0x0000FF, 0x4B0082, 0xEE82EE]

# Delay for scrolling the text
SCROLL_DELAY = 0.03

FONT = "fonts/IBMPlexMono-Medium-24_jep.bdf"
small_font = "fonts/Arial-12.bdf"
med_font = "fonts/Arial-16.bdf"

matrixportal.add_text(
    text_font=terminalio.FONT,
    text_position=(
        (matrixportal.graphics.display.width // 12) - 1,
        (matrixportal.graphics.display.height // 2) - 10,
        ),
    text_scale=.4,
    text_color=0x800000,
    scrolling=False
)

matrixportal.preload_font("°0123456789")
matrixportal.add_text(

    text_font=terminalio.FONT,
    text_position=(2, 24),
    text_color=0x000080,
    scrolling=True,
)

matrixportal.add_text(
    text_font=terminalio.FONT,
    text_position=(
        (matrixportal.graphics.display.width // 12) + 10,
        (matrixportal.graphics.display.height // 2),
        ),
    text_scale=.35,
    text_color=0x800000,
    scrolling=False
)

def scroll_my_text(mytext):
    matrixportal.set_text(mytext, 1)
    mylength = len(mytext)
    
def resetmytime():
            # Retrieving data...struct_time(tm_year=2021, tm_mon=12, tm_mday=26, tm_hour=22, tm_min=46, tm_sec=18, tm_wday=6, tm_yday=360, tm_isdst=-1)
        
    today_date = "{} {} {}, {}".format(
        DAYS[Myweekday].upper(),
        MONTHS[Mymonth-1].upper(),
        Myday,
        Myyear,
    )
        
    if prv_hour > 12 :
        Myhour = (prv_hour - 12)

    else:
        Myhour = prv_hour
        # changeminute = time.monotonic()
    Mydisplaystring = today_date
    matrixportal.set_text(Mydisplaystring, 0)
    if Mymin < 10:
        Myminstr = "0" + str(Mymin)
        
    else:
        Myminstr = str(Mymin)
    mytimestring = str(Myhour) + ":" + str(Myminstr)
    matrixportal.set_text(mytimestring, 2)


def get_forecast_info(index):
    """Parses JSON data returned by the DATA_SOURCE

    """
    if index > DISPLAY_NUM_DAYS:
        raise RuntimeError("Provided index may not be larger than DISPLAY_NUM_DAYS.")
    print("Obtaining forecast info for day %d..." % index)

    # Traverse JSON data for title
    forecast = matrixportal.network.json_traverse(weather_data.json(), FORECAST_TYPE)
    timezone_offset = -18000
    forecast_min = forecast[index]["temp"]["min"]
    forecast_max = forecast[index]["temp"]["max"]
    forecast_humidity = forecast[index]["humidity"]
    forecast_wind = forecast[index]["wind_speed"]
    forecast_chance = forecast[index]["pop"]
    forecast_description = forecast[index]["weather"][0]["description"]
    forecast_icon = forecast[index]["weather"][0]["icon"]
    forecast_min = forecast[index]["temp"]["min"]
    forecast_max = forecast[index]["temp"]["max"]
    forecast_min_text = ("%dF Lo" % forecast_min)
    forecast_max_text = ("%dF Hi" % forecast_max)
    forecast_hum_text = ("%d%% humidity" % forecast_humidity)
    forecast_wind_text = str(forecast_wind) + " mph"
    Myforecastday = time.localtime()[6]
    Myforecastday = (Myforecastday + index) % 7
    Foreday = DAYS[Myforecastday]
    myforecaststring = (Foreday + " " + forecast_description + " " + forecast_min_text + " " +
        forecast_max_text + " " + forecast_hum_text + " " + forecast_wind_text)

    scroll_my_text(myforecaststring)

    # Select color for title text
    color_index = randrange(0, len(colors))

    # Set the title text color
    matrixportal.set_text_color(colors[color_index], 1)

    # Set the title text
    # matrixportal.set_text(forecast_description, 1)


refresh_time = None
forecast_days = 0
prv_hour = 0
changeminute = 0
Mymin = 0
mydrift = None
Myleftover = 0
while True:
    if (not refresh_time) or (time.monotonic() - refresh_time) > 900:
        try:
            print("obtaining time from adafruit.io server...")
            matrixportal.get_local_time()
            refresh_time = time.monotonic()
            changeminute = time.monotonic()
        except RuntimeError as e:
            print("Unable to obtain time from Adafruit IO, retrying - ", e)
            continue

    if time.localtime()[3] != prv_hour:
        print("New Hour, fetching new data...")
        # Fetch and store guide info response
        weather_data = matrixportal.network.fetch(DATA_SOURCE)
        Mymonth = time.localtime()[1]
        Myyear = time.localtime()[0]
        Myday = time.localtime()[2]
        Mymin = time.localtime()[4]
        Myweekday = time.localtime()[6]
        prv_hour = time.localtime()[3]
        resetmytime()
        
    # Cycle through guides retrieved
    if forecast_days < DISPLAY_NUM_DAYS:
        # print(forecast_days)
        get_forecast_info(forecast_days)
        # Scroll the scrollable text block
        matrixportal.scroll_text(SCROLL_DELAY)
        forecast_days += 1
    else:
        forecast_days = 0
    # So all of this below is so that I don't have to keep pinging the time on adafruit    
    if (time.monotonic() - changeminute) > 60:
        mydrift = time.monotonic() - changeminute
        mytimer = math.modf(mydrift/60)
        Mymin += math.floor(mytimer[1])
        Myleftover += mytimer[0] * 60
        print("add another minute")
               
        if Myleftover > 60:
            Mymin += 1
            Myleftover = 0
            print("clearing leftovers")

        changeminute = time.monotonic()
        resetmytime()
    time.sleep(0.05)

Credits

Kelly Sprayberry
3 projects • 6 followers
Contact

Comments

Please log in or sign up to comment.