Installing Project Code
To use with CircuitPython, you need to first install a few libraries, into the lib folder on your CIRCUITPY drive and the font in the font directory. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary font, libraries and the code.py file in a zip file.
Extract the contents of the zip file, open the directory MagTag_CovidTracking/ and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your CIRCUITPY drive (lib folder, font folder, and code.py).
Your CIRCUITPY drive should now look similar to the following image:
# SPDX-FileCopyrightText: 2020 ladyada, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense import time import alarm import supervisor import alarm from adafruit_magtag.magtag import MagTag # Change this to the hour you want to check the data at, for us its 8pm # local time (eastern), which is 20:00 hrs DAILY_UPDATE_HOUR = 20 # Set up where we'll be fetching data from DATA_SOURCE = "https://api.covidtracking.com/v1/us/current.json" DATE_LOCATION = [0, 'dateChecked'] NEWPOS_LOCATION = [0, 'positiveIncrease'] CURRHOSP_LOCATION = [0, 'hospitalizedCurrently'] NEWHOSP_LOCATION = [0, 'hospitalizedIncrease'] ALLDEATH_LOCATION = [0, 'death'] NEWDEATH_LOCATION = [0, 'deathIncrease'] magtag = MagTag( url=DATA_SOURCE, json_path=(DATE_LOCATION, NEWPOS_LOCATION, CURRHOSP_LOCATION, NEWHOSP_LOCATION, ALLDEATH_LOCATION, NEWDEATH_LOCATION), ) # Date stamp of info magtag.add_text( text_font="/fonts/Arial-Bold-12.pcf", text_position=(10, 15), text_transform=lambda x: "Date: {}".format(x[0:10]), ) # Positive increase magtag.add_text( text_font="/fonts/Arial-Bold-12.pcf", text_position=(10, 35), text_transform=lambda x: "New positive: {:,}".format(x), ) # Curr hospitalized magtag.add_text( text_font="/fonts/Arial-Bold-12.pcf", text_position=(10, 55), text_transform=lambda x: "Current Hospital: {:,}".format(x), ) # Change in hospitalized magtag.add_text( text_font="/fonts/Arial-Bold-12.pcf", text_position=(10, 75), text_transform=lambda x: "Change in Hospital: {:,}".format(x), ) # All deaths magtag.add_text( text_font="/fonts/Arial-Bold-12.pcf", text_position=(10, 95), text_transform=lambda x: "Total deaths: {:,}".format(x), ) # new deaths magtag.add_text( text_font="/fonts/Arial-Bold-12.pcf", text_position=(10, 115), text_transform=lambda x: "New deaths: {:,}".format(x), ) # updated time magtag.add_text( text_font="/fonts/Arial-Bold-12.pcf", text_position=(245, 30), line_spacing=0.75, is_data=False ) magtag.graphics.qrcode(b"https://covidtracking.com/data", qr_size=2, x=240, y=70) magtag.peripherals.neopixels.brightness = 0.1 magtag.peripherals.neopixel_disable = False # turn on lights magtag.peripherals.neopixels.fill(0x0F0000) # red! magtag.get_local_time() try: now = time.localtime() print("Now: ", now) # display the current time since its the last-update updated_at = "%d/%d\n%d:%02d" % now[1:5] magtag.set_text(updated_at, 6, False) # get data from the Covid Tracking Project value = magtag.fetch() print("Response is", value) # OK we're done! magtag.peripherals.neopixels.fill(0x000F00) # greten except (ValueError, RuntimeError, ConnectionError, OSError) as e: print("Some error occured, trying again later -", e) time.sleep(2) # let screen finish updating # we only wanna wake up once a day, around the event update time: event_time = time.struct_time((now[0], now[1], now[2], DAILY_UPDATE_HOUR, 0, 0, -1, -1, now[8])) # how long is that from now? remaining = time.mktime(event_time) - time.mktime(now) if remaining < 0: # ah its aready happened today... remaining += 24 * 60 * 60 # wrap around to the next day remaining_hrs = remaining // 3660 remaining_min = (remaining % 3600) // 60 print("Gonna zzz for %d hours, %d minutes" % (remaining_hrs, remaining_min)) # Turn it all off and go to bed till the next update time magtag.exit_and_deep_sleep(remaining)
Code Walkthrough
Thankfully, the Covid Tracking Project folks made a free, easy-to-use JSON API endpoint that you can easily query with the MagTag to get the current stats at https://api.covidtracking.com/v1/us/current.json You can click on it right from your browser to see the current data and you'll get something like this
[ { "date": 20201210, "states": 56, "positive": 15360841, "negative": 167187901, "pending": 12409, "hospitalizedCurrently": 107258, "hospitalizedCumulative": 603554, "inIcuCurrently": 21023, "inIcuCumulative": 32919, "onVentilatorCurrently": 7442, "onVentilatorCumulative": 3394, "recovered": 5985047, "dateChecked": "2020-12-10T24:00:00Z", "death": 283555, "hospitalized": 603554, "totalTestResults": 213015816, "lastModified": "2020-12-10T24:00:00Z", "total": 0, "posNeg": 0, "deathIncrease": 3067, "hospitalizedIncrease": 4335, "negativeIncrease": 1339749, "positiveIncrease": 215669, "totalTestResultsIncrease": 1954686, "hash": "27226d54c5463327b7303d241b4085e06d976068" } ]
These are pretty self-explanatory, note that date
is not the current date, but the date at which the data was collected. We'll be displaying positiveIncrease
, hospitalizedCurrently, hospitalizedIncrease, death
and deathIncrease
but of course the display can be customized.
Daily Update Time
The report from CTP only gets updated once a day, so its a good project for MagTag to deep-sleep between reads. That way it can last many weeks on a charge. Data is updated at around 7:30pm eastern, which is our local time. To account for any delay in reporting, we will check every night at 8pm eastern. 8pm eastern in 24-hour-time numbers is 20:00, so we put in 20 as the daily-check-hour. If you're in another timezone, figure out what local time that translates to if you'd like to catch the report right after its posted.
# Change this to the hour you want to check the data at, for us its 8pm # local time (eastern), which is 20:00 hrs DAILY_UPDATE_HOUR = 20
Text Transforms with lambdas
The numbers we get from CTP need to have some text before them to explain what they are, for example "New Positive" before the number we extract from the json API as "negativeIncrease": 1339749
To do that we use an 'anonymous function' (a.k.a. a lambda) which we can code in-line that will take the string extracted "1339749
" and preface it with the text "New positive:
" as well as putting commas in between the digit groupings.
Thats what this line does:
text_transform=lambda x: "New positive: {:,}".format(x)
lambda x: is basically the same as making a new function with:
def anonymous_function(x):
return "New positive: {:,}".format(x)
except it doesn't even have a name!
Adding a QR Code
For more info, you can visit the CTP website, we insert a QR code which will show on the E-Ink display very nicely and can be scanned to get the full report
magtag.graphics.qrcode(b"https://covidtracking.com/data", qr_size=2, x=240, y=70)
The 'qr_size
' indicates the scaling, e.g. how big the pixel squares are. X
and Y
coordinates puts it over on the bottom right
Connect and Update
The main chunk of code turns on the NeoPixels red for an indicator that we're connecting to the Internet, gets the local time (we need this later), updates a text box in the top-right with the timestamp of the current date/time so you know when it was last running, then calls magtag.fetch()
to update all the text boxes.
magtag.peripherals.neopixels.brightness = 0.1 magtag.peripherals.neopixel_disable = False # turn on lights magtag.peripherals.neopixels.fill(0x0F0000) # red! magtag.get_local_time() try: now = time.localtime() print("Now: ", now) # display the current time since its the last-update updated_at = "%d/%d\n%d:%02d" % now[1:5] magtag.set_text(updated_at, 6, False) # get data from the Covid Tracking Project value = magtag.fetch() print("Response is", value) # OK we're done! magtag.peripherals.neopixels.fill(0x000F00) # greten except (ValueError, RuntimeError) as e: print("Some error occured, trying again later -", e) time.sleep(2) # let screen finish updating
After the display has updated, its time to go to sleep. For this project we want to wake up at exactly 8pm, which might be later today or it might be tomorrow. Since we don't know what day it will be, we first assume that we will be waking up later today by creating a new time structure with the same year, month, day as today but the hour, min, sec is DAILY_UPDATE_HOUR, 0, 0:
event_time = time.struct_time((now[0], now[1], now[2], DAILY_UPDATE_HOUR, 0, 0, -1, -1, now[8]))
Then we convert the current time, and the next-wakeup time to seconds using time.mktime()
and subtract the difference. That is, what is the number of seconds between these two time points
remaining = time.mktime(event_time) - time.mktime(now)
If the amount of time is negative, that mean's that the "wake up today" time already happened, so we add 24-hours-worth of seconds to the time difference, to get to the event time one day later (tomorrow!)
if remaining < 0: # ah its aready happened today...
remaining += 24 * 60 * 60 # wrap around to the next day
We then display that time in hours and minutes, just for us to debug as humans
remaining_hrs = remaining // 3660
remaining_min = (remaining % 3600) // 60
print("Gonna zzz for %d hours, %d minutes" % (remaining_hrs, remaining_min))
And finally, we go into deep sleep mode until that time comes up
# Turn it all off and go to bed till the next update time
magtag.exit_and_deep_sleep(remaining)
Text editor powered by tinymce.