From 936020df580b0ea6f5885b9186fd95177e4dca74 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Sat, 6 Dec 2025 18:52:07 +0100 Subject: [PATCH] feat: Add and deploy frontend Signed-off-by: Matthias Blankertz --- .gitea/workflows/build.yaml | 4 +- software/boards/RPI_PICO_W/manifest.py | 2 + software/build.sh | 5 + software/frontend/index.html | 190 +++++++++++++++++++++++++ software/src/main.py | 1 + software/src/webserver.py | 15 +- 6 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 software/frontend/index.html diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 2a614db..61f51d0 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -11,8 +11,10 @@ jobs: uses: actions/checkout@v4 - name: Initialize submodules run: cd software && ./update-submodules.sh + - name: Prepare venv + run: python -m venv build-venv && source build-venv/bin/activate && pip install freezefs - name: Build - run: cd software && ./build.sh + run: source build-venv/bin/activate && cd software && ./build.sh - name: Upload firmware uses: actions/upload-artifact@v3 with: diff --git a/software/boards/RPI_PICO_W/manifest.py b/software/boards/RPI_PICO_W/manifest.py index f8cb12a..486963d 100644 --- a/software/boards/RPI_PICO_W/manifest.py +++ b/software/boards/RPI_PICO_W/manifest.py @@ -22,3 +22,5 @@ module("mp3player.py", "../../src") module("webserver.py", "../../src") package("utils", base_path="../../src") package("nfc", base_path="../../src") + +module("frozen_frontend.py", "../../build") diff --git a/software/build.sh b/software/build.sh index 4b215cc..3f96779 100755 --- a/software/build.sh +++ b/software/build.sh @@ -25,6 +25,11 @@ mkdir "$FS_STAGE_DIR"/fs trap 'rm -rf $FS_STAGE_DIR' EXIT tools/mklittlefs/mklittlefs -p 256 -s 868352 -c "$FS_STAGE_DIR"/fs "$FS_STAGE_DIR"/filesystem.bin +FRONTEND_STAGE_DIR=$(mktemp -d) +trap 'rm -rf $FRONTEND_STAGE_DIR' EXIT +gzip -c frontend/index.html > "$FRONTEND_STAGE_DIR"/index.html.gz +python -m freezefs "$FRONTEND_STAGE_DIR" build/frozen_frontend.py --target=/frontend + for hwconfig in boards/RPI_PICO_W/manifest-*.py; do hwconfig_base=$(basename "$hwconfig") hwname=${hwconfig_base##manifest-} diff --git a/software/frontend/index.html b/software/frontend/index.html new file mode 100644 index 0000000..b1c2283 --- /dev/null +++ b/software/frontend/index.html @@ -0,0 +1,190 @@ + + + + +Device Admin + + + + +

Device Admin

+ + + + +
+

Main Menu

+

Select a tool:

+ +
    +
  • + +
+
+ + +
+

Configuration Editor

+
Loading…
+ +
+ + + + + diff --git a/software/src/main.py b/software/src/main.py index 613ff97..09afe34 100644 --- a/software/src/main.py +++ b/software/src/main.py @@ -14,6 +14,7 @@ import ubinascii # Own modules import app from audiocore import AudioContext +import frozen_frontend # noqa: F401 from mfrc522 import MFRC522 from mp3player import MP3Player from nfc import Nfc diff --git a/software/src/webserver.py b/software/src/webserver.py index 95cacc5..841935c 100644 --- a/software/src/webserver.py +++ b/software/src/webserver.py @@ -5,7 +5,7 @@ Copyright (c) 2024-2025 Stefan Kratochwil import asyncio -from microdot import Microdot +from microdot import Microdot, send_file webapp = Microdot() server = None @@ -59,3 +59,16 @@ async def config_put(request): except ValueError as ex: return str(ex), 400 return '', 204 + + +@webapp.route('/index.html', methods=['GET']) +async def index_get(request): + return send_file('/frontend/index.html.gz', content_type='text/html', compressed='gzip') + + +@webapp.route('/static/') +async def static(request, path): + if '..' in path: + # directory traversal is not allowed + return 'Not found', 404 + return send_file('/frontend/static/' + path, max_age=86400)