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: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y python3-sphinx python3-cryptography python3-cbor graphviz
|
sudo apt-get install -y python3-sphinx python3-cryptography python3-cbor graphviz
|
||||||
sudo pip3 install recommonmark
|
sudo pip3 install recommonmark tomli
|
||||||
|
|
||||||
- name: Update submodules
|
- name: Update submodules
|
||||||
id: update-submodules
|
id: update-submodules
|
||||||
|
|
3
.gitignore
vendored
|
@ -9,5 +9,8 @@ cscope.out
|
||||||
docs/build
|
docs/build
|
||||||
attic/
|
attic/
|
||||||
wasp/boards/*/watch.py
|
wasp/boards/*/watch.py
|
||||||
|
wasp/boards/manifest_user_apps.py
|
||||||
|
wasp/apps/user
|
||||||
|
wasp/appregistry.py
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
|
|
23
Makefile
|
@ -23,7 +23,10 @@ clean :
|
||||||
reloader/build-$(BOARD) reloader/src/boards/$(BOARD)/bootloader.h \
|
reloader/build-$(BOARD) reloader/src/boards/$(BOARD)/bootloader.h \
|
||||||
micropython/mpy-cross/build \
|
micropython/mpy-cross/build \
|
||||||
micropython/ports/nrf/build-$(BOARD)-s132 \
|
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
|
# Avoid a recursive update... it grabs far too much
|
||||||
submodules :
|
submodules :
|
||||||
|
@ -61,7 +64,7 @@ wasp/boards/$(BOARD_SAFE)/watch.py : wasp/boards/$(BOARD_SAFE)/watch.py.in
|
||||||
micropython/mpy-cross/mpy-cross:
|
micropython/mpy-cross/mpy-cross:
|
||||||
$(MAKE) -C micropython/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
|
$(RM) micropython/ports/nrf/build-$(BOARD)-s132/frozen_content.c
|
||||||
$(MAKE) -C micropython/ports/nrf \
|
$(MAKE) -C micropython/ports/nrf \
|
||||||
BOARD=$(BOARD) SD=s132 \
|
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 \
|
--application micropython/ports/nrf/build-$(BOARD)-s132/firmware.hex \
|
||||||
build-$(BOARD)/micropython.zip
|
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):
|
build-$(BOARD_SAFE):
|
||||||
mkdir -p build-$(BOARD)
|
mkdir -p build-$(BOARD)
|
||||||
|
|
||||||
|
@ -98,12 +109,12 @@ APPS_MPY=$(APPS_PY:%.py=%.mpy)
|
||||||
.PHONY: apps
|
.PHONY: apps
|
||||||
apps: $(APPS_MPY)
|
apps: $(APPS_MPY)
|
||||||
|
|
||||||
docs:
|
docs: wasp/boards/manifest_user_apps.py
|
||||||
$(RM) -rf docs/build/html/*
|
$(RM) -rf docs/build/html/*
|
||||||
$(MAKE) -C docs html
|
$(MAKE) -C docs html
|
||||||
touch docs/build/html/.nojekyll
|
touch docs/build/html/.nojekyll
|
||||||
|
|
||||||
sim:
|
sim: wasp/boards/manifest_user_apps.py
|
||||||
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp \
|
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp \
|
||||||
$(PYTHON) -i wasp/boards/simulator/main.py
|
$(PYTHON) -i wasp/boards/simulator/main.py
|
||||||
|
|
||||||
|
@ -111,8 +122,8 @@ ifeq ("$(origin K)", "command line")
|
||||||
PYTEST_RESTRICT = -k '$(K)'
|
PYTEST_RESTRICT = -k '$(K)'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
check:
|
check: wasp/boards/manifest_user_apps.py
|
||||||
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp \
|
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=.:wasp/boards/simulator:wasp:wasp/apps/system \
|
||||||
$(PYTEST) -v -W ignore $(PYTEST_RESTRICT) wasp/boards/simulator
|
$(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
|
Screenshots
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -134,138 +140,149 @@ PineTime:
|
||||||
:alt: wasp-os digital clock app running on PineTime
|
:alt: wasp-os digital clock app running on PineTime
|
||||||
:width: 233
|
:width: 233
|
||||||
|
|
||||||
Screenshots of the built in applications running on the wasp-os
|
Screenshots of the available applications running on the wasp-os
|
||||||
simulator:
|
simulator:
|
||||||
|
|
||||||
.. image:: res/Bootloader.png
|
.. image:: res/Bootloader.png
|
||||||
:alt: Bootloader splash screen overlaid on the simulator watch art
|
:alt: Bootloader splash screen overlaid on the simulator watch art
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/ClockApp.png
|
Watch faces:
|
||||||
|
|
||||||
|
.. image:: res/screenshots/ClockApp.png
|
||||||
:alt: Digital clock application running on the wasp-os simulator
|
:alt: Digital clock application running on the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/DemoApp.png
|
.. image:: res/screenshots/WeekClockApp.png
|
||||||
:alt: Simple always-on demo for showing off wasp-os at conferences and shows
|
:alt: Digital clock application with week day running on the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/DisaBLEApp.png
|
.. image:: res/screenshots/ChronoApp.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
|
|
||||||
:alt: Analogue clock application running in the wasp-os simulator
|
:alt: Analogue clock application running in the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/DualApp.png
|
.. image:: res/screenshots/DualClockApp.png
|
||||||
:alt: An other clock application running in the wasp-os simulator
|
:alt: An other clock application running in the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/FiboApp.png
|
.. image:: res/screenshots/FibonacciClockApp.png
|
||||||
:alt: Fibonacci clock application running in the wasp-os simulator
|
:alt: Fibonacci clock application running in the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/HaikuApp.png
|
.. image:: res/screenshots/WordClockApp.png
|
||||||
:alt: Haiku application running in the wasp-os simulator
|
:alt: Shows a time as words in the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/LifeApp.png
|
Games:
|
||||||
:alt: Game of Life running in the wasp-os simulator
|
|
||||||
:width: 179
|
|
||||||
|
|
||||||
.. image:: res/AlarmApp.png
|
.. image:: res/screenshots/Play2048App.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
|
|
||||||
:alt: Let's play the 2048 game (in the wasp-os simulator)
|
:alt: Let's play the 2048 game (in the wasp-os simulator)
|
||||||
:width: 179
|
: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
|
:alt: Snake Game running in the wasp-os simulator
|
||||||
:width: 179
|
: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
|
:alt: Countdown timer application running in the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/WeatherApp.png
|
System apps:
|
||||||
:alt: Weather application running in the wasp-os simulator
|
|
||||||
|
.. image:: res/screenshots/DisaBLEApp.png
|
||||||
|
:alt: Small application for disabling bluetooth to save power and enhance security
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/WeekClkApp.png
|
.. image:: res/screenshots/LauncherApp.png
|
||||||
:alt: Digital clock application, including the week day
|
:alt: Application launcher running on the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/WordClkApp.png
|
.. image:: res/screenshots/SettingsApp.png
|
||||||
:alt: Shows a time as words in the wasp-os simulator
|
:alt: Settings application running on the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. image:: res/LevelApp.png
|
.. image:: res/screenshots/SoftwareApp.png
|
||||||
:alt: Shows a time as words in the wasp-os simulator
|
:alt: Software selection app running on the wasp-os simulator
|
||||||
:width: 179
|
: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
|
:alt: Flash the relatively powerful HRS LED repeatedly
|
||||||
:width: 179
|
: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
|
:alt: Find your phone by causing it to ring
|
||||||
:width: 179
|
: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.
|
An application to set a vibration alarm. All settings can be accessed from the Watch UI.
|
||||||
Press the button to turn off ringing alarms.
|
Press the button to turn off ringing alarms.
|
||||||
|
|
||||||
.. figure:: res/AlarmApp.png
|
.. figure:: res/screenshots/AlarmApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
Screenshot of the Alarm Application
|
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,
|
With BLE and/or step counter disabled and blinking frequency set to the minimum,
|
||||||
the watch's battery will last for many days.
|
the watch's battery will last for many days.
|
||||||
|
|
||||||
.. figure:: res/BeaconApp.png
|
.. figure:: res/screenshots/BeaconApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
This is a simple calculator app that uses the build-in eval() function to
|
This is a simple calculator app that uses the build-in eval() function to
|
||||||
compute the solution.
|
compute the solution.
|
||||||
|
|
||||||
.. figure:: res/CalcApp.png
|
.. figure:: res/screenshots/CalculatorApp.png
|
||||||
:width: 179
|
: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
|
and swaps between the logos every 5 images (so if you change
|
||||||
anything make sure len(colors) is not a multiple of 5).
|
anything make sure len(colors) is not a multiple of 5).
|
||||||
|
|
||||||
.. figure:: res/DemoApp.png
|
.. figure:: res/screenshots/DemoApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
The demo also includes code to keep the devie awake making it
|
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
|
Unfortunately, re-enabling bluetooth normally has some issues, so as a
|
||||||
workaround the "enable" button restarts the watch.
|
workaround the "enable" button restarts the watch.
|
||||||
|
|
||||||
.. figure:: res/DisaBLEApp.png
|
.. figure:: res/screenshots/DisaBLEApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
A tool to select a suitable watch face.
|
A tool to select a suitable watch face.
|
||||||
|
|
||||||
.. figure:: res/FacesApp.png
|
.. figure:: res/screenshots/FacesApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
The app is intended to be enabled by default and has, therefore, been carefully
|
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 wasp
|
||||||
import icons
|
import icons
|
||||||
|
import appregistry
|
||||||
|
|
||||||
class FacesApp():
|
class FacesApp():
|
||||||
"""Choose a default watch face."""
|
"""Choose a default watch face."""
|
||||||
|
@ -23,12 +24,8 @@ class FacesApp():
|
||||||
def foreground(self):
|
def foreground(self):
|
||||||
"""Activate the application."""
|
"""Activate the application."""
|
||||||
choices = []
|
choices = []
|
||||||
choices.append(('clock', 'Clock'))
|
for face in appregistry.faces_list:
|
||||||
choices.append(('week_clock', 'WeekClock'))
|
choices.append(face)
|
||||||
choices.append(('chrono', 'Chrono'))
|
|
||||||
choices.append(('dual_clock', 'DualClock'))
|
|
||||||
choices.append(('fibonacci_clock', 'FibonacciClock'))
|
|
||||||
choices.append(('word_clock', 'WordClock'))
|
|
||||||
|
|
||||||
self.choices = choices
|
self.choices = choices
|
||||||
self.choice = 0
|
self.choice = 0
|
||||||
|
@ -68,6 +65,6 @@ class FacesApp():
|
||||||
"""Draw the display from scratch."""
|
"""Draw the display from scratch."""
|
||||||
wasp.watch.drawable.fill()
|
wasp.watch.drawable.fill()
|
||||||
(module, label) = self.choices[self.choice]
|
(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()
|
wasp.system.quick_ring[0].preview()
|
||||||
self.si.draw()
|
self.si.draw()
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
Shows a bright screen that you can tap to change brightness or switch to redlight.
|
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
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import wasp
|
||||||
import icons
|
import icons
|
||||||
|
|
||||||
|
|
||||||
class TorchApp(object):
|
class FlashlightApp(object):
|
||||||
"""Trivial flashlight application."""
|
"""Trivial flashlight application."""
|
||||||
NAME = 'Torch'
|
NAME = 'Torch'
|
||||||
ICON = icons.torch
|
ICON = icons.torch
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
An application that shows images stored in the filesystem.
|
An application that shows images stored in the filesystem.
|
||||||
|
|
||||||
.. figure:: res/GalleryApp.png
|
.. figure:: res/screenshots/GalleryApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
The images have to be uploaded in the "gallery" directory.
|
The images have to be uploaded in the "gallery" directory.
|
||||||
|
@ -27,7 +27,7 @@ And to upload:
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
import icons
|
import icons
|
||||||
from apps.pager import PagerApp
|
from apps.system.pager import PagerApp
|
||||||
|
|
||||||
class GalleryApp():
|
class GalleryApp():
|
||||||
NAME = 'Gallery'
|
NAME = 'Gallery'
|
|
@ -6,7 +6,7 @@
|
||||||
The Game of Life is a "no player game" played on a two dimensional grid
|
The Game of Life is a "no player game" played on a two dimensional grid
|
||||||
where the rules interact to make interesting patterns.
|
where the rules interact to make interesting patterns.
|
||||||
|
|
||||||
.. figure:: res/LifeApp.png
|
.. figure:: res/screenshots/GameOfLifeApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
Screenshot of the Game of Life application
|
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.
|
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
|
:width: 179
|
||||||
|
|
||||||
If there is a file called haiku.txt in the flash filesystem then this app
|
If there is a file called haiku.txt in the flash filesystem then this app
|
||||||
|
@ -22,7 +22,7 @@ import icons
|
||||||
import io
|
import io
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from apps.pager import PagerApp
|
from apps.system.pager import PagerApp
|
||||||
|
|
||||||
class HaikuApp(PagerApp):
|
class HaikuApp(PagerApp):
|
||||||
NAME = 'Haiku'
|
NAME = 'Haiku'
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
A graphing heart rate monitor using a PPG sensor.
|
A graphing heart rate monitor using a PPG sensor.
|
||||||
|
|
||||||
.. figure:: res/HeartApp.png
|
.. figure:: res/screenshots/HeartApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
This program also implements some (entirely optional) debug features to
|
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"
|
To calibrate, place the watch on a flat surface, then tap the "Calibrate"
|
||||||
button while ensuring the watch is stationary.
|
button while ensuring the watch is stationary.
|
||||||
|
|
||||||
.. figure:: res/LevelApp.png
|
.. figure:: res/screenshots/LevelApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -13,7 +13,7 @@ lines will be deleted.
|
||||||
There is a preview of the next letter at the bottom of the screen.
|
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
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"""Music Player for GadgetBridge
|
"""Music Player for GadgetBridge
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. figure:: res/MusicApp.png
|
.. figure:: res/screenshots/MusicPlayerApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
Screenshot of the Music Player application
|
Screenshot of the Music Player application
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
An application to find a phone connected via Gadgetbridge.
|
An application to find a phone connected via Gadgetbridge.
|
||||||
|
|
||||||
.. figure:: res/FinderApp.png
|
.. figure:: res/screenshots/PhoneFinderApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
Screenshot of the Phone Finder Application
|
Screenshot of the Phone Finder Application
|
|
@ -6,7 +6,7 @@
|
||||||
A popular sliding block puzzle game in which tiles are combined to make the
|
A popular sliding block puzzle game in which tiles are combined to make the
|
||||||
number 2048.
|
number 2048.
|
||||||
|
|
||||||
.. figure:: res/2048App.png
|
.. figure:: res/screenshots/Play2048App.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
Screenshot of the 2048 game application
|
Screenshot of the 2048 game application
|
|
@ -15,4 +15,4 @@ class ReadMeApp():
|
||||||
draw = wasp.watch.drawable
|
draw = wasp.watch.drawable
|
||||||
draw.fill()
|
draw.fill()
|
||||||
draw.string('Autoloaded from', 0, 96, width=240)
|
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.
|
This is a classic arcade game called snake.
|
||||||
|
|
||||||
.. figure:: res/SnakeApp.png
|
.. figure:: res/screenshots/SnakeApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
Screenshot of the snake game
|
Screenshot of the snake game
|
||||||
|
@ -46,7 +46,7 @@ snake_icon = (
|
||||||
import wasp, time
|
import wasp, time
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
class SnakeGameApp():
|
class SnakeApp():
|
||||||
NAME = 'Snake'
|
NAME = 'Snake'
|
||||||
ICON = snake_icon
|
ICON = snake_icon
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
A combined stopwatch and step counter.
|
A combined stopwatch and step counter.
|
||||||
|
|
||||||
.. figure:: res/SportsApp.png
|
.. figure:: res/screenshots/SportsApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
"""
|
"""
|
||||||
import wasp
|
import wasp
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
Simple stop/start watch with support for split times.
|
Simple stop/start watch with support for split times.
|
||||||
|
|
||||||
.. figure:: res/StopclockApp.png
|
.. figure:: res/screenshots/StopwatchApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
"""
|
"""
|
||||||
import wasp
|
import wasp
|
|
@ -7,7 +7,7 @@
|
||||||
A collection of tests used to develop features or provide useful metrics such
|
A collection of tests used to develop features or provide useful metrics such
|
||||||
as performance indicators or memory usage.
|
as performance indicators or memory usage.
|
||||||
|
|
||||||
.. figure:: res/SelfTestApp.png
|
.. figure:: res/screenshots/TestApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import fonts
|
||||||
import icons
|
import icons
|
||||||
import machine
|
import machine
|
||||||
|
|
||||||
from apps.pager import PagerApp
|
from apps.system.pager import PagerApp
|
||||||
|
|
||||||
class TestApp():
|
class TestApp():
|
||||||
"""Self test application."""
|
"""Self test application."""
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
An application to set a vibration in a specified amount of time. Like a kitchen timer.
|
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
|
:width: 179
|
||||||
|
|
||||||
Screenshot of the Timer Application
|
Screenshot of the Timer Application
|
|
@ -5,7 +5,7 @@
|
||||||
"""Weather for GadgetBridge and wasp-os companion
|
"""Weather for GadgetBridge and wasp-os companion
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. figure:: res/WeatherApp.png
|
.. figure:: res/screenshots/WeatherApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
Screenshot of the Weather application
|
Screenshot of the Weather application
|
|
@ -203,6 +203,31 @@ a little time into learning the best practices when running
|
||||||
.. _MicroPython: https://micropython.org/
|
.. _MicroPython: https://micropython.org/
|
||||||
__ http://docs.micropython.org/en/latest/reference/constrained.html
|
__ 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
|
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
|
from RAM. Additionally the code is pre-compiled, which also means we don't
|
||||||
need any RAM budget to run the compiler.
|
need any RAM budget to run the compiler.
|
||||||
|
|
||||||
Freezing your application requires you to modify the ``manifest.py``
|
To freeze your app into the wasp-os binary add it to the wasp.toml file.
|
||||||
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``
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -442,25 +462,13 @@ To delete a file from the device:
|
||||||
>>>os.remove("apps/myapp.mpy")
|
>>>os.remove("apps/myapp.mpy")
|
||||||
>>>del os
|
>>>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
|
Application entry points
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
Applications provide entry points for the system manager to use to notify
|
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.
|
the application of a change in system state or an user interface event.
|
||||||
|
|
||||||
.. automodule:: apps.template
|
.. automodule:: template
|
||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
:special-members:
|
:special-members:
|
||||||
|
|
|
@ -9,77 +9,77 @@ Application Library
|
||||||
Watch faces
|
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
|
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.system.pager
|
||||||
|
|
||||||
.. automodule:: apps.software
|
|
||||||
|
|
||||||
.. automodule:: apps.pager
|
|
||||||
|
|
||||||
Applications
|
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
|
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
|
import sys
|
||||||
sys.path.insert(0, os.path.abspath('../wasp'))
|
sys.path.insert(0, os.path.abspath('../wasp'))
|
||||||
sys.path.insert(0, os.path.abspath('../apps'))
|
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'))
|
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 \
|
wget git build-essential libsdl2-2.0-0 python3-click python3-gi \
|
||||||
python3-numpy python3-pexpect python3-pil python3-pip python3-pydbus \
|
python3-numpy python3-pexpect python3-pil python3-pip python3-pydbus \
|
||||||
python3-serial unzip
|
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
|
Additionally if you wish to regenerate the documentation you will require
|
||||||
a complete sphinx toolchain:
|
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.
|
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
|
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 \
|
libcairo2-dev python3-serial unzip python3-sphinx graphviz \
|
||||||
python3-recommonmark python3-pytest \
|
python3-recommonmark python3-pytest \
|
||||||
; \
|
; \
|
||||||
pip3 install cbor pysdl2 pygobject cryptography;
|
pip3 install cbor pysdl2 pygobject cryptography tomli;
|
||||||
|
|
||||||
RUN set -xe; \
|
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
|
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
|
"""Application launcher
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. figure:: res/LauncherApp.png
|
.. figure:: res/screenshots/LauncherApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
Allows a very small set of user preferences (including the date and
|
Allows a very small set of user preferences (including the date and
|
||||||
time) to be set on the device itself.
|
time) to be set on the device itself.
|
||||||
|
|
||||||
.. figure:: res/SettingsApp.png
|
.. figure:: res/screenshots/SettingsApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
.. note::
|
.. note::
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
A tool to enable/disable applications.
|
A tool to enable/disable applications.
|
||||||
|
|
||||||
.. figure:: res/SoftwareApp.png
|
.. figure:: res/screenshots/SoftwareApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
Most applications are disabled by default at boot in order to conserve
|
Most applications are disabled by default at boot in order to conserve
|
||||||
|
@ -18,6 +18,7 @@ import wasp
|
||||||
import icons
|
import icons
|
||||||
import os
|
import os
|
||||||
import gc
|
import gc
|
||||||
|
import appregistry
|
||||||
|
|
||||||
|
|
||||||
class SoftwareApp():
|
class SoftwareApp():
|
||||||
|
@ -39,19 +40,8 @@ class SoftwareApp():
|
||||||
|
|
||||||
y = 0
|
y = 0
|
||||||
db = []
|
db = []
|
||||||
db.append(('alarm', factory('Alarm')))
|
for app in appregistry.software_list:
|
||||||
db.append(('calc', factory('Calculator')))
|
db.append((app[0], factory(app[1])))
|
||||||
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')))
|
|
||||||
|
|
||||||
# Handle user-loaded applications
|
# Handle user-loaded applications
|
||||||
try:
|
try:
|
||||||
|
@ -62,7 +52,14 @@ class SoftwareApp():
|
||||||
if app.endswith('.mpy'):
|
if app.endswith('.mpy'):
|
||||||
name = app[:-4]
|
name = app[:-4]
|
||||||
if name:
|
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:
|
except OSError:
|
||||||
# apps does not exist...
|
# apps does not exist...
|
||||||
pass
|
pass
|
||||||
|
@ -117,7 +114,7 @@ class SoftwareApp():
|
||||||
label = checkbox.label.replace(' ', '')
|
label = checkbox.label.replace(' ', '')
|
||||||
if checkbox.state:
|
if checkbox.state:
|
||||||
gc.collect()
|
gc.collect()
|
||||||
wasp.system.register('apps.{}.{}App'.format(module, label))
|
wasp.system.register('{}.{}App'.format(module, label))
|
||||||
else:
|
else:
|
||||||
for app in wasp.system.launcher_ring:
|
for app in wasp.system.launcher_ring:
|
||||||
if type(app).__name__.startswith(label):
|
if type(app).__name__.startswith(label):
|
||||||
|
@ -131,3 +128,10 @@ class SoftwareApp():
|
||||||
self.si.draw()
|
self.si.draw()
|
||||||
for _, checkbox in self.get_page():
|
for _, checkbox in self.get_page():
|
||||||
checkbox.draw()
|
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.
|
Provide a daily step count.
|
||||||
|
|
||||||
.. figure:: res/StepsApp.png
|
.. figure:: res/screenshots/StepCounterApp.png
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
The step counts automatically reset at midnight.
|
The step counts automatically reset at midnight.
|
|
@ -5,9 +5,10 @@ import os, sys
|
||||||
|
|
||||||
sys.path.append(os.path.dirname(os.getcwd()))
|
sys.path.append(os.path.dirname(os.getcwd()))
|
||||||
import manifest_240x240
|
import manifest_240x240
|
||||||
|
import manifest_user_apps
|
||||||
|
|
||||||
freeze('.', 'watch.py', opt=3)
|
freeze('.', 'watch.py', opt=3)
|
||||||
freeze('../..', manifest_240x240.manifest +
|
freeze('../..', manifest_240x240.manifest + manifest_user_apps.manifest +
|
||||||
(
|
(
|
||||||
'boot.py',
|
'boot.py',
|
||||||
'draw565.py',
|
'draw565.py',
|
||||||
|
|
|
@ -3,33 +3,11 @@
|
||||||
"""Shared manifest for applications that work well on a 240x240 display."""
|
"""Shared manifest for applications that work well on a 240x240 display."""
|
||||||
|
|
||||||
manifest = (
|
manifest = (
|
||||||
'apps/alarm.py',
|
'apps/system/launcher.py',
|
||||||
'apps/calc.py',
|
'apps/system/pager.py',
|
||||||
'apps/clock.py',
|
'apps/system/software.py',
|
||||||
'apps/chrono.py',
|
'apps/system/settings.py',
|
||||||
'apps/disaBLE.py',
|
'apps/system/step_counter.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',
|
|
||||||
'fonts/__init__.py',
|
'fonts/__init__.py',
|
||||||
'fonts/clock.py',
|
'fonts/clock.py',
|
||||||
'fonts/clock_dual.py',
|
'fonts/clock_dual.py',
|
||||||
|
@ -38,6 +16,7 @@ manifest = (
|
||||||
'fonts/sans28.py',
|
'fonts/sans28.py',
|
||||||
'fonts/sans36.py',
|
'fonts/sans36.py',
|
||||||
'icons.py',
|
'icons.py',
|
||||||
'steplogger.py',
|
|
||||||
'widgets.py',
|
'widgets.py',
|
||||||
|
'steplogger.py',
|
||||||
|
'appregistry.py',
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,9 +5,10 @@ import os, sys
|
||||||
|
|
||||||
sys.path.append(os.path.dirname(os.getcwd()))
|
sys.path.append(os.path.dirname(os.getcwd()))
|
||||||
import manifest_240x240
|
import manifest_240x240
|
||||||
|
import manifest_user_apps
|
||||||
|
|
||||||
freeze('.', 'watch.py', opt=3)
|
freeze('.', 'watch.py', opt=3)
|
||||||
freeze('../..', manifest_240x240.manifest +
|
freeze('../..', manifest_240x240.manifest + manifest_user_apps.manifest +
|
||||||
(
|
(
|
||||||
'boot.py',
|
'boot.py',
|
||||||
'draw565.py',
|
'draw565.py',
|
||||||
|
|
|
@ -5,9 +5,10 @@ import os, sys
|
||||||
|
|
||||||
sys.path.append(os.path.dirname(os.getcwd()))
|
sys.path.append(os.path.dirname(os.getcwd()))
|
||||||
import manifest_240x240
|
import manifest_240x240
|
||||||
|
import manifest_user_apps
|
||||||
|
|
||||||
freeze('.', 'watch.py', opt=3)
|
freeze('.', 'watch.py', opt=3)
|
||||||
freeze('../..', manifest_240x240.manifest +
|
freeze('../..', manifest_240x240.manifest + manifest_user_apps.manifest +
|
||||||
(
|
(
|
||||||
'boot.py',
|
'boot.py',
|
||||||
'draw565.py',
|
'draw565.py',
|
||||||
|
|
|
@ -2,23 +2,29 @@ import glob
|
||||||
import importlib
|
import importlib
|
||||||
import inspect
|
import inspect
|
||||||
import pytest
|
import pytest
|
||||||
|
import pprint
|
||||||
|
import json
|
||||||
|
|
||||||
def discover_app_constructors():
|
def discover_app_constructors():
|
||||||
apps = []
|
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 ]
|
names_system = [ g[5:-3].replace('/', '.') for g in globs_system ]
|
||||||
globs_user = glob.glob('apps/*.py')
|
globs_user = glob.glob('apps/*.py')
|
||||||
names_user = [ g[:-3].replace('/', '.') for g in globs_user ]
|
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 m in modules:
|
||||||
for sym in m.__dict__.keys():
|
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]
|
constructor = m.__dict__[sym]
|
||||||
sig = inspect.signature(constructor)
|
sig = inspect.signature(constructor)
|
||||||
if len(sig.parameters) == 0:
|
if len(sig.parameters) == 0:
|
||||||
apps.append(constructor)
|
apps.append(constructor)
|
||||||
|
appClasses.append(sym)
|
||||||
|
|
||||||
return apps
|
return apps
|
||||||
|
|
||||||
|
|