Phone finder app
* Added phone finder app that works with Gadgetbridge * Fixed bug in ToggleButton * Moved send_cmd from music player to gadgetbridge.py for all apps to use Signed-off-by: Adam Blair adampblair@protonmail.com
This commit is contained in:
parent
99272f482f
commit
fd030eeff8
8 changed files with 122 additions and 15 deletions
|
@ -265,3 +265,7 @@ application (and the "blank" white screen is a torch application):
|
||||||
.. image:: res/BeaconApp.png
|
.. image:: res/BeaconApp.png
|
||||||
:alt: Flash the relatively powerful HRS LED repeatedly
|
:alt: Flash the relatively powerful HRS LED repeatedly
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
|
.. image:: res/FinderApp.png
|
||||||
|
:alt: Find your phone by causing it to ring
|
||||||
|
:width: 179
|
||||||
|
|
96
apps/PhoneFinder.py
Normal file
96
apps/PhoneFinder.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
# Copyright (C) 2023 Adam Blair
|
||||||
|
"""Phone finder application
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
An application to find a phone connected via Gadgetbridge.
|
||||||
|
|
||||||
|
.. figure:: res/FinderApp.png
|
||||||
|
:width: 179
|
||||||
|
|
||||||
|
Screenshot of the Phone Finder Application
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import wasp
|
||||||
|
import fonts
|
||||||
|
import widgets
|
||||||
|
from gadgetbridge import send_cmd
|
||||||
|
|
||||||
|
# 2-bit RLE, 96x64, generated from res/phone_finder_icon.png, 403 bytes
|
||||||
|
icon = (
|
||||||
|
b'\x02'
|
||||||
|
b'`@'
|
||||||
|
b'?\xff\xff\x87@\xd0G?\x17C\x07C?\x12B\r'
|
||||||
|
b'B?\x0fA\x11A?\rA\x13A?\x0bA\x15A'
|
||||||
|
b'?\tA?\x1fA!\x80\xb4\x84:A\rG\r\x84'
|
||||||
|
b'9A\x0cB\x07B?\tA\x0bA\x0bA?\x08A'
|
||||||
|
b'\nA\rA\t\x848A\nA\x18\x848A\tA'
|
||||||
|
b'\tD\x0c\x848A\x08A\x08B\x04B\n\x848A'
|
||||||
|
b'\x08A\x06B\x08A\t\x848A\x07A\x06A\x14A'
|
||||||
|
b'\x838A\x07A\x06A\x01A\x91B\x83A7A\x07'
|
||||||
|
b'A\x05A\x01A\x98A7A\x06A\x05A\x01\x82\x16'
|
||||||
|
b'\x827A\x06A\x04A\x02\x82\x04N\x04\x827A\x06'
|
||||||
|
b'A\x04A\x02\x82\x04N\x04\x828A\x05A\x04A\x02'
|
||||||
|
b'\x82\x04N\x04\x828A\x06A\x03A\x02\x82\x16\x829'
|
||||||
|
b'A\x05A\x04A\x01\x82\x02R\x02\x82:A\x05A\x03'
|
||||||
|
b'A\x01\x82\x02R\x02\x82;A\x05A\x03A\x82\x02R'
|
||||||
|
b'\x02\x82<A\x05A\x02A\x82\x02R\x02\x82?\x07\x82'
|
||||||
|
b'\x02R\x02\x82?\x07\x82\x02R\x02\x82?\x07\x82\x02R'
|
||||||
|
b'\x02\x82?\x07\x82\x02R\x02\x82?\x07\x82\x02R\x02\x82'
|
||||||
|
b'?\x07\x82\x02R\x02\x82?\x07\x82\x02R\x02\x82?\x07'
|
||||||
|
b'\x82\x02R\x02\x82?\x07\x82\x02R\x02\x82?\x07\x82\x02'
|
||||||
|
b'R\x02\x82?\x07\x82\x02R\x02\x82?\x07\x82\x02R\x02'
|
||||||
|
b'\x82?\x07\x82\x02R\x02\x82?\x07\x82\x02R\x02\x82?'
|
||||||
|
b'\x07\x82\x02R\x02\x82?\x07\x82\x02R\x02\x82?\x07\x82'
|
||||||
|
b'\x02R\x02\x82?\x07\x82\x02R\x02\x82?\x07\x82\x02R'
|
||||||
|
b'\x02\x82?\x07\x82\x16\x82?\x07\x82\x06J\x06\x82?\x07'
|
||||||
|
b'\x82\x16\x82?\x07A\x98A?\x08A\x96A?\xff\xc1'
|
||||||
|
)
|
||||||
|
|
||||||
|
class PhoneFinderApp():
|
||||||
|
"""Allows the user to set a vibration alarm.
|
||||||
|
"""
|
||||||
|
NAME = 'Finder'
|
||||||
|
ICON = icon
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the application."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def foreground(self):
|
||||||
|
"""Activate the application."""
|
||||||
|
self.ring_btn = widgets.ToggleButton(20, 120, 200, 60, 'Ring')
|
||||||
|
|
||||||
|
self._draw()
|
||||||
|
wasp.system.request_event(wasp.EventMask.TOUCH)
|
||||||
|
wasp.system.request_tick(1000)
|
||||||
|
|
||||||
|
def background(self):
|
||||||
|
"""De-activate the application."""
|
||||||
|
self.ring_btn = None
|
||||||
|
del self.ring_btn
|
||||||
|
|
||||||
|
def tick(self, ticks):
|
||||||
|
"""Notify the application that its periodic tick is due."""
|
||||||
|
wasp.system.bar.update()
|
||||||
|
|
||||||
|
def touch(self, event):
|
||||||
|
"""Notify the application of a touchscreen touch event."""
|
||||||
|
if self.ring_btn.touch(event):
|
||||||
|
if self.ring_btn.state:
|
||||||
|
send_cmd('{"t":"findPhone", "n":"true"} ')
|
||||||
|
else:
|
||||||
|
send_cmd('{"t":"findPhone", "n":"false"} ')
|
||||||
|
|
||||||
|
def _draw(self):
|
||||||
|
"""Draw the display from scratch."""
|
||||||
|
draw = wasp.watch.drawable
|
||||||
|
draw.fill()
|
||||||
|
sbar = wasp.system.bar
|
||||||
|
sbar.clock = True
|
||||||
|
sbar.draw()
|
||||||
|
|
||||||
|
draw.set_font(fonts.sans24)
|
||||||
|
draw.string('Find phone', 60, 70, width=120)
|
||||||
|
self.ring_btn.draw()
|
|
@ -55,6 +55,8 @@ Applications
|
||||||
|
|
||||||
.. automodule:: apps.flashlight
|
.. automodule:: apps.flashlight
|
||||||
|
|
||||||
|
.. automodule:: PhoneFinder
|
||||||
|
|
||||||
.. automodule:: apps.gallery
|
.. automodule:: apps.gallery
|
||||||
|
|
||||||
.. automodule:: apps.haiku
|
.. automodule:: apps.haiku
|
||||||
|
|
BIN
res/FinderApp.png
Normal file
BIN
res/FinderApp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
BIN
res/phone_finder_icon.png
Normal file
BIN
res/phone_finder_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 915 B |
|
@ -23,6 +23,7 @@ import icons
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from micropython import const
|
from micropython import const
|
||||||
|
from gadgetbridge import send_cmd
|
||||||
|
|
||||||
# 2-bit RLE, generated from res/music_icon.png, 358 bytes
|
# 2-bit RLE, generated from res/music_icon.png, 358 bytes
|
||||||
icon = (
|
icon = (
|
||||||
|
@ -74,15 +75,6 @@ class MusicPlayerApp(object):
|
||||||
self._track_changed = True
|
self._track_changed = True
|
||||||
self._artist_changed = True
|
self._artist_changed = True
|
||||||
|
|
||||||
def _send_cmd(self, cmd):
|
|
||||||
print('\r')
|
|
||||||
for i in range(1):
|
|
||||||
for i in range(0, len(cmd), 20):
|
|
||||||
print(cmd[i: i + 20], end='')
|
|
||||||
time.sleep(0.2)
|
|
||||||
print(' ')
|
|
||||||
print(' ')
|
|
||||||
|
|
||||||
def _fill_space(self, key):
|
def _fill_space(self, key):
|
||||||
if key == 'top':
|
if key == 'top':
|
||||||
wasp.watch.drawable.fill(
|
wasp.watch.drawable.fill(
|
||||||
|
@ -151,9 +143,9 @@ class MusicPlayerApp(object):
|
||||||
Notify the application of a touchscreen swipe event.
|
Notify the application of a touchscreen swipe event.
|
||||||
"""
|
"""
|
||||||
if event[0] == wasp.EventType.UP:
|
if event[0] == wasp.EventType.UP:
|
||||||
self._send_cmd('{"t":"music", "n":"volumeup"} ')
|
send_cmd('{"t":"music", "n":"volumeup"} ')
|
||||||
elif event[0] == wasp.EventType.DOWN:
|
elif event[0] == wasp.EventType.DOWN:
|
||||||
self._send_cmd('{"t":"music", "n":"volumedown"} ')
|
send_cmd('{"t":"music", "n":"volumedown"} ')
|
||||||
|
|
||||||
def touch(self, event):
|
def touch(self, event):
|
||||||
if self._pauseplay.touch(event):
|
if self._pauseplay.touch(event):
|
||||||
|
@ -162,16 +154,16 @@ class MusicPlayerApp(object):
|
||||||
self._musicstate = 'play'
|
self._musicstate = 'play'
|
||||||
self._pauseplay.gfx = icons.pause
|
self._pauseplay.gfx = icons.pause
|
||||||
self._pauseplay.draw()
|
self._pauseplay.draw()
|
||||||
self._send_cmd('{"t":"music", "n":"play"} ')
|
send_cmd('{"t":"music", "n":"play"} ')
|
||||||
else:
|
else:
|
||||||
self._musicstate = 'pause'
|
self._musicstate = 'pause'
|
||||||
self._pauseplay.gfx = icons.play
|
self._pauseplay.gfx = icons.play
|
||||||
self._pauseplay.draw()
|
self._pauseplay.draw()
|
||||||
self._send_cmd('{"t":"music", "n":"pause"} ')
|
send_cmd('{"t":"music", "n":"pause"} ')
|
||||||
elif self._back.touch(event):
|
elif self._back.touch(event):
|
||||||
self._send_cmd('{"t":"music", "n":"previous"} ')
|
send_cmd('{"t":"music", "n":"previous"} ')
|
||||||
elif self._fwd.touch(event):
|
elif self._fwd.touch(event):
|
||||||
self._send_cmd('{"t":"music", "n":"next"} ')
|
send_cmd('{"t":"music", "n":"next"} ')
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
"""Redraw the display from scratch."""
|
"""Redraw the display from scratch."""
|
||||||
|
|
|
@ -22,6 +22,7 @@ import io
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import wasp
|
import wasp
|
||||||
|
import time
|
||||||
|
|
||||||
# JSON compatibility
|
# JSON compatibility
|
||||||
null = None
|
null = None
|
||||||
|
@ -66,3 +67,12 @@ def GB(cmd):
|
||||||
sys.print_exception(e, msg)
|
sys.print_exception(e, msg)
|
||||||
_error(msg.getvalue())
|
_error(msg.getvalue())
|
||||||
msg.close()
|
msg.close()
|
||||||
|
|
||||||
|
def send_cmd(cmd = ''):
|
||||||
|
print('\r')
|
||||||
|
for i in range(1):
|
||||||
|
for i in range(0, len(cmd), 20):
|
||||||
|
print(cmd[i: i + 20], end='')
|
||||||
|
time.sleep(0.2)
|
||||||
|
print(' ')
|
||||||
|
print(' ')
|
|
@ -282,6 +282,9 @@ class ToggleButton(Button):
|
||||||
if super().touch(event):
|
if super().touch(event):
|
||||||
self.state = not self.state
|
self.state = not self.state
|
||||||
self.draw()
|
self.draw()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
class Checkbox():
|
class Checkbox():
|
||||||
"""A simple (labelled) checkbox."""
|
"""A simple (labelled) checkbox."""
|
||||||
|
|
Loading…
Reference in a new issue