150 lines
4.5 KiB
Python
150 lines
4.5 KiB
Python
|
import board
|
||
|
import digitalio
|
||
|
from supervisor import ticks_ms
|
||
|
|
||
|
from time import sleep
|
||
|
|
||
|
from kmk.handlers.stock import passthrough as handler_passthrough
|
||
|
from kmk.keys import make_key
|
||
|
from kmk.kmktime import check_deadline
|
||
|
from kmk.modules import Module
|
||
|
|
||
|
|
||
|
class Power(Module):
|
||
|
def __init__(self, powersave_pin=None):
|
||
|
self.enable = False
|
||
|
self.powersave_pin = powersave_pin # Powersave pin board object
|
||
|
self._powersave_start = ticks_ms()
|
||
|
self._usb_last_scan = ticks_ms() - 5000
|
||
|
self._psp = None # Powersave pin object
|
||
|
self._i2c = 0
|
||
|
self._loopcounter = 0
|
||
|
|
||
|
make_key(
|
||
|
names=('PS_TOG',), on_press=self._ps_tog, on_release=handler_passthrough
|
||
|
)
|
||
|
make_key(
|
||
|
names=('PS_ON',), on_press=self._ps_enable, on_release=handler_passthrough
|
||
|
)
|
||
|
make_key(
|
||
|
names=('PS_OFF',), on_press=self._ps_disable, on_release=handler_passthrough
|
||
|
)
|
||
|
|
||
|
def __repr__(self):
|
||
|
return f'Power({self._to_dict()})'
|
||
|
|
||
|
def _to_dict(self):
|
||
|
return {
|
||
|
'enable': self.enable,
|
||
|
'powersave_pin': self.powersave_pin,
|
||
|
'_powersave_start': self._powersave_start,
|
||
|
'_usb_last_scan': self._usb_last_scan,
|
||
|
'_psp': self._psp,
|
||
|
}
|
||
|
|
||
|
def during_bootup(self, keyboard):
|
||
|
self._i2c_scan()
|
||
|
|
||
|
def before_matrix_scan(self, keyboard):
|
||
|
return
|
||
|
|
||
|
def after_matrix_scan(self, keyboard):
|
||
|
if keyboard.matrix_update or keyboard.secondary_matrix_update:
|
||
|
self.psave_time_reset()
|
||
|
|
||
|
def before_hid_send(self, keyboard):
|
||
|
return
|
||
|
|
||
|
def after_hid_send(self, keyboard):
|
||
|
if self.enable:
|
||
|
self.psleep()
|
||
|
|
||
|
def on_powersave_enable(self, keyboard):
|
||
|
'''Gives 10 cycles to allow other extensions to clean up before powersave'''
|
||
|
if self._loopcounter > 10:
|
||
|
self.enable_powersave(keyboard)
|
||
|
self._loopcounter = 0
|
||
|
else:
|
||
|
self._loopcounter += 1
|
||
|
return
|
||
|
|
||
|
def on_powersave_disable(self, keyboard):
|
||
|
self.disable_powersave(keyboard)
|
||
|
return
|
||
|
|
||
|
def enable_powersave(self, keyboard):
|
||
|
'''Enables power saving features'''
|
||
|
if keyboard.i2c_deinit_count >= self._i2c and self.powersave_pin:
|
||
|
# Allows power save to prevent RGB drain.
|
||
|
# Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic
|
||
|
|
||
|
if not self._psp:
|
||
|
self._psp = digitalio.DigitalInOut(self.powersave_pin)
|
||
|
self._psp.direction = digitalio.Direction.OUTPUT
|
||
|
if self._psp:
|
||
|
self._psp.value = True
|
||
|
|
||
|
self.enable = True
|
||
|
keyboard._trigger_powersave_enable = False
|
||
|
return
|
||
|
|
||
|
def disable_powersave(self, keyboard):
|
||
|
'''Disables power saving features'''
|
||
|
if self._psp:
|
||
|
self._psp.value = False
|
||
|
# Allows power save to prevent RGB drain.
|
||
|
# Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic
|
||
|
|
||
|
keyboard._trigger_powersave_disable = False
|
||
|
self.enable = False
|
||
|
return
|
||
|
|
||
|
def psleep(self):
|
||
|
'''
|
||
|
Sleeps longer and longer to save power the more time in between updates.
|
||
|
'''
|
||
|
if check_deadline(ticks_ms(), self._powersave_start, 60000):
|
||
|
sleep(8 / 1000)
|
||
|
elif check_deadline(ticks_ms(), self._powersave_start, 240000) is False:
|
||
|
sleep(180 / 1000)
|
||
|
return
|
||
|
|
||
|
def psave_time_reset(self):
|
||
|
self._powersave_start = ticks_ms()
|
||
|
|
||
|
def _i2c_scan(self):
|
||
|
i2c = board.I2C()
|
||
|
while not i2c.try_lock():
|
||
|
pass
|
||
|
try:
|
||
|
self._i2c = len(i2c.scan())
|
||
|
finally:
|
||
|
i2c.unlock()
|
||
|
return
|
||
|
|
||
|
def usb_rescan_timer(self):
|
||
|
return bool(check_deadline(ticks_ms(), self._usb_last_scan, 5000) is False)
|
||
|
|
||
|
def usb_time_reset(self):
|
||
|
self._usb_last_scan = ticks_ms()
|
||
|
return
|
||
|
|
||
|
def usb_scan(self):
|
||
|
# TODO Add USB detection here. Currently lies that it's connected
|
||
|
# https://github.com/adafruit/circuitpython/pull/3513
|
||
|
return True
|
||
|
|
||
|
def _ps_tog(self, key, keyboard, *args, **kwargs):
|
||
|
if self.enable:
|
||
|
keyboard._trigger_powersave_disable = True
|
||
|
else:
|
||
|
keyboard._trigger_powersave_enable = True
|
||
|
|
||
|
def _ps_enable(self, key, keyboard, *args, **kwargs):
|
||
|
if not self.enable:
|
||
|
keyboard._trigger_powersave_enable = True
|
||
|
|
||
|
def _ps_disable(self, key, keyboard, *args, **kwargs):
|
||
|
if self.enable:
|
||
|
keyboard._trigger_powersave_disable = True
|