More work on the ESP32C3 Boilerplate

This commit is contained in:
2026-06-27 20:00:17 -05:00
parent bb7aa5d5ca
commit 54ae1e66da
21 changed files with 833 additions and 146 deletions

View File

@@ -25,7 +25,7 @@ It provides basic "infrastructure" and "Framework" for specific developments.
- Control the on-board LED (set brightness; 0-> off; 100->full brightness)
- Ping (that returns the current uptime as JSON)
- Add (takes 2 integers and returns the result of adding those integers)
- Admin Web-UI
- Admin Web-UI
- Role based security configuration
- Roles are centrally maintained
- User management
@@ -43,9 +43,12 @@ It provides basic "infrastructure" and "Framework" for specific developments.
- search
- view
- clear logs
- HTTPS configuration
- By default a self-signed certificate is used
- Allows the set up of certificates for HTTPS (file upload)
- Networking configuration
- Host name
- DHCP or static IPv4 parameters
- HTTPS certificate configuration
- By default a self-signed certificate is used
- Allows the set up of certificates for HTTPS (file upload)
- Firmware update handling
- Upload new firmware via file selector
- Check URL for new firmware button (this will reach out to a configurable (in the code) URL to to try and find new firmware. If new firmware is available it offers to install.)
@@ -69,8 +72,9 @@ It provides basic "infrastructure" and "Framework" for specific developments.
- Once the user entered submitted information, the information is stored in non volatile memory, and the device is restarted.
- On subsequent startups, the device looks for configuraiton stored in non volatile memory
- The factory reset functionality deletes the information from the non volatile memory, which will lead to the setup screen.
- Logging is done based on log level.
- The logs are stored in non volatile memory
- Logging is done based on log level.
- Log levels are `Error`, `Warn`, `SecurityAudit`, `Info`, and `Debug`; `SecurityAudit` records security-relevant events such as login/logout, invalid bearer tokens, authorization failures, unknown API URLs/methods, and security configuration changes.
- The logs are stored in non volatile memory
- they need to be implemented as a ring buffer that occupies a configurable space in non volatile memory
- There is a standard API endpoint that returns the logs (restricted to user role Debugger)
@@ -81,17 +85,20 @@ The firmware is split by responsibility:
| Path | Responsibility |
| --- | --- |
| `src/main.cpp` | Arduino `setup()`/`loop()` and boot orchestration |
| `src/app.h` | Shared constants, state, structs, and function declarations |
| `include/app.h` | Framework constants, state, structs, and function declarations |
| `include/custom_api.h` | Custom API handler declarations |
| `src/config/api_definitions.cpp` | Central API catalog, route handlers, and default role/public access mapping |
| `src/config/api_definitions_custom.cpp` | Custom API catalog and default public access mapping |
| `src/core/state.cpp` | Global state, project/device identity, hashing, persisted settings |
| `src/core/logging.cpp` | LittleFS log ring buffer |
| `src/core/auth.cpp` | Users, roles, tokens, and API authorization |
| `src/core/device.cpp` | LED control, factory reset, and WiFi connection |
| `src/util/json_utils.cpp` | Small JSON response and request parsing helpers |
| `src/web/ui.cpp` | LittleFS-backed HTML serving and captive-portal helper pages |
| `src/web/routes.cpp` | Page/captive route registration and generic API route registration from `apiDefs` |
| `src/web/routes.cpp` | Page/captive route registration and generic API route registration from framework and custom API catalogs |
| `src/handlers/handlers_setup.cpp` | Setup and WiFi scan route handlers |
| `src/handlers/handlers_api.cpp` | Public/device API handlers and API ACL handlers |
| `src/handlers/handlers_custom_api.cpp` | Custom API handlers for ping, add, and LED brightness |
| `src/handlers/handlers_api.cpp` | API ACL list/detail management handlers |
| `src/handlers/handlers_auth.cpp` | Login, users, roles, and password route handlers |
| `src/handlers/handlers_admin.cpp` | Settings, logs, and certificate route handlers |
| `src/handlers/handlers_ota.cpp` | Firmware upload and OTA route handlers |
@@ -116,6 +123,7 @@ The firmware in `src/main.cpp` implements the boilerplate as a compact Arduino E
- Ring-buffer logging in LittleFS with default maximum size of 50 KiB.
- Firmware and LittleFS filesystem upload OTA and update-from-URL hooks.
- HTTPS certificate storage API. The default Arduino `WebServer` runs HTTP; stored certificate material is available for applications that add TLS termination.
- Network settings for hostname plus DHCP/static IPv4 configuration.
### Web UI files
@@ -134,6 +142,8 @@ After changing files in `data/`, upload the filesystem image as well as the firm
pio run -t uploadfs
```
In the PlatformIO UI, use the `Upload Firmware and Filesystem` project task when you want one action to upload both firmware and the LittleFS image that contains the web UI.
Uploading the filesystem image replaces the LittleFS contents, including stored log files. WiFi configuration, users, roles, and settings are stored in NVS preferences and are not part of that filesystem image.
### Provisioning
@@ -162,6 +172,24 @@ The default project name is `TSL-Embedded`. The firmware combines the project na
On normal boot, the device connects to the configured WiFi and serves the Admin UI at the IP printed to serial.
### Networking
Open `Networking` in the Admin UI to configure the station-mode host name and IP parameters.
The host name field is optional. If it is empty, the firmware uses the generated default host name based on `PROJECT_NAME` and the chip suffix, for example `TSL-Embedded-BDF5F0`. A custom host name must be 1-31 characters and may contain only letters, digits, and hyphens. It cannot start or end with a hyphen.
Address mode defaults to DHCP. To use a static IPv4 address, select `Static IPv4` and provide:
| Field | Required | Example |
| --- | --- | --- |
| Static IP | Yes | `192.168.1.50` |
| Gateway | Yes | `192.168.1.1` |
| Subnet mask | Yes | `255.255.255.0` |
| DNS 1 | No | `192.168.1.1` |
| DNS 2 | No | `8.8.8.8` |
Networking changes are stored immediately, but they apply on the next WiFi reconnect or reboot.
### Factory reset
The default reset pin is GPIO4. Hold GPIO4 LOW during boot for 10 seconds to clear stored configuration and logs, then the device restarts into setup mode.
@@ -190,6 +218,51 @@ The response contains a bearer token. Pass it to protected APIs:
Authorization: Bearer <token>
```
### HTTPS certificate configuration
The Admin UI stores HTTPS certificate material so applications built on this boilerplate can use it when adding TLS termination. The default Arduino `WebServer` used by this project serves HTTP only; uploading a certificate stores the material in NVS preferences but does not by itself switch the built-in web server to HTTPS.
To configure the stored certificate material:
1. Log in as a user with the `Sysadmin` role.
2. Open `Networking` -> `HTTPS Certificate`.
3. Select a certificate file and click `Save certificate`.
4. Use `Load current` to verify what is currently stored.
The upload file must be a plain text PEM-style file. Use UTF-8 or ASCII text and preserve the PEM block line breaks exactly. The file may use `.pem`, `.cer`, `.crt`, or `.txt`.
Valid content is one or more PEM blocks, for example a certificate chain:
```text
-----BEGIN CERTIFICATE-----
...base64 certificate data...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...base64 intermediate certificate data...
-----END CERTIFICATE-----
```
If your TLS integration expects both the certificate and private key from this stored value, put both PEM blocks in the same text file:
```text
-----BEGIN CERTIFICATE-----
...base64 certificate data...
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
...base64 private key data...
-----END PRIVATE KEY-----
```
Do not upload binary DER, PKCS#12/PFX, or password-protected keystore files directly. Convert those to PEM text first. The equivalent API is:
```http
POST /api/cert
Authorization: Bearer <token>
Content-Type: application/json
{"certificate":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n"}
```
### API response shape
Every API returns JSON with a `success` field. Errors include an `error` string:
@@ -241,6 +314,9 @@ Protected APIs and their default roles:
| `POST /api/settings` | `Sysadmin` |
| `GET /api/logs` | `Debugger` |
| `POST /api/logs/clear` | `Debugger` |
| `GET /api/files` | `Debugger` |
| `GET /api/files/download` | `Debugger` |
| `POST /api/factory-reset` | `Sysadmin` |
| `POST /api/ota/check` | `Sysadmin` |
| `POST /api/ota/run` | `Sysadmin` |
| `POST /api/update` | `Sysadmin` |