The public API that served the JSON data used by this guide is no longer active. It's an open source server project (Github linked below) that could be hosted elsewhere theoretically. But we are unaware of any active instances of the API server. This project will not work without an active server for the data. There is an update in the works to modify this project to pull JSON data directly from NASA. Check back soon if you're interested in the project.

Use your MagTag to show the current status of the James Webb telescope. NASA publishes this information to this official status page.

This GitHub project provides a server application that can parse the status page and return the current data as JSON data. We will fetch the data updates from this server so that it's in an easy format for CircuitPython to consume.

This project will fetch the data and display it on the E-Ink screen using displayio Labels then put the MagTag into deep sleep mode to conserve the battery. It will awaken to refresh the data once per hour, or once per day. Use the reset button any time to immediately refresh it.

Parts

The Adafruit MagTag combines the new ESP32-S2 wireless module and a 2.9" grayscale E-Ink display to make a low-power IoT display that can show data on its screen even when power...
$34.95
In Stock
The Adafruit MagTag combines the new ESP32-S2 wireless module and a 2.9" grayscale E-Ink display to make a low-power IoT display that can show data on its screen...
$44.95
In Stock
Here is the perfect kit with two faceplate options for your MagTag, including a vivid Red Arrow plate and a dreamy white Cloud plate. And of course, the mounting hardware is included,...
$5.95
In Stock
Got a glorious RGB Matrix project you want to mount and display in your workspace or home? If you have one of the matrix panels listed below, you'll need a pack of these...
$2.50
In Stock
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This...
$7.95
In Stock
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also made for USB C for our modernized breakout boards, Feathers, and...
$2.95
In Stock

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

Follow the steps to get CircuitPython installed on your MagTag.

Click the link above and download the latest .BIN and .UF2 file

(depending on how you program the ESP32S2 board you may need one or the other, might as well get both)

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

Plug your MagTag 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.

Option 1 - Load with UF2 Bootloader

This is by far the easiest way to load CircuitPython. However it requires your board has the UF2 bootloader installed. Some early boards do not (we hadn't written UF2 yet!) - in which case you can load using the built in ROM bootloader.

Still, try this first!

Try Launching UF2 Bootloader

Loading CircuitPython by drag-n-drop UF2 bootloader is the easier way and we recommend it. If you have a MagTag where the front of the board is black, your MagTag came with UF2 already on it.

Launch UF2 by double-clicking the Reset button (the one next to the USB C port). You may have to try a few times to get the timing right.

If the UF2 bootloader is installed, you will see a new disk drive appear called MAGTAGBOOT

Copy the UF2 file you downloaded at the first step of this tutorial onto the MAGTAGBOOT drive

If you're using Windows and you get an error at the end of the file copy that says Error from the file copy, Error 0x800701B1: A device which does not exist was specified. You can ignore this error, the bootloader sometimes disconnects without telling Windows, the install completed just fine and you can continue. If its really annoying, you can also upgrade the bootloader (the latest version of the UF2 bootloader fixes this warning)

Your board should auto-reset into CircuitPython, or you may need to press reset. A CIRCUITPY drive will appear. You're done! Go to the next pages.

Option 2 - Use esptool to load BIN file

If you have an original MagTag with while soldermask on the front, we didn't have UF2 written for the ESP32S2 yet so it will not come with the UF2 bootloader.

You can upload with esptool to the ROM (hardware) bootloader instead!

Follow the initial steps found in the Run esptool and check connection section of the ROM Bootloader page to verify your environment is set up, your board is successfully connected, and which port it's using.

In the final command to write a binary file to the board, replace the port with your port, and replace "firmware.bin" with the the file you downloaded above.

The output should look something like the output in the image.

Press reset to exit the bootloader.

Your CIRCUITPY drive should appear!

You're all set! Go to the next pages.

Option 3 - Use Chrome Browser To Upload BIN file

If for some reason you cannot get esptool to run, you can always try using the Chrome-browser version of esptool we have written. This is handy if you don't have Python on your computer, or something is really weird with your setup that makes esptool not run (which happens sometimes and isn't worth debugging!) You can follow along on the Web Serial ESPTool page and either load the UF2 bootloader and then come back to Option 1 on this page, or you can download the CircuitPython BIN file directly using the tool in the same manner as the bootloader.

One of the great things about the ESP32 is the built-in WiFi capabilities. This page covers the basics of getting connected using CircuitPython.

The first thing you need to do is update your code.py to the following. Click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the entire lib folder and the code.py file to your CIRCUITPY drive.

# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import ipaddress
import ssl
import wifi
import socketpool
import adafruit_requests

# URLs to fetch from
TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html"
JSON_QUOTES_URL = "https://www.adafruit.com/api/quotes.php"
JSON_STARS_URL = "https://api.github.com/repos/adafruit/circuitpython"

# Get wifi details and more from a secrets.py file
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

print("ESP32-S2 WebClient Test")

print("My MAC addr:", [hex(i) for i in wifi.radio.mac_address])

print("Available WiFi networks:")
for network in wifi.radio.start_scanning_networks():
    print("\t%s\t\tRSSI: %d\tChannel: %d" % (str(network.ssid, "utf-8"),
            network.rssi, network.channel))
wifi.radio.stop_scanning_networks()

print("Connecting to %s"%secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!"%secrets["ssid"])
print("My IP address is", wifi.radio.ipv4_address)

ipv4 = ipaddress.ip_address("8.8.4.4")
print("Ping google.com: %f ms" % (wifi.radio.ping(ipv4)*1000))

pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())

print("Fetching text from", TEXT_URL)
response = requests.get(TEXT_URL)
print("-" * 40)
print(response.text)
print("-" * 40)

print("Fetching json from", JSON_QUOTES_URL)
response = requests.get(JSON_QUOTES_URL)
print("-" * 40)
print(response.json())
print("-" * 40)

print()

print("Fetching and parsing json from", JSON_STARS_URL)
response = requests.get(JSON_STARS_URL)
print("-" * 40)
print("CircuitPython GitHub Stars", response.json()["stargazers_count"])
print("-" * 40)

print("done")

Your CIRCUITPY drive should resemble the following.

CIRCUITPY

To get connected, the next thing you need to do is update the secrets.py file.

Secrets File

We expect people to share tons of projects as they build CircuitPython WiFi widgets. What we want to avoid is people accidentally sharing their passwords or secret tokens and API keys. So, we designed all our examples to use a secrets.py file, that is on your CIRCUITPY drive, to hold secret/private/custom data. That way you can share your main project without worrying about accidentally sharing private stuff.

The initial secrets.py file on your CIRCUITPY drive should look like this:

# SPDX-FileCopyrightText: 2020 Adafruit Industries
#
# SPDX-License-Identifier: Unlicense

# This file is where you keep secret settings, passwords, and tokens!
# If you put them in the code you risk committing that info or sharing it

secrets = {
    'ssid' : 'home_wifi_network',
    'password' : 'wifi_password',
    'aio_username' : 'my_adafruit_io_username',
    'aio_key' : 'my_adafruit_io_key',
    'timezone' : "America/New_York", # http://worldtimeapi.org/timezones
    }

Inside is a Python dictionary named secrets with a line for each entry. Each entry has an entry name (say 'ssid') and then a colon to separate it from the entry key ('home_wifi_network') and finally a comma (,).

At a minimum you'll need to adjust the ssid and password for your local WiFi setup so do that now!

As you make projects you may need more tokens and keys, just add them one line at a time. See for example other tokens such as one for accessing GitHub or the Hackaday API. Other non-secret data like your timezone can also go here, just cause its called secrets doesn't mean you can't have general customization data in there!

For the correct time zone string, look at http://worldtimeapi.org/timezones and remember that if your city is not listed, look for a city in the same time zone, for example Boston, New York, Philadelphia, Washington DC, and Miami are all on the same time as New York.

Of course, don't share your secrets.py - keep that out of GitHub, Discord or other project-sharing sites.

Don't share your secrets.py file, it has your passwords and API keys in it!

If you connect to the serial console, you should see something like the following:

In order, the example code...

Checks the ESP32's MAC address.

print("My MAC addr:", [hex(i) for i in wifi.radio.mac_address])

Performs a scan of all access points and prints out the access point's name (SSID), signal strength (RSSI), and channel.

print("Avaliable WiFi networks:")
for network in wifi.radio.start_scanning_networks():
    print("\t%s\t\tRSSI: %d\tChannel: %d" % (str(network.ssid, "utf-8"),
            network.rssi, network.channel))
wifi.radio.stop_scanning_networks()

Connects to the access point you defined in the secrets.py file, prints out its local IP address, and attempts to ping google.com to check its network connectivity. 

print("Connecting to %s"%secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print(print("Connected to %s!"%secrets["ssid"]))
print("My IP address is", wifi.radio.ipv4_address)

ipv4 = ipaddress.ip_address("8.8.4.4")
print("Ping google.com: %f ms" % wifi.radio.ping(ipv4))

The code creates a socketpool using the wifi radio's available sockets. This is performed so we don't need to re-use sockets. Then, it initializes a a new instance of the requests interface - which makes getting data from the internet really really easy.

pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())

To read in plain-text from a web URL, call requests.get - you may pass in either a http, or a https url for SSL connectivity. 

print("Fetching text from", TEXT_URL)
response = requests.get(TEXT_URL)
print("-" * 40)
print(response.text)
print("-" * 40)

Requests can also display a JSON-formatted response from a web URL using a call to requests.get

print("Fetching json from", JSON_QUOTES_URL)
response = requests.get(JSON_QUOTES_URL)
print("-" * 40)
print(response.json())
print("-" * 40)

Finally, you can fetch and parse a JSON URL using requests.get. This code snippet obtains the stargazers_count field from a call to the GitHub API.

print("Fetching and parsing json from", JSON_STARS_URL)
response = requests.get(JSON_STARS_URL)
print("-" * 40)
print("CircuitPython GitHub Stars", response.json()["stargazers_count"])
print("-" * 40)

OK you now have your ESP32 board set up with a proper secrets.py file and can connect over the Internet. If not, check that your secrets.py file has the right ssid and password and retrace your steps until you get the Internet connectivity working!

Plug your MagTag into your computer via a known good USB C power and data cable. The MagTag should show up in your computer File Explorer/Finder (depending on your operating system) ad a flash drive named CIRCUITPY.

Download the project files with the button below. Unzip and copy/paste the code.py, lib files and font files to your CIRCUITPY drive.

After copying your drive should look like this. It can contain other files as well, but must contain these at a minimum:

Project

Code

The program code is shown below:

# SPDX-FileCopyrightText: 2022 Tim C, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
"""
MagTag status display for James Webb Telescope
"""
import time
import json
import ssl
import board
import displayio
import terminalio
import supervisor
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import bitmap_label
import wifi
import socketpool
import alarm
import adafruit_requests as requests

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

# Update once per hour
SLEEP_TIME = 60 * 60  # seconds

# Update once per day
# SLEEP_TIME = 60 * 60 * 24 # seconds

# URL to fetch the data from
JSON_GET_URL = (
    "https://jwst.nasa.gov/content/webbLaunch/flightCurrentState2.0.json?unique={}"
)

# Whether to fetch live data or use cached
TEST_RUN = True
# Cached data, helpful when developing interface
# pylint: disable=line-too-long
FAKE_DATA = '{"currentState": {"STEPS": "MirrorAlignSteps, TempBlurb, MirrorBlurb, ArraysForPlots, Plots", "launchDateTimeString": "2021-12-25T12:20Z", "currentDeployTableIndex": 34, "tempWarmSide1C": 37.1, "tempWarmSide2C": 12.0, "tempCoolSide1C": -229.1, "tempCoolSide2C": -233.0, "---INST TEMPS IN KELVIN----": "", "tempInstNirCamK": 42.7, "tempInstNirSpecK": 39.9, "tempInstFgsNirissK": 47.3, "tempInstMiriK": 108.7, "tempInstFsmK": 37.1, "tempsShow": true, "last": ""}}'

# Background Color for the label texts
LBL_BACKGROUND = 0x444444


def try_refresh():
    """Attempt to refresh the display. Catch 'refresh too soon' error
    and retry after waiting 10 seconds.
    """
    try:
        board.DISPLAY.refresh()
    except RuntimeError as too_soon_error:
        # catch refresh too soon
        print(too_soon_error)
        print("waiting before retry refresh()")
        time.sleep(10)
        board.DISPLAY.refresh()


# Get the display object
display = board.DISPLAY

if not TEST_RUN:
    print("Connecting to AP...")
    try:
        # wifi connect
        wifi.radio.connect(secrets["ssid"], secrets["password"])

        # Create Socket, initialize requests
        socket = socketpool.SocketPool(wifi.radio)
        requests = requests.Session(socket, ssl.create_default_context())
    except OSError:
        print("Failed to connect to AP. Rebooting in 3 seconds...")
        time.sleep(3)
        supervisor.reload()


def get_time_str():
    return str(time.monotonic()).replace(".", "")


def make_name_text(text, anchor_point, anchored_position, bg_color=LBL_BACKGROUND):
    """
    Create label object for labeling data values.
    It will get a background color box and appropriate padding.

    :param text: Text to show
    :param anchor_point: location anchor_point
    :param anchored_position: location anchored_position
    :return bitmap_label.Label: the Label object
    """
    return bitmap_label.Label(
        font,
        text=text,
        anchor_point=anchor_point,
        anchored_position=anchored_position,
        background_color=bg_color,
        padding_left=4,
        padding_right=4,
        padding_bottom=3,
        padding_top=3,
        line_spacing=1.0,
    )


def make_value_text(
    anchor_point,
    anchored_position,
    custom_font=True,
    bg_color=0x000000,
    font_color=0xFFFFF,
):
    """
    Create label object for showing data values.

    :param anchor_point: location anchor_point
    :param anchored_position: location anchored_position
    :param bool custom_font: weather to use the custom font or system font
    :return bitmap_label.Label: the Label object
    """
    if custom_font:
        _font = font
    else:
        _font = terminalio.FONT
    return bitmap_label.Label(
        _font,
        text="",
        anchor_point=anchor_point,
        anchored_position=anchored_position,
        line_spacing=1.0,
        padding_top=3,
        background_color=bg_color,
        color=font_color,
        padding_right=4,
        padding_left=4,
        padding_bottom=4,
    )


# main_group to show things
main_group = displayio.Group()

# initialize custom font
font = bitmap_font.load_font("fonts/LeagueSpartan-Light.bdf")

# value text initializations

# top left. Hot side | Cold side temperature values
top_left_value = make_value_text(
    anchor_point=(0, 0),
    anchored_position=(0, 6),
    bg_color=0xBBBBBB,
    font_color=0x000000,
)

# top right. Instrument temperature values
top_right_value = make_value_text(
    anchor_point=(1.0, 0),
    anchored_position=(display.width - 6, 6),
)

# bottom left timestamp
timestamp_val = make_value_text(
    anchor_point=(0, 1.0), anchored_position=(0, display.height - 6), custom_font=False
)

main_group.append(top_left_value)
main_group.append(top_right_value)

main_group.append(timestamp_val)

# label text initialization

# middle left. Hot side | Cold side temps label
middle_left_name = make_name_text(
    text="Temperature", anchor_point=(0.0, 0), anchored_position=(0, 51)
)

# center. Instrument temp labels
inst_temp_labels = "NIRCam Bench\nNIRSpec Bench\nFGS Bench\nMIRI Bench\nFSM"
top_center_name = make_name_text(
    text=inst_temp_labels,
    anchor_point=(1.0, 0.0),
    anchored_position=(top_right_value.x - 2, 6),
)

main_group.append(middle_left_name)
main_group.append(top_center_name)

if not TEST_RUN:
    try:
        print("Fetching JSON data from {}".format(JSON_GET_URL.format(get_time_str())))
        response = requests.get(JSON_GET_URL.format(get_time_str()), timeout=30)
    except (RuntimeError, OSError) as e:
        print(e)
        print("Failed GET request. Rebooting in 3 seconds...")
        time.sleep(3)
        supervisor.reload()

    print("-" * 40)
    print(response.headers)
    json_data = response.json()
    _time_parts = response.headers["date"].split(" ")
    _time_str = "{}\n{}".format(" ".join(_time_parts[:4]), " ".join(_time_parts[4:]))

    print("JSON Response: ", json_data)
    print("-" * 40)
    response.close()
else:
    json_data = json.loads(FAKE_DATA)
    _time_parts = ["Mon,", "28", "Feb", "2022", "17:17:54 GMT"]
    _time_str = "{}\n{}".format(" ".join(_time_parts[:4]), " ".join(_time_parts[4:]))

# Date/Time
timestamp_val.text = _time_str

# instrument temps
top_right_value.text = "{}K\n{}K\n{}K\n{}K\n{}K".format(
    json_data["currentState"]["tempInstNirCamK"],
    json_data["currentState"]["tempInstNirSpecK"],
    json_data["currentState"]["tempInstFgsNirissK"],
    json_data["currentState"]["tempInstMiriK"],
    json_data["currentState"]["tempInstFsmK"],
)

# hot side | cold site temps
top_left_value.text = "{}C | {}C\n{}C | {}C".format(
    json_data["currentState"]["tempWarmSide1C"],
    json_data["currentState"]["tempCoolSide1C"],
    json_data["currentState"]["tempWarmSide2C"],
    json_data["currentState"]["tempCoolSide2C"],
)

# Set the name position after the instrument temps are in the value
# label, so that it's x will be in the proper position.
top_center_name.anchored_position = (top_right_value.x - 2, 6)

# show the group
display.show(main_group)

# refresh display
try_refresh()

# Create a an alarm that will trigger to wake us up
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + SLEEP_TIME)

# Exit the program, and then deep sleep until the alarm wakes us.
alarm.exit_and_deep_sleep_until_alarms(time_alarm)
# Does not return, so we never get here.

Run Once Then Sleep

This project code does not contain a main loop section. Instead it's written such that it will run once, fetch the data, show it on the eInk display and then put the MagTag into deep sleep for either one hour or one day. If there is any problem during the data fetching it will restart the MagTag after a few seconds to try everything once again.

When the MagTag wakes up from deep sleep, it will execute the script again from the beginning. For more information about sleeping see this guide: Deep Sleep with CircuitPython.

Fetching Data

To fetch the current information about the Webb Telescope we use the adafruit_requests library. The script will make an HTTP GET request and receive back a string that contains the current JSON data.

Displaying the Data

The data is displayed with displayio using Labels. The Labels containing units and other information are given a background color to contrast them from the Labels containing the data. All Labels are placed using anchored positioning. For more information about Labels and positioning see this guide: CircuitPython Display_Text Library

Refresh Carefully

The EInk display on the MagTag has a limit to how quickly it can be updated multiple times in succession. If an attempt to refresh too soon occurs the device will raise an exception. The project code guards against this by catching the error and trying again after waiting a suitable length of time.

Further Detail

The project source code is commented thoroughly to explain what each portion of the code does. Read through the code and comments to gain more insight into how it operates.

# SPDX-FileCopyrightText: 2022 Tim C, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
"""
MagTag status display for James Webb Telescope
"""
import time
import json
import ssl
import board
import displayio
import terminalio
import supervisor
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import bitmap_label
import wifi
import socketpool
import alarm
import adafruit_requests as requests

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

# Update once per hour
SLEEP_TIME = 60 * 60  # seconds

# Update once per day
# SLEEP_TIME = 60 * 60 * 24 # seconds

# URL to fetch the data from
JSON_GET_URL = (
    "https://jwst.nasa.gov/content/webbLaunch/flightCurrentState2.0.json?unique={}"
)

# Whether to fetch live data or use cached
TEST_RUN = True
# Cached data, helpful when developing interface
# pylint: disable=line-too-long
FAKE_DATA = '{"currentState": {"STEPS": "MirrorAlignSteps, TempBlurb, MirrorBlurb, ArraysForPlots, Plots", "launchDateTimeString": "2021-12-25T12:20Z", "currentDeployTableIndex": 34, "tempWarmSide1C": 37.1, "tempWarmSide2C": 12.0, "tempCoolSide1C": -229.1, "tempCoolSide2C": -233.0, "---INST TEMPS IN KELVIN----": "", "tempInstNirCamK": 42.7, "tempInstNirSpecK": 39.9, "tempInstFgsNirissK": 47.3, "tempInstMiriK": 108.7, "tempInstFsmK": 37.1, "tempsShow": true, "last": ""}}'

# Background Color for the label texts
LBL_BACKGROUND = 0x444444


def try_refresh():
    """Attempt to refresh the display. Catch 'refresh too soon' error
    and retry after waiting 10 seconds.
    """
    try:
        board.DISPLAY.refresh()
    except RuntimeError as too_soon_error:
        # catch refresh too soon
        print(too_soon_error)
        print("waiting before retry refresh()")
        time.sleep(10)
        board.DISPLAY.refresh()


# Get the display object
display = board.DISPLAY

if not TEST_RUN:
    print("Connecting to AP...")
    try:
        # wifi connect
        wifi.radio.connect(secrets["ssid"], secrets["password"])

        # Create Socket, initialize requests
        socket = socketpool.SocketPool(wifi.radio)
        requests = requests.Session(socket, ssl.create_default_context())
    except OSError:
        print("Failed to connect to AP. Rebooting in 3 seconds...")
        time.sleep(3)
        supervisor.reload()


def get_time_str():
    return str(time.monotonic()).replace(".", "")


def make_name_text(text, anchor_point, anchored_position, bg_color=LBL_BACKGROUND):
    """
    Create label object for labeling data values.
    It will get a background color box and appropriate padding.

    :param text: Text to show
    :param anchor_point: location anchor_point
    :param anchored_position: location anchored_position
    :return bitmap_label.Label: the Label object
    """
    return bitmap_label.Label(
        font,
        text=text,
        anchor_point=anchor_point,
        anchored_position=anchored_position,
        background_color=bg_color,
        padding_left=4,
        padding_right=4,
        padding_bottom=3,
        padding_top=3,
        line_spacing=1.0,
    )


def make_value_text(
    anchor_point,
    anchored_position,
    custom_font=True,
    bg_color=0x000000,
    font_color=0xFFFFF,
):
    """
    Create label object for showing data values.

    :param anchor_point: location anchor_point
    :param anchored_position: location anchored_position
    :param bool custom_font: weather to use the custom font or system font
    :return bitmap_label.Label: the Label object
    """
    if custom_font:
        _font = font
    else:
        _font = terminalio.FONT
    return bitmap_label.Label(
        _font,
        text="",
        anchor_point=anchor_point,
        anchored_position=anchored_position,
        line_spacing=1.0,
        padding_top=3,
        background_color=bg_color,
        color=font_color,
        padding_right=4,
        padding_left=4,
        padding_bottom=4,
    )


# main_group to show things
main_group = displayio.Group()

# initialize custom font
font = bitmap_font.load_font("fonts/LeagueSpartan-Light.bdf")

# value text initializations

# top left. Hot side | Cold side temperature values
top_left_value = make_value_text(
    anchor_point=(0, 0),
    anchored_position=(0, 6),
    bg_color=0xBBBBBB,
    font_color=0x000000,
)

# top right. Instrument temperature values
top_right_value = make_value_text(
    anchor_point=(1.0, 0),
    anchored_position=(display.width - 6, 6),
)

# bottom left timestamp
timestamp_val = make_value_text(
    anchor_point=(0, 1.0), anchored_position=(0, display.height - 6), custom_font=False
)

main_group.append(top_left_value)
main_group.append(top_right_value)

main_group.append(timestamp_val)

# label text initialization

# middle left. Hot side | Cold side temps label
middle_left_name = make_name_text(
    text="Temperature", anchor_point=(0.0, 0), anchored_position=(0, 51)
)

# center. Instrument temp labels
inst_temp_labels = "NIRCam Bench\nNIRSpec Bench\nFGS Bench\nMIRI Bench\nFSM"
top_center_name = make_name_text(
    text=inst_temp_labels,
    anchor_point=(1.0, 0.0),
    anchored_position=(top_right_value.x - 2, 6),
)

main_group.append(middle_left_name)
main_group.append(top_center_name)

if not TEST_RUN:
    try:
        print("Fetching JSON data from {}".format(JSON_GET_URL.format(get_time_str())))
        response = requests.get(JSON_GET_URL.format(get_time_str()), timeout=30)
    except (RuntimeError, OSError) as e:
        print(e)
        print("Failed GET request. Rebooting in 3 seconds...")
        time.sleep(3)
        supervisor.reload()

    print("-" * 40)
    print(response.headers)
    json_data = response.json()
    _time_parts = response.headers["date"].split(" ")
    _time_str = "{}\n{}".format(" ".join(_time_parts[:4]), " ".join(_time_parts[4:]))

    print("JSON Response: ", json_data)
    print("-" * 40)
    response.close()
else:
    json_data = json.loads(FAKE_DATA)
    _time_parts = ["Mon,", "28", "Feb", "2022", "17:17:54 GMT"]
    _time_str = "{}\n{}".format(" ".join(_time_parts[:4]), " ".join(_time_parts[4:]))

# Date/Time
timestamp_val.text = _time_str

# instrument temps
top_right_value.text = "{}K\n{}K\n{}K\n{}K\n{}K".format(
    json_data["currentState"]["tempInstNirCamK"],
    json_data["currentState"]["tempInstNirSpecK"],
    json_data["currentState"]["tempInstFgsNirissK"],
    json_data["currentState"]["tempInstMiriK"],
    json_data["currentState"]["tempInstFsmK"],
)

# hot side | cold site temps
top_left_value.text = "{}C | {}C\n{}C | {}C".format(
    json_data["currentState"]["tempWarmSide1C"],
    json_data["currentState"]["tempCoolSide1C"],
    json_data["currentState"]["tempWarmSide2C"],
    json_data["currentState"]["tempCoolSide2C"],
)

# Set the name position after the instrument temps are in the value
# label, so that it's x will be in the proper position.
top_center_name.anchored_position = (top_right_value.x - 2, 6)

# show the group
display.show(main_group)

# refresh display
try_refresh()

# Create a an alarm that will trigger to wake us up
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + SLEEP_TIME)

# Exit the program, and then deep sleep until the alarm wakes us.
alarm.exit_and_deep_sleep_until_alarms(time_alarm)
# Does not return, so we never get here.

This guide was first published on Jan 12, 2022. It was last updated on 2022-01-12 12:44:43 -0500.