# CircuitPython OctoPrint Controller and Monitor

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/118/275/medium800/projects_edited_P1390768.jpg?1675821214)

[OctoPrint](https://octoprint.org/) is an incredibly popular and capable open-source project created and maintained by Gina Häußge. It allows you to remotely monitor and control your 3D printer. Traditionally you can check your OctoPrint status via a browser, but what if you wanted to get a quick status check without switching tabs?

This project uses Adafruit IO as an MQTT broker for OctoPrint and CircuitPython, running on a Feather ESP32-S2 Reverse TFT. OctoPrint sends MQTT messages to Adafruit IO as individual feeds with the [OctoPrint MQTT plugin](https://github.com/OctoPrint/OctoPrint-MQTT). The Feather checks the Adafruit IO feeds for new messages and updates the display accordingly, letting you see what's happening with your printer at your desk, coffee table, etc.

The Feather can also _send_ messages to OctoPrint using the [OctoPrint REST API](https://docs.octoprint.org/en/master/api/index.html), enabled with the [OctoPrint MQTT Subscribe plugin](https://github.com/jneilliii/OctoPrint-MQTTSubscribe). You'll ping Adafruit IO feeds with the buttons on the Feather to trigger commands in OctoPrint such as pausing or canceling a print.

https://youtube.com/shorts/3Mo7OyOPrVs

The TFT display on the Feather will show the current status of your printer according to OctoPrint alongside the [OctoPrint mascot](https://octoprint.org/trademark-rules/). For additional visualization, the onboard NeoPixel will show the rainbow animation during a print and blink a corresponding color for status states.

![projects_edited_P1390762.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/281/medium640/projects_edited_P1390762.jpg?1675822200)

If you are actively printing, a progress bar will be displayed denoting your print's progress.&nbsp;

![projects_edited_P1390758.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/283/medium640/projects_edited_P1390758.jpg?1675821665)

The D0, D1 and D2 buttons can send REST API commands via Adafruit IO to OctoPrint. Their functionality is shown on the TFT and varies depending on if your printer is printing or not.

If your printer is idle, you can set the hotend temperature to 0 (cooldown), set the hotend temperature to 200 (heat up) or reboot your OctoPrint server. If you are printing, you can pause, resume or cancel your print.

![projects_heatUp2.gif](https://cdn-learn.adafruit.com/assets/assets/000/118/290/medium640thumb/projects_heatUp2.jpg?1675818228)

## Prerequisite Setup and Guides
This project assumes that you are already [running an OctoPrint instance](https://octoprint.org/download/). It will not work unless you have OctoPrint running since it works _in tandem_ with OctoPrint using the MQTT and MQTT Subscribe plugins. [OctoPrint has many resources available](https://community.octoprint.org/c/support/7) to guide you through the setup and installation.

Additionally, you will need an [Adafruit IO account](https://learn.adafruit.com/welcome-to-adafruit-io) since Adafruit IO is acting as the [MQTT broker](https://learn.adafruit.com/mqtt-in-circuitpython/connecting-to-the-adafruit-io-mqtt-broker), logging the MQTT messages from OctoPrint in IO feeds to be accessed by the Feather and sending REST commands to OctoPrint. There are guides on the Learn System, linked here and below, to assist you with this.

Warning: 

[Welcome to Adafruit IO Learn Guide](https://learn.adafruit.com/welcome-to-adafruit-io)
[MQTT in CircuitPython Learn Guide](https://learn.adafruit.com/mqtt-in-circuitpython/overview)
[Adafruit ESP32-S2 TFT Feather Learn Guide](https://learn.adafruit.com/adafruit-esp32-s2-tft-feather)
## Parts
Featured
### Adafruit ESP32-S2 Reverse TFT Feather

[Adafruit ESP32-S2 Reverse TFT Feather](https://www.adafruit.com/product/5345)
Like Missy Elliot, we like to ["put our [Feather] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8)&nbsp;and that's exactly what we've done with this new development board. It's basically our **<a...></a...>**

In Stock
[Buy Now](https://www.adafruit.com/product/5345)
[Related Guides to the Product](https://learn.adafruit.com/products/5345/guides)
![Video of a rectangular microcontroller with a TFT display. A pink manicured finger presses each of the tactile buttons, which are recognized on the TFT display.](https://cdn-shop.adafruit.com/product-videos/640x480/5345-00.jpg)

Featured
### Pink and Purple Woven USB A to USB C Cable - 2 meters long

[Pink and Purple Woven USB A to USB C Cable - 2 meters long](https://www.adafruit.com/product/5044)
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 more.&nbsp; [If you want something just like it but for Micro B, we have a B...](https://www.adafruit.com/product/4111)

Out of Stock
[Buy Now](https://www.adafruit.com/product/5044)
[Related Guides to the Product](https://learn.adafruit.com/products/5044/guides)
![Angled shot of a pink/purple woven USB cable plugged into a laptop port and a small dev board.](https://cdn-shop.adafruit.com/640x480/5044-04.jpg)

Featured
### Black Nylon Machine Screw and Stand-off Set – M2.5 Thread

[Black Nylon Machine Screw and Stand-off Set – M2.5 Thread](https://www.adafruit.com/product/3299)
Totaling 380 pieces, this **M2.5 Screw Set** &nbsp;is a must-have for your workstation.&nbsp;You'll have enough screws, nuts, and hex standoffs to fuel your maker tendencies&nbsp;for days on end! M2.5 size screws fit almost all of the Adafruit breakout/dev board mounting holes...

Out of Stock
[Buy Now](https://www.adafruit.com/product/3299)
[Related Guides to the Product](https://learn.adafruit.com/products/3299/guides)
![Black Nylon Screw and Stand-off Set with M2.5 Threads, kit box](https://cdn-shop.adafruit.com/640x480/3299-00.jpg)

Featured
### Black Nylon Machine Screw and Stand-off Set – M3 Thread

[Black Nylon Machine Screw and Stand-off Set – M3 Thread](https://www.adafruit.com/product/4685)
Totaling **420 pieces** , this **M3 Screw Set** &nbsp;is a must-have for your workstation.&nbsp;You'll have enough screws, nuts, and hex standoffs to fuel your maker tendencies&nbsp;for days on end! M3 size screws fit a number of&nbsp;Adafruit breakout/dev board...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4685)
[Related Guides to the Product](https://learn.adafruit.com/products/4685/guides)
![Opened box showing many nylon screws](https://cdn-shop.adafruit.com/640x480/4685-01.jpg)

## Optional for monitoring additional feeds:
Featured
### Adafruit IO+ Subscription Pass – One Year

[Adafruit IO+ Subscription Pass – One Year](https://www.adafruit.com/product/3792)
The all-in-one Internet of Things service from Adafruit you know and love is now _even better_ with IO+. The 'plus' stands for MORE STUFF! More feeds, dashboards, storage, speed. Power up your [Adafruit IO](https://io.adafruit.com/) with the $99 pass for 1 year of the...

In Stock
[Buy Now](https://www.adafruit.com/product/3792)
[Related Guides to the Product](https://learn.adafruit.com/products/3792/guides)
![Text image that reads "IO+"](https://cdn-shop.adafruit.com/640x480/3792-01.jpg)

# CircuitPython OctoPrint Controller and Monitor

## 3D Printing

![](https://cdn-learn.adafruit.com/assets/assets/000/118/198/medium800/projects_edited_P1390668.jpg?1675779580)

The project may be mounted in a 3D printed case, described below. The case consists of three parts: the main lid, the main box and the tentacles. The case parts can print with no supports.

The STL file can be downloaded directly here or from Printables.

[Printables download](https://www.printables.com/model/392357-circuitpython-octoprint-controller-and-monitor-cas)
[OctoPrint_Case_Files.zip](https://cdn-learn.adafruit.com/assets/assets/000/118/223/original/OctoPrint_Case_Files.zip?1675783010)
The case is modeled to resemble an octopus to honor the OctoPrint mascot.&nbsp;

![projects_edited_P1390672.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/199/medium640/projects_edited_P1390672.jpg?1675779591)

The Feather mounts to the case lid with M2.5 and M2 hardware and the tentacles attach to the box with M3 hardware. There is a slot for a USB cable to plug into the Feather's USB port.

![projects_edited_P1390675.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/200/medium640/projects_edited_P1390675.jpg?1675779617)

# CircuitPython OctoPrint Controller and Monitor

## Installing the OctoPrint MQTT Plugin

## Search for the Plugin

To begin, go to your OctoPrint server in your web browser.

Then, you'll navigate to **OctoPrint Settings** by clicking on the **wrench icon** at the top of your OctoPrint browser window.

![projects_wrench.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/887/medium640/projects_wrench.jpg?1675091721)

In **OctoPrint Settings** , click on **Plugin Manager** in the left navigation menu. In the **Plugin Manager** , click on **+Get More**.

![projects_pluginManager.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/888/medium640/projects_pluginManager.jpg?1675091779)

## Install the Plugin
This will open the **Install new Plugins...** window. In the **search box** , type in **"mqtt"**. The **MQTT plugin** will appear at the top of the list. Click **Install** to install the plugin.

![projects_installMQTT.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/889/medium640/projects_installMQTT.jpg?1675091851)

## Restart OctoPrint
After the installation finishes, a **Plugin management log** dialog box will appear letting you know that you need to restart OctoPrint to complete the installation. Click **Restart now** to restart OctoPrint. When you're asked if you're sure that you want to restart, click **Proceed**.

![projects_mqttInstalled.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/891/medium640/projects_mqttInstalled.jpg?1675091961)

![projects_restartOcto.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/892/medium640/projects_restartOcto.jpg?1675092063)

After OctoPrint finishes restarting, you'll be prompted to reload the server. To do this, click **Reload now**.

![projects_reload.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/893/medium640/projects_reload.jpg?1675092129)

## Confirm Installation
After reloading the server, navigate back to **OctoPrint Settings** and the **Plugin Manager**. In the manager, **search for "mqtt"**. The **MQTT plugin** should now appear under **Installed Plugins**.

![projects_pluginManagerMQTTinstalled.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/894/medium640/projects_pluginManagerMQTTinstalled.jpg?1675118176)

# CircuitPython OctoPrint Controller and Monitor

## Installing the OctoPrint MQTT Subscribe Plugin

## Search for and Install the Plugin
After installing the MQTT plugin, return to the **Install new Plugins...&nbsp;** window and **search** for " **MQTT Subscribe**". Click **Install** to install the plugin.

![projects_mqttSub_0.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/176/medium640/projects_mqttSub_0.jpg?1675716963)

## Reboot OctoPrint
After the installation finishes, a **Plugin management log** dialog box will appear letting you know that you need to restart OctoPrint to complete the installation. Click **Restart now** to restart OctoPrint. When you're asked if you're sure that you want to restart, click **Proceed**.

![projects_mqttSub_1.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/177/medium640/projects_mqttSub_1.jpg?1675717003)

After OctoPrint finishes restarting, you'll be prompted to reload the server. To do this, click **Reload now**.

![projects_reload.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/179/medium640/projects_reload.jpg?1675717250)

## Confirm Installation
After reloading the server, navigate back to **OctoPrint Settings** and the **Plugin Manager**. In the manager, **search for "mqtt subscribe"**. The **MQTT Subscribe plugin** should now appear under **Installed Plugins**.

![projects_installedSubscribe.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/178/medium640/projects_installedSubscribe.jpg?1675717218)

# CircuitPython OctoPrint Controller and Monitor

## Configuring the OctoPrint MQTT Plugin

The OctoPrint MQTT plugin needs to be configured in a specific way in order for Adafruit IO to act as the MQTT broker. For more information on the [Adafruit IO MQTT API, check out the documentation page](https://io.adafruit.com/api/docs/mqtt.html#adafruit-io-mqtt-api).

[Adafruit IO MQTT API Documentation](https://io.adafruit.com/api/docs/mqtt.html#adafruit-io-mqtt-api)
## MQTT Broker Settings
In **OctoPrint Settings** , navigate to the **MQTT** page under **Plugins**. This displays the MQTT plugin configuration.

In the Broker tab, enter **io.adafruit.com** in the **Host box**. Enter **8883** in the **Port box**. Under **Protocol version** , select **MQTTv311**.&nbsp;

![projects_mqttSettings_0.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/895/medium640/projects_mqttSettings_0.jpg?1675119071)

Further down in the Broker tab, **check off**"The broker requires username and password to connect." Enter your **Adafruit IO username** in the **Username box** and your **Adafruit IO password key** in the **Password box**.

Then **check off**"The broker requires TLS to connect."

![projects_mqttSettings_1.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/896/medium640/projects_mqttSettings_1.jpg?1675119187)

## MQTT Topics

For Adafruit IO to subscribe to the MQTT topics in the MQTT plugin, their topic names need to match the Adafruit IO feed format: **{Adafruit IO username}/feeds/{feed name}**. This can be configured in the **Topics** tab.

There are [_many_ possible MQTT topics](https://docs.octoprint.org/en/devel/events/index.html#available-events) to subscribe to in the MQTT plugin. For the purposes of this project, only a few will be selected. If you are on the free tier of Adafruit IO with a ten feed limit, this project may **max out your feeds** if you select too many topics since the feeds are created _automatically_ as they are received by Adafruit IO. For more feeds, you can consider upgrading to [Adafruit IO+](http://io.adafruit.com/plus).

Info: 

[Adafruit IO+](http://io.adafruit.com/plus)
Under **General** , in the **Topics** tab, enter your **Adafruit IO username** followed by a **forward&nbsp;slash** ( **/** ).

![projects_mqttSettings_2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/897/medium640/projects_mqttSettings_2.jpg?1675119415)

Under **Event messages** , **check off**"Activate event messages".&nbsp;

In the **Topic** box, enter **feeds/{event}**. This will let the individual events automatically create feeds in your Adafruit IO account named for the event.

For topics, select **Server events** , **Communication events** and **Printing events**.

![projects_mqttSettings_3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/898/medium640/projects_mqttSettings_3.jpg?1675119808)

Under **Progress messages** , **check off**"Activate progress messages". This allows for the printing progress percentage messages to be monitored.

When you're finished, click the **Save** button at the bottom of the window.

![projects_mqttSettings_4.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/899/medium640/projects_mqttSettings_4.jpg?1675120079)

## Feeds in Adafruit IO
After configuring the plugin, navigate to your **Feeds tab** in **Adafruit IO**. As your printer performs tasks, you should see feeds begin to populate with the MQTT topics from OctoPrint that you selected in the plugin.

![projects_feeds.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/907/medium640/projects_feeds.jpg?1675112043)

# CircuitPython OctoPrint Controller and Monitor

## Configuring the OctoPrint MQTT Subscribe Plugin

After configuring the MQTT plugin, you can setup the MQTT Subscribe plugin. [The MQTT Subscribe plugin](https://github.com/jneilliii/OctoPrint-MQTTSubscribe) listens for REST requests on MQTT topics. These REST requests correspond with the [OctoPrint REST API](https://docs.octoprint.org/en/master/api/index.html). For more information on the OctoPrint REST API, check out the documentation page.

[OctoPrint REST API Documentation](https://docs.octoprint.org/en/master/api/index.html)
## Generate an API Key
Before configuring the plugin, you'll need to generate an API key. Navigate to the **MQTT Subscribe tab** under the **Plugins section**. Next to the **API KEY box** , click on the **blue** **plus sign (+) button**. You'll see your API key populate in the box.

![projects_mqttSub_2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/180/medium640/projects_mqttSub_2.jpg?1675717664)

## Add the Topics

The MQTT topics that MQTT Subscribe will listen to will need to match the Adafruit IO feed format: **{Adafruit IO username}/feeds/{feed name}**.&nbsp;

To add a new topic, click on the **plus sign (+) button** on the right side of the window.&nbsp;

![projects_mqttSub_2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/181/medium640/projects_mqttSub_2.jpg?1675717828)

This will open a blank **MQTT Topic Editor** window. You will add **six topics** to match the CircuitPython code. You'll edit the **Topic** , **Type** , **REST API** and **REST Parameters** sections for each topic. You can reference the charts below to see how each topic should be setup.

![projects_mqttSub_4.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/185/medium640/projects_mqttSub_4.jpg?1675717915)

## Reboot OctoPrint
## Preheat Printer

Preheats printer hotend to 200°C.

## Cooldown Printer

Sets printer hotend to 0°C.

## Pause Print
## Resume Print
## Cancel Print
After setting up the six topics, your MQTT Subscribe plugin window should look similar to this. Once you're finished, click **Save** in the bottom right-hand corner.

![projects_edited_mqttSub_5.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/187/medium640/projects_edited_mqttSub_5.jpg?1675719112)

# CircuitPython OctoPrint Controller and Monitor

## 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** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_feather_esp32s2_reverse_tft/)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/129/medium640/install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg?1620922559)

![](https://cdn-learn.adafruit.com/assets/assets/000/118/188/medium800/projects_boxes_adafruit_products_FRTFT_pinouts_top.jpg?1675720283)

Plug your board into your computer, using a known-good data-sync cable, directly, or via an adapter if needed.

Double-click the **reset** button (highlighted in red above), and you will see the **RGB status LED(s)** turn green (highlighted in green above). If you see red, try another port, or if you're using an adapter or hub, try without the hub, or different adapter or hub.

For this board, tap reset and wait for the LED to turn purple, and as soon as it turns purple, tap reset again. The second tap needs to happen while the LED is still purple.

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

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

You will see a new disk drive appear called&nbsp; **FTHRS2BOOT**. Drag the **adafruit\_feather\_esp32s2\_reverse\_tft\_etc.uf2** file to **FTHRS2BOOT**.

![projects_fthrBoot.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/191/medium640/projects_fthrBoot.jpg?1675720808)

The **BOOT** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it!

![install_circuitpython_on_most_boards_CIRCUITPY.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/130/medium640/install_circuitpython_on_most_boards_CIRCUITPY.jpg?1620923145)

# CircuitPython OctoPrint Controller and Monitor

## Create Your settings.toml File

CircuitPython works with WiFi-capable boards to enable you to make projects that have network connectivity. This means working with various passwords and API keys. As of [CircuitPython 8](https://circuitpython.org/downloads), there is support for a **settings.toml** file. This is a file that is stored on your **CIRCUITPY** drive, that contains all of your secret network information, such as your SSID, SSID password and any API keys for IoT services. It is designed to separate your sensitive information from your **code.py** file so you are able to share your code without sharing your credentials.

CircuitPython previously used a **secrets.py** file for this purpose. The **settings.toml** file is quite similar.

Warning: Your **settings.toml** file should be stored in the main directory of your **CIRCUITPY** drive. It should not be in a folder.

## CircuitPython **settings.toml** File

This section will provide a couple of examples of what your **settings.toml** file should look like, specifically for CircuitPython WiFi projects in general.

The most minimal **settings.toml** file must contain your WiFi SSID and password, as that is the minimum required to connect to WiFi. Copy this example, paste it into your **settings.toml** , and update:

- `your_wifi_ssid`
- `your_wifi_password`

```auto
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
```

Many CircuitPython network-connected projects on the Adafruit Learn System involve using Adafruit IO. For these projects, you must _also_ include your Adafruit IO username and key. Copy the following example, paste it into your settings.toml file, and update:

- `your_wifi_ssid`
- `your_wifi_password`
- `your_aio_username`
- `your_aio_key`

```auto
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
ADAFRUIT_AIO_USERNAME = "your_aio_username"
ADAFRUIT_AIO_KEY = "your_aio_key"
```

Some projects use different variable names for the entries in the **settings.toml** file. For example, a project might use `ADAFRUIT_AIO_ID` in the place of `ADAFRUIT_AIO_USERNAME`. **If you run into connectivity issues, one of the first things to check is that the names in the settings.toml file match the names in the code.**

Warning: Not every project uses the same variable name for each entry in the **settings.toml** file! Always verify it matches the code.

## **settings.toml** File Tips
Here is an example **settings.toml** file.

```auto
# Comments are supported
CIRCUITPY_WIFI_SSID = "guest wifi"
CIRCUITPY_WIFI_PASSWORD = "guessable"
CIRCUITPY_WEB_API_PORT = 80
CIRCUITPY_WEB_API_PASSWORD = "passw0rd"
test_variable = "this is a test"
thumbs_up = "\U0001f44d"
```

In a **settings.toml** file, it's important to keep these factors in mind:

- Strings are wrapped in double quotes; ex: `"your-string-here"`
- Integers are _ **not** _ quoted and may be written in decimal with optional sign (`+1`, `-1`, `1000`) or hexadecimal (`0xabcd`).
  - Floats (decimal numbers), octal (`0o567`) and binary (`0b11011`) are not supported.

- Use `\u` escapes for weird characters, `\x` and `\ooo` escapes are not available in **.toml** files
  - Example: `\U0001f44d` for 👍 (thumbs up emoji) and `\u20ac` for € (EUR sign)

- Unicode emoji, and non-ASCII characters, stand for themselves as long as you're careful to save in "UTF-8 without BOM" format

&nbsp;

&nbsp;

When your&nbsp; **settings.toml&nbsp;** file is ready, you can save it in your text editor with the **.toml** &nbsp;extension.

![adafruit_products_dotToml.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/071/medium640/adafruit_products_dotToml.jpg?1671034293)

## Accessing Your **settings.toml** Information in **code.py**
In your **code.py** file, you'll need to `import` the `os` library to access the **settings.toml** file. Your settings are accessed with the `os.getenv()` function. You'll pass your settings entry to the function to import it into the **code.py** file.

```python
import os

print(os.getenv("test_variable"))
```

![](https://cdn-learn.adafruit.com/assets/assets/000/117/072/medium800/adafruit_products_tomlOutput.jpg?1671034496)

In the upcoming CircuitPython WiFi examples, you'll see how the **settings.toml&nbsp;** file is used for connecting to your SSID and accessing your API keys.

# CircuitPython OctoPrint Controller and Monitor

## Coding the OctoPrint Status Viewer

Once you've finished setting up your reverse TFT Feather ESP32-S2 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.

To do this, click on the **Download Project Bundle** button in the window below. It will download as a zipped folder.

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

## Upload the Code and Libraries to the Reverse TFT Feather ESP32-S2

After downloading the Project Bundle, plug your reverse TFT Feather ESP32-S2 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called&nbsp; **CIRCUITPY**. Unzip the folder and copy the following items to the reverse TFT Feather ESP32-S2's&nbsp; **CIRCUITPY** &nbsp;drive.&nbsp;

- **lib** &nbsp;folder
- **code.py**
- **octoprint\_logo.bmp**
- **finished\_icon.bmp**
- **idle\_icons.bmp**
- **printing\_icons.bmp**

Your reverse TFT Feather ESP32-S2&nbsp; **CIRCUITPY&nbsp;** drive should look like this after copying the&nbsp; **lib** &nbsp;folder, **octoprint\_logo.bmp** , **finished\_icon.bmp** , **idle\_icons.bmp** , **printing\_icons.bmp** image files and the&nbsp; **code.py&nbsp;** file.

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

## Add Your **settings.toml** File

As of CircuitPython 8.0.0, there is support for [Environment Variables](https://docs.circuitpython.org/en/latest/docs/environment.html). These Environmental Variables are stored in a **settings.toml** file. Similar to **secrets.py** , the **settings.toml** file separates your sensitive information from your main **code.py** file. Add your **settings.toml** file as described in the [Create Your settings.toml File page](https://learn.adafruit.com/neopixel-sprite-weather-display/create-your-settings-toml-file) earlier in this guide. You'll need to include your `aio_username`, `aio_key`, `CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD`.

```python
CIRCUITPY_WIFI_SSID = "your-ssid-here"
CIRCUITPY_WIFI_PASSWORD = "your-ssid-password-here"

aio_username = "your-aio-username-here"
aio_key = "your-aio-key-here"
```

## How the CircuitPython Code Works

The code begins by creating a `HorizontalProgressBar()` object. This progress bar will display the progress of an active print and will act as an additional visual cue for the current status of the printer when it is idle.

```python
# Make the display context
splash = displayio.Group()
board.DISPLAY.root_group = splash

width = 165
height = 30

x = 70
y = 100

# Create a new progress_bar object at (x, y)
progress_bar = HorizontalProgressBar(
    (x, y),
    (width, height),
    fill_color=0x000000,
    outline_color=0xFFFFFF,
    bar_color=0x13c100,
    direction=HorizontalFillDirection.LEFT_TO_RIGHT
)

# Append progress_bar to the splash group
splash.append(progress_bar)
```

## Display Attributes

Next, a rectangle is created to act as a display divider. It appears as a thick white line on the display to separate the button icons from the progress bar and status message. Then, the OctoPrint logo and idle icons are imported as `TileGrid` objects.&nbsp;

```python
rect = Rect(60, 0, 2, 135, fill=0xFFFFFF)
splash.append(rect)

img = displayio.OnDiskBitmap("octoprint_logo.bmp")
idle_icons = displayio.OnDiskBitmap("idle_icons.bmp")
printing_icons = displayio.OnDiskBitmap("printing_icons.bmp")
finished_icon = displayio.OnDiskBitmap("finished_icon.bmp")

tile_grid = displayio.TileGrid(bitmap=img, pixel_shader=img.pixel_shader, x = 185, y=5)
splash.append(tile_grid)

text = bitmap_label.Label(terminalio.FONT, text="Connecting", scale=2, x=75, y=45)
splash.append(text)
```

## Buttons and NeoPixel

The front buttons are setup as inputs and the onboard NeoPixel is setup as a NeoPixel object.

```python
button0 = digitalio.DigitalInOut(board.D0)
button0.direction = digitalio.Direction.INPUT
button0.pull = digitalio.Pull.UP

button1 = digitalio.DigitalInOut(board.D1)
button1.direction = digitalio.Direction.INPUT
button1.pull = digitalio.Pull.DOWN

button2 = digitalio.DigitalInOut(board.D2)
button2.direction = digitalio.Direction.INPUT
button2.pull = digitalio.Pull.DOWN

button0_state = False
button1_state = False
button2_state = False

pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness = 0.6)
```

## Feeds

After connecting to Adafruit IO, the code tries to get the feeds corresponding to the MQTT topics defined in the OctoPrint MQTT plugins. If the feeds do not exist, they are created.

```python
pool = socketpool.SocketPool(wifi.radio)

requests = adafruit_requests.Session(pool, ssl.create_default_context())
io = IO_HTTP(aio_username, aio_key, requests)

try:
    # get feed
    printing_status = io.get_feed("printing")
    print_done = io.get_feed("printdone")
    printer_state = io.get_feed("printerstatechanged")
    shutdown = io.get_feed("shutdown")
    heat_up = io.get_feed("heatup")
    cooldown = io.get_feed("cooldown")
    resume = io.get_feed("printresumed")
    pause = io.get_feed("printpaused")
    cancelled = io.get_feed("printcancelled")

except AdafruitIO_RequestError:
    # if no feed exists, create one
    printing_status = io.create_new_feed("printing")
    print_done = io.create_new_feed("printdone")
    printer_state = io.create_new_feed("printerstatechanged")
    shutdown = io.create_new_feed("shutdown")
    heat_up = io.create_new_feed("heatup")
    cooldown = io.create_new_feed("cooldown")
    resume = io.create_new_feed("printresumed")
    pause = io.create_new_feed("printpaused")
    cancelled = io.create_new_feed("printcancelled")
```

## The Loop

In the loop, the code functionality is determined by the current state of the printer. This status is determined by the incoming messages on the `PrinterStateChanged` topic. If the printer is `PRINTING`, `PAUSED` or `PAUSING`, then the onboard NeoPixel displays the rainbow swirl animation and the buttons have the ability to send pause, resume and cancel messages to OctoPrint.

```python
if current_state in ("PRINTING", "PAUSED", "PAUSING"):
        rainbow.animate()
        if not button0.value and not button0_state:
            led.value = True
            io.send_data(send_while_printing_feeds[0]["key"], "ping")
            button0_state = True
        if button1.value and not button1_state:
            led.value = True
            io.send_data(send_while_printing_feeds[1]["key"], "ping")
            button1_state = True
        if button2.value and not button2_state:
            led.value = True
            io.send_data(send_while_printing_feeds[2]["key"], "ping")
            button2_state = True
```

For any other state, the onboard NeoPixel will blink a color that matches the status message. For example, red for disconnected and green for operational.

The buttons can send heat up, cooldown and reboot messages to OctoPrint unless a print has just finished. In that case, the `D0` button confirms that the print has completed and that updates the display and button abilities.&nbsp;

The button icons are updated by changing the `icon_grid` `bitmap` and `pixel_shader` attributes to the different icon bitmap files.

```python
else:
        blink.color=colors[state_value]
        blink.animate()
        if not button0.value and not button0_state:
            if finished_file == current_file:
                current_file = "None"
                progress_bar.value = 100
                progress_bar.bar_color = colors[state_value]
                text.text = "\n".join(wrap_text_to_lines("Status: %s" % current_state, 11))
                icon_grid.bitmap = idle_icons
                icon_grid.pixel_shader = idle_icons.pixel_shader
                button0_state = True
            else:
                led.value = True
                io.send_data(send_while_idle_feeds[0]["key"], "ping")
                button0_state = True
        if button1.value and not button1_state:
            led.value = True
            io.send_data(send_while_idle_feeds[1]["key"], "ping")
            button1_state = True
        if button2.value and not button2_state:
            led.value = True
            io.send_data(send_while_idle_feeds[2]["key"], "ping")
            button2_state = True
```

## Ping IO

Every fifteen seconds, Adafruit IO is checked for a new message from OctoPrint. If a new message has been logged in a feed, then that message is converted to a JSON entry so that it can be parsed.

```python
if (time.monotonic() - clock) > 15:
        #  get data
        for feed in range(3):
            try:
                data = io.receive_data(read_feeds[feed]["key"])
            except AdafruitIO_RequestError:
                print("Check that OctoPrint is sending data! Check your IO dashboard.")
            #  if a new value is detected
            if data["value"] != last_feed_msg[feed]:
                #  assign value to new_msg
                new_feed_msg[feed] = data["value"]
                msg_json[feed] = json.loads(data["value"])
                print(read_feeds[feed]["key"])
                print()
                print(new_feed_msg[feed])
                print()
                print_progress = int(msg_json[0]['progress'])
                current_file = str(msg_json[0]['path'])
                current_state = str(msg_json[1]['state_id'])
                finished_file = str(msg_json[2]['path'])
                state_value = printer_state_options.index(current_state)
                #  log msg
                last_feed_msg[feed] = new_feed_msg[feed]
```

If the printer is printing, then the progress bar and status text is updated with the print progress percentage.

```python
if current_state == "PRINTING":
            progress_bar.value = print_progress
            #octoprint green
            progress_bar.bar_color = 0x13c100
            text.text = "\n".join(wrap_text_to_lines("%d%% Printed" % print_progress, 7))
            icon_grid.bitmap = printing_icons
            icon_grid.pixel_shader = printing_icons.pixel_shader
```

If the printer is paused, then the progress bar's color is updated to yellow.

```python
elif current_state in ("PAUSED", "PAUSING"):
            progress_bar.value = print_progress
            progress_bar.bar_color = colors[state_value]
            text.text = "\n".join(wrap_text_to_lines("Status: %s" % current_state, 11))
            icon_grid.bitmap = printing_icons
            icon_grid.pixel_shader = printing_icons.pixel_shader
```

The code determines if a print has finished by comparing the file name on the `printing` topic and the `PrintDone` topic. If those file names match and the print progress is 100%, then the display updates to show that a print is finished.

```python
# when a print is finished:
        elif finished_file == current_file and print_progress == 100:
            progress_bar.value = 100
            progress_bar.bar_color = purple
            text.text = "\n".join(wrap_text_to_lines("Print Finished!", 11))
            icon_grid.bitmap = finished_icon
            icon_grid.pixel_shader = finished_icon.pixel_shader
```

If the printer is idle, then the progress bar displays a color that matches the blinking NeoPixel and the button icon bitmap changes to match their functionality.

```python
# when printer is idle, display status
        else:
            progress_bar.value = 100
            progress_bar.bar_color = colors[state_value]
            text.text = "\n".join(wrap_text_to_lines("Status: %s" % current_state, 11))
            icon_grid.bitmap = idle_icons
            icon_grid.pixel_shader = idle_icons.pixel_shader
```

# CircuitPython OctoPrint Controller and Monitor

## Assembly

![](https://cdn-learn.adafruit.com/assets/assets/000/118/201/medium800/projects_edited_P1390653.jpg?1675779681)

Insert an M3 screw into the mounting hole in the tentacle base.

![projects_edited_P1390647.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/204/medium640/projects_edited_P1390647.jpg?1675779733)

Attach the case box to the tentacle base using an M3 nut.

![projects_edited_P1390642.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/205/medium640/projects_edited_P1390642.jpg?1675779741)

## Mount the Feather
![](https://cdn-learn.adafruit.com/assets/assets/000/118/211/medium800/projects_edited_P1390662.jpg?1675779859)

Place the case lid on top of the Feather so that the buttons and TFT slot into their cutout areas.

![projects_edited_P1390659.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/206/medium640/projects_edited_P1390659.jpg?1675779772)

Attach the left side of the Feather (side with the three buttons) to the lid using M2.5 hardware.

![projects_edited_P1390656.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/207/medium640/projects_edited_P1390656.jpg?1675779791)

Attach the right side of the Feather (side with the reset button) to the lid using M2 hardware.

![projects_edited_P1390682.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/208/medium640/projects_edited_P1390682.jpg?1675779808)

## Create the Octopus
Close the case by snapping the lid onto the case box.

![projects_edited_P1390688.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/209/medium640/projects_edited_P1390688.jpg?1675779818)

That completes the assembly! You can power the Feather over USB or with a battery connected to the JST-PH battery port.

![projects_edited_P1390692.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/210/medium640/projects_edited_P1390692.jpg?1675779828)

# CircuitPython OctoPrint Controller and Monitor

## Usage

![](https://cdn-learn.adafruit.com/assets/assets/000/118/292/medium800thumb/projects_heatUp2.jpg?1675818384)

After confirming that OctoPrint is transmitting MQTT messages to Adafruit IO, power-up the Feather ESP32-S2 reverse TFT. You should see the TFT screen display the latest status message transmitted to Adafruit IO from OctoPrint.

If the printer is not printing, the latest event message will be displayed on the TFT. The onboard NeoPixel will blink in a corresponding color that matches the event message. For example, red for Offline, green for Operational, etc.

You'll have options for sending cooldown, heat up and reboot messages with the three buttons.

![projects_offline.gif](https://cdn-learn.adafruit.com/assets/assets/000/118/291/medium640thumb/projects_offline.jpg?1675824070)

If a print is running, the print progress will be shown on the screen as a percentage and a progress bar. The onboard NeoPixel will display the rainbow animation. You'll have options for sending pause, resume and cancel messages with the three buttons.

![projects_resume.gif](https://cdn-learn.adafruit.com/assets/assets/000/118/289/medium640thumb/projects_resume.jpg?1675824601)

When a print finishes, the display will show text letting you know that the print has completed. You can press the D0 button to dismiss the message and resume showing the latest event message.

![projects_pintFinished.gif](https://cdn-learn.adafruit.com/assets/assets/000/118/287/medium640thumb/projects_pintFinished.jpg?1675824483)

## Going Further

There are _a lot_ of MQTT topics that you can monitor or control for OctoPrint. This project really only began to scratch the surface of what is available and possible. Adafruit IO also has actions available, such as SMS and IFTTT, that could be helpful for OctoPrint. For example, you could monitor the `PrintDone` topic with an SMS action so that you recieve a text message when a print finishes.


## Guide Products

### Adafruit ESP32-S2 Reverse TFT Feather

[Adafruit ESP32-S2 Reverse TFT Feather](https://www.adafruit.com/product/5345)
Like Missy Elliot, we like to ["put our [Feather] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8)&nbsp;and that's exactly what we've done with this new development board. It's basically our **<a...></a...>**

In Stock
[Buy Now](https://www.adafruit.com/product/5345)
[Related Guides to the Product](https://learn.adafruit.com/products/5345/guides)
### Pink and Purple Woven USB A to USB C Cable - 2 meters long

[Pink and Purple Woven USB A to USB C Cable - 2 meters long](https://www.adafruit.com/product/5044)
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 more.&nbsp; [If you want something just like it but for Micro B, we have a B...](https://www.adafruit.com/product/4111)

Out of Stock
[Buy Now](https://www.adafruit.com/product/5044)
[Related Guides to the Product](https://learn.adafruit.com/products/5044/guides)
### Black Nylon Machine Screw and Stand-off Set – M2.5 Thread

[Black Nylon Machine Screw and Stand-off Set – M2.5 Thread](https://www.adafruit.com/product/3299)
Totaling 380 pieces, this **M2.5 Screw Set** &nbsp;is a must-have for your workstation.&nbsp;You'll have enough screws, nuts, and hex standoffs to fuel your maker tendencies&nbsp;for days on end! M2.5 size screws fit almost all of the Adafruit breakout/dev board mounting holes...

Out of Stock
[Buy Now](https://www.adafruit.com/product/3299)
[Related Guides to the Product](https://learn.adafruit.com/products/3299/guides)
### Black Nylon Machine Screw and Stand-off Set – M3 Thread

[Black Nylon Machine Screw and Stand-off Set – M3 Thread](https://www.adafruit.com/product/4685)
Totaling **420 pieces** , this **M3 Screw Set** &nbsp;is a must-have for your workstation.&nbsp;You'll have enough screws, nuts, and hex standoffs to fuel your maker tendencies&nbsp;for days on end! M3 size screws fit a number of&nbsp;Adafruit breakout/dev board...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4685)
[Related Guides to the Product](https://learn.adafruit.com/products/4685/guides)
### Adafruit IO+ Subscription Pass – One Year

[Adafruit IO+ Subscription Pass – One Year](https://www.adafruit.com/product/3792)
The all-in-one Internet of Things service from Adafruit you know and love is now _even better_ with IO+. The 'plus' stands for MORE STUFF! More feeds, dashboards, storage, speed. Power up your [Adafruit IO](https://io.adafruit.com/) with the $99 pass for 1 year of the...

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

## Related Guides

- [Adafruit ESP32-S2 Reverse TFT Feather](https://learn.adafruit.com/esp32-s2-reverse-tft-feather.md)
- [RP2040 RunCPM Emulator with USB Keyboard & HDMI screen](https://learn.adafruit.com/rp2040-runcpm-emulator-with-usb-keyboard-hdmi-screen.md)
- [Feather Guitar Hero Adapter](https://learn.adafruit.com/feather-guitar-hero-adapter.md)
- [PlayStation Spinner Controller](https://learn.adafruit.com/playstation-spinner-controller.md)
- [Modal MIDI Keyboard](https://learn.adafruit.com/modal-midi-keyboard.md)
- [How to Make Animated Graphics for Hologram Displays](https://learn.adafruit.com/how-to-make-animated-graphics-for-hologram-displays.md)
- [DOOM on Fruit Jam](https://learn.adafruit.com/doom-on-fruit-jam.md)
- [Pathfinder Robot Companion](https://learn.adafruit.com/pathfinder.md)
- [CircuitPython Webcam with OV2640](https://learn.adafruit.com/circuitpython-webcam-with-ov2640.md)
- [Severence-Inspired Lumon Bluetooth Speaker](https://learn.adafruit.com/bluetooth-speaker.md)
- [Planetary Gear Dreidels](https://learn.adafruit.com/planetary-gear-dreidels.md)
- [Party Parrot Zoetrope](https://learn.adafruit.com/party-parrot-zoetrope.md)
- [Bluetooth Controlled NeoPixel Lightbox](https://learn.adafruit.com/bluetooth-neopixel-lightbox.md)
- [Glowy Message Crown](https://learn.adafruit.com/glowy-message-crown.md)
- [PyPortal Weather Station](https://learn.adafruit.com/pyportal-weather-station.md)
- [LED Matrix Alarm Clock](https://learn.adafruit.com/led-matrix-alarm-clock.md)
