From a7e58853bb7d86e8faf5234c7b75386cb9cc9e48 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Wed, 3 Dec 2025 20:12:29 +0100 Subject: [PATCH] feat: Add api/v1/config to get, put config Signed-off-by: Matthias Blankertz --- software/src/main.py | 2 +- software/src/utils/config.py | 20 +++++++++++++++++++- software/src/webserver.py | 20 ++++++++++++++++++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/software/src/main.py b/software/src/main.py index a02b9a1..62282ad 100644 --- a/software/src/main.py +++ b/software/src/main.py @@ -65,7 +65,7 @@ def run(): # Wifi with default config setup_wifi() - start_webserver() + start_webserver(config) # Setup MP3 player with SDContext(mosi=hwconfig.SD_DI, miso=hwconfig.SD_DO, sck=hwconfig.SD_SCK, ss=hwconfig.SD_CS, diff --git a/software/src/utils/config.py b/software/src/utils/config.py index 432c2b8..b0e0104 100644 --- a/software/src/utils/config.py +++ b/software/src/utils/config.py @@ -5,7 +5,7 @@ from errno import ENOENT import json import os try: - from typing import TYPE_CHECKING, Mapping + from typing import TYPE_CHECKING, Mapping, Any except ImportError: TYPE_CHECKING = False @@ -71,3 +71,21 @@ class Configuration: def get_button_map(self) -> Mapping[str, int | None]: return self._get('BUTTON_MAP') + + # For the web API + def get_config(self) -> Mapping[str, Any]: + return self.config + + def _validate(self, default, config, path=''): + for k in config.keys(): + if k not in default: + raise ValueError(f'Invalid config key {path}/{k}') + if isinstance(default[k], dict): + if not isinstance(config[k], dict): + raise ValueError(f'Invalid config: Value of {path}/{k} must be mapping') + self._validate(default[k], config[k], f'{path}/{k}') + + def set_config(self, config): + self._validate(self.DEFAULT_CONFIG, config) + self.config = config + self._save() diff --git a/software/src/webserver.py b/software/src/webserver.py index eeb2a95..6f1aaf6 100644 --- a/software/src/webserver.py +++ b/software/src/webserver.py @@ -9,11 +9,13 @@ from microdot import Microdot webapp = Microdot() server = None +config = None -def start_webserver(): - global server +def start_webserver(config_): + global server, config server = asyncio.create_task(webapp.start_server(port=80)) + config = config_ @webapp.route('/') @@ -39,3 +41,17 @@ async def filesystem_post(request): async def playlist_post(request): print(request) return {'success': False} + + +@webapp.route('/api/v1/config', methods=['GET']) +async def config_get(request): + return config.get_config() + + +@webapp.route('/api/v1/config', methods=['PUT']) +async def config_put(request): + try: + config.set_config(request.json) + except ValueError as ex: + return str(ex), 400 + return '', 204