From 524714148b0c9e4f405c6421bb39e078aa59ec38 Mon Sep 17 00:00:00 2001 From: Ronny Eia <3652665+eiaro@users.noreply.github.com> Date: Wed, 8 Jul 2026 19:54:25 +0200 Subject: [PATCH] Rebuild firmware scaffold for ESP32-C6/ESP-IDF, replacing NCS/Zephyr The product pivoted away from a Matter-first nRF54L15 device to an ESP32-C6/ESP-IDF/C++17 platform where behaviour is defined by a Blockly-generated Lua program instead of custom firmware (see the updated kvida meta-repo vision). Removes the west/NCS/Zephyr scaffold and replaces it with: - A pinned ESP-IDF v6.0.2 Docker build environment (Espressif's official image already bundles the toolchain, unlike NCS/west). - A layered component structure (drivers -> sensors -> profiles -> lua_runtime -> transport) matching the new architecture principles, with per-component READMEs describing responsibilities. - An A/B OTA + LittleFS partition table and a minimal main.cpp. Co-Authored-By: Claude Sonnet 5 --- .gitignore | 15 +++++-------- CMakeLists.txt | 7 ++++++ README.md | 31 +++++++++++++------------- app/CMakeLists.txt | 11 --------- app/Kconfig | 1 - app/prj.conf | 6 ----- app/src/config_manager/README.md | 3 --- app/src/gpio_manager/README.md | 3 --- app/src/hal/README.md | 3 --- app/src/main.c | 10 --------- app/src/matter_manager/README.md | 3 --- app/src/ota/README.md | 3 --- app/src/power_manager/README.md | 3 --- app/src/rule_engine/README.md | 3 --- app/src/sensor_profiles/README.md | 3 --- components/drivers/CMakeLists.txt | 2 ++ components/drivers/README.md | 5 +++++ components/lua_runtime/CMakeLists.txt | 3 +++ components/lua_runtime/README.md | 5 +++++ components/profiles/CMakeLists.txt | 3 +++ components/profiles/README.md | 3 +++ components/sensors/CMakeLists.txt | 3 +++ components/sensors/README.md | 3 +++ components/transport/CMakeLists.txt | 1 + components/transport/README.md | 11 +++++++++ docker-compose.yml | 32 ++++++++++++++------------- docker/Dockerfile | 26 ++++++++-------------- main/CMakeLists.txt | 5 +++++ main/main.cpp | 10 +++++++++ partitions.csv | 12 ++++++++++ sdkconfig.defaults | 6 +++++ test/README.md | 7 ++++++ west.yml | 23 ------------------- 33 files changed, 133 insertions(+), 132 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 app/CMakeLists.txt delete mode 100644 app/Kconfig delete mode 100644 app/prj.conf delete mode 100644 app/src/config_manager/README.md delete mode 100644 app/src/gpio_manager/README.md delete mode 100644 app/src/hal/README.md delete mode 100644 app/src/main.c delete mode 100644 app/src/matter_manager/README.md delete mode 100644 app/src/ota/README.md delete mode 100644 app/src/power_manager/README.md delete mode 100644 app/src/rule_engine/README.md delete mode 100644 app/src/sensor_profiles/README.md create mode 100644 components/drivers/CMakeLists.txt create mode 100644 components/drivers/README.md create mode 100644 components/lua_runtime/CMakeLists.txt create mode 100644 components/lua_runtime/README.md create mode 100644 components/profiles/CMakeLists.txt create mode 100644 components/profiles/README.md create mode 100644 components/sensors/CMakeLists.txt create mode 100644 components/sensors/README.md create mode 100644 components/transport/CMakeLists.txt create mode 100644 components/transport/README.md create mode 100644 main/CMakeLists.txt create mode 100644 main/main.cpp create mode 100644 partitions.csv create mode 100644 sdkconfig.defaults create mode 100644 test/README.md delete mode 100644 west.yml diff --git a/.gitignore b/.gitignore index 1c4b729..cf92c03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,13 @@ -# Zephyr / nRF Connect SDK +# ESP-IDF /build/ -/.west/ -/bootloader/ -/modules/ -/nrf/ -/nrfxlib/ -/zephyr/ -/tools/ +/managed_components/ +/dependencies.lock +sdkconfig +sdkconfig.old *.o *.elf -*.hex *.bin *.map -*.uf2 # Python __pycache__/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..59fa3e0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.16) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(kvida_os) diff --git a/README.md b/README.md index ddd451c..c9d2679 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,37 @@ # kvida-os -Fastvare for Kvida — en universell, batteridrevet Matter-node (Nordic nRF54L15) fra Xylon. +Fastvare for Kvida — en konfigurerbar automasjonsplattform (ESP32-C6) fra Xylon. -Visjon og arkitektur er beskrevet i meta-repoet [`kvida`](../kvida/AGENTS.md). Dette repoet inneholder kun fastvaren, bygget på Nordic nRF Connect SDK (Zephyr). +Visjon og arkitektur er beskrevet i meta-repoet [`kvida`](../kvida/AGENTS.md). Dette repoet inneholder kun fastvaren, bygget på ESP-IDF (C++17). ## Forutsetninger - Docker - WSL2 -- `usbipd-win` (for å videresende J-Link/SWD-probe fra Windows til WSL2 ved flashing) +- `usbipd-win` (for å videresende ESP32-C6 sin USB-seriellport fra Windows til WSL2 ved flashing) -## Board +## Arkitektur -Bygget er foreløpig satt opp mot Nordic sitt offisielle utviklingskort (`nrf54l15dk/nrf54l15/cpuapp`) som plassholder. Kvida sin egen hardware trenger et custom board-oppsett under `boards/` når skjema/pinout er klart — ikke gjort ennå. +Lagdelt: `drivers` -> `sensors` -> `profiles` -> `lua_runtime` -> `transport`, se komponent-READMEene under `components/` og `AGENTS.md` for detaljer. Bruker konfigurerer enheten visuelt (Blockly -> Lua), ikke ved å skrive/kompilere fastvare. ## Quickstart -Containeren kjører med arbeidsmappe `/workspace` (west-workspacets topdir), hvor dette repoet er mountet inn som undermappen `kvida-os/`. NCS/Zephyr-modulene havner som søsken av repoet (`/workspace/nrf`, `/workspace/zephyr`, ...) i et eget navngitt Docker-volum. - ```sh -# Bygg toolchain-imaget +# Bygg toolchain-imaget (Espressif sitt offisielle ESP-IDF v6.0.2-image) docker compose build -# Hent NCS/Zephyr-moduler (kjøres én gang, lagres i det navngitte volumet) -docker compose run --rm build west init -l kvida-os -docker compose run --rm build west update +# Velg target (kjøres én gang; genererer sdkconfig) +docker compose run --rm build idf.py set-target esp32c6 # Bygg fastvaren -docker compose run --rm build west build -b nrf54l15dk/nrf54l15/cpuapp kvida-os/app +docker compose run --rm build idf.py build -# Flash (krever J-Link-probe videresendt via usbipd-win til WSL2) -docker compose run --rm build west flash +# Flash + monitor (krever seriellport videresendt via usbipd-win til WSL2) +docker compose run --rm build idf.py -p flash monitor ``` -`west.yml` er pinnet til NCS `v3.4.0`. +Prosjektet er pinnet til ESP-IDF `v6.0.2` (se `docker/Dockerfile`). + +## Status + +`main/` bygger og logger oppstart. `components/*` inneholder foreløpig bare README-er som beskriver ansvar per lag — ingen reell logikk ennå. `partitions.csv` har et A/B OTA + LittleFS-oppsett med plassholder-størrelser (4MB flash) som bør justeres når ekte flash-størrelse/image-størrelse er kjent. diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt deleted file mode 100644 index 6a96653..0000000 --- a/app/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 3.20.0) - -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(kvida_os) - -target_sources(app PRIVATE src/main.c) - -# Module directories under src/ (hal, gpio_manager, power_manager, -# matter_manager, ota, config_manager, sensor_profiles, rule_engine) are -# currently placeholders with no source files. Add add_subdirectory() -# calls for each once it gains a CMakeLists.txt and real sources. diff --git a/app/Kconfig b/app/Kconfig deleted file mode 100644 index d3e1164..0000000 --- a/app/Kconfig +++ /dev/null @@ -1 +0,0 @@ -rsource "Kconfig.zephyr" diff --git a/app/prj.conf b/app/prj.conf deleted file mode 100644 index 1a14476..0000000 --- a/app/prj.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Minimal base configuration so the application boots and logs. -# Matter, Thread, power management, and other feature-specific Kconfig -# options are added as the corresponding modules gain real implementations. - -CONFIG_LOG=y -CONFIG_GPIO=y diff --git a/app/src/config_manager/README.md b/app/src/config_manager/README.md deleted file mode 100644 index 525cbd4..0000000 --- a/app/src/config_manager/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# config_manager - -Stores and applies the user's device configuration (selected sensor profile, GPIO assignment, options) without requiring a firmware change. diff --git a/app/src/gpio_manager/README.md b/app/src/gpio_manager/README.md deleted file mode 100644 index 1e9a727..0000000 --- a/app/src/gpio_manager/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# gpio_manager - -Maps configured sensor profiles to physical GPIO/ADC/I2C pins at runtime, based on the active configuration rather than build-time wiring. diff --git a/app/src/hal/README.md b/app/src/hal/README.md deleted file mode 100644 index b8d7cc6..0000000 --- a/app/src/hal/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# hal - -Hardware abstraction layer: wraps nRF54L15 peripherals (GPIO, ADC, I2C) behind a board-independent interface used by the other modules. diff --git a/app/src/main.c b/app/src/main.c deleted file mode 100644 index ac75236..0000000 --- a/app/src/main.c +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -LOG_MODULE_REGISTER(kvida_os, LOG_LEVEL_INF); - -int main(void) -{ - LOG_INF("kvida-os starting"); - return 0; -} diff --git a/app/src/matter_manager/README.md b/app/src/matter_manager/README.md deleted file mode 100644 index 0d0c707..0000000 --- a/app/src/matter_manager/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# matter_manager - -Exposes configured sensor profiles as Matter endpoints/clusters over Thread, and handles Matter commissioning. diff --git a/app/src/ota/README.md b/app/src/ota/README.md deleted file mode 100644 index 2f10218..0000000 --- a/app/src/ota/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# ota - -Firmware update handling (DFU over Matter/Thread, image validation, rollback). diff --git a/app/src/power_manager/README.md b/app/src/power_manager/README.md deleted file mode 100644 index 48e28cb..0000000 --- a/app/src/power_manager/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# power_manager - -Battery-first power management: sleep/wake scheduling, power state transitions, and battery level reporting. diff --git a/app/src/rule_engine/README.md b/app/src/rule_engine/README.md deleted file mode 100644 index 2a6ddfe..0000000 --- a/app/src/rule_engine/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# rule_engine - -Executes user-defined behavior rules (level 3: Lua scripts, level 2: Blockly-generated intermediate representation) without requiring a firmware rebuild. diff --git a/app/src/sensor_profiles/README.md b/app/src/sensor_profiles/README.md deleted file mode 100644 index 941eb3a..0000000 --- a/app/src/sensor_profiles/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# sensor_profiles - -Reusable sensor profile implementations (reed switch, hall sensor, push button, pulse counter, analog input, DS18B20, BME280, leak sensor, PIR, generic I2C device) selectable via configuration. diff --git a/components/drivers/CMakeLists.txt b/components/drivers/CMakeLists.txt new file mode 100644 index 0000000..f0ba79b --- /dev/null +++ b/components/drivers/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register() + diff --git a/components/drivers/README.md b/components/drivers/README.md new file mode 100644 index 0000000..e09fe9c --- /dev/null +++ b/components/drivers/README.md @@ -0,0 +1,5 @@ +# drivers + +Hardware abstraction: wraps ESP32-C6 peripherals (GPIO, ADC, I2C) behind a board-independent interface used by `sensors`. No dependency on other Kvida components. + +TODO: mounting the `storage` LittleFS partition (see `partitions.csv`) belongs here once a LittleFS component (e.g. `joltwallet/esp_littlefs` from the IDF Component Registry) is picked and pinned via `idf_component.yml`. diff --git a/components/lua_runtime/CMakeLists.txt b/components/lua_runtime/CMakeLists.txt new file mode 100644 index 0000000..240f6af --- /dev/null +++ b/components/lua_runtime/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register( + REQUIRES profiles transport +) diff --git a/components/lua_runtime/README.md b/components/lua_runtime/README.md new file mode 100644 index 0000000..c737246 --- /dev/null +++ b/components/lua_runtime/README.md @@ -0,0 +1,5 @@ +# lua_runtime + +Executes the sandboxed Lua program (compiled from Blockly) that defines device behaviour. Exposes the Kvida API (e.g. `publish("temperature", 21.3)`) to Lua scripts; Lua never touches ESP-IDF or `transport` directly. `REQUIRES profiles transport`. + +TODO: needs an actual Lua interpreter dependency, pinned via `idf_component.yml` once a specific IDF Component Registry package/version is confirmed (not guessed here, same caution as pinning `west.yml`'s NCS revision previously). diff --git a/components/profiles/CMakeLists.txt b/components/profiles/CMakeLists.txt new file mode 100644 index 0000000..7c0f8ba --- /dev/null +++ b/components/profiles/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register( + REQUIRES sensors +) diff --git a/components/profiles/README.md b/components/profiles/README.md new file mode 100644 index 0000000..14b5be4 --- /dev/null +++ b/components/profiles/README.md @@ -0,0 +1,3 @@ +# profiles + +Exposes reusable sensor/actuator capabilities (reed switch, hall sensor, push button, pulse counter, analog input, DS18B20, BME280, leak sensor, PIR, generic I2C device) to the Lua runtime, backed by `sensors`. `REQUIRES sensors`. diff --git a/components/sensors/CMakeLists.txt b/components/sensors/CMakeLists.txt new file mode 100644 index 0000000..baf3438 --- /dev/null +++ b/components/sensors/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register( + REQUIRES drivers +) diff --git a/components/sensors/README.md b/components/sensors/README.md new file mode 100644 index 0000000..d0641b2 --- /dev/null +++ b/components/sensors/README.md @@ -0,0 +1,3 @@ +# sensors + +Turns raw `drivers` readings into typed sensor values (e.g. debounced contact state, calibrated analog readings). Knows values, not hardware. `REQUIRES drivers`. diff --git a/components/transport/CMakeLists.txt b/components/transport/CMakeLists.txt new file mode 100644 index 0000000..a96dced --- /dev/null +++ b/components/transport/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register() diff --git a/components/transport/README.md b/components/transport/README.md new file mode 100644 index 0000000..41c3167 --- /dev/null +++ b/components/transport/README.md @@ -0,0 +1,11 @@ +# transport + +Wi-Fi connectivity, MQTT client, and Home Assistant MQTT Discovery payloads. Exposes a semantic `publish(topic, value)`-style API — application code (including Lua) never depends on MQTT directly, per the transport abstraction principle in `AGENTS.md`. No dependency on other Kvida components. + +Also owns Wi-Fi/MQTT configuration storage for now (not broken out into its own component since `AGENTS.md` doesn't call out a separate config layer — revisit if this grows). + +Future transports (Zigbee, Thread, Matter) should implement the same publish API as alternate backends behind this component's interface, without changing callers. + +TODO: built on ESP-IDF's own `esp_wifi` and `mqtt_client` (`esp-mqtt`) components once real code lands — both ship with ESP-IDF, no extra registry dependency needed. + +TODO: A/B OTA update-checking belongs here, driven by ESP-IDF's native `esp_ota_ops` against the `ota_0`/`ota_1` partitions in `partitions.csv` — no extra dependency needed either. diff --git a/docker-compose.yml b/docker-compose.yml index 4031950..bee37fb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,23 +3,25 @@ services: build: context: . dockerfile: docker/Dockerfile - working_dir: /workspace + working_dir: /project + environment: + - IDF_TARGET=esp32c6 volumes: - # West workspace topdir: holds .west/, and the NCS/Zephyr module - # tree fetched by `west update` (nrf/, zephyr/, modules/, ...). - - ncs-workspace:/workspace - # This repo, bind-mounted as the manifest project inside the - # workspace (matches `self.path: kvida-os` in west.yml). - - .:/workspace/kvida-os + # Project source, bind-mounted. + - .:/project + # Build output and IDF Component Registry cache, kept in named + # volumes so they survive across container runs without polluting + # the bind-mounted source tree. + - build-cache:/project/build + - managed-components-cache:/project/managed_components tty: true - # USB/J-Link access (for `west flash`) is expected to be handled via - # usbipd-win forwarding the probe into WSL2. If `west flash` needs to - # run inside this container rather than on the WSL2 host, uncomment - # and adjust one of the following once the forwarded device node is - # known: + # USB access (for `idf.py flash`/`monitor`) is expected to be handled + # via usbipd-win forwarding the board's serial port into WSL2. If + # flashing needs to run inside this container rather than on the WSL2 + # host, uncomment and adjust once the forwarded device node is known: # devices: - # - "/dev/bus/usb:/dev/bus/usb" - # privileged: true + # - "/dev/ttyUSB0:/dev/ttyUSB0" volumes: - ncs-workspace: + build-cache: + managed-components-cache: diff --git a/docker/Dockerfile b/docker/Dockerfile index 70ba771..766ee37 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,21 +1,13 @@ # Build-only toolchain image for kvida-os. # -# Provides the Zephyr SDK toolchain, west, CMake, Ninja and Python that -# NCS builds need. It intentionally does NOT bake in the NCS/Zephyr -# module tree (nrf/, zephyr/, modules/, ...) fetched by `west update` -- -# that is left to a named volume mounted at /workspace at container run -# time, so the image stays small and NCS revisions can be bumped without -# rebuilding it. +# Unlike the previous NCS/Zephyr setup, Espressif's official image already +# bakes in the full ESP-IDF toolchain and the SDK itself for the pinned +# version, so there is no separate multi-GB "fetch SDK into a volume" step +# here -- just pin the image tag. # -# NOTE: verify this base image tag still exists/is current before relying -# on it -- it could not be checked against the live registry while -# writing this Dockerfile. -FROM ghcr.io/zephyrproject-rtos/zephyr-build:latest +# NOTE: verify this tag still exists before relying on it -- it could not +# be checked against the live registry while writing this Dockerfile. If +# the exact patch tag "v6.0.2" isn't published, fall back to "release-v6.0". +FROM espressif/idf:v6.0.2 -RUN pip3 install --no-cache-dir -U west - -WORKDIR /workspace - -# TODO: install Nordic's nRF Command Line Tools / nrfutil here if -# `west flash` should run from inside this container against a J-Link -# probe forwarded into WSL2 via usbipd-win, instead of from the host. +WORKDIR /project diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..495c0e1 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS "main.cpp" + INCLUDE_DIRS "." + REQUIRES drivers sensors profiles transport lua_runtime +) diff --git a/main/main.cpp b/main/main.cpp new file mode 100644 index 0000000..d50b1ba --- /dev/null +++ b/main/main.cpp @@ -0,0 +1,10 @@ +#include "esp_log.h" + +namespace { +constexpr const char *TAG = "kvida_os"; +} + +extern "C" void app_main(void) +{ + ESP_LOGI(TAG, "kvida-os starting"); +} diff --git a/partitions.csv b/partitions.csv new file mode 100644 index 0000000..131f3fd --- /dev/null +++ b/partitions.csv @@ -0,0 +1,12 @@ +# ESP-IDF partition table: A/B OTA app slots + LittleFS storage. +# +# Sized for a 4MB flash module (TODO: adjust once real flash size and +# firmware image size are known). +# +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x6000, +otadata, data, ota, 0xf000, 0x2000, +phy_init, data, phy, 0x11000, 0x1000, +ota_0, app, ota_0, 0x20000, 0x180000, +ota_1, app, ota_1, 0x1A0000, 0x180000, +storage, data, littlefs, 0x320000, 0xE0000, diff --git a/sdkconfig.defaults b/sdkconfig.defaults new file mode 100644 index 0000000..a9d6391 --- /dev/null +++ b/sdkconfig.defaults @@ -0,0 +1,6 @@ +# Shared defaults. Target-specific settings are generated into `sdkconfig` +# by `idf.py set-target esp32c6` (first-time setup, see README) rather than +# hardcoded here. + +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..4a7a74d --- /dev/null +++ b/test/README.md @@ -0,0 +1,7 @@ +# test + +Host-based unit tests for business logic that doesn't need real hardware, per the testing philosophy in `AGENTS.md`: "Everything that can be tested on a desktop should be." + +Primary candidates once they have real code: `components/sensors`, `components/profiles`, and the non-hardware parts of `components/lua_runtime` (Lua sandboxing/API surface, not GPIO access). + +ESP-IDF supports building against its `linux` target (`idf.py --preview set-target linux`) to run component unit tests on the host without a board. No test scaffolding is wired up yet since there's no logic to test. diff --git a/west.yml b/west.yml deleted file mode 100644 index 59e40fd..0000000 --- a/west.yml +++ /dev/null @@ -1,23 +0,0 @@ -# West manifest for kvida-os (freestanding NCS application). -# -# This repo is meant to sit as a named subdirectory ("kvida-os") inside a -# west workspace topdir, e.g. `/workspace/kvida-os`. Running -# `west init -l kvida-os && west update` from the topdir fetches sdk-nrf -# (which pulls in Zephyr, MCUboot, Matter, etc. via its own manifest) as -# siblings of this repo (`/workspace/nrf`, `/workspace/zephyr`, ...). -# -# Pinned to NCS v3.4.0. -manifest: - remotes: - - name: ncs - url-base: https://github.com/nrfconnect - - projects: - - name: nrf - remote: ncs - repo-path: sdk-nrf - revision: v3.4.0 - import: true - - self: - path: kvida-os