Skip to content

Instantly share code, notes, and snippets.

@jepler
Last active October 2, 2024 15:40
Show Gist options
  • Save jepler/b2c020a6caa65a31297053b7216fcc15 to your computer and use it in GitHub Desktop.
Save jepler/b2c020a6caa65a31297053b7216fcc15 to your computer and use it in GitHub Desktop.
import os
import math
import sys
import time
import alarm
import board
import displayio
import socketpool
import rtc
import wifi
from fourwire import FourWire
import adafruit_datetime
import adafruit_ntp
import adafruit_ssd1680
import adafruit_lc709203f
from font_orbitron_medium_webfont_54_latin1 import FONT
from adafruit_display_text.bitmap_label import Label
def connect_wifi():
if wifi.radio.ipv4_address is None:
print("connect wifi")
print(os.getenv('WIFI_SSID'), os.getenv('WIFI_PASSWORD'))
for _ in range(5):
try:
wifi.radio.connect(os.getenv('WIFI_SSID'), os.getenv('WIFI_PASSWORD'))
return
except Exception as e:
print(e)
# This pinout works on a Metro M4 and may need to be altered for other boards.
spi = board.SPI() # Uses SCK and MOSI
epd_cs = board.D9
epd_dc = board.D10
epd_reset = None
epd_busy = None
def setup_display():
global display, group
displayio.release_displays()
display_bus = FourWire(
spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000
)
time.sleep(1)
# For issues with display not updating top/bottom rows correctly set colstart to 8
display = adafruit_ssd1680.SSD1680(
display_bus,
height=250,
width=122,
busy_pin=epd_busy,
highlight_color=0x000000,
colstart=0,
rotation=180,
black_bits_inverted=1
)
group = displayio.Group()
display.root_group = group
def main():
battery_monitor = adafruit_lc709203f.LC709203F(board.I2C())
for _ in range(5):
try:
percent = battery_monitor.cell_percent
break
except Exception as e:
print(e)
else:
print("too much battery polling")
percent = 100
if percent < 5: return 86400
target = adafruit_datetime.datetime(2025, 3, 28, 21) # UTC, 4PM local time
sm0 = alarm.sleep_memory[0]
if sm0 == 0:
# Assumes wifi connected via settings.toml before code.py started!
connect_wifi()
pool = socketpool.SocketPool(wifi.radio)
ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_seconds=3600, socket_timeout=1)
for _ in range(10):
try:
rtc.RTC().datetime = ntp.datetime
alarm.sleep_memory[0] = 24 # Don't set again for about 24h
break
except Exception as e:
print(e)
else:
print("NTP too much")
# Hopefully it's better in a few hundred seconds
return 300
else:
print(f"Don't need to set for {sm0} hours")
alarm.sleep_memory[0] = sm0-1
labels = [
Label(
FONT,
text="",
anchor_point=(0.5, 0.5),
anchored_position=(display.width // 2, display.height * (i + 0.5) // 3),
)
for i in range(4)
]
for l in labels:
group.append(l)
for _ in range(10):
try:
now = adafruit_datetime.datetime.now()
break
except Exception as e:
print(e)
else:
print("NTP too much")
# Hopefully it's better in a few hundred seconds
return 300
delta = target - now
delta = adafruit_datetime.timedelta(
seconds=math.ceil(delta.total_seconds() / 3600) * 3600
)
weeks = delta.days // 7
days = delta.days % 7
hours = delta.seconds // 3600
low_bat = percent < 25
if delta.total_seconds() < 0:
labels[0].text = "GO"
labels[1].text = "GO"
labels[2].text = "GO"
else:
labels[0].text = f"{weeks}"
labels[1].text = f"{days}"
labels[2].text = "bat!" if low_bat else f"{hours}"
t0 = time.time()
display.refresh()
t1 = time.time()
if delta.total_seconds() < 0:
return sys.maxsize
if low_bat:
# Sleep until tomorrow to preserve the battery...
sleep_until = (now + adafruit_datetime.timedelta(seconds=86400)).replace(
hour=6, minute=0, second=0
)
else:
# Sleep a bit into the next hour, it's just fine to be 90 seconds late,
# but avoid waking if somehow we get 90 seconds of clock skew within
# the next hour...
sleep_until = (now + adafruit_datetime.timedelta(seconds=3600)).replace(
minute=1, second=30
)
return (sleep_until - now).total_seconds()
if __name__ == "__main__":
to_sleep = 300
try:
setup_display()
to_sleep = main()
finally:
displayio.release_displays()
print(f"sleeping for {to_sleep} seconds")
alarm.exit_and_deep_sleep_until_alarms(
alarm.time.TimeAlarm(monotonic_time=time.monotonic() + to_sleep)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment