# PyPortal US Election Calendar

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/092/851/medium800/adafruit_io_electioncal-screenshot.png?1594149494)

Voting is important to make the voice of the people as loud as possible.

But, it is also very complicated to remember all of the involved dates, so much so that you are almost certain to miss a registration date.

![](https://cdn-learn.adafruit.com/assets/assets/000/092/850/medium800/adafruit_io_untitled.jpg?1594147988)

To try to make it easier for us with forgetful minds, a community driven effort has been gathering all of the hard to find information and dates, and compiling it on the [Electioncal Website](https://electioncal.us).

It's designed to share this information as an iCalendar url, which is super easy to add to your favorite desktop software or to your mobile phone.

![](https://cdn-learn.adafruit.com/assets/assets/000/092/761/medium800/adafruit_io_Electioncal_screenshot.png?1594015022)

But sometimes we need a little visual reminder, and a beautiful way to do it, is with a PyPortal.

We are going to use CircuitPython to connect to the Internet, download and process the data, and then display it in a nice and clean way, so we can always keep the pulse on our Election Calendar.

## Parts
### Adafruit PyPortal - CircuitPython Powered Internet Display

[Adafruit PyPortal - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4116)
 **PyPortal** , our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface GUIs, all open-source, and Python-powered using&nbsp;tinyJSON / APIs to get news, stock, weather, cat photos,...

In Stock
[Buy Now](https://www.adafruit.com/product/4116)
[Related Guides to the Product](https://learn.adafruit.com/products/4116/guides)
![Front view of a Adafruit PyPortal - CircuitPython Powered Internet Display with a pyportal logo image on the display. ](https://cdn-shop.adafruit.com/640x480/4116-00.jpeg)

### Adafruit PyPortal Desktop Stand Enclosure Kit

[Adafruit PyPortal Desktop Stand Enclosure Kit](https://www.adafruit.com/product/4146)
PyPortal is&nbsp;our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Create little pocket universes of joy that connect to something good.

And now that you've made a cool internet-connected project...

In Stock
[Buy Now](https://www.adafruit.com/product/4146)
[Related Guides to the Product](https://learn.adafruit.com/products/4146/guides)
![Demo Shot of the Assembled Adafruit PyPortal Desktop Stand Enclosure Kit.](https://cdn-shop.adafruit.com/640x480/4146-03.jpg)

### Fully Reversible Pink/Purple USB A to micro B Cable - 1m long

[Fully Reversible Pink/Purple USB A to micro B Cable - 1m long](https://www.adafruit.com/product/4111)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also fully reversible! That's right, you will save _seconds_ a day by not having to flip the cable around.

First let's talk about the cover and over-molding. We got these...

In Stock
[Buy Now](https://www.adafruit.com/product/4111)
[Related Guides to the Product](https://learn.adafruit.com/products/4111/guides)
![Fully Reversible Pink/Purple USB A to micro B Cable](https://cdn-shop.adafruit.com/640x480/4111-02.jpg)

### 5V 1A (1000mA) USB port power supply - UL Listed

[5V 1A (1000mA) USB port power supply - UL Listed](https://www.adafruit.com/product/501)
Need a USB jack for charging or powering a project, but don't want to lug around a computer? This switching supply gives a clean regulated output at up to 1000mA! 110 or 240 input, so it works in any country. The plugs are "US 2-prong" style so you may need a plug adapter, but...

In Stock
[Buy Now](https://www.adafruit.com/product/501)
[Related Guides to the Product](https://learn.adafruit.com/products/501/guides)
![Wall wart power supply with 2 US prong power](https://cdn-shop.adafruit.com/640x480/501-05.jpg)

# PyPortal US Election Calendar

## Install CircuitPython

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) 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** &nbsp;"flash" drive to iterate.

The following instructions will show you how to install CircuitPython. If you've already installed CircuitPython but are looking to update it or reinstall it, the same steps work for that as well!

## Set up CircuitPython Quick Start!

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

[Download the latest version of CircuitPython for the PyPortal via CircuitPython.org](https://circuitpython.org/board/pyportal/)
[Download the latest version of CircuitPython for the PyPortal Pynt via CircuitPython.org](https://circuitpython.org/board/pyportal_pynt/)
 **Click the link above to download the latest version of CircuitPython for the PyPortal.**

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

![circuitpython_pyportal-uf2.png](https://cdn-learn.adafruit.com/assets/assets/000/073/615/medium640/circuitpython_pyportal-uf2.png?1553610968)

Plug your PyPortal 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.**

Double-click the **Reset** button on the top in the middle (magenta arrow) on your board, and you will see the NeoPixel RGB LED (green arrow) turn green. If it turns red, check the USB cable, try another USB port, etc.&nbsp; **Note:** The little red LED next to the USB connector will pulse red. That's ok!

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

![circuitpython_PyPortalResetNeoPIxel.jpg](https://cdn-learn.adafruit.com/assets/assets/000/071/993/medium640/circuitpython_PyPortalResetNeoPIxel.jpg?1551213425)

You will see a new disk drive appear called **PORTALBOOT**.

Drag the **adafruit-circuitpython-pyportal-\<whatever\>.uf2** file to **PORTALBOOT.**

![circuitpython_PyPortal_PORTALBOOT.png](https://cdn-learn.adafruit.com/assets/assets/000/072/029/medium640/circuitpython_PyPortal_PORTALBOOT.png?1551287972)

![circuitpython_PyPortal_Drag_UF2.png](https://cdn-learn.adafruit.com/assets/assets/000/072/030/medium640/circuitpython_PyPortal_Drag_UF2.png?1551287983)

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

If you haven't added any code to your board, the only file that will be present is **boot\_out.txt**. This is absolutely normal! It's time for you to add your **code.py** and get started!

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

![circuitpython_PyPortalCIRCUITPY.png](https://cdn-learn.adafruit.com/assets/assets/000/071/995/medium640/circuitpython_PyPortalCIRCUITPY.png?1551213875)

## PyPortal Default Files

Click below to download a zip of the files that shipped on the PyPortal or PyPortal Pynt.

[PyPortal Default Files](https://github.com/adafruit/circuitpython-default-files/tree/main/boards/pyportal/4.x)
[PyPortal Pynt Default Files](https://github.com/adafruit/circuitpython-default-files/tree/main/boards/pyportal_pynt/5.x)
# PyPortal US Election Calendar

## CircuitPython Libraries

Danger: 

Each CircuitPython program you run needs to have a lot of information to work. The reason CircuitPython is so simple to use is that most of that information is stored in other files and works in the background. These files are called _libraries_. Some of them are built into CircuitPython. Others are stored on your **CIRCUITPY** drive in a folder called **lib**. Part of what makes CircuitPython so great is its ability to store code separately from the firmware itself. Storing code separately from the firmware makes it easier to update both the code you write and the libraries you depend.

Your board may ship with a **lib** folder already, it's in the base directory of the drive. If not, simply create the folder yourself. When you first install CircuitPython, an empty **lib** directory will be created for you.

![](https://cdn-learn.adafruit.com/assets/assets/000/105/961/medium800/circuitpython_WtCP_CIRCUITPY_contents.png?1635281033)

CircuitPython libraries work in the same way as regular Python modules so the [Python docs](https://docs.python.org/3/tutorial/modules.html) are an excellent reference for how it all should work. In Python terms, you can place our library files in the **lib** directory because it's part of the Python path by default.

One downside of this approach of separate libraries is that they are not built in. To use them, one needs to copy them to the **CIRCUITPY** drive before they can be used. Fortunately, there is a library bundle.

The bundle and the library releases on GitHub also feature optimized versions of the libraries with the **.mpy** file extension. These files take less space on the drive and have a smaller memory footprint as they are loaded.

Due to the regular updates and space constraints, Adafruit does not ship boards with the entire bundle. Therefore, you will need to load the libraries you need when you begin working with your board. You can find example code in the guides for your board that depends on external libraries.

Either way, as you start to explore CircuitPython, you'll want to know how to get libraries on board.

# The Adafruit Learn Guide Project Bundle

The quickest and easiest way to get going with a project from the Adafruit Learn System is by utilising the Project Bundle. Most guides now have a **Download Project Bundle** button available at the top of the full code example embed. This button downloads all the necessary files, including images, etc., to get the guide project up and running. Simply click, open the resulting zip, copy over the right files, and you're good to go!

The first step is to find the Download Project Bundle button in the guide you're working on.

Info: 

![](https://cdn-learn.adafruit.com/assets/assets/000/111/837/medium800/circuitpython_PB_download_project_bundle_button.png?1652915277)

Warning: 

The Download Project Bundle button downloads a zip file. This zip contains a series of directories, nested within which is the **code.py** , any applicable assets like images or audio, and the **lib/** folder containing all the necessary libraries. The following zip was downloaded from the Piano in the Key of Lime guide.

![](https://cdn-learn.adafruit.com/assets/assets/000/111/838/medium800/circuitpython_PB_downloaded_and_expanded_zip.png?1652915317)

Info: 

When you open the zip, you'll find some nested directories. Navigate through them until you find what you need. You'll eventually find a directory for your CircuitPython version (in this case, 7.x). In the version directory, you'll find the file and directory you need: **code.py** and **lib/**. Once you find the content you need, you can copy it all over to your **CIRCUITPY** drive, replacing any files already on the drive with the files from the freshly downloaded zip.

Info: 

Once you copy over all the relevant files, the project should begin running! If you find that the project is not running as expected, make sure you've copied ALL of the project files onto your microcontroller board.

That's all there is to using the Project Bundle!

# The Adafruit CircuitPython Library Bundle

Adafruit provides CircuitPython libraries for much of the hardware they provide, including sensors, breakouts and more. To eliminate the need for searching for each library individually, the libraries are available together in the Adafruit CircuitPython Library Bundle. The bundle contains all the files needed to use each library.

## Downloading the Adafruit CircuitPython Library Bundle

You can download the latest Adafruit CircuitPython Library Bundle release by clicking the button below. The libraries are being constantly updated and improved, so you'll always want to download the latest bundle.&nbsp;

**Match up the bundle version with the version of CircuitPython you are running.** For example, you would download the 6.x library bundle if you're running any version of CircuitPython 6, or the 7.x library bundle if you're running any version of CircuitPython 7, etc. If you mix libraries with major CircuitPython versions, you will get incompatible mpy errors due to changes in library interfaces possible during major version changes.

[Click to visit circuitpython.org for the latest Adafruit CircuitPython Library Bundle](https://circuitpython.org/libraries)
 **Download the bundle version that matches your CircuitPython firmware version.** If you don't know the version, check the version info in **boot\_out.txt** file on the **CIRCUITPY** drive, or the initial prompt in the CircuitPython REPL. For example, if you're running v7.0.0, download the 7.x library bundle.

There's also a **py** bundle which contains the uncompressed python files, you probably _don't_ want that unless you are doing advanced work on libraries.

# The CircuitPython Community Library Bundle

The CircuitPython Community Library Bundle is made up of libraries written and provided by members of the CircuitPython community. These libraries are often written when community members encountered hardware not supported in the Adafruit Bundle, or to support a personal project. The authors all chose to submit these libraries to the Community Bundle make them available to the community.

**These libraries are maintained by their authors and are not supported by Adafruit.** As you would with any library, if you run into problems, feel free to file an issue on the GitHub repo for the library. Bear in mind, though, that most of these libraries are supported by a single person and you should be patient about receiving a response. Remember, these folks are not paid by Adafruit, and are volunteering their personal time when possible to provide support.

## Downloading the CircuitPython Community Library Bundle

You can download the latest CircuitPython Community Library Bundle release by clicking the button below. The libraries are being constantly updated and improved, so you'll always want to download the latest bundle.

[Click for the latest CircuitPython Community Library Bundle release](https://github.com/adafruit/CircuitPython_Community_Bundle/releases)
The link takes you to the latest release of the CircuitPython Community Library Bundle on GitHub. There are multiple versions of the bundle available. **Download the bundle version that matches your CircuitPython firmware version.** If you don't know the version, check the version info in **boot\_out.txt** file on the **CIRCUITPY** drive, or the initial prompt in the CircuitPython REPL. For example, if you're running v7.0.0, download the 7.x library bundle.

# Understanding the Bundle

After downloading the zip, extract its contents. This is usually done by double clicking on the zip. On Mac OSX, it places the file in the same directory as the zip.

![](https://cdn-learn.adafruit.com/assets/assets/000/105/908/medium800/circuitpython_WtCP_lib_bundle_extracted.png?1635183852)

Open the bundle folder. Inside you'll find two information files, and two folders. One folder is the lib bundle, and the other folder is the examples bundle.

![](https://cdn-learn.adafruit.com/assets/assets/000/105/909/medium800/circuitpython_WtCP_lib_zip_contents.png?1635183864)

Now open the lib folder. When you open the folder, you'll see a large number of **.**** mpy** files, and folders.

![](https://cdn-learn.adafruit.com/assets/assets/000/105/910/medium800/circuitpython_WtCP_lib_bundle_folder_contents.png?1635183871)

## Example Files

All example files from each library are now included in the bundles in an **examples** directory (as seen above), as well as an examples-only bundle. These are included for two main reasons:

- Allow for quick testing of devices.
- Provide an example base of code, that is easily built upon for individualized purposes.

![](https://cdn-learn.adafruit.com/assets/assets/000/105/911/medium800/circuitpython_WtCP_examples_bundle_directory_contents.png?1635184002)

## Copying Libraries to Your Board

First open the **lib** folder on your **CIRCUITPY** drive. Then, open the **lib** folder you extracted from the downloaded zip. Inside you'll find a number of folders and **.mpy** files. Find the library you'd like to use, and copy it to the **lib** folder on **CIRCUITPY**.

If the library is a directory with multiple **.mpy** files in it, be sure to **copy the entire folder to CIRCUITPY/lib**.

This also applies to example files. Open the **examples** folder you extracted from the downloaded zip, and copy the applicable file to your **CIRCUITPY** drive. Then, rename it to **code.py** to run it.

Info: 

# Understanding Which Libraries to Install

You now know how to load libraries on to your CircuitPython-compatible microcontroller board. You may now be wondering, how do you know _which_ libraries you need to install? Unfortunately, it's not always straightforward. Fortunately, there is an obvious place to start, and a relatively simple way to figure out the rest. First up: the best place to start.

When you look at most CircuitPython examples, you'll see they begin with one or more `import` statements. These typically look like the following:

- `import library_or_module`

However, `import` statements can also sometimes look like the following:

- `from library_or_module import name`
- `from library_or_module.subpackage import name`
- `from library_or_module import name as local_name`

They can also have more complicated formats, such as including a `try` / `except` block, etc.

The important thing to know is that **an** `import` **statement will always include the name of the module or library that you're importing**.

Therefore, the best place to start is by reading through the `import` statements.

Here is an example import list for you to work with in this section. There is no setup or other code shown here, as the purpose of this section involves only the import list.

```python
import time
import board
import neopixel
import adafruit_lis3dh
import usb_hid
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode
```

Keep in mind, not all imported items are libraries. Some of them are almost always built-in CircuitPython modules. How do you know the difference? Time to visit the REPL.

In the [Interacting with the REPL section](https://learn.adafruit.com/welcome-to-circuitpython/the-repl#interacting-with-the-repl-2977486-14) on [The REPL page](https://learn.adafruit.com/welcome-to-circuitpython/the-repl) in this guide, the `help("modules")` command is discussed. This command provides a list of all of the built-in modules available in CircuitPython for your board. So, if you connect to the serial console on your board, and enter the REPL, you can run `help("modules")` to see what modules are available for your board. Then, as you read through the `import` statements, you can, for the purposes of figuring out which libraries to load, ignore the statement that import modules.

The following is the list of modules built into CircuitPython for the Feather RP2040. Your list may look similar or be anything down to a significant subset of this list for smaller boards.

![](https://cdn-learn.adafruit.com/assets/assets/000/105/967/medium800/circuitpython_WtCP_CP_libs_help_modules_feather_rp2040.png?1635369618)

Now that you know what you're looking for, it's time to read through the import statements. The first two, `time` and `board`, are on the modules list above, so they're built-in.

The next one, `neopixel`, is not on the module list. That means it's your first library! So, you would head over to the bundle zip you downloaded, and search for **neopixel**. There is a **neopixel.mpy** file in the bundle zip. Copy it over to the **lib** folder on your **CIRCUITPY** drive. The following one, `adafruit_lis3dh`, is also not on the module list. Follow the same process for **adafruit\_lis3dh** , where you'll find **adafruit\_lis3dh.mpy** , and copy that over.

The fifth one is `usb_hid`, and it is in the modules list, so it is built in. Often all of the built-in modules come first in the import list, but sometimes they don't! Don't assume that everything after the first library is also a library, and verify each import with the modules list to be sure. Otherwise, you'll search the bundle and come up empty!

The final two imports are not as clear. Remember, when `import` statements are formatted like this, the first thing after the `from` is the library name. In this case, the library name is `adafruit_hid`. A search of the bundle will find an **adafruit\_hid _folder_**. When a library is a folder, you must copy the **entire folder and its contents&nbsp;_as it is in the bundle_** to the **lib** folder on your **CIRCUITPY** drive. In this case, you would copy the entire **adafruit\_hid** folder to your **CIRCUITPY/lib** folder.

Notice that there are _two_ imports that begin with `adafruit_hid`. Sometimes you will need to import more than one thing from the same library. Regardless of how many times you import the same library, you only need to load the library by copying over the **adafruit\_hid** folder _once_.

That is how you can use your example code to figure out what libraries to load on your CircuitPython-compatible board!

There are cases, however, where libraries require other libraries internally. The internally required library is called a _dependency_. In the event of library dependencies, the easiest way to figure out what other libraries are required is to connect to the serial console and follow along with the `ImportError` printed there. The following is a very simple example of an `ImportError`, but the concept is the same for any missing library.

# Example: `ImportError` Due to Missing Library

If you choose to load libraries as you need them, or you're starting fresh with an existing example, you may end up with code that tries to use a library you haven't yet loaded.&nbsp; This section will demonstrate what happens when you try to utilise a library that you don't have loaded on your board, and cover the steps required to resolve the issue.

This demonstration will only return an error if you do not have the required library loaded into the **lib** folder on your **CIRCUITPY** drive **.**

Let's use a modified version of the Blink example.

```auto
import board
import time
import simpleio

led = simpleio.DigitalOut(board.LED)

while True:
    led.value = True
    time.sleep(0.5)
    led.value = False
    time.sleep(0.5)
```

Save this file. Nothing happens to your board. Let's check the serial console to see what's going on.

![](https://cdn-learn.adafruit.com/assets/assets/000/105/964/medium800/circuitpython_WtCP_serial_console_ImportError.png?1635355664)

You have an `ImportError`. It says there is `no module named 'simpleio'`. That's the one you just included in your code!

Click the link above to download the correct bundle. Extract the lib folder from the downloaded bundle file. Scroll down to find **simpleio.mpy**. This is the library file you're looking for! Follow the steps above to load an individual library file.

The LED starts blinking again! Let's check the serial console.

![](https://cdn-learn.adafruit.com/assets/assets/000/105/965/medium800/circuitpython_WtCP_CP_libraries_ImportError_resolved.png?1635355829)

No errors! Excellent. You've successfully resolved an `ImportError`!

If you run into this error in the future, follow along with the steps above and choose the library that matches the one you're missing.

# Library Install on Non-Express Boards

If you have an M0 non-Express board such as Trinket M0, Gemma M0, QT Py M0, or one of the M0 Trinkeys, you'll want to follow the same steps in the example above to install libraries as you need them. Remember, you don't need to wait for an `ImportError` if you know what library you added to your code. Open the library bundle you downloaded, find the library you need, and drag it to the **lib** folder on your **CIRCUITPY** drive.

You can still end up running out of space on your M0 non-Express board even if you only load libraries as you need them. There are a number of steps you can use to try to resolve this issue. You'll find suggestions on the [Troubleshooting page](https://learn.adafruit.com/welcome-to-circuitpython/troubleshooting).

# Updating CircuitPython Libraries and Examples

Libraries and examples are updated from time to time, and it's important to update the files you have on your **CIRCUITPY** drive.

To update a single library or example, follow the same steps above. When you drag the library file to your lib folder, it will ask if you want to replace it. Say yes. That's it!

A new library bundle is released every time there's an update to a library. Updates include things like bug fixes and new features. It's important to check in every so often to see if the libraries you're using have been updated.

## CircUp CLI Tool

There is a command line interface (CLI) utility called [CircUp](https://learn.adafruit.com/keep-your-circuitpython-libraries-on-devices-up-to-date-with-circup) that can be used to easily install and update libraries on your device. Follow the directions on the [install page within the CircUp learn guide](https://learn.adafruit.com/keep-your-circuitpython-libraries-on-devices-up-to-date-with-circup/install-circup). Once you've got it installed you run the command `circup update` in a terminal to interactively update all libraries on the connected CircuitPython device. See the [usage page in the CircUp guide](https://learn.adafruit.com/keep-your-circuitpython-libraries-on-devices-up-to-date-with-circup/usage) for a full list of functionality

# PyPortal US Election Calendar

## Code PyPortal with CircuitPython

## Location

In the **code.py** file (which you will have renamed from **electioncal.py** ), you can change the location for which you want to display the election data in this lines:

```python
# Change this to your state and county, replacing spaces for underscores and in lowercase
STATE="new_york"
COUNTY="new_york"
```

## Adafruit IO Time Server

In order to get the precise time, our project will query the Adafruit IO Internet of Things service for the time. Adafruit IO is absolutely free to use, but you'll need to log in with your Adafruit account to use it. If you don't already have an Adafruit login, create [one here](https://accounts.adafruit.com/users/sign_up).

If you haven't used Adafruit IO before, [check out this guide for more info](https://learn.adafruit.com/welcome-to-adafruit-io/getting-started-with-adafruit-io).

Once you have logged into your account, there are two pieces of information you'll need to place in your **settings.toml** file: `Adafruit IO username`, and `Adafruit IO key`. Head to [io.adafruit.com](https://io.adafruit.com/) and simply click the **View AIO Key** link on the left hand side of the Adafruit IO page to get this information.

Then, add them to the **settings.toml** file like this:

```python
CIRCUITPY_WIFI_SSID="your-wifi-ssid"
CIRCUITPY_WIFI_PASSWORD="your-wifi-password"
ADAFRUIT_AIO_USERNAME="my_username"
ADAFRUIT_AIO_KEY="my_key"
```

## Installing Project Code

To use with CircuitPython, you need to first install a few libraries, into the lib folder on your **CIRCUITPY** drive. 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 libraries and the **code.py** file in a zip file. Extract the contents of the zip file, open the directory **PyPortal\_Electioncal\_US/** 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.

Your **CIRCUITPY** drive should now look similar to the following image:

![CIRCUITPY](https://adafruit.github.io/Adafruit_Learning_System_Guides/PyPortal_PyPortal_Electioncal_US.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/PyPortal/PyPortal_Electioncal_US/code.py

Warning: 

## How It Works

The PyPortal Electioncal US has a few steps it takes to provide you with the information desired. It has a boot-up screen, a nice simple background, and multiple fonts for displaying the election dates.

## PyPortal Constructor

When setting up the `pyportal` constructor, we are providing it with these things:

- `url` to query
- `json_path` to traverse and find the key:value pairs we need
- `default_bg` default background color

### Background

First, it displays a bitmap graphic as the screen's startup background while getting ready to download the Election dates. This is a 320 x 240 pixel RGB 16-bit raster graphic in **.bmp** format.

![](https://cdn-learn.adafruit.com/assets/assets/000/072/618/medium800/weather_pyportal16.bmp?1552412079)

## Time

Next, the program connects through the WiFi to get the local time via the adafruit.io server, for which we will display today's date at the bottom of the screen, to give you better context of the election dates.

## API Query and JSON

At the top of this page, you configured:

`DATA_SOURCE = "https://electioncal.us/en/" + STATE +"/" + COUNTY + "/voter.json"`

This, with the STATE and COUNTY you defined, will turn into something like (New York County, New York State in this example):

`https://electioncal.us/en/new_york/new_york/voter.json`

When this query is complete, it returns a JSON file that looks like this:

```python
{
  "version": 0,
  "name": null,
  "description": null,
  "dates": 
  	[
      {
        "date": "2020-04-28", 
        "name": "Presidential Primary",
        "original_date": "2020-04-28", 
        "state": "New York", 
        "county": "New York County",
        "key": "20200428", 
        "type": "election"
      }, 
      {
        "state": "New York", 
        "county": "New York County", 
        "name": "Mail voter registration",
        "type": "reminder",
        "election_key": "20200623",
        "subtype": "registration.received_by",
        "date": "2020-05-26", 
        "postmark_too_late": true,
        "deadline_date": "2020-06-03", 
        "explanation": "Voter registration must be received by June 3rd."
      }
    ]
}
```

Here is the same file beautified with the Firefox browser's built in tools (You can also use online code "beautifiers" such as [https://codebeautify.org/jsonviewer](https://codebeautify.org/jsonviewer) or [http://jsonviewer.stack.hu](http://jsonviewer.stack.hu)) :

![](https://cdn-learn.adafruit.com/assets/assets/000/092/759/medium800/adafruit_io_json_on_firefox.png?1594010284)

## Fetch

With the PyPortal set up, we can then use `pyportal.fetch()` and then from the screen object we call `load_data()` to load the JSON data to a way that is easy to pass through all the dates.

All of the heavy lifting of parsing that data and displaying it as text or bitmaps is done in the **electioncal\_graphics.py** code.

## JSON Traversal

The JSON file is formatted in a way that makes it easy to traverse the hierarchy and parse the data. In it, you'll see keys, such as `state`, `county`, `name`, `type` and `date`, and their respective values. So, here are some **key : value** pairs we care about:

- `state: "New York"`
- `county: "New York County"`
- `name: "Presidential Primary"`
- `date: "2020-04-28"```

In order to fetch this data from the file, we need to be able to describe their locations in the file hierarchically. This is helpful, for example, in differentiating between the `'name'` value that you have in the Presidential Primary and the `'name'` of the Mail voter registration. To avoid name clashing, we rely on JSON traversal.

In the **electioncal\_graphics.py** file, you'll see how this is done. For example, the first date is found in&nbsp; this hierarchy of the JSON file: `["dates"][0]["date"]`.

In this case the number `0` is quite important, as it has the sub-tree that is relevant for the first, date, but if you change it to a number such as `1` or `2`, you will print the second and third date. Please note that the counter starts at zero.

Depending of the STATE and COUNTY you configured, you will have several election dates, so the program then tries to replace this number by `[i]`, so that we can display not one date but many, and cycle them through the screen.

### Font

The data is displayed as text created with bitmapped fonts to overlay on top of the background. The fonts used here are bitmap fonts made from the Arial typeface. You can learn more about [converting type in this guide](https://learn.adafruit.com/custom-fonts-for-pyportal-circuitpython-display).

## Graphics

Let's have a look at how the **electioncal\_graphics.py** code places the elements on screen. Below, we can see the icon and text that are displayed. The items in quotes are the key names from the JSON file, and their values are what we see displayed using the CircuitPython `label` from the `displayio` library.

![](https://cdn-learn.adafruit.com/assets/assets/000/092/760/medium800/adafruit_io_electioncal-screen.png?1594014785)

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/PyPortal/PyPortal_OpenWeather/openweather_graphics.py

## Text Position

Depending on the design of your background bitmap and the length of the text you're displaying, you may want to reposition the text and caption.

The PyPortal's display is 320 pixels wide and 240 pixels high. In order to refer to those positions on the screen, we use an x/y coordinate system, where x is horizontal and y is vertical.

The origin of this coordinate system is the upper left corner. This means that a pixel placed at the upper left corner would be (0,0) and the lower right corner would be (320, 240).

![](https://cdn-learn.adafruit.com/assets/assets/000/072/123/medium800/internet_of_things___iot_pyportal_grid.jpg?1551460792)

So, if you wanted to move the subscriber count text to the right and up closer to the top, your code may look like this for that part of the pyportal constructor: `text_position=(250, 10)`

## Text Color

Another way to customize your display is to adjust the color of the text. The line `text_color=0xFFFFFF` in the constructor shows how. You will need to use the hexadecimal value for any color you want to display.

You can use something like [https://htmlcolorcodes.com/](https://htmlcolorcodes.com/) to pick your color and then copy the hex value, in this example it would be `0x0ED9EE`

![](https://cdn-learn.adafruit.com/assets/assets/000/072/129/medium800/internet_of_things___iot_hecxolor.png?1551462671)

Now, we get ready to assemble the case on the next page.

# PyPortal US Election Calendar

## Build The PyPortal Stand

![](https://cdn-learn.adafruit.com/assets/assets/000/072/835/medium800/circuitpython_untitled_0058_2k.jpg?1552626290)

![](https://cdn-learn.adafruit.com/assets/assets/000/072/836/medium800/circuitpython_untitled_0061_2k.jpg?1552626303)

Here's how to assemble the laser cut acrylic stand for the PyPortal. The kit comes with six pieces of acrylic and six nylon screws and nuts.

## Prep

First, remove the protective paper from all of the acrylic pieces.

![circuitpython_untitled_0002_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/838/medium640/circuitpython_untitled_0002_2k.jpg?1552626396)

![circuitpython_untitled_0003_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/839/medium640/circuitpython_untitled_0003_2k.jpg?1552626410)

![circuitpython_untitled_0005_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/841/medium640/circuitpython_untitled_0005_2k.jpg?1552626428)

![circuitpython_untitled_0006_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/842/medium640/circuitpython_untitled_0006_2k.jpg?1552626786)

![](https://cdn-learn.adafruit.com/assets/assets/000/072/848/medium800/circuitpython_untitled_0007_2k.jpg?1552626837)

## Sandwich

Next, do a dry fit of the three clear piece of acrylic on the back side of the PyPortal to get everything oriented properly.

The two small pieces are used as spacers to allow clearance around some of the larger parts. Lay them onto the board first, as shown.

Then, place the large clear piece on top, making sure to align the hole for the reset and the cutout for the three JST ports.

Complete the sandwich by placing the stack on top of the black front bezel with the hole for the light sensor oriented as shown here.

![circuitpython_untitled_0008_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/849/medium640/circuitpython_untitled_0008_2k.jpg?1552626923)

![circuitpython_untitled_0009_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/850/medium640/circuitpython_untitled_0009_2k.jpg?1552626937)

![circuitpython_untitled_0010_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/851/medium640/circuitpython_untitled_0010_2k.jpg?1552626948)

![circuitpython_untitled_0011_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/852/medium640/circuitpython_untitled_0011_2k.jpg?1552627052)

![circuitpython_untitled_0012_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/853/medium640/circuitpython_untitled_0012_2k.jpg?1552627067)

![circuitpython_untitled_0013_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/854/medium640/circuitpython_untitled_0013_2k.jpg?1552627104)

![circuitpython_untitled_0014_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/855/medium640/circuitpython_untitled_0014_2k.jpg?1552627173)

![](https://cdn-learn.adafruit.com/assets/assets/000/072/860/medium800/circuitpython_untitled_0016_2k.jpg?1552627208)

## Legs

Now that the fit and orientation have been established, we'll install the legs.

The two legs are identical. Pick one and slot it into the case back as shown.

Place a nut into the captive slot of the leg and then feed a short screw through from the front of the clear acrylic case back. Fasten the screw (not too tight!) and then repeat for the second leg.

&nbsp;

![circuitpython_untitled_0031_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/869/medium640/circuitpython_untitled_0031_2k.jpg?1552628953)

![circuitpython_untitled_0032_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/870/medium640/circuitpython_untitled_0032_2k.jpg?1552631665)

![circuitpython_untitled_0033_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/871/medium640/circuitpython_untitled_0033_2k.jpg?1552631675)

![circuitpython_untitled_0034_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/872/medium640/circuitpython_untitled_0034_2k.jpg?1552631683)

![circuitpython_untitled_0035_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/873/medium640/circuitpython_untitled_0035_2k.jpg?1552631690)

![](https://cdn-learn.adafruit.com/assets/assets/000/072/883/medium800/circuitpython_untitled_0036_2k.jpg?1552631725)

## Add Long Screws

To put it all together, we'll use the four long screws to secure the entire acrylic - PyPortal - acrylic - acrylic sandwich!

Run the four long screws from the front to the back, as shown.

![circuitpython_untitled_0039_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/892/medium640/circuitpython_untitled_0039_2k.jpg?1552631888)

![circuitpython_untitled_0040_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/893/medium640/circuitpython_untitled_0040_2k.jpg?1552631983)

![circuitpython_untitled_0041_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/894/medium640/circuitpython_untitled_0041_2k.jpg?1552631994)

![circuitpython_untitled_0042_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/895/medium640/circuitpython_untitled_0042_2k.jpg?1552632010)

![circuitpython_untitled_0043_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/896/medium640/circuitpython_untitled_0043_2k.jpg?1552632017)

![circuitpython_untitled_0044_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/897/medium640/circuitpython_untitled_0044_2k.jpg?1552632026)

![](https://cdn-learn.adafruit.com/assets/assets/000/072/907/medium800/circuitpython_untitled_0046_2k.jpg?1552632076)

## Screw It All Together

Finally, add the case back and legs assemblage and then thread on the four nuts to secure it all in place.

Be **careful not to over-tighten** the screws. Doing so can potentially crack the Pyportal display!

![circuitpython_untitled_0047_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/922/medium640/circuitpython_untitled_0047_2k.jpg?1552632800)

![circuitpython_untitled_0049_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/923/medium640/circuitpython_untitled_0049_2k.jpg?1552632809)

![circuitpython_untitled_0052_2k.jpg](https://cdn-learn.adafruit.com/assets/assets/000/072/924/medium640/circuitpython_untitled_0052_2k.jpg?1552632817)

![](https://cdn-learn.adafruit.com/assets/assets/000/072/938/medium800/circuitpython_untitled_0053_2k.jpg?1552632866)

![](https://cdn-learn.adafruit.com/assets/assets/000/072/958/medium800/circuitpython_untitled_0057_2k.jpg?1552632938)

![](https://cdn-learn.adafruit.com/assets/assets/000/073/004/medium800/circuitpython_untitled_0059_2k.jpg?1552633061)

![](https://cdn-learn.adafruit.com/assets/assets/000/073/050/medium800/circuitpython_untitled_0060_2k.jpg?1552633241)

## Bonus! Penny Roll Weight

If you'd like to give your PyPortal a bit of extra heft so it won't get pushed around on your desk, you can make a great weight for $0.50. A roll of 50 pennies does the trick! The legs are designed to hold a roll of coins perfectly!

![](https://cdn-learn.adafruit.com/assets/assets/000/073/087/medium800/circuitpython_untitled_0063_2k.jpg?1552633546)

![](https://cdn-learn.adafruit.com/assets/assets/000/073/112/medium800/circuitpython_untitled_0065_2k.jpg?1552633618)

![](https://cdn-learn.adafruit.com/assets/assets/000/073/131/medium800/circuitpython_untitled_0067_2k.jpg?1552633666)

# Laser Cutter Files for PyPortal Stand

If you need to replace a piece or just want to make a spare for another PyPortal, here are the vector files for 1/8" (3mm) acrylic, in Adobe Illustrator format:

[pyPortal_CUT_Black.ai](https://cdn-learn.adafruit.com/assets/assets/000/073/959/original/pyPortal_CUT_Black.ai?1554157488)
[pyPortal_CUT_Clear.ai](https://cdn-learn.adafruit.com/assets/assets/000/073/960/original/pyPortal_CUT_Clear.ai?1554157498)
# PyPortal US Election Calendar

## Troubleshooting

While setting up our PyPortal with this project for Electioncal US, you might run into a bit of trouble. Nothing to worry, all should be easy to solve.

## Problems with the WiFi

If something is wrong with the WiFi connection, one way to recognize this problem is by connecting to the REPL Serial Console, where you might find messages like:

`Connecting to AP my-access-point`  
`Could not connect to internet ('Failed to connect to ssid', b'my-access-point')`  
`Retrying in 3 seconds...`

Here are some things you might look at to solve this:

- Checking the name of the access point and it's password on the **secrets.py** file
- Getting closer to the access point if it is far away

## Problems setting up the county/state

If the JSON data cannot be found, you will see an error such as:

`Error loading JSON data: Please check the configuration of county and state, in code.py`

`Traceback (most recent call last):`

`File "code.py", line 60, in `

`File "code.py", line 57, in `

`File "electioncal_graphics.py", line 76, in load_data`

`File "electioncal_graphics.py", line 72, in load_data`

`ValueError: syntax error in JSON`

If this happens:

- Check the spelling of the state and county
- If the name of your state or county has a space, replace it with an underscore \_
- Remember to lowercase both names

## PyPortal library on other devices

The PyPortal is a wonderful device, but it is not the only device that has a screen, such as the larger and smaller versions of the PyPortal such as the PyPortal Titano and the PyPortal Pynt.

Everything in the code should work well, but the laying of the text and background might be a bit off. Nothing to worry here.

Make gradual changes to **electioncal\_graphics.py** in the ` __init__ ` section, where `x` and `y` are defined for all of the displayed objects.


## Featured Products

### Adafruit PyPortal - CircuitPython Powered Internet Display

[Adafruit PyPortal - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4116)
 **PyPortal** , our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface GUIs, all open-source, and Python-powered using&nbsp;tinyJSON / APIs to get news, stock, weather, cat photos,...

In Stock
[Buy Now](https://www.adafruit.com/product/4116)
[Related Guides to the Product](https://learn.adafruit.com/products/4116/guides)
### Adafruit PyPortal Desktop Stand Enclosure Kit

[Adafruit PyPortal Desktop Stand Enclosure Kit](https://www.adafruit.com/product/4146)
PyPortal is&nbsp;our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Create little pocket universes of joy that connect to something good.

And now that you've made a cool internet-connected project...

In Stock
[Buy Now](https://www.adafruit.com/product/4146)
[Related Guides to the Product](https://learn.adafruit.com/products/4146/guides)
### Fully Reversible Pink/Purple USB A to micro B Cable - 1m long

[Fully Reversible Pink/Purple USB A to micro B Cable - 1m long](https://www.adafruit.com/product/4111)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also fully reversible! That's right, you will save _seconds_ a day by not having to flip the cable around.

First let's talk about the cover and over-molding. We got these...

In Stock
[Buy Now](https://www.adafruit.com/product/4111)
[Related Guides to the Product](https://learn.adafruit.com/products/4111/guides)
### 5V 1A (1000mA) USB port power supply - UL Listed

[5V 1A (1000mA) USB port power supply - UL Listed](https://www.adafruit.com/product/501)
Need a USB jack for charging or powering a project, but don't want to lug around a computer? This switching supply gives a clean regulated output at up to 1000mA! 110 or 240 input, so it works in any country. The plugs are "US 2-prong" style so you may need a plug adapter, but...

In Stock
[Buy Now](https://www.adafruit.com/product/501)
[Related Guides to the Product](https://learn.adafruit.com/products/501/guides)
### PyPortal Starter Kit

[PyPortal Starter Kit](https://www.adafruit.com/product/4303)
# Copy change

&nbsp;

Why not trick out your fresh new board with some&nbsp;accessories? The Pi 2 is a big deal - a big, big deal. &nbsp;It has an upgraded ARMv7 multicore procssor and a full Gigabyte of RAM - meaning you're going to see ~2x the performance on processor-upgrade...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/4303)
[Related Guides to the Product](https://learn.adafruit.com/products/4303/guides)
### Adafruit PyPortal Pynt - CircuitPython Powered Internet Display

[Adafruit PyPortal Pynt - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4465)
The **PyPortal Pynt** is the little&nbsp;sister to our [popular PyPortal](https://www.adafruit.com/product/4116) - zapped with a shrink ray to take the design from a 3.2" diagonal down to 2.4" diagonal screen - but otherwise the same! The PyPortal is&nbsp;our...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/4465)
[Related Guides to the Product](https://learn.adafruit.com/products/4465/guides)
### Adafruit PyPortal Titano

[Adafruit PyPortal Titano](https://www.adafruit.com/product/4444)
The **PyPortal Titano** is the big sister to our [popular PyPortal](https://www.adafruit.com/product/4116) now with _twice as many pixels!_ The PyPortal is our easy-to-use IoT device that allows you to create all the things for the “Internet of...

In Stock
[Buy Now](https://www.adafruit.com/product/4444)
[Related Guides to the Product](https://learn.adafruit.com/products/4444/guides)

## Related Guides

- [Adafruit PyPortal - IoT for CircuitPython](https://learn.adafruit.com/adafruit-pyportal.md)
- [Adafruit PyPortal Titano](https://learn.adafruit.com/adafruit-pyportal-titano.md)
- [Infinite Text Adventure](https://learn.adafruit.com/infinite-text-adventure.md)
- [Data Logging IoT Weight Scale](https://learn.adafruit.com/data-logging-iot-weight-scale.md)
- [CircuitPython Day 2020 Countdown Clock](https://learn.adafruit.com/circuitpython-day-2020-countdown-clock.md)
- [How to Make Animated Graphics for Hologram Displays](https://learn.adafruit.com/how-to-make-animated-graphics-for-hologram-displays.md)
- [Getting Started with Braille Output for CircuitPython REPL](https://learn.adafruit.com/getting-started-braille-output-circuitpython-repl.md)
- [PyPortal WFH Busy Sounds Simulator](https://learn.adafruit.com/pyportal-wfh-busy-sounds-simulator.md)
- [PyPortal YouTube Views and Subscribers Display](https://learn.adafruit.com/pyportal-youtube-views-and-subscribers-display.md)
- [ Memory-saving tips for CircuitPython](https://learn.adafruit.com/memory-saving-tips-for-circuitpython.md)
- [PyPortal Astronauts in Space](https://learn.adafruit.com/pyportal-astronauts-in-space.md)
- [Upgrading AirLift ESP32 Firmware](https://learn.adafruit.com/upgrading-esp32-firmware.md)
- [Using Dashblock to Create Custom APIs for PyPortal](https://learn.adafruit.com/using-dashblock-to-create-custom-apis-for-pyportal.md)
- [PyPortal Tides Viewer](https://learn.adafruit.com/pyportal-tides-viewer.md)
- [Karel The Robot In CircuitPython](https://learn.adafruit.com/karel-the-robot-in-circuitpython.md)
- [PyPortal Quarantine Clock](https://learn.adafruit.com/pyportal-quarantine-clock.md)
- [CircuitPython Animated Holiday Wreath Lights](https://learn.adafruit.com/circuitpython-animated-holiday-wreath-lights.md)
