# Qualia S3 Space Clock

## Overview

https://www.youtube.com/watch?v=1aKPpNjMM1k

David Bowie asked if there was life on Mars, but what about time? With this project, you can easily switch between viewing your local time on Earth and coordinated Mars time (MTC) on a beautiful round 720x720 display housed in a retro space-themed orb enclosure.

The display shows a classic analog clock face for viewing the time. Hour and minute hands are created with `vectorio` polygons in CircuitPython.

![lcds___displays_hero-clock-face.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/260/medium640/lcds___displays_hero-clock-face.jpg?1701185507)

An arcade button mounted to the back of the clock lets you switch between Earth and Mars time.

![lcds___displays_hero-button.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/280/medium640/lcds___displays_hero-button.jpg?1701190718)

Inspired by mid-century modern clocks, this 3D printed enclosure embodies a space-age retro aesthetic. The base features beautiful curves that blend the neck to the wide base. The display is mounted to a spherical dome that's tilted 15 degrees for the best viewing angle. The display can swivel slightly, allowing the user to adjust it.

![lcds___displays_hero-side.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/282/medium640/lcds___displays_hero-side.jpg?1701190863)

The base features an opening for the USB-C port, two user buttons and a reset button.

![lcds___displays_hero-base-port.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/283/medium640/lcds___displays_hero-base-port.jpg?1701191182)

## Prerequisite Guides

Take a moment to review the following guides to learn more about the products.

- [Adafruit Qualia ESP32-S3 Guide](https://learn.adafruit.com/adafruit-qualia-esp32-s3-for-rgb666-displays)

## Parts
![](https://cdn-learn.adafruit.com/assets/assets/000/126/278/medium800/lcds___displays_hero-space-bg.jpg?1701190623)

### Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays

[Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays](https://www.adafruit.com/product/5800)
There's a few things everyone loves: ice cream, kittens, and honkin' large TFT screens. We're no strangers to small TFT's - [from our itsy 1.14" color display](https://www.adafruit.com/search?q=1.14+tft) that graces many-a-TFT-Feather to <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/5800)
[Related Guides to the Product](https://learn.adafruit.com/products/5800/guides)
![Overhead shot of TFT driver board connected to a round TFT display, which says, "Hello world!"](https://cdn-shop.adafruit.com/640x480/5800-06.jpg)

### Round RGB TTL TFT Display - 4" 720x720 - No Touchscreen

[Round RGB TTL TFT Display - 4" 720x720 - No Touchscreen](https://www.adafruit.com/product/5793)
This is a screen for advanced hackers who like the look of a nice, round TFT screen with tons of pixels. This massive&nbsp;4" diagonal-sized display has 720x720 16-bit full-color pixels and is an&nbsp; **IPS** &nbsp;display, so the color looks great up to 80 degrees off-axis in...

In Stock
[Buy Now](https://www.adafruit.com/product/5793)
[Related Guides to the Product](https://learn.adafruit.com/products/5793/guides)
![Overhead shot of round TFT display with a color gradient rainbow image.](https://cdn-shop.adafruit.com/640x480/5793-03.jpg)

### 40-pin FPC Extension Board + 200mm Cable

[40-pin FPC Extension Board + 200mm Cable](https://www.adafruit.com/product/2098)
Give your 40 pin, 0.5mm pitch, devices a strrrreeeetch with this extension board.&nbsp; This 40pin FPC extension board has two 40-pin flex connectors (both are bottom contact type), and an extension cable to add ~22cm (20cm cable plus 2cm board)&nbsp; Each order comes with one board a 20cm...

In Stock
[Buy Now](https://www.adafruit.com/product/2098)
[Related Guides to the Product](https://learn.adafruit.com/products/2098/guides)
![40-pin FPC Extension Board with  200mm long Cable](https://cdn-shop.adafruit.com/640x480/2098-02.jpg)

### Mini LED Arcade Button - 24mm Translucent Clear

[Mini LED Arcade Button - 24mm Translucent Clear](https://www.adafruit.com/product/3429)
A button is a button, and a switch is a switch, but these translucent arcade buttons are in a class of their own. Particularly because they have **LEDs built right in!** That's right, you'll be button-mashing amidst a wash of beautiful light with these lil'...

In Stock
[Buy Now](https://www.adafruit.com/product/3429)
[Related Guides to the Product](https://learn.adafruit.com/products/3429/guides)
![Video of 24mm mini translucent clear LED arcade button flashing on and off.](https://cdn-shop.adafruit.com/product-videos/640x480/3429-03.jpg)

### STEMMA JST PH 2mm 3-Pin to Female Socket Cable - 200mm

[STEMMA JST PH 2mm 3-Pin to Female Socket Cable - 200mm](https://www.adafruit.com/product/3894)
This cable will let you turn a JST PH 3-pin cable port into 3 individual wires with high-quality 0.1" female header sockets on the end. We're carrying these to match up with our Hallowing, for extending and connecting sensors or LEDs - and the wires are even color coded!

<a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/3894)
[Related Guides to the Product](https://learn.adafruit.com/products/3894/guides)
![Angled shot of STEMMA JST PH 3-Pin to Female Header Cable - 200mm.](https://cdn-shop.adafruit.com/640x480/3894-03.jpg)

### Pink and Purple Woven USB A to USB C Cable - 1 meter long

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

Out of Stock
[Buy Now](https://www.adafruit.com/product/5153)
[Related Guides to the Product](https://learn.adafruit.com/products/5153/guides)
![Angled shot of coiled pink and purple USB cable with USB A and USB C connectors.](https://cdn-shop.adafruit.com/640x480/5153-02.jpg)

## Hardware

Required screws and nuts for assembly.

- 4x M2.5 x 6mm long pan head machine screw

![](https://cdn-learn.adafruit.com/assets/assets/000/126/259/medium800/lcds___displays_hero-mars.jpg?1701185419)

![](https://cdn-learn.adafruit.com/assets/assets/000/126/261/medium800/lcds___displays_hero-earth.jpg?1701185602)

# Qualia S3 Space Clock

## Circuit Diagram

The diagram below provides a general visual reference for wiring of the components once you get to the **Assembly** page. This diagram was created using the software package [Fritzing](http://fritzing.org/download/).

## Adafruit Library for Fritzing

Adafruit uses the Adafruit's Fritzing parts library to create circuit diagrams for projects. You can download the library or just grab individual parts. Get the library and parts from [GitHub - Adafruit Fritzing Parts](https://github.com/adafruit/Fritzing-Library/tree/master/parts).

![](https://cdn-learn.adafruit.com/assets/assets/000/126/262/medium800/lcds___displays_circuit-diagram.jpg?1701187510)

## Wired Connections

The Qualia ESP32-S3 is powered by a 5V 1A USB power supply.

- The arcade button connects to the Qualia ESP32-S3 using a 3-pin JST Stemma cable.

# Qualia S3 Space Clock

## 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.

This microcontroller requires the latest **unstable (development)&nbsp;**release of CircuitPython. Click below to visit the downloads page on **circuitpython.org** for your board. Then, Browse **S3** under **Absolute Newest**.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_qualia_s3_rgb666/)
 **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)

Warning: 

![](https://cdn-learn.adafruit.com/assets/assets/000/124/831/medium800/circuitpython_bootloader.jpg?1696442767)

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.

Warning: 

For this board, tap reset and wait about a half a second and then tap reset again.

Warning: 

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 **TFT\_S3BOOT**.

&nbsp;

Drag the **adafruit\_circuitpython\_etc.uf2** file to **TFT\_S3BOOT**.

![circuitpython_Screenshot_2023-10-03_at_1.54.46_PM.png](https://cdn-learn.adafruit.com/assets/assets/000/124/832/medium640/circuitpython_Screenshot_2023-10-03_at_1.54.46_PM.png?1696442912)

![circuitpython_Screenshot_2023-10-05_at_10.20.11_AM.png](https://cdn-learn.adafruit.com/assets/assets/000/124/889/medium640/circuitpython_Screenshot_2023-10-05_at_10.20.11_AM.png?1696526572)

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)

# Qualia S3 Space Clock

## 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.

# Qualia S3 Space Clock

## Code the Clock

Once you've finished setting up your Qualia ESP32-S3 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 to your computer as a zipped folder.

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

## Upload the Code and Libraries to the Qualia ESP32-S3

After downloading the Project Bundle, plug your Qualia ESP32-S3 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 **CIRCUITPY**. Unzip the folder and copy the following items to the Qualia ESP32-S3's **CIRCUITPY** drive.

- **lib** folder
- **code.py**
- **earth.bmp**
- **mars.bmp**
- **Roboto-Regular-47.pcf**

Your Qualia ESP32-S3 **CIRCUITPY** drive should look like this after copying the **lib** folder, **earth.bmp** file, **mars.bmp** file, **Roboto-Regular-47.pcf** file and the **code.py** file.

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

## Install the udecimal Library from the Community Bundle

This project uses one additional library from the Community Bundle: the [jepler\_udecimal library](https://github.com/jepler/Jepler_CircuitPython_udecimal). You'll need to [download the Community Bundle](https://circuitpython.org/libraries) and copy the / **jepler\_udecimal** library folder to your **/lib** folder or use [circup](https://learn.adafruit.com/keep-your-circuitpython-libraries-on-devices-up-to-date-with-circup/overview) to install with:

`circup install jepler-circuitpython-udecimal`

## 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). Environment 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/mars-clock/create-your-settings-toml-file) earlier in this guide. You'll need to include your `ADAFRUIT_AIO_USERNAME`, `ADAFRUIT_AIO_KEY`,&nbsp; `CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD`.

```python
CIRCUITPY_WIFI_SSID = "your-ssid-here"
CIRCUITPY_WIFI_PASSWORD = "your-ssid-password-here"
ADAFRUIT_AIO_USERNAME = "your-io-username-here"
ADAFRUIT_AIO_KEY = "your-io-key-here"
```

## How the CircuitPython Code Works

At the top of the code, you'll edit the `timezone` variable to equal your [UTC time zone offset](https://en.wikipedia.org/wiki/UTC_offset). This is used when calculating Mars time (MTC).

```python
# timezone offset for calculating mars time
timezone = -5
```

After that, pin `A0` is setup as a `keypad` object. Pressing the button attached to this pin will switch the display between Earth and Mars time. Then, the board connects to your WiFi SSID and Adafruit IO.

```python
key = keypad.Keys((board.A0,), value_when_pressed=False, pull=True)

wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}")

aio_username = os.getenv('ADAFRUIT_AIO_USERNAME')
aio_key = os.getenv('ADAFRUIT_AIO_KEY')

context = ssl.create_default_context()
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, context)
io = IO_HTTP(aio_username, aio_key, requests)
```

## Graphics

The display is instantiated with the Qualia Graphics library. Then, the Earth and Mars are loaded as `OnDiskBitmap`'s. Display groups are created for each planet.

```python
earth_bitmap = displayio.OnDiskBitmap("/earth.bmp")
mars_bitmap = displayio.OnDiskBitmap("/mars.bmp")

graphics = Graphics(Displays.ROUND40, default_bg=None, auto_refresh=True)

earth_grid = displayio.TileGrid(earth_bitmap, pixel_shader=earth_bitmap.pixel_shader)
earth_group = displayio.Group()
earth_group.append(earth_grid)

mars_grid = displayio.TileGrid(mars_bitmap, pixel_shader=mars_bitmap.pixel_shader)
mars_group = displayio.Group()
mars_group.append(mars_grid)

def center(grid, bitmap):
    # center the image
    grid.x -= (bitmap.width - graphics.display.width) // 2
    grid.y -= (bitmap.height - graphics.display.height) // 2

center(mars_grid, mars_bitmap)
center(earth_grid, earth_bitmap)

graphics.display.root_group = mars_group
```

[vectorio shapes](https://docs.circuitpython.org/en/latest/shared-bindings/vectorio/index.html) are used for the clock face graphics. A circle is created for the center of the display for the minute and hour hands to fan out from.

```python
# pointer using vectorio, first the hub
pointer_pal = displayio.Palette(4)
pointer_pal[0] = 0xff0000
pointer_pal[1] = 0x000000
pointer_pal[2] = 0x0000ff
pointer_pal[3] = 0xffffff
pointer_hub = vectorio.Circle(pixel_shader=pointer_pal, radius=26, x=0, y=0)
pointer_hub.x = graphics.display.width // 2
pointer_hub.y = graphics.display.height // 2
```

The minute and hour hands are polygon shapes. The clock hands are added to both display groups.

```python
# minute hand
mw = 23
mh = 225
min_points = [(mw,0), (mw,-mh), (-mw,-mh), (-mw,0)]
min_hand = vectorio.Polygon(pixel_shader=pointer_pal, points=min_points, x=0,y=0)
min_hand.x = graphics.display.width // 2
min_hand.y = graphics.display.height // 2
mars_group.append(min_hand)
earth_group.append(min_hand)
# hour hand
hw = 25
hh = 175
hour_points = [(hw,0), (hw,-hh), (-hw,-hh), (-hw,0)]
hour_hand = vectorio.Polygon(pixel_shader=pointer_pal, points=hour_points,
                             x=0, y=0, color_index=1)
hour_hand.x = graphics.display.width // 2
hour_hand.y = graphics.display.height // 2
mars_group.append(hour_hand)
earth_group.append(hour_hand)
```

The clock face numbers are placed around the perimeter of the circular display. These coordinates are calculated with the `calculate_number_position()` function. In a `for` loop, `vectorio` circles are created to act as a background for the clock numbers. The clock numbers are added as text labels. There are two instances of these circle and number pairs created for the display groups. The colors differ between the two to better complement the planet backgrounds.

```python
# add numbers to the clock face
def calculate_number_position(number, center_x, center_y, radius):
    angle = (360 / 12) * (number - 3)  # -3 adjusts the angle to start at 12 o'clock
    rad_angle = pi * angle / 180
    if number &gt;=8:
        x = int(center_x + cos(rad_angle) * radius-40)
    x = int(center_x + cos(rad_angle) * radius)
    y = int(center_y + sin(rad_angle) * radius)
    return x, y

clock_face_numbers = {i: calculate_number_position(i, graphics.display.width // 2,
                        graphics.display.height // 2, 300) for i in range(1, 13)}

font_file = "/Roboto-Regular-47.pcf"

for i in range(1, 13):
    mars_c = vectorio.Circle(pixel_shader=pointer_pal, radius=30, x=clock_face_numbers[i][0]+12,
                             y=clock_face_numbers[i][1], color_index=1)
    earth_c = vectorio.Circle(pixel_shader=pointer_pal, radius=30, x=clock_face_numbers[i][0]+12,
                             y=clock_face_numbers[i][1], color_index=3)
    if i &gt;= 10:
        mars_c.x = mars_c.x + 14
        earth_c.x = earth_c.x + 14
    mars_group.append(mars_c)
    earth_group.append(earth_c)
    text = str(i)
    font = bitmap_font.load_font(font_file)

    mars_text = label.Label(font, text=text, color=0xFFFFFF)
    earth_text = label.Label(font, text=text, color=0x000000)
    mars_text.x = clock_face_numbers[i][0]
    mars_text.y = clock_face_numbers[i][1]
    earth_text.x = clock_face_numbers[i][0]
    earth_text.y = clock_face_numbers[i][1]
    mars_group.append(mars_text)
    earth_group.append(earth_text)
```

## Time Functions

The internet time is retrieved using the `io.receive_time()` function. This returns a `struct_time` timestamp in the same time zone as your IP address.

```python
# get time from adafruit io
# called once an hour in the loop
def update_time():
    print("time")
    now = io.receive_time()
    return now
```

The `convert_time()` function is used to convert the `struct_time` from 24 hour to 12 hour time.

```python
def convert_time(the_time):
    h = the_time[3]
    if h &gt;= 12:
        h -= 12
        a = "PM"
    else:
        a = "AM"
    if h == 0:
        h = 12
    return h, a
```

The `mars_time()` function converts the current time to the Unix timestamp and calculates coordinated Mars time (MTC). This function makes use of the **jepler\_udecimal** library. This library is a subset of the CPython&nbsp;[Decimal library](https://docs.python.org/3/library/decimal.html), which is designed for arithmetic and greater accuracy over&nbsp;`float`&nbsp;numbers. CircuitPython does not have an accurate enough `float` accuracy for this calculation otherwise.

A more in-depth explanation on calculating Mars time with CircuitPython can be found in [this Playground Note](https://adafruit-playground.com/u/BlitzCityDIY/pages/accurately-calculating-coordinated-mars-time-with-circuitpython).

```python
# get mars time
def mars_time():
    dt = io.receive_time()
    print(dt)
    utc_offset = 3600 * -timezone
    tai_offset = 37
    millis = time.mktime(dt)
    unix_timestamp = millis + utc_offset

    # Convert to MSD
    msd = (unix_timestamp + tai_offset) / Decimal("88775.244147") + Decimal("34127.2954262")
    print(msd)
    # Convert MSD to MTC
    mtc = (msd % 1) * 24
    mtc_hours = int(mtc)
    mtc_minutes = int((mtc * 60) % 60)
    mtc_seconds = int(((mtc * 3600)) % 60)

    print(f"Mars Time: {mtc_hours:02d}:{mtc_minutes:02d}:{mtc_seconds:02d}")
    return mtc_minutes, mtc_hours
```

The `time_angle()` function calculates the angle of the minute and hour hand polygon shapes by updating their coordinates.

```python
def time_angle(m, the_hour):
    m_offset = 25 if 12 &lt;= m &lt; 18 or 42 &lt;= m &lt; 48 else 5
    h_offset = 25 if 2 &lt;= the_hour % 12 &lt; 4 or 8 &lt;= the_hour % 12 &lt; 10 else 5
    # Adjusted angle calculation for minute hand
    theta_minute = 360 - (m / 60) * 360
    theta_hour = ((the_hour / 12) + (m / (12 * 60))) * 360
    # Calculate coordinates for minute hand (mirrored)
    minute_x = -int(cos(pi * (theta_minute - 90) / 180) * mh)
    minute_y = int(sin(pi * (theta_minute + 90) / 180) * mh)
    hour_x = int(cos(pi * (theta_hour - 90) / 180) * hh)
    hour_y = int(sin(pi * (theta_hour + 90) / 180) * hh)
    min_hand.points = [(mw, 0), (minute_x + m_offset, -minute_y),
                       (minute_x - m_offset, -minute_y), (-mw, 0)]
    hour_hand.points = [(hw, 0), (hour_x + h_offset, -hour_y),
                        (hour_x - h_offset, -hour_y), (-hw, 0)]
```

## The Loop

In the loop, if the button attached to `A0` is pressed, then the display swaps to either show the Earth time or Mars time. When the display swaps, the background images changes, the clock hand colors change and the associated time is displayed.

```python
while True:
    event = key.events.get()
    # swap between earth or mars time
    if event:
        if event.pressed:
            print("updating display")
            show_earth = not show_earth
    # update background image
    # change minute hand color depending on background
    if show_earth:
        if min_hand.color_index != 2:
            time_angle(minute, hour)
            graphics.display.root_group = earth_group
            min_hand.color_index = 2
            pointer_hub.color_index = 2
    else:
        if min_hand.color_index != 0:
            time_angle(mars_min, mars_hour)
            graphics.display.root_group = mars_group
            min_hand.color_index = 0
            pointer_hub.color_index = 0
```

## Time Keeping

After the initial time fetch, `ticks` is used to keep time. Every minute, the angle of the clock hands are updated. Every hour, Adafruit IO is pinged to update the time to keep ticks accurate.

```python
# use ticks for timekeeping
    # every minute update clock hands
    # recheck IO time every hour
    if ticks_diff(ticks_ms(), clock_clock) &gt;= clock_timer:
        tick += 1
        if tick &gt; 59:
            tick = 0
            minute += 1
            if minute &gt; 59:
                clock = update_time()
                hour, am_pm = convert_time(clock)
                tick = clock[5]
                minute = clock[4]
            print(f"{hour}:{minute:02} {am_pm}")
            mars_min, mars_hour = mars_time()
            if show_earth:
                time_angle(minute, hour)
            else:
                time_angle(mars_min, mars_hour)
        clock_clock = ticks_add(clock_clock, clock_timer)
```

# Qualia S3 Space Clock

## CAD Files

## 3D Printed Parts

STL files for 3D printing are oriented to print "as-is" on FDM style machines. Parts are designed to 3D print without any support material using PLA filament. Original design source may be downloaded using the links below.

![lcds___displays_cura-sliced.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/137/medium640/lcds___displays_cura-sliced.jpg?1700499529)

## Parts List

- Back Dome
- Base
- Bottom Cover
- Display Mount
- Display Frame
- Dome Cover
- Front Frame
- Neck Collar

![lcds___displays_3d-parts.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/174/medium640/lcds___displays_3d-parts.jpg?1701104170)

[Download CAD source](https://cdn-learn.adafruit.com/assets/assets/000/126/171/original/CAD.zip?1701099980)
[Download STLs.zip](https://cdn-learn.adafruit.com/assets/assets/000/126/172/original/STLs.zip?1701100049)
## Build Volume

The parts require a 3D printer with a minimum build volume.

- 132mm (X) x 132mm (Y) x 102mm (Z)

![lcds___displays_cura-slice.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/136/medium640/lcds___displays_cura-slice.jpg?1700496673)

# CAD Assembly

The 4in round display press fits into the display mount. The display mount snap fits into the front frame. The display frame snap fits over the 4in round display. The back dome and front frame snap fit together. The button is panel mounted to the dome cover. The base and back dome are connected using the neck collar. The Qualia ESP32-S3 board is secured to the bottom cover using four M2.5 x 6mm long screws. The bottom cover snap fits onto the bottom of the base. The 4in round display is connected to a 40-pin FPC extension board and ribbon cable that connects to the Qualia ESP32-S3 board.

![lcds___displays_CAD.gif](https://cdn-learn.adafruit.com/assets/assets/000/126/170/medium640thumb/lcds___displays_CAD.jpg?1701095383)

## Design Source Files

The project assembly was designed in Fusion 360. This can be downloaded in different formats like STEP, STL and more. Electronic components like Adafruit's boards, displays, connectors and more can be downloaded from the&nbsp;[Adafruit CAD parts GitHub Repo](https://github.com/adafruit/Adafruit_CAD_Parts/).

![circuitpython_5800-Qualia-ESP32-S3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/445/medium640/circuitpython_5800-Qualia-ESP32-S3.jpg?1701278239)

# Qualia S3 Space Clock

## Wiring Assembly

## JST Cable for Button

Get the 3-pin JST cable ready to solder to the 24mm arcade button.

![lcds___displays_button-cable.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/183/medium640/lcds___displays_button-cable.jpg?1701115476)

## Setup JST Cable

Remove the red wire from the cable using wire cutters. The arcade button only needs two wires (black and white).

![lcds___displays_button-cable-cut.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/206/medium640/lcds___displays_button-cable-cut.jpg?1701118950)

## Solder Cable

Attach the wires to the two terminals on the buttons switch. Polarity does not have to match.

![lcds___displays_button-w-cable.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/207/medium640/lcds___displays_button-w-cable.jpg?1701118963)

![lcds___displays_button-soldered.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/208/medium640/lcds___displays_button-soldered.jpg?1701119043)

## Button Labels

The buttons switch terminals are fitted inside the gray colored plastic housing.

![lcds___displays_button-labels.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/211/medium640/lcds___displays_button-labels.jpg?1701119150)

## Wired Button&nbsp;

Take a moment to test the 3-pin JST cable by plugging it into the JST port on the Qualia ESP32-S3 board.&nbsp;

Disconnect the button from the board when finished testing.

![lcds___displays_button-wired.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/209/medium640/lcds___displays_button-wired.jpg?1701119060)

![lcds___displays_button-qualia-test.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/210/medium640/lcds___displays_button-qualia-test.jpg?1701119134)

## FPC Extension

Get the 40-pin FPC extension board and ribbon cable ready to connect to the 4in round display.

![lcds___displays_display-fpc-ext.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/212/medium640/lcds___displays_display-fpc-ext.jpg?1701119883)

## Connect Ribbon Cables

Carefully lift the two latches on the FPC extension board to open them.

Insert the 40-pin ribbon cable into one of the connectors with the blue side facing up.

Push ribbon cable to fully seat into the connector then gently press down on latch to close.

Insert ribbon cable from the 4in round display into the remaining connector on the FPC extension board. Press down to close latch.

![lcds___displays_fpc-ribbon-connect.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/214/medium640/lcds___displays_fpc-ribbon-connect.jpg?1701120049)

![lcds___displays_fpc-display-connect.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/215/medium640/lcds___displays_fpc-display-connect.jpg?1701120062)

## Install Display to Mount

Get the Display Mount part and 4in round display ready.

Carefully place the display into the recess in the 3D printed display mount with the edges lined up.

Flip the display ribbon cable so it lays flat against the back.&nbsp;

Gently press the edges of the display into the lip of the 3D printed display mount.&nbsp;

![lcds___displays_display-mount.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/216/medium640/lcds___displays_display-mount.jpg?1701120117)

![lcds___displays_display-mount-install.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/217/medium640/lcds___displays_display-mount-install.jpg?1701120140)

## Install Display Frame

Get the 3D printed display frame ready.

Insert the display frame underneath the three clips on the inside of the display mount.

The display frame can be flexed to sit flush over the display and under the three clips.

![lcds___displays_display-frame.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/218/medium640/lcds___displays_display-frame.jpg?1701120188)

![lcds___displays_display-frame-install.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/219/medium640/lcds___displays_display-frame-install.jpg?1701120229)

## Front Frame

Get the 3D printed front frame ready.

Orient the two parts so the notches and keys are lined up.&nbsp;

![lcds___displays_display-front-frame.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/220/medium640/lcds___displays_display-front-frame.jpg?1701120285)

## Install Display to Front Frame

Carefully insert the display assembly into the front frame with the keys fitted into the notches.

Gently press down on all edges so the display frame sits flush with the front frame.

![lcds___displays_front-frame-installing.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/221/medium640/lcds___displays_front-frame-installing.jpg?1701120312)

![lcds___displays_front-frame-press.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/222/medium640/lcds___displays_front-frame-press.jpg?1701120329)

## Secured Display

Take a moment to check the display is secured to the front frame.

![lcds___displays_front-frame-installed.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/224/medium640/lcds___displays_front-frame-installed.jpg?1701120448)

## Dome Parts

Get the neck collar, back dome and base parts ready.

![lcds___displays_dome-parts.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/225/medium640/lcds___displays_dome-parts.jpg?1701120462)

## Install Dome to Base

Line up the hole with the neck of the base and place the back dome onto the base.

Press the neck collar into the hole of the base to secure the back dome and base.

![lcds___displays_dome-base-fit.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/226/medium640/lcds___displays_dome-base-fit.jpg?1701120486)

![lcds___displays_dome-neck-fit.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/227/medium640/lcds___displays_dome-neck-fit.jpg?1701120507)

## Installed Neck Collar

Take a moment to check the orientation of the neck collar. The side notches should be lined up perpendicularly.&nbsp;

![lcds___displays_dome-base-installed.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/228/medium640/lcds___displays_dome-base-installed.jpg?1701120527)

## Install Front to Dome

Line up the side keys on the front frame with the notches on the back dome.

Insert the displays FPC ribbon cable through the back dome.

Press the two parts together so they snap fit closed.

![lcds___displays_front-dome-installing.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/229/medium640/lcds___displays_front-dome-installing.jpg?1701120551)

![lcds___displays_front-dome-installed.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/230/medium640/lcds___displays_front-dome-installed.jpg?1701120559)

## Install Ribbon Cable

Insert the FPC ribbon cable from the display into the neck collar.

Pull the FPC ribbon cable through the base.

![lcds___displays_fpc-ribbon-neck-install.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/231/medium640/lcds___displays_fpc-ribbon-neck-install.jpg?1701120574)

![lcds___displays_ribbon-base.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/232/medium640/lcds___displays_ribbon-base.jpg?1701120585)

## Dome Cover

Get the arcade button and dome cover ready.

Remove the nut from the button by unscrewing it.

![lcds___displays_dome-cover-button.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/233/medium640/lcds___displays_dome-cover-button.jpg?1701120601)

## Panel Mount Button

Insert the arcade button into the back cover with the actuator facing the flush surface.

Fasten the included nut to secure the button to the back cover.

![lcds___displays_dome-cover-button-installed.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/234/medium640/lcds___displays_dome-cover-button-installed.jpg?1701120627)

## Install Button Cable

Insert the 3-pin JST cable from the arcade button through the opening in the neck collar and pull it through the base.

![lcds___displays_button-cable-neck-install.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/235/medium640/lcds___displays_button-cable-neck-install.jpg?1701120648)

## Snap Fit Cover

Press fit the dome cover into the back dome to snap fit closed.

![lcds___displays_dome-cover-install.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/236/medium640/lcds___displays_dome-cover-install.jpg?1701120660)

![lcds___displays_dome-cover-installed.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/237/medium640/lcds___displays_dome-cover-installed.jpg?1701120678)

## Connect Display Cable

Insert the FPC ribbon cable from the display into the connector on the Qualia ESP32-S23 board.

![lcds___displays_qualia-display-connect.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/238/medium640/lcds___displays_qualia-display-connect.jpg?1701120691)

## Connect Button Cable

Plug in the 3-pin JST cable from the arcade button to the port on the side of the Qualia ESP32-S3 board.

![lcds___displays_qualia-button-connect.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/239/medium640/lcds___displays_qualia-button-connect.jpg?1701120746)

## Base Cover

Get the base cover and Qualia ESP32-S3 board ready.

Orient the Qualia ESP32-S3 board face down, bottom up and line up the mounting holes with base cover's built in standoffs.&nbsp;

![lcds___displays_base-cover-qualia.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/241/medium640/lcds___displays_base-cover-qualia.jpg?1701120762)

## Secure Qualia ESP32-S3

Use 4x M2.5 x 6mm long machine steel screws to secure the Qualia ESP32-S3 board to the base cover.

![lcds___displays_secure-qualia.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/242/medium640/lcds___displays_secure-qualia.jpg?1701120778)

![lcds___displays_secured-qualia.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/243/medium640/lcds___displays_secured-qualia.jpg?1701120791)

## Install Base Cover

Orient the base cover with the base so the port and buttons on the Qualia ESP32-S3 board line up with the opening.

Firmly press the base cover into the base to snap fit close.

![lcds___displays_base-cover-installing.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/244/medium640/lcds___displays_base-cover-installing.jpg?1701120814)

![lcds___displays_base-cover-installed.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/245/medium640/lcds___displays_base-cover-installed.jpg?1701120822)

## USB Power

Use a 5V 1A power supply and USB-C cable to power on the clock.

![lcds___displays_usb-power.jpg](https://cdn-learn.adafruit.com/assets/assets/000/126/247/medium640/lcds___displays_usb-power.jpg?1701120870)


## Featured Products

### Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays

[Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays](https://www.adafruit.com/product/5800)
There's a few things everyone loves: ice cream, kittens, and honkin' large TFT screens. We're no strangers to small TFT's - [from our itsy 1.14" color display](https://www.adafruit.com/search?q=1.14+tft) that graces many-a-TFT-Feather to <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/5800)
[Related Guides to the Product](https://learn.adafruit.com/products/5800/guides)
### Round RGB TTL TFT Display - 4" 720x720 - No Touchscreen

[Round RGB TTL TFT Display - 4" 720x720 - No Touchscreen](https://www.adafruit.com/product/5793)
This is a screen for advanced hackers who like the look of a nice, round TFT screen with tons of pixels. This massive&nbsp;4" diagonal-sized display has 720x720 16-bit full-color pixels and is an&nbsp; **IPS** &nbsp;display, so the color looks great up to 80 degrees off-axis in...

In Stock
[Buy Now](https://www.adafruit.com/product/5793)
[Related Guides to the Product](https://learn.adafruit.com/products/5793/guides)
### 40-pin FPC Extension Board + 200mm Cable

[40-pin FPC Extension Board + 200mm Cable](https://www.adafruit.com/product/2098)
Give your 40 pin, 0.5mm pitch, devices a strrrreeeetch with this extension board.&nbsp; This 40pin FPC extension board has two 40-pin flex connectors (both are bottom contact type), and an extension cable to add ~22cm (20cm cable plus 2cm board)&nbsp; Each order comes with one board a 20cm...

In Stock
[Buy Now](https://www.adafruit.com/product/2098)
[Related Guides to the Product](https://learn.adafruit.com/products/2098/guides)
### Mini LED Arcade Button - 24mm Translucent Clear

[Mini LED Arcade Button - 24mm Translucent Clear](https://www.adafruit.com/product/3429)
A button is a button, and a switch is a switch, but these translucent arcade buttons are in a class of their own. Particularly because they have **LEDs built right in!** That's right, you'll be button-mashing amidst a wash of beautiful light with these lil'...

In Stock
[Buy Now](https://www.adafruit.com/product/3429)
[Related Guides to the Product](https://learn.adafruit.com/products/3429/guides)
### STEMMA JST PH 2mm 3-Pin to Female Socket Cable - 200mm

[STEMMA JST PH 2mm 3-Pin to Female Socket Cable - 200mm](https://www.adafruit.com/product/3894)
This cable will let you turn a JST PH 3-pin cable port into 3 individual wires with high-quality 0.1" female header sockets on the end. We're carrying these to match up with our Hallowing, for extending and connecting sensors or LEDs - and the wires are even color coded!

<a...></a...>

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

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

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

## Related Guides

- [Adafruit Qualia ESP32-S3 for RGB-666 Displays](https://learn.adafruit.com/adafruit-qualia-esp32-s3-for-rgb666-displays.md)
- [Video Playing 2.1" Round Ornament TFT](https://learn.adafruit.com/2-1-round-ornament-tft.md)
- [Theme Park Wait Time Display](https://learn.adafruit.com/park-wait-time.md)
- [1D Chomper Tabletop Arcade Game](https://learn.adafruit.com/1d-chomper-tabletop-arcade-game.md)
- [CircuitPython Day 2024 Countdown Clock](https://learn.adafruit.com/circuitpython-day-2024-countdown-clock.md)
- [Simplifying Qualia CircuitPython Projects](https://learn.adafruit.com/simplifying-qualia-circuitpython-projects.md)
- [Qualia S3 Sushi Conveyor Belt](https://learn.adafruit.com/qualia-s3-sushi-conveyor-belt.md)
- [Qualia S3 Compass](https://learn.adafruit.com/qualia-s3-compass.md)
- [Qualia 3D Printed Cases](https://learn.adafruit.com/qualia-3d-printed-cases.md)
- [Qualia S3 iOS Photo Display with itsaSNAP](https://learn.adafruit.com/qualia-s3-ios-photo-display-with-itsasnap.md)
- [Qualia S3 Fireplace](https://learn.adafruit.com/qualia-s3-fireplace.md)
- [QT Py RP2040 USB to Serial MIDI Friends](https://learn.adafruit.com/qt-py-rp2040-usb-to-serial-midi-friends.md)
- [Wireless ESP32-S2 Touch Screen Controller for Pure Data](https://learn.adafruit.com/wireless-esp32-s2-controller-for-pure-data.md)
- [Adafruit 3.5" Capacitive Touch TFT FeatherWing](https://learn.adafruit.com/adafruit-3-5-capacitive-touch-tft-featherwing.md)
- [PyPortal Reddit Stats Trophy](https://learn.adafruit.com/pyportal-reddit-stats-trophy.md)
