pimoroni-pico/micropython/modules_py/inky_frame.py

182 lines
4.4 KiB
Python

from pimoroni import ShiftRegister, PWMLED
from machine import Pin, I2C, RTC
from wakeup import get_shift_state, reset_shift_state
from micropython import const
import pcf85063a
import ntptime
import time
BLACK = const(0)
WHITE = const(1)
GREEN = const(2)
BLUE = const(3)
RED = const(4)
YELLOW = const(5)
ORANGE = const(6)
TAUPE = const(7)
SR_CLOCK = const(8)
SR_LATCH = const(9)
SR_OUT = const(10)
LED_A = const(11)
LED_B = const(12)
LED_C = const(13)
LED_D = const(14)
LED_E = const(15)
LED_BUSY = const(6)
LED_WIFI = const(7)
HOLD_VSYS_EN = const(2)
RTC_ALARM = const(2)
EXTERNAL_TRIGGER = const(1)
EINK_BUSY = const(0)
SHIFT_STATE = get_shift_state()
reset_shift_state()
i2c = I2C(0)
rtc = pcf85063a.PCF85063A(i2c)
i2c.writeto_mem(0x51, 0x00, b'\x00') # ensure rtc is running (this should be default?)
rtc.enable_timer_interrupt(False)
vsys = Pin(HOLD_VSYS_EN)
vsys.on()
def woken_by_rtc():
mask = (1 << RTC_ALARM)
return bool(sr.read() & mask) or bool(SHIFT_STATE & mask)
def woken_by_ext_trigger():
mask = (1 << EXTERNAL_TRIGGER)
return bool(sr.read() & mask) or bool(SHIFT_STATE & mask)
def woken_by_button():
return bool(sr.read() & 0b11111000) or bool(SHIFT_STATE & 0b11111000)
def pico_rtc_to_pcf():
# Set the PCF85063A to the time stored by Pico W's RTC
year, month, day, dow, hour, minute, second, _ = RTC().datetime()
rtc.datetime((year, month, day, hour, minute, second, dow))
def pcf_to_pico_rtc():
# Set Pico W's RTC to the time stored by the PCF85063A
t = rtc.datetime()
# BUG ERRNO 22, EINVAL, when date read from RTC is invalid for the Pico's RTC.
try:
RTC().datetime((t[0], t[1], t[2], t[6], t[3], t[4], t[5], 0))
return True
except OSError:
return False
def sleep_for(minutes):
year, month, day, hour, minute, second, dow = rtc.datetime()
# if the time is very close to the end of the minute, advance to the next minute
# this aims to fix the edge case where the board goes to sleep right as the RTC triggers, thus never waking up
if second >= 55:
minute += 1
# Can't sleep beyond a month, so clamp the sleep to a 28 day maximum
minutes = min(minutes, 40320)
# Calculate the future alarm date; first, turn the current time into seconds since epoch
sec_since_epoch = time.mktime((year, month, day, hour, minute, second, dow, 0))
# Add the required minutes to this
sec_since_epoch += minutes * 60
# And convert it back into a more useful tuple
(ayear, amonth, aday, ahour, aminute, asecond, adow, adoy) = time.localtime(sec_since_epoch)
# And now set the alarm as before, now including the day
rtc.clear_alarm_flag()
rtc.set_alarm(0, aminute, ahour, aday)
rtc.enable_alarm_interrupt(True)
turn_off()
# Simulate sleep while on USB power
while minutes > 0:
time.sleep(60)
minutes -= 1
def turn_off():
time.sleep(0.1)
vsys.off()
def set_time():
# Set both Pico W's RTC and PCF85063A to NTP time
ntptime.settime()
pico_rtc_to_pcf()
class Button:
def __init__(self, sr, idx, led, debounce=50):
self.sr = sr
self.startup_state = bool(SHIFT_STATE & (1 << idx))
self.led = PWMLED(led)
self.led.off()
self._idx = idx
self._debounce_time = debounce
self._changed = time.ticks_ms()
self._last_value = None
def led_on(self):
self.led.on()
def led_off(self):
self.led.off()
def led_brightness(self, brightness):
self.led.brightness(brightness)
def led_toggle(self):
self.led.toggle()
def read(self):
if self.startup_state:
self.startup_state = False
return True
value = self.raw()
if value != self._last_value and time.ticks_ms() - self._changed > self._debounce_time:
self._last_value = value
self._changed = time.ticks_ms()
return value
return False
def raw(self):
if self.startup_state:
self.startup_state = False
return True
return self.sr[self._idx] == 1
@property
def is_pressed(self):
return self.raw()
sr = ShiftRegister(SR_CLOCK, SR_LATCH, SR_OUT)
button_a = Button(sr, 7, LED_A)
button_b = Button(sr, 6, LED_B)
button_c = Button(sr, 5, LED_C)
button_d = Button(sr, 4, LED_D)
button_e = Button(sr, 3, LED_E)
led_busy = PWMLED(LED_BUSY)
led_wifi = PWMLED(LED_WIFI)