apps: timer: Add a countdown timer application
Signed-off-by: Wolfgang Ginolas <wolfgang.ginolas@gwif.eu> [daniel@redfelineninja.org.uk: squashed into a single commit, rebase to latest master, integrate with the Software application and rename the screenshots to match the application name] Signed-off-by: Daniel Thompson <daniel@redfelineninja.org.uk>
This commit is contained in:
parent
4e9a576a2d
commit
5b74c45e58
9 changed files with 185 additions and 3 deletions
|
@ -137,7 +137,7 @@ simulator (the "blank" screen is the torch application):
|
|||
:alt: Heart rate application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/TimerApp.png
|
||||
.. image:: res/StopclockApp.png
|
||||
:alt: Stop watch application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
|
@ -192,3 +192,7 @@ using one of the techniques is the Application Writer's guide.
|
|||
.. image:: res/SnakeApp.png
|
||||
:alt: Snake Game running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/TimerApp.png
|
||||
:alt: Countdown timer application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
|
|
@ -40,3 +40,5 @@ Integration
|
|||
.. automodule:: apps.alarm
|
||||
|
||||
.. automodule:: apps.musicplayer
|
||||
|
||||
.. automodule:: apps.timer
|
||||
|
|
BIN
res/StopclockApp.png
Normal file
BIN
res/StopclockApp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
BIN
res/TimerApp.png
BIN
res/TimerApp.png
Binary file not shown.
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 15 KiB |
BIN
res/timer_icon.png
Normal file
BIN
res/timer_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 KiB |
|
@ -22,6 +22,7 @@ class SoftwareApp():
|
|||
('snake', wasp.widgets.Checkbox(0, 40, 'Snake Game')),
|
||||
('flashlight', wasp.widgets.Checkbox(0, 80, 'Torch')),
|
||||
('testapp', wasp.widgets.Checkbox(0, 120, 'Test')),
|
||||
('timer', wasp.widgets.Checkbox(0, 160, 'Timer')),
|
||||
)
|
||||
self.si = wasp.widgets.ScrollIndicator()
|
||||
self.page = 0
|
||||
|
|
|
@ -8,12 +8,13 @@ import fonts
|
|||
class StopwatchApp():
|
||||
"""Stopwatch application.
|
||||
|
||||
.. figure:: res/TimerApp.png
|
||||
.. figure:: res/StopclockApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the stopwatch application
|
||||
"""
|
||||
NAME = 'Timer'
|
||||
# Stopwatch requires too many pixels to fit into the launcher
|
||||
NAME = 'Stopclock'
|
||||
ICON = icons.app
|
||||
|
||||
def __init__(self):
|
||||
|
|
173
wasp/apps/timer.py
Normal file
173
wasp/apps/timer.py
Normal file
|
@ -0,0 +1,173 @@
|
|||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
# Copyright (C) 2020 Wolfgang Ginolas
|
||||
"""Timer Application
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An application to set a vibration in a specified amount of time. Like a kitchen timer.
|
||||
|
||||
.. figure:: res/TimerApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the Timer Application
|
||||
|
||||
"""
|
||||
|
||||
import wasp
|
||||
import fonts
|
||||
import time
|
||||
import widgets
|
||||
import math
|
||||
from micropython import const
|
||||
|
||||
# 2-bit RLE, generated from res/timer_icon.png, 345 bytes
|
||||
icon = (
|
||||
b'\x02'
|
||||
b'`@'
|
||||
b'?\xff\r@\xb4I?\x14Q?\rW?\x08[?'
|
||||
b'\x04_?\x00c<Q\x80\xd0\x83Q:L\x87\x01\x87'
|
||||
b'L8K\x89\x01\x89K6J\x8b\x01\x8bJ4I\x8d'
|
||||
b'\x01\x8dI2I\x9dI0I\x83\x01\x97\x01\x83I.'
|
||||
b'H\x86\x01\x95\x01\x86H-H\xa3H,H\x92\x01\x92'
|
||||
b'H+G\x92\x03\x92G*G\x92\x05\x92G)G\x92'
|
||||
b"\x05\x92G(G\x82\x01\x8f\x07\x8f\x01\x82G'G\x83"
|
||||
b"\x01\x8e\x07\x8e\x01\x83G'F\x93\x07\x93F&G\x93"
|
||||
b'\x07\x93G%F\x94\x07\x94F%F\x94\x07\x94F%'
|
||||
b'F\x94\x07\x94F$G\x94\x07\x94G#G\x94\x07\x94'
|
||||
b'G#G\x94\x07\x94G#F\x95\x07\x95F#F\x81'
|
||||
b'\x04\x90\x07\x90\x04\x81F#F\x95\x07\x95F#G\x94'
|
||||
b'\x07\x94G#G\x94\x07\x94G#G\x94\x07\x94G$'
|
||||
b'F\x94\x07\x94F%F\x94\x07\x94F%F\x94\x07\x94'
|
||||
b"F%G\x93\x07\x93G%G\x93\x07\x93F'G\x83"
|
||||
b"\x01\x8e\x07\x8e\x01\x83G'G\x82\x01\x8f\x07\x8f\x01\x82"
|
||||
b'G(G\x92\x05\x92G)G\x93\x03\x93G*G\xa7'
|
||||
b'G+H\xa5H,G\xa5G-H\x86\x01\x9cH.'
|
||||
b'H\x84\x01\x96\x01\x85H0I\x9a\x01\x82I1J\x8d'
|
||||
b'\x01\x8dJ2K\x8b\x01\x8bK4K\x8a\x01\x89L5'
|
||||
b'N\x87\x01\x87N5S\x85S5k5k5k5'
|
||||
b'k5k5k\x1b'
|
||||
)
|
||||
|
||||
_STOPPED = const(0)
|
||||
_RUNNING = const(1)
|
||||
_RINGING = const(2)
|
||||
|
||||
_BUTTON_Y = const(200)
|
||||
|
||||
class TimerApp():
|
||||
"""Allows the user to set a vibration alarm.
|
||||
"""
|
||||
NAME = 'Timer'
|
||||
ICON = icon
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the application."""
|
||||
self.minutes = widgets.Spinner(50, 60, 0, 99, 2)
|
||||
self.seconds = widgets.Spinner(130, 60, 0, 60, 2)
|
||||
self.current_alarm = None
|
||||
|
||||
self.minutes.value = 10
|
||||
self.state = _STOPPED
|
||||
|
||||
def foreground(self):
|
||||
"""Activate the application."""
|
||||
self._draw()
|
||||
wasp.system.request_event(wasp.EventMask.TOUCH)
|
||||
wasp.system.request_tick(1000)
|
||||
|
||||
def background(self):
|
||||
"""De-activate the application."""
|
||||
if self.state == _RINGING:
|
||||
self.state = _STOPPED
|
||||
|
||||
def tick(self, ticks):
|
||||
"""Notify the application that its periodic tick is due."""
|
||||
if self.state == _RINGING:
|
||||
wasp.watch.vibrator.pulse(duty=50, ms=500)
|
||||
wasp.system.keep_awake()
|
||||
self._update()
|
||||
|
||||
def touch(self, event):
|
||||
"""Notify the application of a touchscreen touch event."""
|
||||
if self.state == _RINGING:
|
||||
mute = wasp.watch.display.mute
|
||||
mute(True)
|
||||
self._stop()
|
||||
mute(False)
|
||||
elif self.state == _RUNNING:
|
||||
self._stop()
|
||||
else: # _STOPPED
|
||||
if self.minutes.touch(event) or self.seconds.touch(event):
|
||||
pass
|
||||
else:
|
||||
y = event[2]
|
||||
if y >= _BUTTON_Y:
|
||||
self._start()
|
||||
|
||||
|
||||
def _start(self):
|
||||
self.state = _RUNNING
|
||||
now = wasp.watch.rtc.time()
|
||||
self.current_alarm = now + self.minutes.value * 60 + self.seconds.value
|
||||
wasp.system.set_alarm(self.current_alarm, self._alert)
|
||||
self._draw()
|
||||
|
||||
def _stop(self):
|
||||
self.state = _STOPPED
|
||||
wasp.system.cancel_alarm(self.current_alarm, self._alert)
|
||||
self._draw()
|
||||
|
||||
def _draw(self):
|
||||
"""Draw the display from scratch."""
|
||||
draw = wasp.watch.drawable
|
||||
draw.fill()
|
||||
sbar = wasp.system.bar
|
||||
sbar.clock = True
|
||||
sbar.draw()
|
||||
|
||||
if self.state == _RINGING:
|
||||
draw.set_font(fonts.sans24)
|
||||
draw.string(self.NAME, 0, 150, width=240)
|
||||
draw.blit(icon, 73, 50)
|
||||
elif self.state == _RUNNING:
|
||||
self._draw_stop(104, _BUTTON_Y)
|
||||
draw.string(':', 110, 120-14, width=20)
|
||||
self._update()
|
||||
else: # _STOPPED
|
||||
draw.set_font(fonts.sans28)
|
||||
draw.string(':', 110, 120-14, width=20)
|
||||
|
||||
self.minutes.draw()
|
||||
self.seconds.draw()
|
||||
|
||||
self._draw_play(114, _BUTTON_Y)
|
||||
|
||||
def _update(self):
|
||||
wasp.system.bar.update()
|
||||
draw = wasp.watch.drawable
|
||||
if self.state == _RUNNING:
|
||||
now = wasp.watch.rtc.time()
|
||||
s = self.current_alarm - now
|
||||
if s<0:
|
||||
s = 0
|
||||
m = str(math.floor(s // 60))
|
||||
s = str(math.floor(s) % 60)
|
||||
if len(m) < 2:
|
||||
m = '0' + m
|
||||
if len(s) < 2:
|
||||
s = '0' + s
|
||||
draw.set_font(fonts.sans28)
|
||||
draw.string(m, 50, 120-14, width=60)
|
||||
draw.string(s, 130, 120-14, width=60)
|
||||
|
||||
def _draw_play(self, x, y):
|
||||
draw = wasp.watch.drawable
|
||||
for i in range(0,20):
|
||||
draw.fill(0xffff, x+i, y+i, 1, 40 - 2*i)
|
||||
|
||||
def _draw_stop(self, x, y):
|
||||
wasp.watch.drawable.fill(0xffff, x, y, 40, 40)
|
||||
|
||||
def _alert(self):
|
||||
self.state = _RINGING
|
||||
wasp.system.wake()
|
||||
wasp.system.switch(self)
|
|
@ -21,6 +21,7 @@ manifest = (
|
|||
'apps/stopwatch.py',
|
||||
'apps/snake.py',
|
||||
'apps/testapp.py',
|
||||
'apps/timer.py',
|
||||
'fonts/__init__.py',
|
||||
'fonts/clock.py',
|
||||
'fonts/sans24.py',
|
||||
|
|
Loading…
Reference in a new issue