1
0
Fork 0

Wasp A La carte

Configure wasp using a central toml file

Signed-off-by: Adam Blair <adampblair@protonmail.com>
This commit is contained in:
Adam Blair 2023-03-06 18:02:07 -07:00 committed by Daniel Thompson
parent b84276b456
commit e494eab608
111 changed files with 474 additions and 277 deletions

View file

@ -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
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
"""

View file

@ -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
"""

View file

@ -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

View file

@ -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
"""

View file

@ -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()

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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
"""

View file

@ -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
"""

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -6,7 +6,7 @@
A combined stopwatch and step counter.
.. figure:: res/SportsApp.png
.. figure:: res/screenshots/SportsApp.png
:width: 179
"""
import wasp

View file

@ -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

View file

@ -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."""

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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'))

View file

@ -1 +1 @@
../wasp/apps/hello.py
../apps/hello.py

View file

@ -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
----------------

View file

Before

Width:  |  Height:  |  Size: 8 KiB

After

Width:  |  Height:  |  Size: 8 KiB

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 568 B

View file

Before

Width:  |  Height:  |  Size: 750 B

After

Width:  |  Height:  |  Size: 750 B

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 396 B

After

Width:  |  Height:  |  Size: 396 B

View file

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View file

Before

Width:  |  Height:  |  Size: 695 B

After

Width:  |  Height:  |  Size: 695 B

View file

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 5 KiB

View file

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 563 B

View file

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View file

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 392 B

View file

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View file

Before

Width:  |  Height:  |  Size: 915 B

After

Width:  |  Height:  |  Size: 915 B

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 688 B

View file

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

View file

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View file

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View file

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View 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')

View file

@ -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
View 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'

View file

@ -4,7 +4,7 @@
"""Application launcher
~~~~~~~~~~~~~~~~~~~~~~~
.. figure:: res/LauncherApp.png
.. figure:: res/screenshots/LauncherApp.png
:width: 179
"""

View file

@ -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::

View file

@ -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

View file

@ -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.

View file

@ -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',

View file

@ -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',
)

View file

@ -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',

View file

@ -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',

View file

@ -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

Some files were not shown because too many files have changed in this diff Show more