From cc075cbfbad8fd12e347770b8b3ef3855424ddac Mon Sep 17 00:00:00 2001 From: Naomi Pentrel <5212232+npentrel@users.noreply.github.com> Date: Sat, 18 May 2024 21:38:16 +0200 Subject: [PATCH 1/2] Add eventbus docs --- docs/index.md | 4 +- docs/tildagon-apps/development.md | 14 +-- docs/tildagon-apps/index.md | 9 +- .../widgets-and-hardware/badge-hardware.md | 32 +++---- .../widgets-and-hardware/eventbus.md | 86 +++++++++++++++++++ .../widgets-and-hardware/ui-elements.md | 2 +- 6 files changed, 116 insertions(+), 31 deletions(-) create mode 100644 docs/tildagon-apps/widgets-and-hardware/eventbus.md diff --git a/docs/index.md b/docs/index.md index 052e2e6..48836b8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -74,8 +74,8 @@ Hexpansions are accessories that plug into the badge's expansion connectors. Alm For more information, see: -- [Hexpansion hardware developer guide](hexpansions/index.md). -- [Technical documentation, pinout, and paper and PCB templates][badge-2024-hardware]. +- [Hexpansion hardware developer guide](hexpansions/index.md) +- [Technical documentation, pinout, and paper and PCB templates][badge-2024-hardware] ## A reusable platform with an interchangeable part diff --git a/docs/tildagon-apps/development.md b/docs/tildagon-apps/development.md index 91139d0..3da4c63 100644 --- a/docs/tildagon-apps/development.md +++ b/docs/tildagon-apps/development.md @@ -38,10 +38,6 @@ To test the app, go to the instructions for [simulating your app](./simulate.md) ## The `App` class -!!! quote "Quote by Tom Catshoek" - - Apps are just objects with `update()` and `draw()` methods. And optionally async `background_update()`. - To make a badge app in Python, you subclass the [`App` class](https://github.com/emfcamp/badge-2024-software/blob/main/modules/app.py). When you subclass the `App` class to create your app, you need to _overwrite_ some of its methods to make it do something useful. ??? note "Wondering what a subclass is or what _overwrite_ means? Expand this!" @@ -124,10 +120,16 @@ To make a badge app in Python, you subclass the [`App` class](https://github.com ### Usage -This section walks you through the most [common usage](#common-usage) first which is enough to build many apps. Afterwards, you'll learn how to [update state while an app is minimized](#update-app-state-while-minimised), how to [draw multiple objects](#draw-multiple-objects), and how to [add asynchronous functionality](#asynchronous-functionality). +This section walks you through the most [common usage](#common-usage) first which is enough to build many apps. + +Afterwards, you'll learn how to [update state while an app is minimized](#update-app-state-while-minimised), how to [draw multiple objects](#draw-multiple-objects), and how to [add asynchronous functionality](#asynchronous-functionality). #### Common Usage +!!! important "" + + You can think of the apps on your badge as objects with `update()` and `draw()` methods. + 1. To be able to subclass the `App` class, import the `app` package at the top of your Python file: ```python @@ -361,7 +363,7 @@ By default, the `background_task()` method is automatically run by the scheduler | Property | Type | Description | | -------- | ---- | ----------- | -| `overlays` | Any object with a draw method. | Your app's list of overlays. | +| `overlays` | An array of objects that each have a draw method. | Your app's list of overlays. | ### Methods diff --git a/docs/tildagon-apps/index.md b/docs/tildagon-apps/index.md index 8b4f937..355eda2 100644 --- a/docs/tildagon-apps/index.md +++ b/docs/tildagon-apps/index.md @@ -4,16 +4,11 @@ Tildagon OS is the name for the firmware that runs on the badge. It is based on ## App Development -!!! warning - - This is a work in progress. The badge firmware is not yet ready for general use. - -You can write apps for the badge in MicroPython. You can use most MicroPython libraries, and for some functionality we provide -abstractions - for example, you can access all buttons through `events.input`. +You can write apps for the badge in MicroPython. You can use most MicroPython libraries, and for some functionality we provide abstractions - for example, you can access all buttons through [`events.input`](./widgets-and-hardware/badge-hardware.md#buttons). While developing, you can use your hardware badge for testing your code, or you can use the [simulator]. -For more info check out our [Getting Started guide][app-getting-started]. +For more info check out [Write a Tildagon OS App][app-getting-started]. ## Publishing your app diff --git a/docs/tildagon-apps/widgets-and-hardware/badge-hardware.md b/docs/tildagon-apps/widgets-and-hardware/badge-hardware.md index 05ad151..5004304 100644 --- a/docs/tildagon-apps/widgets-and-hardware/badge-hardware.md +++ b/docs/tildagon-apps/widgets-and-hardware/badge-hardware.md @@ -150,16 +150,31 @@ You can also use the `ButtonDownEvent` and the `ButtonUpEvent` directly with an ```python from events.input import Button, BUTTON_TYPES, ButtonDownEvent, ButtonUpEvent + from system.eventbus import eventbus ``` -2. Add an event handler in the `__init__` method of your app with the event (`ButtonDownEvent` or `ButtonUpEvent`) and a function that should be called when the event happens: +2. Add a method to handle the event: + + ```python + def _handle_buttondown(self, event: ButtonDownEvent): + if BUTTON_TYPES["CANCEL"] in event.button: + self._cleanup() + # perform other actions as needed + + if BUTTON_TYPES["CONFIRM"] in event.button: + self._cleanup() + # perform other actions as needed + ``` + +3. Add an event handler in the `__init__` method of your app with the event (`ButtonDownEvent` or `ButtonUpEvent`) and a function that should be called when the event happens. Depending on whether the event handler is a synchronoush or asynchronoush method call `on()` or `on_async`: ```python def __init__(self): eventbus.on(ButtonDownEvent, self._handle_buttondown, self.app) + # eventbus.on_async(ButtonDownEvent, self._handle_buttondown, self.app) ``` -3. Remove the event handler when the app is minimised or closed: +4. Remove the event handler when the app is minimised or closed: ```python def _cleanup(self): @@ -170,17 +185,4 @@ You can also use the `ButtonDownEvent` and the `ButtonUpEvent` directly with an Make sure you remove the event handler when the app is minimised or closed! -4. Add a function to handle the event: - - ```python - def _handle_buttondown(self, event: ButtonDownEvent): - if BUTTON_TYPES["CANCEL"] in event.button: - self._cleanup() - # perform other actions as needed - - if BUTTON_TYPES["CONFIRM"] in event.button: - self._cleanup() - # perform other actions as needed - ``` - You can see a more comprehensive example in [`dialog.py`](https://github.com/emfcamp/badge-2024-software/blob/main/modules/app_components/dialog.py). diff --git a/docs/tildagon-apps/widgets-and-hardware/eventbus.md b/docs/tildagon-apps/widgets-and-hardware/eventbus.md new file mode 100644 index 0000000..ef589e9 --- /dev/null +++ b/docs/tildagon-apps/widgets-and-hardware/eventbus.md @@ -0,0 +1,86 @@ +# Eventbus + +You can register your events and event handlers with the [`Eventbus`](https://github.com/emfcamp/badge-2024-software/blob/main/modules/system/eventbus.py) package: + +## Usage + +You can use your own events directly with an event handler that you register on the [`eventbus`](https://github.com/emfcamp/badge-2024-software/blob/main/modules/system/eventbus.py). + +1. Import the `system.eventbus` package: + + ```python + from system.eventbus import eventbus + ``` + +2. Define an event: + + ```python + class SpecialEvent: + def __init__(self): + pass + + def __str__(self): + return "special event" + ``` + +3. Define a synchronous or asynchronous method to be called when the event occurs: + + ```python + def handle_event(self, event): + # do something + ``` + + ```python + async def handle_event_async(self, event): + # do something + ``` + +4. Register your event handler, for example in the `__init__` method of your app with the event and the event handler. Depending on whether the event handler is a synchronous or asynchronous method call `on()` or `on_async()`: + + ```python + def __init__(self): + eventbus.on(SpecialEvent, self.handle_event, self.app) + ``` + + ```python + def __init__(self): + eventbus.on(SpecialEvent, self.handle_event_async, self.app) + ``` + +5. Add code to emit the event, for example in your app's `update()` method. Depending on whether the event handler is a synchronous or asynchronous method call `emit()` or `emit_async()`: + + ```python + def update(self, delta): + # If something happens + eventbus.emit(SpecialEvent()) + ``` + + ```python + def update(self, delta): + # If something happens + eventbus.emit_async(SpecialEvent()) + ``` + +6. Remove the event handler when the app is minimised or closed. + + ```python + eventbus.remove(SpecialEvent, self.handle_event, self.app) + ``` + + !!! caution + + Make sure you remove the event handler when the app is minimised or closed! + +You can see a more comprehensive example in [`dialog.py`](https://github.com/emfcamp/badge-2024-software/blob/main/modules/app_components/dialog.py) or [`pingpong_app.py`](https://github.com/emfcamp/badge-2024-software/blob/main/modules/firmware_apps/pingpong_app.py). + +## Methods + +You can use the following methods on the `eventbus`: + +| Method | Description | Arguments | Returns | +| ------ | ----------- | --------- | ------- | +| `on(event_type, event_handler, app)` | Register an event for an app alongside the synchronous handler to be called when the event fires. | | None | +| `on_async(event_type, event_handler, app)` | Register an event for an app alongside the asynchronous handler to be called when the event fires. | | None | +| `emit(event)` | Emit an event to the eventbus. The handler for the event must be synchronous. | `event` : The event, for example `ButtonDownEvent`. An `event` object must have the methods `__init__()` and `__str__()`. | None | +| `emit_async(event)` | Emit an event to the eventbus. The handler for the event must be asynchronous. | `event` : The event, for example `ButtonDownEvent`. An `event` object must have the methods `__init__()` and `__str__()`. | None | +| `remove(event_type, event_handler, app)` | Remove the event for an app from the eventbus. | | None | diff --git a/docs/tildagon-apps/widgets-and-hardware/ui-elements.md b/docs/tildagon-apps/widgets-and-hardware/ui-elements.md index 4a792fc..5dbfeab 100644 --- a/docs/tildagon-apps/widgets-and-hardware/ui-elements.md +++ b/docs/tildagon-apps/widgets-and-hardware/ui-elements.md @@ -358,7 +358,7 @@ The [`Tokens`](https://github.com/emfcamp/badge-2024-software/blob/main/modules/ | Method | Description | Arguments | Returns | | ------ | ----------- | --------- | ------- | | `clear_background(ctx)` | Clear the badge background. | `ctx`: context that let's you add graphics or texts. See [`ctx` library](../development.md#the-ctx-library). | None | -| `set_color(ctx, color)` | Set the color for the context. The color must be provided as a string from the following options: `pale_green`, `mid_green`, `dark_green`, `colors.yellow`, `colors.orange`, `colors.pink`, `colors.blue`, `ui_colors.background`, `ui_colors.label`. | - `ctx`: context that let's you add graphics or texts. See [`ctx` library](../development.md#the-ctx-library). | None | +| `set_color(ctx, color)` | Set the color for the context. | | None | From 051dcd6d5c5e9f7477521a2928be48fb07dc026f Mon Sep 17 00:00:00 2001 From: Naomi Pentrel <5212232+npentrel@users.noreply.github.com> Date: Sat, 18 May 2024 23:33:07 +0200 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: b0xcat <94014546+b0xcat@users.noreply.github.com> --- docs/tildagon-apps/widgets-and-hardware/eventbus.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tildagon-apps/widgets-and-hardware/eventbus.md b/docs/tildagon-apps/widgets-and-hardware/eventbus.md index ef589e9..7ce7397 100644 --- a/docs/tildagon-apps/widgets-and-hardware/eventbus.md +++ b/docs/tildagon-apps/widgets-and-hardware/eventbus.md @@ -44,7 +44,7 @@ You can use your own events directly with an event handler that you register on ```python def __init__(self): - eventbus.on(SpecialEvent, self.handle_event_async, self.app) + eventbus.on_async(SpecialEvent, self.handle_event_async, self.app) ``` 5. Add code to emit the event, for example in your app's `update()` method. Depending on whether the event handler is a synchronous or asynchronous method call `emit()` or `emit_async()`: @@ -56,9 +56,9 @@ You can use your own events directly with an event handler that you register on ``` ```python - def update(self, delta): + async def update(self, delta): # If something happens - eventbus.emit_async(SpecialEvent()) + await eventbus.emit_async(SpecialEvent()) ``` 6. Remove the event handler when the app is minimised or closed.