Wasp A La carte
Configure wasp using a central toml file Signed-off-by: Adam Blair <adampblair@protonmail.com>
2
.github/workflows/main.yml
vendored
|
@ -39,7 +39,7 @@ jobs:
|
|||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y python3-sphinx python3-cryptography python3-cbor graphviz
|
||||
sudo pip3 install recommonmark
|
||||
sudo pip3 install recommonmark tomli
|
||||
|
||||
- name: Update submodules
|
||||
id: update-submodules
|
||||
|
|
3
.gitignore
vendored
|
@ -9,5 +9,8 @@ cscope.out
|
|||
docs/build
|
||||
attic/
|
||||
wasp/boards/*/watch.py
|
||||
wasp/boards/manifest_user_apps.py
|
||||
wasp/apps/user
|
||||
wasp/appregistry.py
|
||||
.idea
|
||||
.vscode
|
||||
|
|
23
Makefile
|
@ -23,7 +23,10 @@ clean :
|
|||
reloader/build-$(BOARD) reloader/src/boards/$(BOARD)/bootloader.h \
|
||||
micropython/mpy-cross/build \
|
||||
micropython/ports/nrf/build-$(BOARD)-s132 \
|
||||
wasp/boards/$(BOARD)/watch.py
|
||||
wasp/boards/$(BOARD)/watch.py \
|
||||
wasp/apps/user \
|
||||
wasp/boards/manifest_user_apps.py \
|
||||
wasp/appregistry.py
|
||||
|
||||
# Avoid a recursive update... it grabs far too much
|
||||
submodules :
|
||||
|
@ -61,7 +64,7 @@ wasp/boards/$(BOARD_SAFE)/watch.py : wasp/boards/$(BOARD_SAFE)/watch.py.in
|
|||
micropython/mpy-cross/mpy-cross:
|
||||
$(MAKE) -C micropython/mpy-cross
|
||||
|
||||
micropython: build-$(BOARD_SAFE) wasp/boards/$(BOARD_SAFE)/watch.py micropython/mpy-cross/mpy-cross
|
||||
micropython: build-$(BOARD_SAFE) wasp/boards/manifest_user_apps.py wasp/boards/$(BOARD_SAFE)/watch.py micropython/mpy-cross/mpy-cross
|
||||
$(RM) micropython/ports/nrf/build-$(BOARD)-s132/frozen_content.c
|
||||
$(MAKE) -C micropython/ports/nrf \
|
||||
BOARD=$(BOARD) SD=s132 \
|
||||
|
@ -73,6 +76,14 @@ micropython: build-$(BOARD_SAFE) wasp/boards/$(BOARD_SAFE)/watch.py micropython/
|
|||
--application micropython/ports/nrf/build-$(BOARD)-s132/firmware.hex \
|
||||
build-$(BOARD)/micropython.zip
|
||||
|
||||
wasp/boards/manifest_user_apps.py: wasp.toml
|
||||
$(RM) -r \
|
||||
wasp/apps/user \
|
||||
wasp/boards/manifest_user_apps.py \
|
||||
wasp/appregistry.py
|
||||
mkdir -p wasp/apps/user
|
||||
$(PYTHON) tools/configure_wasp_apps.py wasp.toml
|
||||
|
||||
build-$(BOARD_SAFE):
|
||||
mkdir -p build-$(BOARD)
|
||||
|
||||
|
@ -98,12 +109,12 @@ APPS_MPY=$(APPS_PY:%.py=%.mpy)
|
|||
.PHONY: apps
|
||||
apps: $(APPS_MPY)
|
||||
|
||||
docs:
|
||||
docs: wasp/boards/manifest_user_apps.py
|
||||
$(RM) -rf docs/build/html/*
|
||||
$(MAKE) -C docs html
|
||||
touch docs/build/html/.nojekyll
|
||||
|
||||
sim:
|
||||
sim: wasp/boards/manifest_user_apps.py
|
||||
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp \
|
||||
$(PYTHON) -i wasp/boards/simulator/main.py
|
||||
|
||||
|
@ -111,8 +122,8 @@ ifeq ("$(origin K)", "command line")
|
|||
PYTEST_RESTRICT = -k '$(K)'
|
||||
endif
|
||||
|
||||
check:
|
||||
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp \
|
||||
check: wasp/boards/manifest_user_apps.py
|
||||
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp:wasp/apps/system \
|
||||
$(PYTEST) -v -W ignore $(PYTEST_RESTRICT) wasp/boards/simulator
|
||||
|
||||
|
||||
|
|
197
README.rst
|
@ -124,6 +124,12 @@ Videos
|
|||
|
||||
-
|
||||
|
||||
Custom builds
|
||||
-------------
|
||||
|
||||
Wasp-os is designed to allow users to easily create their own custom builds. Simply modify the wasp.toml file
|
||||
to include your favorite apps and watch faces. See the docs for more information on how to build wasp-os.
|
||||
|
||||
Screenshots
|
||||
-----------
|
||||
|
||||
|
@ -134,138 +140,149 @@ PineTime:
|
|||
:alt: wasp-os digital clock app running on PineTime
|
||||
:width: 233
|
||||
|
||||
Screenshots of the built in applications running on the wasp-os
|
||||
Screenshots of the available applications running on the wasp-os
|
||||
simulator:
|
||||
|
||||
.. image:: res/Bootloader.png
|
||||
:alt: Bootloader splash screen overlaid on the simulator watch art
|
||||
:width: 179
|
||||
|
||||
.. image:: res/ClockApp.png
|
||||
Watch faces:
|
||||
|
||||
.. image:: res/screenshots/ClockApp.png
|
||||
:alt: Digital clock application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/DemoApp.png
|
||||
:alt: Simple always-on demo for showing off wasp-os at conferences and shows
|
||||
.. image:: res/screenshots/WeekClockApp.png
|
||||
:alt: Digital clock application with week day running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/DisaBLEApp.png
|
||||
:alt: Small application for disabling bluetooth to save power and enhance security
|
||||
:width: 179
|
||||
|
||||
.. image:: res/GalleryApp.png
|
||||
:alt: Gallery application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/HeartApp.png
|
||||
:alt: Heart rate application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/MorseApp.png
|
||||
:alt: Morse translator/notepad application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/SportsApp.png
|
||||
:alt: Sports applications, a combined stopwatch and step counter
|
||||
:width: 179
|
||||
|
||||
.. image:: res/StopclockApp.png
|
||||
:alt: Stop watch application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/StepsApp.png
|
||||
:alt: Step counter application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/LauncherApp.png
|
||||
:alt: Application launcher running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/SettingsApp.png
|
||||
:alt: Settings application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/SoftwareApp.png
|
||||
:alt: Software selection app running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
|
||||
wasp-os also contains a library of additional applications for you to choose.
|
||||
These are disabled by default but can be easily enabled using the Software
|
||||
application (and the "blank" white screen is a torch application):
|
||||
|
||||
.. image:: res/SelfTestApp.png
|
||||
:alt: Self test application running a rendering benchmark on the simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/TorchApp.png
|
||||
:alt: Torch application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/ChronoApp.png
|
||||
.. image:: res/screenshots/ChronoApp.png
|
||||
:alt: Analogue clock application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/DualApp.png
|
||||
.. image:: res/screenshots/DualClockApp.png
|
||||
:alt: An other clock application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/FiboApp.png
|
||||
.. image:: res/screenshots/FibonacciClockApp.png
|
||||
:alt: Fibonacci clock application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/HaikuApp.png
|
||||
:alt: Haiku application running in the wasp-os simulator
|
||||
.. image:: res/screenshots/WordClockApp.png
|
||||
:alt: Shows a time as words in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/LifeApp.png
|
||||
:alt: Game of Life running in the wasp-os simulator
|
||||
:width: 179
|
||||
Games:
|
||||
|
||||
.. image:: res/AlarmApp.png
|
||||
:alt: Alarm clock application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/MusicApp.png
|
||||
:alt: Music Player running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/CalcApp.png
|
||||
:alt: Calculator running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/2048App.png
|
||||
.. image:: res/screenshots/Play2048App.png
|
||||
:alt: Let's play the 2048 game (in the wasp-os simulator)
|
||||
:width: 179
|
||||
|
||||
.. image:: res/SnakeApp.png
|
||||
.. image:: res/screenshots/GameOfLifeApp.png
|
||||
:alt: Game of Life running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/SnakeApp.png
|
||||
:alt: Snake Game running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/TimerApp.png
|
||||
Time management apps:
|
||||
|
||||
.. image:: res/screenshots/AlarmApp.png
|
||||
:alt: Alarm clock application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/StopwatchApp.png
|
||||
:alt: Stop watch application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/TimerApp.png
|
||||
:alt: Countdown timer application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/WeatherApp.png
|
||||
:alt: Weather application running in the wasp-os simulator
|
||||
System apps:
|
||||
|
||||
.. image:: res/screenshots/DisaBLEApp.png
|
||||
:alt: Small application for disabling bluetooth to save power and enhance security
|
||||
:width: 179
|
||||
|
||||
.. image:: res/WeekClkApp.png
|
||||
:alt: Digital clock application, including the week day
|
||||
.. image:: res/screenshots/LauncherApp.png
|
||||
:alt: Application launcher running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/WordClkApp.png
|
||||
:alt: Shows a time as words in the wasp-os simulator
|
||||
.. image:: res/screenshots/SettingsApp.png
|
||||
:alt: Settings application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/LevelApp.png
|
||||
:alt: Shows a time as words in the wasp-os simulator
|
||||
.. image:: res/screenshots/SoftwareApp.png
|
||||
:alt: Software selection app running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/BeaconApp.png
|
||||
.. image:: res/screenshots/FacesApp.png
|
||||
:alt: Switch watch faces
|
||||
:width: 179
|
||||
|
||||
|
||||
Other apps: (The "blank" white screenshot is a flashlight app)
|
||||
|
||||
.. image:: res/screenshots/BeaconApp.png
|
||||
:alt: Flash the relatively powerful HRS LED repeatedly
|
||||
:width: 179
|
||||
|
||||
.. image:: res/FinderApp.png
|
||||
.. image:: res/screenshots/CalculatorApp.png
|
||||
:alt: Calculator running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/DemoApp.png
|
||||
:alt: Simple always-on demo for showing off wasp-os at conferences and shows
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/FlashlightApp.png
|
||||
:alt: Torch application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/GalleryApp.png
|
||||
:alt: Gallery application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/HeartApp.png
|
||||
:alt: Heart rate application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/HaikuApp.png
|
||||
:alt: Haiku application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/LevelApp.png
|
||||
:alt: Shows a time as words in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/MorseApp.png
|
||||
:alt: Morse translator/notepad application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/PhoneFinderApp.png
|
||||
:alt: Find your phone by causing it to ring
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/SportsApp.png
|
||||
:alt: Sports applications, a combined stopwatch and step counter
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/StepCounterApp.png
|
||||
:alt: Step counter application running on the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/TestApp.png
|
||||
:alt: Self test application running a rendering benchmark on the simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/MusicPlayerApp.png
|
||||
:alt: Music Player running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
.. image:: res/screenshots/WeatherApp.png
|
||||
:alt: Weather application running in the wasp-os simulator
|
||||
:width: 179
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
An application to set a vibration alarm. All settings can be accessed from the Watch UI.
|
||||
Press the button to turn off ringing alarms.
|
||||
|
||||
.. figure:: res/AlarmApp.png
|
||||
.. figure:: res/screenshots/AlarmApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the Alarm Application
|
|
@ -11,7 +11,7 @@ The blinking is handled by the HRS, so this app consumes very little power.
|
|||
With BLE and/or step counter disabled and blinking frequency set to the minimum,
|
||||
the watch's battery will last for many days.
|
||||
|
||||
.. figure:: res/BeaconApp.png
|
||||
.. figure:: res/screenshots/BeaconApp.png
|
||||
:width: 179
|
||||
"""
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
This is a simple calculator app that uses the build-in eval() function to
|
||||
compute the solution.
|
||||
|
||||
.. figure:: res/CalcApp.png
|
||||
.. figure:: res/screenshots/CalculatorApp.png
|
||||
:width: 179
|
||||
"""
|
||||
|
|
@ -9,7 +9,7 @@ MicroPython logos. It cycles through a variety of colours
|
|||
and swaps between the logos every 5 images (so if you change
|
||||
anything make sure len(colors) is not a multiple of 5).
|
||||
|
||||
.. figure:: res/DemoApp.png
|
||||
.. figure:: res/screenshots/DemoApp.png
|
||||
:width: 179
|
||||
|
||||
The demo also includes code to keep the devie awake making it
|
|
@ -10,7 +10,7 @@ This app shows the bluetooth status and provides a button to disable/enable it.
|
|||
Unfortunately, re-enabling bluetooth normally has some issues, so as a
|
||||
workaround the "enable" button restarts the watch.
|
||||
|
||||
.. figure:: res/DisaBLEApp.png
|
||||
.. figure:: res/screenshots/DisaBLEApp.png
|
||||
:width: 179
|
||||
"""
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
A tool to select a suitable watch face.
|
||||
|
||||
.. figure:: res/FacesApp.png
|
||||
.. figure:: res/screenshots/FacesApp.png
|
||||
:width: 179
|
||||
|
||||
The app is intended to be enabled by default and has, therefore, been carefully
|
||||
|
@ -14,6 +14,7 @@ structured to minimize memory usage when the app is not active.
|
|||
|
||||
import wasp
|
||||
import icons
|
||||
import appregistry
|
||||
|
||||
class FacesApp():
|
||||
"""Choose a default watch face."""
|
||||
|
@ -23,12 +24,8 @@ class FacesApp():
|
|||
def foreground(self):
|
||||
"""Activate the application."""
|
||||
choices = []
|
||||
choices.append(('clock', 'Clock'))
|
||||
choices.append(('week_clock', 'WeekClock'))
|
||||
choices.append(('chrono', 'Chrono'))
|
||||
choices.append(('dual_clock', 'DualClock'))
|
||||
choices.append(('fibonacci_clock', 'FibonacciClock'))
|
||||
choices.append(('word_clock', 'WordClock'))
|
||||
for face in appregistry.faces_list:
|
||||
choices.append(face)
|
||||
|
||||
self.choices = choices
|
||||
self.choice = 0
|
||||
|
@ -68,6 +65,6 @@ class FacesApp():
|
|||
"""Draw the display from scratch."""
|
||||
wasp.watch.drawable.fill()
|
||||
(module, label) = self.choices[self.choice]
|
||||
wasp.system.register('apps.{}.{}App'.format(module, label), watch_face=True)
|
||||
wasp.system.register('{}.{}App'.format(module, label), watch_face=True)
|
||||
wasp.system.quick_ring[0].preview()
|
||||
self.si.draw()
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Shows a bright screen that you can tap to change brightness or switch to redlight.
|
||||
|
||||
.. figure:: res/TorchApp.png
|
||||
.. figure:: res/screenshots/FlashlightApp.png
|
||||
:width: 179
|
||||
"""
|
||||
|
||||
|
@ -14,7 +14,7 @@ import wasp
|
|||
import icons
|
||||
|
||||
|
||||
class TorchApp(object):
|
||||
class FlashlightApp(object):
|
||||
"""Trivial flashlight application."""
|
||||
NAME = 'Torch'
|
||||
ICON = icons.torch
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
An application that shows images stored in the filesystem.
|
||||
|
||||
.. figure:: res/GalleryApp.png
|
||||
.. figure:: res/screenshots/GalleryApp.png
|
||||
:width: 179
|
||||
|
||||
The images have to be uploaded in the "gallery" directory.
|
||||
|
@ -27,7 +27,7 @@ And to upload:
|
|||
|
||||
import wasp
|
||||
import icons
|
||||
from apps.pager import PagerApp
|
||||
from apps.system.pager import PagerApp
|
||||
|
||||
class GalleryApp():
|
||||
NAME = 'Gallery'
|
|
@ -6,7 +6,7 @@
|
|||
The Game of Life is a "no player game" played on a two dimensional grid
|
||||
where the rules interact to make interesting patterns.
|
||||
|
||||
.. figure:: res/LifeApp.png
|
||||
.. figure:: res/screenshots/GameOfLifeApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the Game of Life application
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
These three lines poems are fun to write and fit nicely on a tiny screen.
|
||||
|
||||
.. figure:: res/HaikuApp.png
|
||||
.. figure:: res/screenshots/HaikuApp.png
|
||||
:width: 179
|
||||
|
||||
If there is a file called haiku.txt in the flash filesystem then this app
|
||||
|
@ -22,7 +22,7 @@ import icons
|
|||
import io
|
||||
import sys
|
||||
|
||||
from apps.pager import PagerApp
|
||||
from apps.system.pager import PagerApp
|
||||
|
||||
class HaikuApp(PagerApp):
|
||||
NAME = 'Haiku'
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
A graphing heart rate monitor using a PPG sensor.
|
||||
|
||||
.. figure:: res/HeartApp.png
|
||||
.. figure:: res/screenshots/HeartApp.png
|
||||
:width: 179
|
||||
|
||||
This program also implements some (entirely optional) debug features to
|
|
@ -8,7 +8,7 @@ A tap opens a menu with the option to calibrate or reset the level.
|
|||
To calibrate, place the watch on a flat surface, then tap the "Calibrate"
|
||||
button while ensuring the watch is stationary.
|
||||
|
||||
.. figure:: res/LevelApp.png
|
||||
.. figure:: res/screenshots/LevelApp.png
|
||||
:width: 179
|
||||
"""
|
||||
|
|
@ -13,7 +13,7 @@ lines will be deleted.
|
|||
There is a preview of the next letter at the bottom of the screen.
|
||||
|
||||
|
||||
.. figure:: res/MorseApp.png
|
||||
.. figure:: res/screenshots/MorseApp.png
|
||||
:width: 179
|
||||
"""
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
"""Music Player for GadgetBridge
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. figure:: res/MusicApp.png
|
||||
.. figure:: res/screenshots/MusicPlayerApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the Music Player application
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
An application to find a phone connected via Gadgetbridge.
|
||||
|
||||
.. figure:: res/FinderApp.png
|
||||
.. figure:: res/screenshots/PhoneFinderApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the Phone Finder Application
|
|
@ -6,7 +6,7 @@
|
|||
A popular sliding block puzzle game in which tiles are combined to make the
|
||||
number 2048.
|
||||
|
||||
.. figure:: res/2048App.png
|
||||
.. figure:: res/screenshots/Play2048App.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the 2048 game application
|
|
@ -15,4 +15,4 @@ class ReadMeApp():
|
|||
draw = wasp.watch.drawable
|
||||
draw.fill()
|
||||
draw.string('Autoloaded from', 0, 96, width=240)
|
||||
draw.string('apps/ReadMe.py', 0, 96+32, width=240)
|
||||
draw.string('apps/read_me.py', 0, 96+32, width=240)
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
This is a classic arcade game called snake.
|
||||
|
||||
.. figure:: res/SnakeApp.png
|
||||
.. figure:: res/screenshots/SnakeApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the snake game
|
||||
|
@ -46,7 +46,7 @@ snake_icon = (
|
|||
import wasp, time
|
||||
from random import randint
|
||||
|
||||
class SnakeGameApp():
|
||||
class SnakeApp():
|
||||
NAME = 'Snake'
|
||||
ICON = snake_icon
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
A combined stopwatch and step counter.
|
||||
|
||||
.. figure:: res/SportsApp.png
|
||||
.. figure:: res/screenshots/SportsApp.png
|
||||
:width: 179
|
||||
"""
|
||||
import wasp
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Simple stop/start watch with support for split times.
|
||||
|
||||
.. figure:: res/StopclockApp.png
|
||||
.. figure:: res/screenshots/StopwatchApp.png
|
||||
:width: 179
|
||||
"""
|
||||
import wasp
|
|
@ -7,7 +7,7 @@
|
|||
A collection of tests used to develop features or provide useful metrics such
|
||||
as performance indicators or memory usage.
|
||||
|
||||
.. figure:: res/SelfTestApp.png
|
||||
.. figure:: res/screenshots/TestApp.png
|
||||
:width: 179
|
||||
"""
|
||||
|
||||
|
@ -18,7 +18,7 @@ import fonts
|
|||
import icons
|
||||
import machine
|
||||
|
||||
from apps.pager import PagerApp
|
||||
from apps.system.pager import PagerApp
|
||||
|
||||
class TestApp():
|
||||
"""Self test application."""
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
An application to set a vibration in a specified amount of time. Like a kitchen timer.
|
||||
|
||||
.. figure:: res/TimerApp.png
|
||||
.. figure:: res/screenshots/TimerApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the Timer Application
|
|
@ -5,7 +5,7 @@
|
|||
"""Weather for GadgetBridge and wasp-os companion
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. figure:: res/WeatherApp.png
|
||||
.. figure:: res/screenshots/WeatherApp.png
|
||||
:width: 179
|
||||
|
||||
Screenshot of the Weather application
|
|
@ -203,6 +203,31 @@ a little time into learning the best practices when running
|
|||
.. _MicroPython: https://micropython.org/
|
||||
__ http://docs.micropython.org/en/latest/reference/constrained.html
|
||||
|
||||
App naming conventions and placement
|
||||
------------------------------------
|
||||
|
||||
Your app must be named in a specific way and placed in the /apps directory to be compatible with wasp-os.
|
||||
Watch faces follow the same rules but are placed in the /watch_faces directory.
|
||||
|
||||
1. The name of the python file must be in snake case (ie: music_player.py)
|
||||
2. The class of your app must be the name of the file in pascal case with "App" appended (ie: MusicPlayerApp)
|
||||
3. The NAME variable in your app must short and will be used on the launcher screen (ie: NAME = 'Music')
|
||||
|
||||
If you wish to submit your app to the project it must additionally meet these requirements:
|
||||
|
||||
1. The app must be added to docs/apps.rst
|
||||
2. The app must be added to the README.rst
|
||||
3. A simulator screenshot must exist in the /res/screenshots directory having the name of the app class (ie: MusicPlayerApp.png). Press s in the simulator to take a screenshot.
|
||||
4. The app must include a README comment at the top of the file (see existing apps)
|
||||
5. The app README must include a link to the simulator screenshot in the /res/screenshots directory
|
||||
6. If your app has an icon (encouraged) than the image used to generate the RLE must be in the /res/icons directory. Its name should be the snake case name of the app file with "_icon" appended. (ie: music_player_icon.png)
|
||||
|
||||
To check if your app meets these requirements you can run the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
make check
|
||||
|
||||
|
||||
How to run your application
|
||||
---------------------------
|
||||
|
@ -391,12 +416,7 @@ because they can execute directly from the internal FLASH rather than running
|
|||
from RAM. Additionally the code is pre-compiled, which also means we don't
|
||||
need any RAM budget to run the compiler.
|
||||
|
||||
Freezing your application requires you to modify the ``manifest.py``
|
||||
file for your board (e.g. ``wasp/boards/pinetime/manifest.py``) to include
|
||||
your application and then the whole binary must be re-compiled as normal.
|
||||
|
||||
After that you an use the same technique described in the previous
|
||||
section to add an import and register for you application from ``main.py``
|
||||
To freeze your app into the wasp-os binary add it to the wasp.toml file.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -442,25 +462,13 @@ To delete a file from the device:
|
|||
>>>os.remove("apps/myapp.mpy")
|
||||
>>>del os
|
||||
|
||||
Application naming conventions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You app will have two names. A short name that will be displayed on the home
|
||||
screen and a long name to be displayed in the software list. Your files must be
|
||||
named according to the following rules:
|
||||
|
||||
1) The class must be named the long name of the python file plus "App" (ie: "eggtimer.py" and "class EggTimerApp")
|
||||
2) Within your class the variable "NAME" must be set to the short name (ie: NAME= 'Timer' )
|
||||
3) Your app's documentation screenshot must be stored as the short name plus "App" (ie: res/TimerApp.png)
|
||||
4) The png used to generate your icon should be stored as the long name plus icon (ie: res/egg_timer_icon.png)
|
||||
|
||||
Application entry points
|
||||
------------------------
|
||||
|
||||
Applications provide entry points for the system manager to use to notify
|
||||
the application of a change in system state or an user interface event.
|
||||
|
||||
.. automodule:: apps.template
|
||||
.. automodule:: template
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members:
|
||||
|
|
|
@ -9,77 +9,77 @@ Application Library
|
|||
Watch faces
|
||||
-----------
|
||||
|
||||
.. automodule:: apps.faces
|
||||
.. automodule:: faces
|
||||
|
||||
.. automodule:: apps.clock
|
||||
.. automodule:: clock
|
||||
|
||||
.. automodule:: apps.chrono
|
||||
.. automodule:: chrono
|
||||
|
||||
.. automodule:: apps.dual_clock
|
||||
.. automodule:: dual_clock
|
||||
|
||||
.. automodule:: apps.fibonacci_clock
|
||||
.. automodule:: fibonacci_clock
|
||||
|
||||
.. automodule:: apps.week_clock
|
||||
.. automodule:: week_clock
|
||||
|
||||
.. automodule:: apps.word_clock
|
||||
.. automodule:: word_clock
|
||||
|
||||
Built-in
|
||||
--------
|
||||
|
||||
.. automodule:: apps.heart
|
||||
.. automodule:: apps.system.step_counter
|
||||
|
||||
.. automodule:: apps.stopwatch
|
||||
.. automodule:: apps.system.launcher
|
||||
|
||||
.. automodule:: apps.steps
|
||||
.. automodule:: apps.system.settings
|
||||
|
||||
.. automodule:: apps.launcher
|
||||
.. automodule:: apps.system.software
|
||||
|
||||
.. automodule:: apps.settings
|
||||
|
||||
.. automodule:: apps.software
|
||||
|
||||
.. automodule:: apps.pager
|
||||
.. automodule:: apps.system.pager
|
||||
|
||||
Applications
|
||||
------------
|
||||
|
||||
.. automodule:: apps.alarm
|
||||
.. automodule:: alarm
|
||||
|
||||
.. automodule:: Beacon
|
||||
.. automodule:: beacon
|
||||
|
||||
.. automodule:: apps.calc
|
||||
.. automodule:: calculator
|
||||
|
||||
.. automodule:: apps.demo
|
||||
.. automodule:: demo
|
||||
|
||||
.. automodule:: apps.disaBLE
|
||||
.. automodule:: disa_b_l_e
|
||||
|
||||
.. automodule:: apps.flashlight
|
||||
.. automodule:: flashlight
|
||||
|
||||
.. automodule:: PhoneFinder
|
||||
.. automodule:: gallery
|
||||
|
||||
.. automodule:: apps.gallery
|
||||
.. automodule:: haiku
|
||||
|
||||
.. automodule:: apps.haiku
|
||||
.. automodule:: heart
|
||||
|
||||
.. automodule:: Level
|
||||
.. automodule:: level
|
||||
|
||||
.. automodule:: Morse
|
||||
.. automodule:: morse
|
||||
|
||||
.. automodule:: apps.musicplayer
|
||||
.. automodule:: music_player
|
||||
|
||||
.. automodule:: apps.sports
|
||||
.. automodule:: phone_finder
|
||||
|
||||
.. automodule:: apps.testapp
|
||||
.. automodule:: sports
|
||||
|
||||
.. automodule:: apps.timer
|
||||
.. automodule:: stopwatch
|
||||
|
||||
.. automodule:: apps.weather
|
||||
.. automodule:: test
|
||||
|
||||
.. automodule:: timer
|
||||
|
||||
.. automodule:: weather
|
||||
|
||||
Games
|
||||
-----
|
||||
|
||||
.. automodule:: GameOfLife
|
||||
.. automodule:: game_of_life
|
||||
|
||||
.. automodule:: apps.play2048
|
||||
.. automodule:: play2048
|
||||
|
||||
.. automodule:: apps.snake
|
||||
.. automodule:: snake
|
||||
|
|
|
@ -14,6 +14,7 @@ import os
|
|||
import sys
|
||||
sys.path.insert(0, os.path.abspath('../wasp'))
|
||||
sys.path.insert(0, os.path.abspath('../apps'))
|
||||
sys.path.insert(0, os.path.abspath('../watch_faces'))
|
||||
sys.path.insert(0, os.path.abspath('../wasp/boards/sphinx'))
|
||||
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
../wasp/apps/hello.py
|
||||
../apps/hello.py
|
|
@ -25,7 +25,7 @@ following commands:
|
|||
wget git build-essential libsdl2-2.0-0 python3-click python3-gi \
|
||||
python3-numpy python3-pexpect python3-pil python3-pip python3-pydbus \
|
||||
python3-serial unzip
|
||||
pip3 install --user cbor pysdl2
|
||||
pip3 install --user cbor pysdl2 tomli
|
||||
|
||||
Additionally if you wish to regenerate the documentation you will require
|
||||
a complete sphinx toolchain:
|
||||
|
@ -114,6 +114,17 @@ To rebuild the documentation:
|
|||
|
||||
The docs will be browsable in ``docs/build/html`` as per Sphinx standards.
|
||||
|
||||
Custom builds
|
||||
-------------
|
||||
|
||||
Wasp-os can be configured to include a custom selection of apps and watch faces using the wasp.toml file.
|
||||
There are many more apps available than can fit on a device. Choose your favorites and roll your own flavor of wasp.
|
||||
Apps that are configured as quick_ring will be automatically added to the wasp quick ring (swipe left and right from
|
||||
the watch face). If an app is configured with auto load it will load into memory at startup and any apps that
|
||||
are not auto loaded can be enabled using the software app. Add as many watch faces as you like and switch
|
||||
between them using the faces app.
|
||||
|
||||
|
||||
Binary downloads
|
||||
----------------
|
||||
|
||||
|
|
Before Width: | Height: | Size: 8 KiB After Width: | Height: | Size: 8 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 568 B After Width: | Height: | Size: 568 B |
Before Width: | Height: | Size: 750 B After Width: | Height: | Size: 750 B |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 396 B After Width: | Height: | Size: 396 B |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 695 B After Width: | Height: | Size: 695 B |
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 563 B After Width: | Height: | Size: 563 B |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 915 B After Width: | Height: | Size: 915 B |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 688 B After Width: | Height: | Size: 688 B |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 6 KiB After Width: | Height: | Size: 6 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
93
tools/configure_wasp_apps.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
"""Configure the wasp distribution based on the provided wasp.toml config
|
||||
|
||||
This script generates the following files and directories
|
||||
wasp/apps/user/
|
||||
wasp/boards/manifest_user_apps.py
|
||||
wasp/appregistry.py
|
||||
"""
|
||||
|
||||
import tomli
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def _snake_case_to_pascal_case(s):
|
||||
out = ''
|
||||
for word in s.split('_'):
|
||||
out = out + word[:1].upper() + word[1:]
|
||||
return out
|
||||
|
||||
|
||||
def _file_path_to_class_name(path):
|
||||
return _snake_case_to_pascal_case(path.split('/')[-1].split('.')[0]) + 'App'
|
||||
|
||||
|
||||
def _file_path_to_display_name(path):
|
||||
return _snake_case_to_pascal_case(path.split('/')[-1].split('.')[0])
|
||||
|
||||
|
||||
with open(sys.argv[1:][0], 'rb') as config_file:
|
||||
config = tomli.load(config_file)
|
||||
|
||||
# Copy selected apps to the wasp app user directory
|
||||
for app in config.get('app'):
|
||||
os.system('cp ' + app.get('file') + ' wasp/apps/user/' + app.get('file').split('/')[-1])
|
||||
|
||||
# Copy selected watch faces to the wasp app user directory
|
||||
for app in config.get('watchface'):
|
||||
os.system('cp ' + app.get('file') + ' wasp/apps/user/' + app.get('file').split('/')[-1])
|
||||
|
||||
# Create the user app manifest containing all user apps and watch faces
|
||||
with open('wasp/boards/manifest_user_apps.py', 'w') as manifest_file:
|
||||
manifest_file.write('# This file is auto generated from the wasp.toml. Manual changes will be overwritten. \n\n')
|
||||
manifest_file.write('manifest = (\n')
|
||||
for app in config.get('app'):
|
||||
manifest_file.write(' \'' + 'apps/user/' + app.get('file').split('/')[-1] + '\',\n')
|
||||
for watchface in config.get('watchface'):
|
||||
manifest_file.write(' \'' + 'apps/user/' + watchface.get('file').split('/')[-1] + '\',\n')
|
||||
manifest_file.write(')')
|
||||
|
||||
# Create a registry for the os to use to populate its lists
|
||||
with open('wasp/appregistry.py', 'w') as reg_file:
|
||||
|
||||
# Software to display in the software app
|
||||
reg_file.write('# This file is auto generated from the wasp.toml. Manual changes will be overwritten. \n\n')
|
||||
reg_file.write('software_list = (\n')
|
||||
for app in config.get('app'):
|
||||
if not app.get('quick_ring'):
|
||||
app_module_name = 'apps.user.' + app.get('file').split('/')[-1].split('.')[0]
|
||||
app_display_name = _file_path_to_display_name(app.get('file'))
|
||||
reg_file.write(' (\'' + app_module_name + '\', \'' + app_display_name + '\'),\n')
|
||||
reg_file.write(')\n\n')
|
||||
|
||||
# Software to display in the faces app
|
||||
reg_file.write('faces_list = (\n')
|
||||
for face in config.get('watchface'):
|
||||
watchface_module = 'apps.user.' + face.get('file').split('/')[-1].split('.')[0]
|
||||
watchface_class = _file_path_to_display_name(face.get('file'))
|
||||
reg_file.write(' (\'' + watchface_module + '\',\'' + watchface_class + '\'),\n')
|
||||
reg_file.write(')\n\n')
|
||||
|
||||
|
||||
# Software to be loaded at startup (default watch face, quick ring apps, any apps marked auto_load in the config)
|
||||
reg_file.write('autoload_list = (\n')
|
||||
|
||||
# Fist app to autoload should be the default watch face
|
||||
default_watchface = None
|
||||
for watchface in config.get('watchface'):
|
||||
if watchface.get('default'):
|
||||
default_watchface = watchface
|
||||
elif not default_watchface:
|
||||
default_watchface = watchface
|
||||
watchface_path = 'apps.user.' + default_watchface.get('file').split('/')[-1].split('.')[0] + '.' + _file_path_to_class_name(default_watchface.get('file'))
|
||||
reg_file.write(' (\'' + watchface_path + '\', True, False, True),\n')
|
||||
|
||||
# The next apps should be the quick ring and any auto_load apps (in order specified in the config)
|
||||
for app in config.get('app'):
|
||||
if (app.get('quick_ring') or app.get('auto_load')):
|
||||
app_path = 'apps.user.' + app.get('file').split('/')[-1].split('.')[0] + '.' + _file_path_to_class_name(app.get('file'))
|
||||
app_quick_ring = str(not (app.get('quick_ring') is None))
|
||||
app_no_except = str(not (app.get('no_except') is None))
|
||||
reg_file.write(' (\'' + app_path + '\', ' + app_quick_ring + ', False, ' + app_no_except + '),\n')
|
||||
reg_file.write(')\n\n')
|
||||
|
|
@ -12,7 +12,7 @@ RUN set -xe; \
|
|||
libcairo2-dev python3-serial unzip python3-sphinx graphviz \
|
||||
python3-recommonmark python3-pytest \
|
||||
; \
|
||||
pip3 install cbor pysdl2 pygobject cryptography;
|
||||
pip3 install cbor pysdl2 pygobject cryptography tomli;
|
||||
|
||||
RUN set -xe; \
|
||||
wget --progress=dot:mega -O - https://developer.arm.com/-/media/Files/downloads/gnu-rm/10-2020q4/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 | tar xjf - -C /opt
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 1164d3d844290fc330e366e1881f7c10cf7a8be6
|
||||
Subproject commit 5572b01b26e04c7f8c79e8407f4d202e7258bf6b
|
39
wasp.toml
Normal file
|
@ -0,0 +1,39 @@
|
|||
# The default build for wasp-os. Modify to customize your own build.
|
||||
# At least one watch face must be specified. Quick ring apps will be added in order.
|
||||
|
||||
[[app]]
|
||||
file = 'apps/stopwatch.py'
|
||||
quick_ring = true
|
||||
|
||||
[[app]]
|
||||
file = 'apps/heart.py'
|
||||
quick_ring = true
|
||||
|
||||
[[app]]
|
||||
file = 'apps/alarm.py'
|
||||
auto_load = true
|
||||
|
||||
[[app]]
|
||||
file = 'apps/timer.py'
|
||||
auto_load = true
|
||||
|
||||
[[app]]
|
||||
file = 'apps/calculator.py'
|
||||
|
||||
[[app]]
|
||||
file = 'apps/disa_b_l_e.py'
|
||||
|
||||
[[app]] # If only one watch face is included this app can be removed
|
||||
file = 'apps/faces.py'
|
||||
auto_load = true
|
||||
no_except = true
|
||||
|
||||
[[watchface]]
|
||||
file = 'watch_faces/clock.py'
|
||||
|
||||
[[watchface]] # Requires ClockApp to also be installed
|
||||
file = 'watch_faces/week_clock.py'
|
||||
default = true
|
||||
|
||||
[[watchface]]
|
||||
file = 'watch_faces/chrono.py'
|
|
@ -4,7 +4,7 @@
|
|||
"""Application launcher
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. figure:: res/LauncherApp.png
|
||||
.. figure:: res/screenshots/LauncherApp.png
|
||||
:width: 179
|
||||
"""
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
Allows a very small set of user preferences (including the date and
|
||||
time) to be set on the device itself.
|
||||
|
||||
.. figure:: res/SettingsApp.png
|
||||
.. figure:: res/screenshots/SettingsApp.png
|
||||
:width: 179
|
||||
|
||||
.. note::
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
A tool to enable/disable applications.
|
||||
|
||||
.. figure:: res/SoftwareApp.png
|
||||
.. figure:: res/screenshots/SoftwareApp.png
|
||||
:width: 179
|
||||
|
||||
Most applications are disabled by default at boot in order to conserve
|
||||
|
@ -18,6 +18,7 @@ import wasp
|
|||
import icons
|
||||
import os
|
||||
import gc
|
||||
import appregistry
|
||||
|
||||
|
||||
class SoftwareApp():
|
||||
|
@ -39,19 +40,8 @@ class SoftwareApp():
|
|||
|
||||
y = 0
|
||||
db = []
|
||||
db.append(('alarm', factory('Alarm')))
|
||||
db.append(('calc', factory('Calculator')))
|
||||
db.append(('disaBLE', factory('DisaBLE')))
|
||||
db.append(('faces', factory('Faces')))
|
||||
db.append(('gallery', factory('Gallery')))
|
||||
db.append(('musicplayer', factory('Music Player')))
|
||||
db.append(('play2048', factory('Play 2048')))
|
||||
db.append(('snake', factory('Snake Game')))
|
||||
db.append(('sports', factory('Sports')))
|
||||
db.append(('flashlight', factory('Torch')))
|
||||
db.append(('testapp', factory('Test')))
|
||||
db.append(('timer', factory('Timer')))
|
||||
db.append(('weather', factory('Weather')))
|
||||
for app in appregistry.software_list:
|
||||
db.append((app[0], factory(app[1])))
|
||||
|
||||
# Handle user-loaded applications
|
||||
try:
|
||||
|
@ -62,7 +52,14 @@ class SoftwareApp():
|
|||
if app.endswith('.mpy'):
|
||||
name = app[:-4]
|
||||
if name:
|
||||
db.append((name, factory(name)))
|
||||
# Don't add apps that already exist (prioritize frozen apps)
|
||||
load = True
|
||||
for db_app in db:
|
||||
if db_app[0][db_app[0].rindex('.') + 1:] == name:
|
||||
load = False
|
||||
break
|
||||
if load:
|
||||
db.append(('apps.' + name, factory(self._snake_case_to_pascal_case(name))))
|
||||
except OSError:
|
||||
# apps does not exist...
|
||||
pass
|
||||
|
@ -117,7 +114,7 @@ class SoftwareApp():
|
|||
label = checkbox.label.replace(' ', '')
|
||||
if checkbox.state:
|
||||
gc.collect()
|
||||
wasp.system.register('apps.{}.{}App'.format(module, label))
|
||||
wasp.system.register('{}.{}App'.format(module, label))
|
||||
else:
|
||||
for app in wasp.system.launcher_ring:
|
||||
if type(app).__name__.startswith(label):
|
||||
|
@ -131,3 +128,10 @@ class SoftwareApp():
|
|||
self.si.draw()
|
||||
for _, checkbox in self.get_page():
|
||||
checkbox.draw()
|
||||
|
||||
@staticmethod
|
||||
def _snake_case_to_pascal_case(s):
|
||||
out = ''
|
||||
for word in s.split('_'):
|
||||
out = out + word[:1].upper() + word[1:]
|
||||
return out
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Provide a daily step count.
|
||||
|
||||
.. figure:: res/StepsApp.png
|
||||
.. figure:: res/screenshots/StepCounterApp.png
|
||||
:width: 179
|
||||
|
||||
The step counts automatically reset at midnight.
|
|
@ -5,9 +5,10 @@ import os, sys
|
|||
|
||||
sys.path.append(os.path.dirname(os.getcwd()))
|
||||
import manifest_240x240
|
||||
import manifest_user_apps
|
||||
|
||||
freeze('.', 'watch.py', opt=3)
|
||||
freeze('../..', manifest_240x240.manifest +
|
||||
freeze('../..', manifest_240x240.manifest + manifest_user_apps.manifest +
|
||||
(
|
||||
'boot.py',
|
||||
'draw565.py',
|
||||
|
|
|
@ -3,33 +3,11 @@
|
|||
"""Shared manifest for applications that work well on a 240x240 display."""
|
||||
|
||||
manifest = (
|
||||
'apps/alarm.py',
|
||||
'apps/calc.py',
|
||||
'apps/clock.py',
|
||||
'apps/chrono.py',
|
||||
'apps/disaBLE.py',
|
||||
'apps/dual_clock.py',
|
||||
'apps/faces.py',
|
||||
'apps/fibonacci_clock.py',
|
||||
'apps/flashlight.py',
|
||||
'apps/gallery.py',
|
||||
'apps/haiku.py',
|
||||
'apps/heart.py',
|
||||
'apps/musicplayer.py',
|
||||
'apps/launcher.py',
|
||||
'apps/pager.py',
|
||||
'apps/play2048.py',
|
||||
'apps/settings.py',
|
||||
'apps/software.py',
|
||||
'apps/sports.py',
|
||||
'apps/steps.py',
|
||||
'apps/stopwatch.py',
|
||||
'apps/snake.py',
|
||||
'apps/testapp.py',
|
||||
'apps/timer.py',
|
||||
'apps/weather.py',
|
||||
'apps/week_clock.py',
|
||||
'apps/word_clock.py',
|
||||
'apps/system/launcher.py',
|
||||
'apps/system/pager.py',
|
||||
'apps/system/software.py',
|
||||
'apps/system/settings.py',
|
||||
'apps/system/step_counter.py',
|
||||
'fonts/__init__.py',
|
||||
'fonts/clock.py',
|
||||
'fonts/clock_dual.py',
|
||||
|
@ -38,6 +16,7 @@ manifest = (
|
|||
'fonts/sans28.py',
|
||||
'fonts/sans36.py',
|
||||
'icons.py',
|
||||
'steplogger.py',
|
||||
'widgets.py',
|
||||
'steplogger.py',
|
||||
'appregistry.py',
|
||||
)
|
||||
|
|
|
@ -5,9 +5,10 @@ import os, sys
|
|||
|
||||
sys.path.append(os.path.dirname(os.getcwd()))
|
||||
import manifest_240x240
|
||||
import manifest_user_apps
|
||||
|
||||
freeze('.', 'watch.py', opt=3)
|
||||
freeze('../..', manifest_240x240.manifest +
|
||||
freeze('../..', manifest_240x240.manifest + manifest_user_apps.manifest +
|
||||
(
|
||||
'boot.py',
|
||||
'draw565.py',
|
||||
|
|
|
@ -5,9 +5,10 @@ import os, sys
|
|||
|
||||
sys.path.append(os.path.dirname(os.getcwd()))
|
||||
import manifest_240x240
|
||||
import manifest_user_apps
|
||||
|
||||
freeze('.', 'watch.py', opt=3)
|
||||
freeze('../..', manifest_240x240.manifest +
|
||||
freeze('../..', manifest_240x240.manifest + manifest_user_apps.manifest +
|
||||
(
|
||||
'boot.py',
|
||||
'draw565.py',
|
||||
|
|
|
@ -2,23 +2,29 @@ import glob
|
|||
import importlib
|
||||
import inspect
|
||||
import pytest
|
||||
import pprint
|
||||
import json
|
||||
|
||||
def discover_app_constructors():
|
||||
apps = []
|
||||
appClasses = []
|
||||
|
||||
globs_system = glob.glob('wasp/apps/*.py')
|
||||
globs_system = glob.glob('wasp/apps/system/*.py')
|
||||
names_system = [ g[5:-3].replace('/', '.') for g in globs_system ]
|
||||
globs_user = glob.glob('apps/*.py')
|
||||
names_user = [ g[:-3].replace('/', '.') for g in globs_user ]
|
||||
modules = [ importlib.import_module(n) for n in names_system + names_user ]
|
||||
globs_watchface = glob.glob('watch_faces/*.py')
|
||||
names_watchface = [ g[:-3].replace('/', '.') for g in globs_watchface ]
|
||||
modules = [ importlib.import_module(n) for n in names_system + names_user + names_watchface ]
|
||||
|
||||
for m in modules:
|
||||
for sym in m.__dict__.keys():
|
||||
if len(sym) > 3 and sym[-3:] == 'App':
|
||||
if len(sym) > 3 and sym[-3:] == 'App' and not sym in appClasses:
|
||||
constructor = m.__dict__[sym]
|
||||
sig = inspect.signature(constructor)
|
||||
if len(sig.parameters) == 0:
|
||||
apps.append(constructor)
|
||||
appClasses.append(sym)
|
||||
|
||||
return apps
|
||||
|
||||
|
|