Skip to content

Commit 0217c1b

Browse files
committed
Update Countdown Clock to support Qualia + include assets
1 parent 24457b8 commit 0217c1b

File tree

4 files changed

+175
-51
lines changed

4 files changed

+175
-51
lines changed
Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
2-
# SPDX-FileCopyrightText: 2024 Tyeth Gundry for Adafruit Industries
3-
#
4-
# SPDX-License-Identifier: MIT
5-
61
import os
72
import time
83
import wifi
@@ -24,21 +19,34 @@
2419
## See TZ Identifier column at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
2520
## If you want to set the timezone, you can do so with the following line:
2621
timezone = "GB"
27-
#timezone = None # Or instead rely on automatic timezone detection based on IP Address
22+
# timezone = None # Or instead rely on automatic timezone detection based on IP Address
2823

2924

3025
## The time of the thing!
3126
EVENT_YEAR = 2024
3227
EVENT_MONTH = 8
33-
EVENT_DAY = 16
34-
EVENT_HOUR = 0
35-
EVENT_MINUTE = 0
28+
EVENT_DAY = 11 # 16
29+
EVENT_HOUR = 10 # 0
30+
EVENT_MINUTE = 28 # 0
3631
## we'll make a python-friendly structure
37-
event_time = time.struct_time((EVENT_YEAR, EVENT_MONTH, EVENT_DAY,
38-
EVENT_HOUR, EVENT_MINUTE, 0, # we don't track seconds
39-
-1, -1, False)) # we dont know day of week/year or DST
40-
41-
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
32+
event_time = time.struct_time(
33+
(
34+
EVENT_YEAR,
35+
EVENT_MONTH,
36+
EVENT_DAY,
37+
EVENT_HOUR,
38+
EVENT_MINUTE,
39+
0, # we don't track seconds
40+
-1, # we dont know day of week/year or DST
41+
-1,
42+
False,
43+
)
44+
)
45+
46+
print("Connecting to WiFi...")
47+
wifi.radio.connect(
48+
os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")
49+
)
4250

4351
## Initialize a requests session using the newer connection manager
4452
## See https://adafruit-playground.com/u/justmobilize/pages/adafruit-connection-manager
@@ -47,28 +55,38 @@
4755
requests = adafruit_requests.Session(pool, ssl_context)
4856

4957
## Create an instance of the Adafruit IO HTTP client
50-
io = IO_HTTP(os.getenv("ADAFRUIT_AIO_USERNAME"), os.getenv("ADAFRUIT_AIO_KEY"), requests)
51-
52-
## Setup RGB LEDs - comment out the DotStar import and setup if using NeoPixel
53-
pixels_length = 1 # Set to the number of pixels in your strip (funhouse has 5)
54-
pixels_brightness = 0.4 # Set to a value between 0.0 and 1.0
55-
# Uncomment the following lines if you are using DotStar and update pins if necessary
56-
dotstar_clock_pin = board.DOTSTAR_CLOCK
57-
dotstar_data_pin = board.DOTSTAR_DATA
58-
pixels = DotStar(dotstar_clock_pin, dotstar_data_pin, pixels_length, brightness=pixels_brightness)
59-
## Uncomment the following lines if you are using NeoPixel and update pin if necessary
60-
# neopixel_pin = board.NEOPIXEL
61-
# pixels = neopixel.NeoPixel(neopixel_pin, pixels_length, brightness=pixels_brightness)
62-
63-
pixels.fill((0, 0, 0)) # Turn off all pixels
64-
65-
# Setup built-in display
66-
display = board.DISPLAY
58+
io = IO_HTTP(
59+
os.getenv("ADAFRUIT_AIO_USERNAME"), os.getenv("ADAFRUIT_AIO_KEY"), requests
60+
)
61+
62+
## Setup display and size appropriate assets
63+
if board.board_id == "adafruit_qualia_s3_rgb666":
64+
# Display Initialisation for 3.2" Bar display (320x820)
65+
from qualia_bar_display_320x820 import setup_display
66+
display = setup_display()
67+
display.rotation = 90 # Rotate the display
68+
BITMAP_FILE = "/circuitpython_day_2024_820x260_16bit.bmp"
69+
FONT_FILE = "/font_free_mono_bold_48.pcf"
70+
FONT_Y_OFFSET = 30
71+
blinka_bitmap = displayio.OnDiskBitmap(BITMAP_FILE)
72+
PIXEL_SHADER = displayio.ColorConverter(
73+
input_colorspace=displayio.Colorspace.RGB565
74+
)
75+
else:
76+
# Setup built-in display
77+
display = board.DISPLAY
78+
BITMAP_FILE = "/cpday_tft.bmp"
79+
FONT_FILE = "/Helvetica-Bold-16.pcf"
80+
FONT_Y_OFFSET = 13
81+
PIXEL_SHADER = displayio.ColorConverter()
82+
blinka_bitmap = displayio.OnDiskBitmap(BITMAP_FILE)
83+
PIXEL_SHADER = blinka_bitmap.pixel_shader
6784
group = displayio.Group()
68-
font = bitmap_font.load_font("/Helvetica-Bold-16.pcf")
69-
blinka_bitmap = displayio.OnDiskBitmap("/cpday_tft.bmp")
85+
font = bitmap_font.load_font(FONT_FILE)
86+
# blinka_bitmap = displayio.OnDiskBitmap(BITMAP_FILE)
7087
blinka_grid = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_bitmap.pixel_shader)
71-
scrolling_label = bitmap_label.Label(font, text=" ", y=display.height - 13)
88+
# blinka_grid.y = -100
89+
scrolling_label = bitmap_label.Label(font, text=" ", y=display.height - FONT_Y_OFFSET)
7290

7391
group.append(blinka_grid)
7492
group.append(scrolling_label)
@@ -94,9 +112,9 @@
94112
print(now)
95113
total_seconds = time.mktime(now)
96114
refresh_clock = ticks_add(refresh_clock, refresh_timer)
97-
except Exception as e: # pylint: disable=broad-except
98-
print("Some error occured, retrying via reset in 5seconds! -", e)
99-
time.sleep(5)
115+
except Exception as e: # pylint: disable=broad-except
116+
print("Some error occured, retrying via reset in 15seconds! -", e)
117+
time.sleep(15)
100118
microcontroller.reset()
101119

102120
if ticks_diff(ticks_ms(), clock_clock) >= clock_timer:
@@ -113,35 +131,44 @@
113131
days_remaining = -remaining
114132
finished = True
115133
if not first_run and days_remaining == 0:
116-
scrolling_label.text = "It's CircuitPython Day 2024! The snakiest day of the year!"
117-
# Flash on/off blinka colours (nice purple) each second
118-
if pixels[0] == (0, 0, 0):
119-
pixels.fill((0x40, 0x00, 0x80))
120-
else:
121-
pixels.fill((0, 0, 0))
134+
scrolling_label.text = (
135+
"It's CircuitPython Day 2024! The snakiest day of the year!"
136+
)
122137

123138
# Check for the moment of the event to trigger something (a NASA snake launch)
124139
if not triggered and (
125-
hours_remaining==0 and mins_remaining == 0 and secs_remaining <= 0
140+
hours_remaining == 0
141+
and mins_remaining == 0
142+
and secs_remaining <= 1
143+
# Change at/after xx:yy:01 seconds so we've already updated the display
126144
):
127145
# send a signal to an adafruit IO feed, where an Action is listening
128-
print("Launch the snakes!")
146+
print("Launch the snakes! (sending message to Adafruit IO)")
129147
triggered = True
130148
io.send_data("cpday-countdown", "Launch the snakes!")
131-
else:
132-
pixels.fill((0, 0, 0)) # Turn off all pixels
149+
133150
else:
151+
# calculate time until event
134152
secs_remaining = remaining % 60
135153
remaining //= 60
136154
mins_remaining = remaining % 60
137155
remaining //= 60
138156
hours_remaining = remaining % 24
139157
remaining //= 24
140158
days_remaining = remaining
141-
pixels.fill((0, 0, 0)) # Turn off all pixels
142159
if not finished or (finished and days_remaining < 0):
143-
scrolling_label.text = (f"{days_remaining} DAYS, {hours_remaining} HOURS," +
144-
f"{mins_remaining} MINUTES & {secs_remaining} SECONDS")
160+
# Remove 1 from days_remaining to count from end of day instead of start
161+
if days_remaining < 0:
162+
print(
163+
f"Event time in past: Adding 1 to days_remaining ({days_remaining}) to count from end of day"
164+
)
165+
days_remaining += 1
166+
# Update the display with current countdown value
167+
scrolling_label.text = (
168+
f"{days_remaining} DAYS, {hours_remaining} HOURS,"
169+
+ f"{mins_remaining} MINUTES & {secs_remaining} SECONDS"
170+
)
171+
145172
total_seconds += 1
146173
clock_clock = ticks_add(clock_clock, clock_timer)
147174
if ticks_diff(ticks_ms(), scroll_clock) >= scroll_timer:
@@ -150,5 +177,5 @@
150177
scrolling_label.x = display.width + 2
151178
display.refresh()
152179
scroll_clock = ticks_add(scroll_clock, scroll_timer)
153-
180+
154181
first_run = False
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
def setup_display():
2+
from displayio import release_displays
3+
release_displays()
4+
5+
import random
6+
import displayio
7+
import time
8+
import busio
9+
import board
10+
import dotclockframebuffer
11+
from framebufferio import FramebufferDisplay
12+
13+
init_sequence_tl032 = bytes((
14+
b'\x11\x80d'
15+
b'\xff\x05w\x01\x00\x00\x13'
16+
b'\xef\x01\x08'
17+
b'\xff\x05w\x01\x00\x00\x10'
18+
b'\xc0\x02\xe5\x02'
19+
b'\xc1\x02\x0c\n'
20+
b'\xc2\x02\x07\x0f'
21+
b'\xc3\x01\x02'
22+
b'\xcc\x01\x10'
23+
b'\xcd\x01\x08'
24+
b'\xb0\x10\x00\x08Q\r\xce\x06\x00\x08\x08\x1d\x02\xd0\x0fo6?'
25+
b'\xb1\x10\x00\x10O\x0c\x11\x05\x00\x07\x07\x1f\x05\xd3\x11n4?'
26+
b'\xff\x05w\x01\x00\x00\x11'
27+
b'\xb0\x01M'
28+
b'\xb1\x01\x1c'
29+
b'\xb2\x01\x87'
30+
b'\xb3\x01\x80'
31+
b'\xb5\x01G'
32+
b'\xb7\x01\x85'
33+
b'\xb8\x01!'
34+
b'\xb9\x01\x10'
35+
b'\xc1\x01x'
36+
b'\xc2\x01x'
37+
b'\xd0\x81\x88d'
38+
b'\xe0\x03\x80\x00\x02'
39+
b'\xe1\x0b\x04\xa0\x00\x00\x05\xa0\x00\x00\x00``'
40+
b'\xe2\r00``<\xa0\x00\x00=\xa0\x00\x00\x00'
41+
b'\xe3\x04\x00\x0033'
42+
b'\xe4\x02DD'
43+
b'\xe5\x10\x06>\xa0\xa0\x08@\xa0\xa0\nB\xa0\xa0\x0cD\xa0\xa0'
44+
b'\xe6\x04\x00\x0033'
45+
b'\xe7\x02DD'
46+
b'\xe8\x10\x07?\xa0\xa0\tA\xa0\xa0\x0bC\xa0\xa0\rE\xa0\xa0'
47+
b'\xeb\x07\x00\x01NN\xeeD\x00'
48+
b"\xed\x10\xff\xff\x04Vr\xff\xff\xff\xff\xff\xff'e@\xff\xff"
49+
b'\xef\x06\x10\r\x04\x08?\x1f'
50+
b'\xff\x05w\x01\x00\x00\x13'
51+
b'\xe8\x02\x00\x0e'
52+
b'\xff\x05w\x01\x00\x00\x00'
53+
b'\x11\x80x'
54+
b'\xff\x05w\x01\x00\x00\x13'
55+
b'\xe8\x82\x00\x0c\n'
56+
b'\xe8\x02\x00\x00'
57+
b'\xff\x05w\x01\x00\x00\x00'
58+
b'6\x01\x00'
59+
b':\x01f'
60+
b'\x11\x80x'
61+
b')\x80x'
62+
))
63+
64+
board.I2C().deinit()
65+
i2c = busio.I2C(board.SCL, board.SDA, frequency=400_000)
66+
tft_io_expander = dict(board.TFT_IO_EXPANDER)
67+
#tft_io_expander['i2c_address'] = 0x38 # uncomment for rev B
68+
dotclockframebuffer.ioexpander_send_init_sequence(i2c, init_sequence_tl032, **tft_io_expander)
69+
i2c.deinit()
70+
71+
tft_pins = dict(board.TFT_PINS)
72+
73+
tft_timings = {
74+
"frequency": 16000000,
75+
"width": 320,
76+
"height": 820,
77+
78+
"hsync_pulse_width": 3,
79+
"hsync_back_porch": 251,
80+
"hsync_front_porch": 150,
81+
"hsync_idle_low": False,
82+
83+
"vsync_pulse_width": 6,
84+
"vsync_back_porch": 90,
85+
"vsync_front_porch": 100,
86+
"vsync_idle_low": False,
87+
88+
"pclk_active_high": False,
89+
"pclk_idle_high": False,
90+
"de_idle_high": False,
91+
}
92+
93+
#bitmap = displayio.OnDiskBitmap("/display-ruler-720p.bmp")
94+
95+
fb = dotclockframebuffer.DotClockFramebuffer(**tft_pins, **tft_timings)
96+
display = FramebufferDisplay(fb, auto_refresh=False)
97+
return display

0 commit comments

Comments
 (0)