244 lines
8 KiB
Python
244 lines
8 KiB
Python
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
# Written by Liz Clark (Adafruit Industries) with OpenAI ChatGPT v4 Aug 3rd, 2023 build
|
|
# https://help.openai.com/en/articles/6825453-chatgpt-release-notes
|
|
|
|
# https://chat.openai.com/share/63cbe4c6-007f-4934-a458-a9c8a521620e
|
|
# https://chat.openai.com/share/674c0f13-bc78-4d1e-be79-3bc777e29991
|
|
|
|
import time
|
|
from math import pi, cos, sin
|
|
import os
|
|
import ssl
|
|
import wifi
|
|
import socketpool
|
|
import adafruit_requests
|
|
import board
|
|
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
|
|
import vectorio
|
|
import displayio
|
|
from adafruit_io.adafruit_io import IO_HTTP
|
|
from jepler_udecimal import Decimal
|
|
import keypad
|
|
from adafruit_display_text import label
|
|
from adafruit_bitmap_font import bitmap_font
|
|
from adafruit_qualia.graphics import Graphics, Displays
|
|
|
|
# timezone offset for calculating mars time
|
|
timezone = -5
|
|
|
|
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)
|
|
|
|
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
|
|
|
|
# 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
|
|
|
|
# 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)
|
|
|
|
# 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 >=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 >= 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)
|
|
|
|
mars_group.append(pointer_hub)
|
|
earth_group.append(pointer_hub)
|
|
|
|
# get time from adafruit io
|
|
# called once an hour in the loop
|
|
def update_time():
|
|
print("time")
|
|
now = io.receive_time()
|
|
return now
|
|
|
|
def convert_time(the_time):
|
|
h = the_time[3]
|
|
if h >= 12:
|
|
h -= 12
|
|
a = "PM"
|
|
else:
|
|
a = "AM"
|
|
if h == 0:
|
|
h = 12
|
|
return h, a
|
|
|
|
# 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
|
|
|
|
def time_angle(m, the_hour):
|
|
m_offset = 25 if 12 <= m < 18 or 42 <= m < 48 else 5
|
|
h_offset = 25 if 2 <= the_hour % 12 < 4 or 8 <= the_hour % 12 < 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)]
|
|
|
|
clock_timer = 1 * 1000
|
|
clock_clock = ticks_ms()
|
|
clock = update_time()
|
|
hour, am_pm = convert_time(clock)
|
|
tick = clock[5]
|
|
minute = clock[4]
|
|
mars_min, mars_hour = mars_time()
|
|
show_earth = True
|
|
|
|
time_angle(minute, hour)
|
|
|
|
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
|
|
# use ticks for timekeeping
|
|
# every minute update clock hands
|
|
# recheck IO time every hour
|
|
if ticks_diff(ticks_ms(), clock_clock) >= clock_timer:
|
|
tick += 1
|
|
if tick > 59:
|
|
tick = 0
|
|
minute += 1
|
|
if minute > 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)
|