kopia lustrzana https://github.com/pimoroni/pimoroni-pico
182 wiersze
4.4 KiB
Python
182 wiersze
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)
|