Maker.io main logo

itsaSNAP Daily Weather Forecast Board

2025-01-24 | By Adafruit Industries

License: See Original Project LED Matrix

Courtesy of Adafruit

Guide by Trevor Beaton

Overview

weather_1

You can build a wonderful weather display using an Adafruit Matrix ‎Portal S3 and a 64x32 RGB LED Matrix. Using CircuitPython, you can ‎create a display that shows the current temperature and weather ‎conditions using custom BMP graphics. The weather displayed is the ‎same as your iPhone's weather so you don't need a separate ‎‎(paid/subscription) weather service and no matter where you live, it ‎will have the exact weather for your location.‎

The project uses Adafruit IO to store weather data, itsaSNAP to send ‎weather data to Adafruit IO from your iOS device, and Apple ‎shortcuts to automate itsaSNAP functions. ‎

You'll need to use the Matrix Portal S3 for this project to work, will not ‎work with the Matrix Portal M4!‎

itsaSNAP for iOS

itsaSNAP is a simple iOS app designed for exploring Adafruit IO. It ‎allows you to send data to your Adafruit IO feeds. You can also link it ‎to control or monitor your internet-connected projects. This lets you ‎control and check Adafruit devices from your phone, anywhere. ‎

It also allows us use of Apple's Shortcuts app to create a code-free ‎automation from your iOS device.‎

shortcuts_2

This project works with Apple devices. There is no Android app at this ‎time.‎

Parts

The following products and parts are required to complete this ‎project:‎

Optional:‎

Text editor powered by tinymce.‎

Get Started with Adafruit IO

Adafruit IO is integrated with your adafruit.com account so you don't ‎need to create yet another online account! You need an Adafruit ‎account to use Adafruit IO because to make sure the data you ‎upload is available to only you (unless you decide to publish your ‎data).‎

I have an Adafruit.com Account ‎already

If you already have an Adafruit account, then you already have ‎access to Adafruit IO. It doesn't matter how you signed up; your ‎account will make all three available.‎

To access Adafruit IO, simply visit https://io.adafruit.com to start ‎streaming, logging, and interacting with your data.‎

Create an Adafruit Account (for ‎Adafruit IO)‎

An Adafruit account makes Adafruit content and services available ‎to you in one place. Your account provides access to the Adafruit ‎shop, the Adafruit Learning System, and Adafruit IO. This means only ‎one account, one username, and one password are necessary to ‎engage with the content and services that Adafruit offers.‎

If you do not have an Adafruit account, signing up for a new Adafruit ‎account only takes a couple of steps.‎

Begin by visiting https://accounts.adafruit.com.‎

Click the Sign Up button under the "Need An Adafruit Account?" ‎title, below the Sign In section.‎

signup_3

This will take you to the Sign Up page.‎

Fill in the requested information and click the Create Account ‎button.‎

create account button

For example, to begin working with Adafruit IO, click the IO ‎link between the Forum and LIVE! Links. ‎

That's all there is to creating a new Adafruit account and navigating ‎to Adafruit IO.‎

Text editor powered by tinymce.‎

Create an Adafruit IO Feed

Adafruit IO's main feature is creating feeds to write or read data in a ‎centralized place. In this project, you will create an Adafruit IO feed ‎to send and read weather data to.‎

In a web browser, navigate to io.adafruit.com/feeds and click "+ New ‎Feed"

seekwill feeds

Give your new feed a name. The description is optional. ‎Click Create to create the new feed.‎

create a new feed

Under My Feeds, you should see the weather_feed you created. ‎Take note of your feed key, which is located here; you will need it ‎later.

myfeeds_7

Text editor powered by tinymce.‎

Download the ItsaSnap by Adafruit App

This section will guide you through downloading and installing the ‎ItsaSnap by Adafruit app.‎

Download and Install ItsaSnap

To install and download ItsaSnap for your iOS device,‎

‎1.‎ Open the App Store.
‎2.‎ Tap on the "Search" icon at the bottom of the screen.‎
‎3.‎ Type "ItsaSnap by Adafruit" or "ItsaSnap" in the search bar ‎and tap "Search".
‎4.‎ Locate the ItsaSnap app in the search results and tap on it

download_8

5. Tap the "Get" button to download and install the app on your ‎device. ‎

You may be prompted to enter your Apple ID password or use Face ‎ID/Touch ID to confirm the installation.

prompt_9

After you have downloaded and installed ItsaSnap, open the app.‎

itsasnap app

You will need to enter your Adafruit username and Adafruit IO ‎Key (which is different from your Adafruit account password).‎

Your Adafruit IO key is a long string of letters and numbers. To make ‎it easier to add to the app, we've also included a QR code scanner ‎that allows you to easily copy the Adafruit IO Key from the Adafruit ‎IO website to the app.‎

enter_11

On the ItaSnap app, the QR code scanner is located below the ‎Adafruit IO Key and above the login button. To access it, press the ‎‎'Scan QR code for IO Key' button. This will open the QR code ‎scanner.‎

Scan here

To find the QR code for your Adafruit IO account, navigate go to the ‎overview page. Once there, click the yellow button with a key in the ‎center (it's next to the "New Device" button) to reveal your Adafruit ‎IO Key.

code_13

After clicking it, a window with your information will appear. Then, ‎find the QR code and scan it, and log in.‎

IO key

Text editor powered by tinymce.‎

Install CircuitPython

CircuitPython is a derivative of MicroPython designed to simplify ‎experimentation and education on low-cost microcontrollers. It ‎makes it easier than ever to get prototyping by requiring no upfront ‎desktop software downloads. Simply copy and edit files on ‎the CIRCUITPY drive to iterate.‎

Set up CircuitPython Quick Start!‎

Follow this quick step-by-step for super-fast Python power :)‎

The MatrixPortal S3 requires CircuitPython 8.2.1 or later.‎

Download the latest version of CircuitPython for this board via ‎circuitpython.org

Further Information

For more detailed info on installing CircuitPython, check ‎out Installing CircuitPython.‎

Click the link above and download the latest UF2 file.

Download and save it to your desktop (or wherever is handy).‎

installing circuitpython

Plug your MatrixPortal S3 into your computer using a known-good ‎USB cable.‎

A lot of people end up using charge-only USB cables and it is very ‎frustrating! So, make sure you have a USB cable you know is good ‎for data sync.‎

Click the Reset button (indicated by the green arrow) on your board. ‎When you see the NeoPixel RGB LED (indicated by the magenta ‎arrow) turn purple, press it again. At that point, the NeoPixel should ‎turn green. If it turns red, check the USB cable, try another USB port, ‎etc.‎

If double-clicking doesn't work the first time, try again. Sometimes it ‎can take a few tries to get the rhythm right!‎

board_16

You will see a new disk drive appear called MATRXS3BOOT.‎

Drag the adafruit_circuitpython_etc.uf2 file over to MATRXS3BOOT.‎

MATRXS3BOOT

The LED will flash. Then, the MATRXS3BOOT drive will disappear, ‎and a new disk drive called CIRCUITPY will appear.‎

That's it, you're done! :)‎

circuitpy

Text editor powered by tinymce.‎

Setting Up Your Credentials

To make network inquiries using your MatrixPortal, you'll need to ‎provide your WiFi and Adafruit IO credentials in a settings.toml file.‎

Plug your Matrix Portal S3 into your computer via a known good data ‎‎+ power USB cable. Your board should show up as a thumb drive in ‎your File Explorer / Finder (depending on your operating system) ‎named CIRCUITPY.‎

Create a file with the name settings.toml in the root directory of ‎the CIRCUITPY drive.‎

Add the following below:‎

The file should contain the ‎keys CIRCUITPY_WIFI_SSID, CIRCUITPY_WIFI_PASSWORD, CIRCUITPY_WEB_API_PASSWORD, ‎AIO_USERNAME, and AIO_KEY. ‎

Once these are defined, CircuitPython will automatically connect to ‎the network and start the webserver used for the workflow.‎

The web server is on port 80 unless overridden ‎by CIRCUITPY_WEB_API_PORT. It also enables MDNS.‎

Here is an example settings.toml:‎

‎Download File

Copy Code
# To auto-connect to WiFi
CIRCUITPY_WIFI_SSID="YOUR-WIFI-NETWORK-NAME"
CIRCUITPY_WIFI_PASSWORD="YOUR-WIFI-NETWORK-PASSWORD"

# For Adafruit IO
AIO_USERNAME="YOUR-USERNAME"
AIO_KEY="YOUR-AO-KEY"

# To enable modifying files from the web. Change this too!
# Leave the User field blank in the browser.
CIRCUITPY_WEB_API_PASSWORD="passw0rd"

CIRCUITPY_WEB_API_PORT=80

Text editor powered by tinymce.‎

Code with CircuitPython

Once you've finished setting up your Matrix Portal S3 with ‎CircuitPython and have connected to the Internet, you can download ‎the Project Bundle to access the code and necessary libraries.‎

To do this, click the Download Project Bundle button in the window ‎below. It will download to your computer as a zipped folder.‎

Download Project Bundle

Copy Code
# SPDX-FileCopyrightText: 2024 Trevor Beaton for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import time
import terminalio
from adafruit_matrixportal.matrixportal import MatrixPortal

# --- Display setup ---
matrixportal = MatrixPortal(width=64, height=32, bit_depth=6, debug=True)

# Create a label for the temperature
matrixportal.add_text(
    text_font=terminalio.FONT,
    text_position=(33, 24),  # Positioned on the right side, near the bottom
    scrolling=False,
)

# Create a label for the weather condition
matrixportal.add_text(
    text_font=terminalio.FONT,
    text_position=(33, 8),  # Positioned on the right side, above the temperature
    scrolling=False,
)

# Dictionary mapping weather conditions to BMP filenames
WEATHER_IMAGES = {
    "Sunny": "images/sunny.bmp",
    "Clear": "images/moon.bmp",
    "Cldy": "images/cloudy.bmp",  # Updated to use shortened version
    "Drizzle": "images/rain.bmp",
    "Rainy": "images/cloudy.bmp",
    "Heavy rain": "images/rain.bmp",
    "TStorms": "images/thunder.bmp",
    "Sun showers": "images/rain.bmp",
    "Snow": "images/snow.bmp",
}

# Update this to your weather feed
WEATHER_FEED = "weather-feed"
UPDATE_DELAY = 1800  # 30 minutes

def get_last_data(feed_key):
    try:
        data = matrixportal.get_io_data(feed_key)
        if data:
            return data[0]["value"]
    except (KeyError, IndexError) as e:
        print(f"Error fetching data from feed {feed_key}: {e}")
    return None

def is_daytime(hour):
    return 5 <= hour < 18  # True if between 5:00 AM and 5:59 PM

def clean_condition(condition, is_day):
    condition = condition.replace("Mostly ", "").replace("Partly ", "")
    condition_mapping = {
        "Cloudy": "Cldy",  # Added shortened version of Cloudy
        "Drizzle or light rain": "Rainy",
        "Heavy rain": "Rainy",
        "Isolated thunderstorms": "TStorms",
        "Sun showers": "Rainy",
        "Scattered thunderstorms": "TStorms",
        "Strong storms": "TStorms",
        "Light snow": "Snow",
        "Heavy snow": "Snow",
    }
    if condition == "Sunny" and not is_day:
        return "Clear"
    return condition_mapping.get(condition, condition)

def parse_weather_data(data):
    try:
        _, weather_info = data.split(" at ")
        time_str, weather_data = weather_info.split(" ", 1)
        hour = int(time_str.split(":")[0])
        if "PM" in time_str and hour != 12:
            hour += 12
        elif "AM" in time_str and hour == 12:
            hour = 0
        temperature, condition = weather_data.split(" and ")
        return hour, temperature, condition
    except ValueError as e:
        print(f"Error parsing weather data: {e}")
        return None, None, None

def update_display():
    weather_data = get_last_data(WEATHER_FEED)
    if weather_data:
        hour, temperature, condition = parse_weather_data(weather_data)
        if hour is not None and temperature is not None and condition is not None:
            is_day = is_daytime(hour)
            current_condition = clean_condition(condition, is_day)

            matrixportal.set_text(temperature, 0)
            matrixportal.set_text(current_condition, 1)

            # Determine which image to show based on condition and time
            if current_condition == "Sunny" and is_day:
                image_key = "images/sunny.bmp"
            elif current_condition == "Clear" or (current_condition == "Sunny" and not is_day):
                image_key = "images/moon.bmp"
            else:
                image_key = WEATHER_IMAGES.get(current_condition, "images/sunny.bmp")

            try:
                matrixportal.set_background(image_key)
            except OSError as e:
                print(f"Error loading image for {current_condition}: {e}")
        else:
            print(f"Failed to parse weather data: {weather_data}")
            matrixportal.set_text("Error", 0)
            matrixportal.set_text("", 1)
    else:
        print("Failed to retrieve data from feed")
        matrixportal.set_text("No Data", 0)
        matrixportal.set_text("", 1)

last_update = time.monotonic()
update_display()

# Main loop
while True:
    current_time = time.monotonic()
    if current_time - last_update > UPDATE_DELAY:
        update_display()
        last_update = current_time

    time.sleep(1)  # Sleep for 1 second

View on GitHub

Upload the Code and Libraries

After downloading the Project Bundle, plug your Matrix Portal ‎S3 into the computer's USB port with a known good USB data + ‎power cable. You should see a new flash drive appear in the ‎computer's File Explorer or Finder (depending on your operating ‎system) called CIRCUITPY. Unzip the folder and copy the following ‎items to the CIRCUITPY drive.‎

  • lib folder

  • Images folder

  • code.py

The CIRCUITPY drive should look like this after copying ‎the lib folder, images folder, and the code.py file.‎

drive_19

Get the Latest Data

get_last_data retrieves the most recent data from an Adafruit IO feed. ‎If successful, it returns a value or None if there's an error or no data ‎available.‎

‎Download File

Copy Code
def get_last_data(feed_key):
    try:
        data = matrixportal.get_io_data(feed_key)
        if data:
            return data[0]["value"]
    except (KeyError, IndexError) as e:
        print(f"Error fetching data from feed {feed_key}: {e}")
    return None

Daytime Checker

This function determines if it's daytime based on the given hour. It ‎considers daytime to be between 5:00 AM and 5:59 PM, but you can ‎update it to fit your needs. ‎

Download File

Copy Code
def is_daytime(hour):
    return 5 <= hour < 18  # True if between 5:00 AM and 5:59 PM

Clean Weather Condition

This function simplifies the weather condition descriptions for the ‎display since there is limited space. It also adjusts conditions based ‎on whether it's day or night, such as changing "Sunny" to "Clear" at ‎night.‎

Download File

Copy Code
def clean_condition(condition, is_day):
    condition = condition.replace("Mostly ", "").replace("Partly ", "")
    condition_mapping = {
        "Cloudy": "Cldy",  # Added shortened version of Cloudy
        "Drizzle or light rain": "Rainy",
        "Heavy rain": "Rainy",
        "Isolated thunderstorms": "TStorms",
        "Sun showers": "Rainy",
        "Scattered thunderstorms": "TStorms",
        "Strong storms": "TStorms",
        "Light snow": "Snow",
        "Heavy snow": "Snow",
    }
    if condition == "Sunny" and not is_day:
        return "Clear"
    return condition_mapping.get(condition, condition)

Parse Weather Data

This function extracts the hour, temperature, and weather conditions ‎from the weather data string found in Adafruit IO. It also handles ‎time conversion and splits the data into usable components.‎

Download File

Copy Code
def parse_weather_data(data):
    try:
        _, weather_info = data.split(" at ")
        time_str, weather_data = weather_info.split(" ", 1)
        hour = int(time_str.split(":")[0])
        if "PM" in time_str and hour != 12:
            hour += 12
        elif "AM" in time_str and hour == 12:
            hour = 0
        temperature, condition = weather_data.split(" and ")
        return hour, temperature, condition
    except ValueError as e:
        print(f"Error parsing weather data: {e}")
        return None, None, None

Update Display

Gets the latest weather data, processes it, and updates the LED ‎matrix display. It sets the temperature, weather condition text, and ‎selects the weather icon to display.‎

Download File

Copy Code
def update_display():
    weather_data = get_last_data(WEATHER_FEED)
    if weather_data:
        hour, temperature, condition = parse_weather_data(weather_data)
        if hour is not None and temperature is not None and condition is not None:
            is_day = is_daytime(hour)
            current_condition = clean_condition(condition, is_day)

            matrixportal.set_text(temperature, 0)
            matrixportal.set_text(current_condition, 1)

            # Determine which image to show based on condition and time
            if current_condition == "Sunny" and is_day:
                image_key = "images/sunny.bmp"
            elif current_condition == "Clear" or (current_condition == "Sunny" and not is_day):
                image_key = "images/moon.bmp"
            else:
                image_key = WEATHER_IMAGES.get(current_condition, "images/sunny.bmp")

            try:
                matrixportal.set_background(image_key)
            except OSError as e:
                print(f"Error loading image for {current_condition}: {e}")
        else:
            print(f"Failed to parse weather data: {weather_data}")
            matrixportal.set_text("Error", 0)
            matrixportal.set_text("", 1)
    else:
        print("Failed to retrieve data from feed")
        matrixportal.set_text("No Data", 0)
        matrixportal.set_text("", 1)

The Main Loop

The Main loop runs the program, checking if it's time to update the ‎display. It calls update_display() every 30 minutes to refresh the ‎weather information.‎

Download File

Copy Code
current_time = time.monotonic()
    if current_time - last_update > UPDATE_DELAY:
        update_display()
        last_update = current_time

    time.sleep(1)  # Sleep for 1 second

Text editor powered by tinymce.‎

LED Matrix Diffuser

LED Diffusion Acrylic

You can add an LED diffusion acrylic faceplate to your LED matrix ‎display. (Pictured here with the ON AIR project.)‎

This can help protect the LEDs as well as enhance the look of the ‎sign both indoors and out by reducing glare and specular highlights ‎of the plastic matrix grid.‎

matrix_20

Measure and Cut the Plastic

You can use the sign to measure and mark cut lines on the paper ‎backing of the acrylic sheet.‎

Then, use a tablesaw or bandsaw with a fine-toothed blade and a ‎guide or sled to make the cuts.‎

Note: it is possible to score and snap acrylic, but it can be very tricky ‎to get an even snap without proper clamping.‎

measure_21

measure_22

measure_23

measure_24

measure_25

Peel away the paper backing from both sides and set the acrylic ‎onto your matrix display with the matte finished side facing out.‎

peel_26

Uglu Dashes

The best method we've found for adhering acrylic to the matrix ‎display is to use Uglu Dashes clear adhesive rectangles from Pro ‎Tapes. They are incredibly strong (although can be removed if ‎necessary), easy to apply, and are invisible once attached.‎

Use one at each corner and one each at the halfway point of the long ‎edges, then press the acrylic and matrix panel together for about 20 ‎seconds.‎

dash_27

dash_28

dash_30

Here you can see the impact of using the diffusion acrylic. (Pictured ‎here with the ON AIR sign project.)‎

led_matrices_diffusionOnAir

Stand

A very simple and attractive way to display your matrix is with the ‎adjustable bent-wire stand.‎

stand_31

stand_32

stand_33

stand_34

stand_35

Alternately, you can use a frame, 3D printed brackets, tape, glue, or ‎even large binder clips to secure the acrylic to the sign and then ‎mount it on a wall, shelf, or display cabinet.‎

These mini-magnet feet can be used to stick the sign to a ferrous ‎surface.‎

Text editor powered by tinymce.‎

Creating the "itsaSNAP Weather Grabber" ‎shortcut

shortcut_36

Apple Shortcuts are only available in the latest version of itsaSNAP ‎on the Apple app store by Adafruit.‎

itsaSNAP includes several actions for the Apple Shortcuts App, ‎allowing you to integrate Adafruit IO functionality. This project ‎focuses on sending current location weather data from your iPhone ‎to an Adafruit IO feed. ‎

This step will demonstrate how to use itsaSNAP with Apple ‎Shortcuts to send a value to an Adafruit IO feed when the shortcut is ‎run. ‎

Open Apple Shortcuts on your iPhone or iPad. To create a new ‎shortcut, tap the "+" button.‎

open_37

Add an action

Tap "Add Action". Then, search for Current Weather.‎

action_38

Select the "Location" action, "Get Current Weather."

select_39

select_40

Tap on the keyboard bar. Then, search for itsaSNAP and select Send ‎Value.

tap_41

Additionally, I suggest changing the shortcut's name to something ‎unique like "itsaSNAP Forecast Grabber." ‎

Configure Action

Add your feed key and the value you want to send to your Feed ‎here. Tap the Value field and select Current Date and Weather ‎Condition from the keyboard bar (the keyboard bar is scrollable).‎

configure_42

configure_43

Now that your shortcut is assembled, try giving it a test run. Press ‎the Play button at the bottom of the screen. ‎

testrun_44

If all works well, you should see this message prompt, notifying you ‎that your current weather data and time have been sent to your ‎Adafruit IO Weather Feed.‎

message_45

Text editor powered by tinymce.‎

Setting up Apple Shortcuts Automation

To create a new automation, go to the automation screen and tap ‎the "+" button. ‎

new_46

Here you can select which types of triggers can initiate an action. For ‎now, we'll use "Time of Day" to set a time to schedule a time to run ‎our Apple Shortcut. ‎

Select "Time of Day" as the trigger for the automation.‎

select_47

Add the time of day here. I prefer to send this update at sunrise, have ‎it repeat daily, and run immediately (you will be notified whenever ‎the shortcut task is attempted).‎

Once you're all set - tap Done.

tap_48

In the My Shortcuts row, select the shortcut action you made earlier.

shortcuts_49

Upon selecting your Apple shortcut, your automation will be set. Be ‎sure to set your automation for any time you want. I've set my ‎shortcuts to run multiple times of the day.

auto_50

Text editor powered by tinymce.‎

Use

Check the Weather on your Matrix ‎Portal ‎

Plug the Matrix Portal S3 into USB-C power. The display should ‎change, reflecting the current temperature and condition from the ‎Weather feed.‎

If no value has been posted to this feed yet, your Matrix Portal screen ‎will display "Error".‎

There are multiple graphics that represent the conditions that might ‎occur. There is a graphic for cloudy, sunny, rainy, or snowy days and a ‎graphic for thunderstorms.‎

graphic_51

The Matrix Portal will attempt to fetch weather data every thirty ‎minutes. You can change it to the frequency you see fit.‎

Once you have followed these steps, you will have your own ‎automated weather display!‎

Text editor powered by tinymce.

制造商零件编号 5778
ADAFRUIT MATRIX PORTAL S3 CIRCUI
Adafruit Industries LLC
制造商零件编号 2279
64X32 RGB LED MATRIX - 3MM PITCH
Adafruit Industries LLC
制造商零件编号 5801
VERTICAL WALL POWER SUPPLY WITH
Adafruit Industries LLC
制造商零件编号 4474
CABLE A PLUG TO C PLUG 3'
Adafruit Industries LLC
Add all DigiKey Parts to Cart
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.