What to Wear? eInk Weather Display

Hello, and happy new year! It’s been awhile since I’ve posted, but I did manage to work on a few projects over the holiday break that I’d love to share. With today’s post we’ll discuss a home project, making a “what to wear today” display for my kids.

weather eink display

The eInk display solves a problem where our kids may not have the information needed to dress properly on the way to school. I worked with the kids to design the display interface, which was a fun exercise in application design. It presented a neat opportunity to show the kids what I actually do with my job, and having a project with a small feature set, quick turn around time, and visual output kept them really engaged.

For the project I’m using a Raspberry Pi Zero 2 W, which is one of the smallest form factors (other than a Pico). I decided to go with the Zero this time around to avoid any sort of memory limit that is present on the Pico, which only has about 2 megabytes of RAM available for your application running MicroPython. Hooked up to the RPi Zero is a Waveshare 400x300 eInk display, which comes with its own set of python libraries to help you easily display information on the screen.

back of frame

The Design

Once we discussed the initial idea, I worked with the kids to sketch out a few requirements. The problem we’re trying to solve was helping them decide what to wear when they leave for school, so we first discussed all the different alerts that could be possible.

- really cold; wear ski pants and winter gear
- cold; toque and mitts
- kinda cold; jacket or sweater
- rainy; rain jacket & rubber boots
- warm; tshirt
- really warm; shorts

From here we discussed what those temperature ranges might look like, and also a few other things we might want to show (i.e. plugging in the cars at night, having to shovel). Once we had an idea of what we needed to show, we worked together on what we wanted the screen to look like.

wireframe 1

wireframe 2

After figuring out the general layout (first image), we decided what information to show (second image). Figuring out the sizes as well helped with the next step, where I had the kids draw the images we’d use for the display to show them what to wear.

status images

They had originally drawn them in pencil, but those scanned images weren’t showing up well on the black & white display, so I had them go back over the drawings with marker.

We also decided that the information was only really relevant at certain times of the day - when they were heading to school, what lunch recess might look like, the walk home, and a few other key times (i.e. heading out for activities after school, the evening when we were going to bed and potentially plugging in cars).

Weather API

While they were drawing I started writing some python code to integrate with the OpenWeather OneCall API. It’s a free API (up to a certain # of calls) that would give us all the information we needed in one large JSON object.

def getWeatherData():
    response = requests.get("https://api.openweathermap.org/data/3.0/onecall?lat=50&lon=-104&units=metric&exclude=minutely,daily&appid={appid}}")
    return response.json()

This allowed us to specify what lat & long we wanted the weather for and the specific pieces of information we were querying. The API call returns a large weather object shaped something like this:

{
    "lat": 50,
    "lon": -104,
    "current": {
        "dt": 1735620059,
        "sunrise": 1735570780,
        "sunset": 1735599793,
        "temp": -7.01,
        "feels_like": -14.01,
        "pressure": 1026,
        "humidity": 79,
        "dew_point": -9.7,
        "uvi": 0,
        "clouds": 100,
        "visibility": 10000,
        "wind_speed": 7.72,
        "wind_deg": 310,
        "weather": [
            {
                "id": 804,
                "main": "Clouds",
                "description": "overcast clouds",
                "icon": "04n"
            }
        ]
    },
    "hourly": [
        {
            "dt": 1735617600,
            "temp": -8.31,
            "feels_like": -15.31,
            "pressure": 1026,
            "humidity": 83,
            "dew_point": -10.42,
            "uvi": 0,
            "clouds": 99,
            "visibility": 1430,
            "wind_speed": 5.5,
            "wind_deg": 295,
            "wind_gust": 11.62,
            "weather": [
                {
                    "id": 804,
                    "main": "Clouds",
                    "description": "overcast clouds",
                    "icon": "04n"
                }
            ],
            "pop": 0
        },
        //...
    ]
}

From there it was a simple matter of parsing out the current weather, and the specific hourly blocks we were interested in:

# hours = [8, 12, 16, 18, 22]
def findNextHours(hourlyData, hours):
    hourBlocks = []
    for hour in hourlyData:
        blockTime = datetime.fromtimestamp(hour['dt'])
        if(blockTime.hour in hours):
            hourBlocks.append(hour)
            if(len(hourBlocks) == 3):
                return hourBlocks

This method gives us a quick way of parsing out the next 3 hour blocks we want to display on the clock.

Drawing the Interface

This isn’t much different from my prior eink project; the interface was just a matter of drawing on an in-memory canvas. Using an ImageDraw canvas based on the size of the eInk display, we used methods like .text((x,y), "string", font, fill) to position the information around the display.

One of the differences from previous approaches was loading those images scanned from the drawings my kids made. Using the Python Image Library, we load the specific image required into memory and then “paste” it into the image that the in-memory canvas is based on.

newimage = Image.open(os.path.join(picdir, imagefile))
HBlackimage.paste(newimage.resize((130, 210)), ((blockIndex * blockWidth), 70))

Once we’re done populating that image, we push it to the eInk display through the python library provided by Waveshare, sleep the display controller, and then wait for 60 seconds! (because we’re showing the current time)