feat: Implement shutdown on idle when on battery
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 3m42s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 11s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 9s
Run pytests / Check-Pytest (push) Successful in 11s
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 3m42s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 11s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 9s
Run pytests / Check-Pytest (push) Successful in 11s
Allow the PlayerApp to turn off the device if it is idle for longer then the timeout. The timeout is currently hardcoded to 1 minute, this will be made configurable in the future. Signed-off-by: Matthias Blankertz <matthias@blankertz.org>
This commit is contained in:
@@ -6,7 +6,7 @@ import time
|
||||
from utils import TimerManager
|
||||
|
||||
|
||||
Dependencies = namedtuple('Dependencies', ('mp3player', 'nfcreader', 'buttons', 'playlistdb', 'leds'))
|
||||
Dependencies = namedtuple('Dependencies', ('mp3player', 'nfcreader', 'buttons', 'playlistdb', 'hwconfig', 'leds'))
|
||||
|
||||
# Should be ~ 6dB steps
|
||||
VOLUME_CURVE = [1, 2, 4, 8, 16, 32, 63, 126, 251]
|
||||
@@ -44,6 +44,7 @@ class PlayerApp:
|
||||
self.player = deps.mp3player(self)
|
||||
self.nfc = deps.nfcreader(self.tag_state_machine)
|
||||
self.playlist_db = deps.playlistdb(self)
|
||||
self.hwconfig = deps.hwconfig(self)
|
||||
self.leds = deps.leds(self)
|
||||
self.tag_mode = self.playlist_db.getSetting('tagmode')
|
||||
self.playing_tag = None
|
||||
@@ -97,6 +98,13 @@ class PlayerApp:
|
||||
self.mp3file = None
|
||||
self._play_next()
|
||||
|
||||
def onIdleTimeout(self):
|
||||
if self.hwconfig.get_on_battery():
|
||||
self.hwconfig.power_off()
|
||||
else:
|
||||
# Check again in a minute
|
||||
self.timer_manager.schedule(time.ticks_ms() + 60*1000, self.onIdleTimeout)
|
||||
|
||||
def _set_playlist(self, tag: bytes):
|
||||
if self.playlist is not None:
|
||||
pos = self.player.stop()
|
||||
@@ -136,7 +144,9 @@ class PlayerApp:
|
||||
self._onActive()
|
||||
|
||||
def _onIdle(self):
|
||||
self.timer_manager.schedule(time.ticks_ms() + 60*1000, self.onIdleTimeout)
|
||||
self.leds.set_state('idle')
|
||||
|
||||
def _onActive(self):
|
||||
self.timer_manager.cancel(self.onIdleTimeout)
|
||||
self.leds.set_state('playing')
|
||||
|
||||
@@ -39,6 +39,7 @@ BUTTON_POWER = Pin.board.GP21
|
||||
# Power
|
||||
POWER_EN = Pin.board.GP22
|
||||
VBAT_ADC = Pin.board.GP26
|
||||
VBUS_DET = Pin.board.WL_GPIO2
|
||||
|
||||
|
||||
def board_init():
|
||||
@@ -61,3 +62,13 @@ def get_battery_voltage():
|
||||
adc = machine.ADC(VBAT_ADC) # create ADC object on ADC pin
|
||||
battv = adc.read_u16()/65535.0*3.3*2
|
||||
return battv
|
||||
|
||||
|
||||
def power_off():
|
||||
POWER_EN.init(mode=Pin.OUT)
|
||||
POWER_EN.value(0)
|
||||
|
||||
|
||||
def get_on_battery():
|
||||
vbus = VBUS_DET.value()
|
||||
return not vbus
|
||||
|
||||
@@ -47,3 +47,12 @@ def board_init():
|
||||
def get_battery_voltage():
|
||||
# Not supported on breadboard
|
||||
return None
|
||||
|
||||
|
||||
def power_off():
|
||||
# Not supported on breadboard
|
||||
pass
|
||||
|
||||
|
||||
def get_on_battery():
|
||||
return False
|
||||
|
||||
@@ -78,6 +78,7 @@ def run():
|
||||
pin_voldown=hwconfig.BUTTON_VOLDOWN,
|
||||
pin_next=hwconfig.BUTTON_NEXT),
|
||||
playlistdb=lambda _: playlistdb,
|
||||
hwconfig=lambda _: hwconfig,
|
||||
leds=lambda _: LedManager(np))
|
||||
the_app = app.PlayerApp(deps)
|
||||
|
||||
|
||||
@@ -101,6 +101,18 @@ class FakePlaylistDb:
|
||||
return None
|
||||
|
||||
|
||||
class FakeHwconfig:
|
||||
def __init__(self):
|
||||
self.powered = True
|
||||
self.on_battery = False
|
||||
|
||||
def power_off(self):
|
||||
self.powered = False
|
||||
|
||||
def get_on_battery(self):
|
||||
return self.on_battery
|
||||
|
||||
|
||||
class FakeLeds:
|
||||
def __init__(self):
|
||||
self.state = None
|
||||
@@ -121,11 +133,12 @@ def faketimermanager(monkeypatch):
|
||||
|
||||
|
||||
def _makedeps(mp3player=FakeMp3Player, nfcreader=FakeNfcReader, buttons=FakeButtons,
|
||||
playlistdb=FakePlaylistDb, leds=FakeLeds):
|
||||
playlistdb=FakePlaylistDb, hwconfig=FakeHwconfig, leds=FakeLeds):
|
||||
return app.Dependencies(mp3player=lambda _: mp3player() if callable(mp3player) else mp3player,
|
||||
nfcreader=lambda x: nfcreader(x) if callable(nfcreader) else nfcreader,
|
||||
buttons=lambda _: buttons() if callable(buttons) else buttons,
|
||||
playlistdb=lambda _: playlistdb() if callable(playlistdb) else playlistdb,
|
||||
hwconfig=lambda _: hwconfig() if callable(hwconfig) else hwconfig,
|
||||
leds=lambda _: leds() if callable(leds) else leds)
|
||||
|
||||
|
||||
@@ -275,3 +288,32 @@ def test_led_state(micropythonify, faketimermanager, monkeypatch):
|
||||
FakeNfcReader.tag_callback.onTagChange(None)
|
||||
faketimermanager.testing_run_queued()
|
||||
assert fake_leds.state == 'idle'
|
||||
|
||||
|
||||
def test_idle_shutdown_after_start(micropythonify, faketimermanager, monkeypatch):
|
||||
fake_hwconfig = FakeHwconfig()
|
||||
fake_hwconfig.on_battery = True
|
||||
deps = _makedeps(hwconfig=fake_hwconfig)
|
||||
app.PlayerApp(deps)
|
||||
assert fake_hwconfig.powered
|
||||
faketimermanager.testing_run_queued()
|
||||
assert not fake_hwconfig.powered
|
||||
|
||||
|
||||
def test_idle_shutdown_after_playback(micropythonify, faketimermanager, monkeypatch):
|
||||
fake_hwconfig = FakeHwconfig()
|
||||
fake_hwconfig.on_battery = True
|
||||
deps = _makedeps(hwconfig=fake_hwconfig)
|
||||
app.PlayerApp(deps)
|
||||
assert fake_hwconfig.powered
|
||||
with monkeypatch.context() as m:
|
||||
m.setattr(builtins, 'open', fake_open)
|
||||
FakeNfcReader.tag_callback.onTagChange([23, 42, 1, 2, 3])
|
||||
faketimermanager.testing_run_queued()
|
||||
assert fake_hwconfig.powered
|
||||
# Stop playback
|
||||
FakeNfcReader.tag_callback.onTagChange(None)
|
||||
faketimermanager.testing_run_queued()
|
||||
# Elapse idle timer
|
||||
faketimermanager.testing_run_queued()
|
||||
assert not fake_hwconfig.powered
|
||||
|
||||
Reference in New Issue
Block a user