Update Countdown Clock to support Qualia + include assets

This commit is contained in:
Tyeth Gundry 2024-08-12 15:55:35 +01:00
parent 24457b8a7b
commit 0217c1b612
4 changed files with 173 additions and 49 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

View file

@ -1,8 +1,3 @@
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
# SPDX-FileCopyrightText: 2024 Tyeth Gundry for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import time
import wifi
@ -24,21 +19,34 @@ from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
## See TZ Identifier column at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
## If you want to set the timezone, you can do so with the following line:
timezone = "GB"
#timezone = None # Or instead rely on automatic timezone detection based on IP Address
# timezone = None # Or instead rely on automatic timezone detection based on IP Address
## The time of the thing!
EVENT_YEAR = 2024
EVENT_MONTH = 8
EVENT_DAY = 16
EVENT_HOUR = 0
EVENT_MINUTE = 0
EVENT_DAY = 11 # 16
EVENT_HOUR = 10 # 0
EVENT_MINUTE = 28 # 0
## we'll make a python-friendly structure
event_time = time.struct_time((EVENT_YEAR, EVENT_MONTH, EVENT_DAY,
EVENT_HOUR, EVENT_MINUTE, 0, # we don't track seconds
-1, -1, False)) # we dont know day of week/year or DST
event_time = time.struct_time(
(
EVENT_YEAR,
EVENT_MONTH,
EVENT_DAY,
EVENT_HOUR,
EVENT_MINUTE,
0, # we don't track seconds
-1, # we dont know day of week/year or DST
-1,
False,
)
)
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print("Connecting to WiFi...")
wifi.radio.connect(
os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")
)
## Initialize a requests session using the newer connection manager
## See https://adafruit-playground.com/u/justmobilize/pages/adafruit-connection-manager
@ -47,28 +55,38 @@ ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)
## Create an instance of the Adafruit IO HTTP client
io = IO_HTTP(os.getenv("ADAFRUIT_AIO_USERNAME"), os.getenv("ADAFRUIT_AIO_KEY"), requests)
io = IO_HTTP(
os.getenv("ADAFRUIT_AIO_USERNAME"), os.getenv("ADAFRUIT_AIO_KEY"), requests
)
## Setup RGB LEDs - comment out the DotStar import and setup if using NeoPixel
pixels_length = 1 # Set to the number of pixels in your strip (funhouse has 5)
pixels_brightness = 0.4 # Set to a value between 0.0 and 1.0
# Uncomment the following lines if you are using DotStar and update pins if necessary
dotstar_clock_pin = board.DOTSTAR_CLOCK
dotstar_data_pin = board.DOTSTAR_DATA
pixels = DotStar(dotstar_clock_pin, dotstar_data_pin, pixels_length, brightness=pixels_brightness)
## Uncomment the following lines if you are using NeoPixel and update pin if necessary
# neopixel_pin = board.NEOPIXEL
# pixels = neopixel.NeoPixel(neopixel_pin, pixels_length, brightness=pixels_brightness)
pixels.fill((0, 0, 0)) # Turn off all pixels
# Setup built-in display
display = board.DISPLAY
## Setup display and size appropriate assets
if board.board_id == "adafruit_qualia_s3_rgb666":
# Display Initialisation for 3.2" Bar display (320x820)
from qualia_bar_display_320x820 import setup_display
display = setup_display()
display.rotation = 90 # Rotate the display
BITMAP_FILE = "/circuitpython_day_2024_820x260_16bit.bmp"
FONT_FILE = "/font_free_mono_bold_48.pcf"
FONT_Y_OFFSET = 30
blinka_bitmap = displayio.OnDiskBitmap(BITMAP_FILE)
PIXEL_SHADER = displayio.ColorConverter(
input_colorspace=displayio.Colorspace.RGB565
)
else:
# Setup built-in display
display = board.DISPLAY
BITMAP_FILE = "/cpday_tft.bmp"
FONT_FILE = "/Helvetica-Bold-16.pcf"
FONT_Y_OFFSET = 13
PIXEL_SHADER = displayio.ColorConverter()
blinka_bitmap = displayio.OnDiskBitmap(BITMAP_FILE)
PIXEL_SHADER = blinka_bitmap.pixel_shader
group = displayio.Group()
font = bitmap_font.load_font("/Helvetica-Bold-16.pcf")
blinka_bitmap = displayio.OnDiskBitmap("/cpday_tft.bmp")
font = bitmap_font.load_font(FONT_FILE)
# blinka_bitmap = displayio.OnDiskBitmap(BITMAP_FILE)
blinka_grid = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_bitmap.pixel_shader)
scrolling_label = bitmap_label.Label(font, text=" ", y=display.height - 13)
# blinka_grid.y = -100
scrolling_label = bitmap_label.Label(font, text=" ", y=display.height - FONT_Y_OFFSET)
group.append(blinka_grid)
group.append(scrolling_label)
@ -94,9 +112,9 @@ while True:
print(now)
total_seconds = time.mktime(now)
refresh_clock = ticks_add(refresh_clock, refresh_timer)
except Exception as e: # pylint: disable=broad-except
print("Some error occured, retrying via reset in 5seconds! -", e)
time.sleep(5)
except Exception as e: # pylint: disable=broad-except
print("Some error occured, retrying via reset in 15seconds! -", e)
time.sleep(15)
microcontroller.reset()
if ticks_diff(ticks_ms(), clock_clock) >= clock_timer:
@ -113,24 +131,24 @@ while True:
days_remaining = -remaining
finished = True
if not first_run and days_remaining == 0:
scrolling_label.text = "It's CircuitPython Day 2024! The snakiest day of the year!"
# Flash on/off blinka colours (nice purple) each second
if pixels[0] == (0, 0, 0):
pixels.fill((0x40, 0x00, 0x80))
else:
pixels.fill((0, 0, 0))
scrolling_label.text = (
"It's CircuitPython Day 2024! The snakiest day of the year!"
)
# Check for the moment of the event to trigger something (a NASA snake launch)
if not triggered and (
hours_remaining==0 and mins_remaining == 0 and secs_remaining <= 0
hours_remaining == 0
and mins_remaining == 0
and secs_remaining <= 1
# Change at/after xx:yy:01 seconds so we've already updated the display
):
# send a signal to an adafruit IO feed, where an Action is listening
print("Launch the snakes!")
print("Launch the snakes! (sending message to Adafruit IO)")
triggered = True
io.send_data("cpday-countdown", "Launch the snakes!")
else:
pixels.fill((0, 0, 0)) # Turn off all pixels
else:
# calculate time until event
secs_remaining = remaining % 60
remaining //= 60
mins_remaining = remaining % 60
@ -138,10 +156,19 @@ while True:
hours_remaining = remaining % 24
remaining //= 24
days_remaining = remaining
pixels.fill((0, 0, 0)) # Turn off all pixels
if not finished or (finished and days_remaining < 0):
scrolling_label.text = (f"{days_remaining} DAYS, {hours_remaining} HOURS," +
f"{mins_remaining} MINUTES & {secs_remaining} SECONDS")
# Remove 1 from days_remaining to count from end of day instead of start
if days_remaining < 0:
print(
f"Event time in past: Adding 1 to days_remaining ({days_remaining}) to count from end of day"
)
days_remaining += 1
# Update the display with current countdown value
scrolling_label.text = (
f"{days_remaining} DAYS, {hours_remaining} HOURS,"
+ f"{mins_remaining} MINUTES & {secs_remaining} SECONDS"
)
total_seconds += 1
clock_clock = ticks_add(clock_clock, clock_timer)
if ticks_diff(ticks_ms(), scroll_clock) >= scroll_timer:
@ -150,5 +177,5 @@ while True:
scrolling_label.x = display.width + 2
display.refresh()
scroll_clock = ticks_add(scroll_clock, scroll_timer)
first_run = False

View file

@ -0,0 +1,97 @@
def setup_display():
from displayio import release_displays
release_displays()
import random
import displayio
import time
import busio
import board
import dotclockframebuffer
from framebufferio import FramebufferDisplay
init_sequence_tl032 = bytes((
b'\x11\x80d'
b'\xff\x05w\x01\x00\x00\x13'
b'\xef\x01\x08'
b'\xff\x05w\x01\x00\x00\x10'
b'\xc0\x02\xe5\x02'
b'\xc1\x02\x0c\n'
b'\xc2\x02\x07\x0f'
b'\xc3\x01\x02'
b'\xcc\x01\x10'
b'\xcd\x01\x08'
b'\xb0\x10\x00\x08Q\r\xce\x06\x00\x08\x08\x1d\x02\xd0\x0fo6?'
b'\xb1\x10\x00\x10O\x0c\x11\x05\x00\x07\x07\x1f\x05\xd3\x11n4?'
b'\xff\x05w\x01\x00\x00\x11'
b'\xb0\x01M'
b'\xb1\x01\x1c'
b'\xb2\x01\x87'
b'\xb3\x01\x80'
b'\xb5\x01G'
b'\xb7\x01\x85'
b'\xb8\x01!'
b'\xb9\x01\x10'
b'\xc1\x01x'
b'\xc2\x01x'
b'\xd0\x81\x88d'
b'\xe0\x03\x80\x00\x02'
b'\xe1\x0b\x04\xa0\x00\x00\x05\xa0\x00\x00\x00``'
b'\xe2\r00``<\xa0\x00\x00=\xa0\x00\x00\x00'
b'\xe3\x04\x00\x0033'
b'\xe4\x02DD'
b'\xe5\x10\x06>\xa0\xa0\x08@\xa0\xa0\nB\xa0\xa0\x0cD\xa0\xa0'
b'\xe6\x04\x00\x0033'
b'\xe7\x02DD'
b'\xe8\x10\x07?\xa0\xa0\tA\xa0\xa0\x0bC\xa0\xa0\rE\xa0\xa0'
b'\xeb\x07\x00\x01NN\xeeD\x00'
b"\xed\x10\xff\xff\x04Vr\xff\xff\xff\xff\xff\xff'e@\xff\xff"
b'\xef\x06\x10\r\x04\x08?\x1f'
b'\xff\x05w\x01\x00\x00\x13'
b'\xe8\x02\x00\x0e'
b'\xff\x05w\x01\x00\x00\x00'
b'\x11\x80x'
b'\xff\x05w\x01\x00\x00\x13'
b'\xe8\x82\x00\x0c\n'
b'\xe8\x02\x00\x00'
b'\xff\x05w\x01\x00\x00\x00'
b'6\x01\x00'
b':\x01f'
b'\x11\x80x'
b')\x80x'
))
board.I2C().deinit()
i2c = busio.I2C(board.SCL, board.SDA, frequency=400_000)
tft_io_expander = dict(board.TFT_IO_EXPANDER)
#tft_io_expander['i2c_address'] = 0x38 # uncomment for rev B
dotclockframebuffer.ioexpander_send_init_sequence(i2c, init_sequence_tl032, **tft_io_expander)
i2c.deinit()
tft_pins = dict(board.TFT_PINS)
tft_timings = {
"frequency": 16000000,
"width": 320,
"height": 820,
"hsync_pulse_width": 3,
"hsync_back_porch": 251,
"hsync_front_porch": 150,
"hsync_idle_low": False,
"vsync_pulse_width": 6,
"vsync_back_porch": 90,
"vsync_front_porch": 100,
"vsync_idle_low": False,
"pclk_active_high": False,
"pclk_idle_high": False,
"de_idle_high": False,
}
#bitmap = displayio.OnDiskBitmap("/display-ruler-720p.bmp")
fb = dotclockframebuffer.DotClockFramebuffer(**tft_pins, **tft_timings)
display = FramebufferDisplay(fb, auto_refresh=False)
return display