Merge pull request #35 from xJARiD/develop

fix TBeam 1W, improve cache, sync docs, add AGENTS.md
This commit is contained in:
xJARiD
2026-04-19 09:06:19 +10:00
committato da GitHub
8 ha cambiato i file con 566 aggiunte e 52 eliminazioni
+222
Vedi File
@@ -0,0 +1,222 @@
# AGENTS.md
## Purpose
EastMesh layer on top of upstream MeshCore.
**Default:** preserve upstream behavior.
Only modify code for clearly scoped EastMesh features:
- `*_repeater_mqtt`
- `*_companion_radio_wifi`
- MQTT uplink/broker
- repeater web panel
- docs, releases, automation
## Principles
- Minimal, targeted changes
- Prefer additive over modifying upstream code
- Avoid unrelated refactors
- Maintain parity with upstream behavior
## Guardrails
### Upstream
- Do not modify unrelated MeshCore logic
- Do not change CLI semantics unless explicitly required
- Do not introduce breaking changes to existing targets
### Docs (update in same PR when practical)
| Change | File |
| --------------------- | -------------------- |
| CLI / allowlist | `docs/custom-cli.md` |
| Web panel UI/behavior | `docs/web-panel.md` |
| Releases | `release-notes.yml` |
| Flashing guidance | `docs/releases.md` |
### Web Panel Gate
If editing `examples/simple_repeater/MyMesh.cpp`, also update `docs/custom-cli.md`.
## Tooling
- Use `uv` + PlatformIO via `uv run`
- Do not assume global `pio`
### Build Policy
Builds are expensive. Avoid unless necessary.
Do NOT build for:
- docs / HTML / CSS only
Prefer:
- user-run local builds
- reasoning over execution
Build only if:
- high-risk change
- firmware behavior must be verified
### Commands
```bash
uv sync
uv run pio run -e <env>
uv run pio device monitor --port <port> --baud 115200
uv run --group docs zensical serve
uv run --group docs zensical build
```
Do not assume `pio` is installed globally.
## Common Commands
List build targets:
```bash
bash build.sh list
```
Build a single target:
```bash
uv run pio run -e heltec_v4_repeater_mqtt
uv run pio run -e T_Beam_S3_Supreme_SX1262_repeater_mqtt
uv run pio run -e heltec_v4_companion_radio_wifi
uv run pio run -e T_Beam_S3_Supreme_SX1262_companion_radio_wifi
```
Build with release-style metadata:
```bash
export FIRMWARE_VERSION=v1.14.1
export EASTMESH_VERSION=v1.0.1
bash build.sh build-firmware heltec_v4_repeater_mqtt
bash build.sh build-firmware T_Beam_S3_Supreme_SX1262_repeater_mqtt
```
Flash a target:
```bash
uv run pio run -e heltec_v4_repeater_mqtt -t upload --upload-port /dev/tty.usbmodemXXXX
uv run pio run -e T_Beam_S3_Supreme_SX1262_repeater_mqtt -t upload --upload-port /dev/tty.usbmodemXXXX
```
## Key Files
- `build.sh` — build wrapper
- `platformio.ini`
- `variants/eastmesh_mqtt/platformio.ini`
- `examples/simple_repeater/MyMesh.cpp`
- `src/helpers/mqtt/MQTTUplink.cpp`
- `docs/*.md`
- `RELEASE.md`
- `release-notes.yml`
## Docs Sync Requirements
If you change any of the following, update docs in the same PR when practical:
- Web-panel allowlisted commands:
- update `docs/custom-cli.md`
- Web-panel user-facing behavior, sections, controls, or troubleshooting:
- update `docs/web-panel.md`
- EastMesh CLI additions or changed semantics:
- update `docs/custom-cli.md`
- Release/tag preparation:
- update `release-notes.yml`
- Flashing/release asset guidance:
- update `docs/releases.md`
## Repeater MQTT Notes
`*_repeater_mqtt` builds may include the local HTTPS web panel on supported ESP32 targets.
Operational guidance already reflected in docs:
- use for initial setup and troubleshooting
- prefer `set web off` afterward for maximum heap headroom
## Companion WiFi Notes
`*_companion_radio_wifi` targets support persisted Wi-Fi rescue commands via serial `CLI Rescue`.
Do not document companion rescue commands in repeater docs. Do not assume web-panel behavior applies.
Companion release/version rule:
- companion tags use the official upstream MeshCore release version only
- the current official MeshCore version is `v1.14.1`
- companion releases are only cut when `meshcore-dev/MeshCore` has made an official release
- do not invent separate EastMesh companion version numbers
## Release Workflow
Current tag formats:
```bash
git tag companion-wifi-v1.2.3
git tag repeater-mqtt-eastmesh-v1.0.1
```
Rules:
- `companion-wifi` tags use the upstream MeshCore version directly
- `repeater-mqtt` tags use the EastMesh release version in the tag
- GitHub Actions variable `OFFICIAL_MESHCORE_VERSION` supplies the upstream base version for repeater MQTT release builds
- if the upstream MeshCore release version changes, update `OFFICIAL_MESHCORE_VERSION` in GitHub before cutting release tags
Typical release flow:
1. Update `OFFICIAL_MESHCORE_VERSION` if upstream changed.
2. Update `release-notes.yml` on `develop`.
3. Merge the release PR from `develop` to `main`.
4. Create the desired release tag or tags on the target commit on `main`.
5. Push the tags.
## Upstream Sync Workflow
When asked to pull from upstream MeshCore:
- pull from `meshcore-dev/MeshCore:dev`
- start from local `develop`
- create a temporary integration branch off `develop`
- merge upstream `dev` into that temporary integration branch
- resolve conflicts in a way that preserves EastMesh-specific changes
- merge the finished integration branch back into `develop`
Do not merge upstream directly into `main`.
## Scope Boundaries
Do NOT (unless asked):
- rename tracks
- change tag formats
- expand allowlist without updating docs
- change upstream CLI semantics
- introduce new versioning schemes
## Commit Messages
Use concise, conventional prefixes:
- `feat:` new functionality
- `fix:` bug fixes
- `docs:` documentation changes
- `chore:` maintenance, tooling, non-functional
- `refactor:` code changes without behavior change
Keep messages short and scoped.
## Decision Rule
If a change is not clearly EastMesh-specific, do not modify the code.
When uncertain, prefer no change or request clarification.
+265 -48
Vedi File
File diff soppresso perché troppo grande Carica Diff
+27 -1
Vedi File
@@ -75,6 +75,8 @@ Legacy dotted aliases are also accepted:
- `stats-radio`: shows radio noise floor, last RSSI, last SNR, and TX/RX airtime.
- `stats-packets`: shows packet receive/send totals, flood/direct breakdown, and receive errors.
> If `noise_floor` reports `0`, check `get agc.reset.interval`; if it is not `0`, try `set agc.reset.interval 0` and test again.
### Board Battery Reporting
- `get battery.reporting`: shows whether board battery reporting is enabled. Support is board-dependent.
@@ -94,13 +96,15 @@ That allowlist currently includes:
- `advert`
- `reboot`
- `start ota`
- `set repeat on|off`
- `memory`
- `stats-core`
- `stats-radio`
- `stats-packets`
- `get wifi.status`
- `get wifi.powersaving`
- `set wifi.ssid <ssid>`
- `set wifi.pwd <password>`
- `set wifi.powersaving on|off`
- `get mqtt.iata`
- `set mqtt.iata <code>`
- `get mqtt.owner`
@@ -117,29 +121,51 @@ That allowlist currently includes:
- `set mqtt.tx on|off`
- `get mqtt.eastmesh-au`
- `set mqtt.eastmesh-au on|off`
- `get mqtt.eastmesh.au`
- `set mqtt.eastmesh.au on|off`
- `get mqtt.letsmesh-eu`
- `set mqtt.letsmesh-eu on|off`
- `get mqtt.letsmesh.eu`
- `set mqtt.letsmesh.eu on|off`
- `get mqtt.letsmesh-us`
- `set mqtt.letsmesh-us on|off`
- `get mqtt.letsmesh.us`
- `set mqtt.letsmesh.us on|off`
- `set web on|off`
- `set.web on|off`
- `set web.stats on|off`
- `set.web.stats on|off`
- `get name`
- `set name <device-name>`
- `get lat`
- `set lat <latitude>`
- `get lon`
- `set lon <longitude>`
- `get radio`
- `set radio <freq> <bw> <sf> <cr>`
- `get prv.key`
- `get guest.password`
- `password <admin-password>`
- `set guest.password <password>`
- `set prv.key <64-hex-char-private-key>`
- `get role`
- `get public.key`
- `get advert.interval`
- `set advert.interval <minutes>`
- `get agc.reset.interval`
- `set agc.reset.interval <seconds>`
- `get flood.advert.interval`
- `set flood.advert.interval <hours>`
- `get repeat`
- `set repeat on|off`
- `get flood.max`
- `set flood.max <count>`
- `get path.hash.mode`
- `set path.hash.mode <mode>`
- `get owner.info`
- `set owner.info <text>`
- `time <iso-or-epoch>`
- `time.force <iso-or-epoch>`
## Companion WiFi Rescue Commands
+1
Vedi File
@@ -140,6 +140,7 @@ This is a small terminal for allowlisted commands.
- command history is shown in the terminal box below
- save buttons elsewhere in the page also show the generated command and the reply here
- `clock` is available here if you want to check the repeater's current board time
- the full current allowlist is documented in `docs/custom-cli.md` under `Web Panel Allowlisted Commands`
This makes it easy to see exactly what the panel sent to the repeater.
+2
Vedi File
@@ -2036,6 +2036,7 @@ void MyMesh::runWebCommand(const char* command, char* reply, size_t reply_size)
matches_exact("get role") ||
matches_exact("get public.key") ||
matches_exact("get advert.interval") ||
matches_exact("get agc.reset.interval") ||
matches_exact("get flood.advert.interval") ||
matches_exact("get repeat") ||
matches_exact("get flood.max") ||
@@ -2070,6 +2071,7 @@ void MyMesh::runWebCommand(const char* command, char* reply, size_t reply_size)
matches_prefix("set guest.password ") ||
matches_prefix("set prv.key ") ||
matches_prefix("set advert.interval ") ||
matches_prefix("set agc.reset.interval ") ||
matches_prefix("set flood.advert.interval ") ||
matches_prefix("set repeat ") ||
matches_prefix("set flood.max ") ||
+21
Vedi File
@@ -275,3 +275,24 @@ releases:
area: web-panel
text: "Updated the web panel docs to describe the rough 2 MB PSRAM boot-history cutoff."
breaking_changes: []
- track: repeater-mqtt
version: "1.3.4"
tag: "repeater-mqtt-eastmesh-v1.3.4"
date: "2026-04-18"
previous_version: "1.3.3"
summary: "Polished the repeater web panel, fixed a T-Beam 1W build issue, and synced the documented web CLI allowlist with the shipped browser console."
changes:
- type: fixed
area: board-support
text: "Added the missing T-Beam 1W flash partition size so the repeater_mqtt target builds with the correct partition layout."
- type: changed
area: web-panel
text: "Cached the repeater title across both the /app and /stats pages so the local admin UI presents a more consistent device label."
- type: changed
area: web-panel
text: "Applied the newer four-band threshold styling to the largest-block memory meters in the /stats Memory card."
- type: docs
area: web-panel
text: "Updated the documented web CLI allowlist to match the actual browser command gate, including the AGC reset interval commands and the troubleshooting note for `noise_floor` reporting `0`."
breaking_changes: []
+26 -3
Vedi File
@@ -994,6 +994,7 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
const RADIO_PRESETS_URL = "https://api.meshcore.nz/api/v1/config";
const isStatsPage = window.location.pathname === "/stats";
const LAST_PAGE_KEY = "repeater-last-page";
const PANEL_TITLE_KEY = "repeater-panel-title";
let token = sessionStorage.getItem("repeater-token") || "";
let commandQueue = Promise.resolve();
let radioPresetEntries = [];
@@ -1005,7 +1006,19 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
function updatePanelTitle(nameValue) {
const fallbackTitle = "Repeater Config";
const trimmedName = String(nameValue == null ? "" : nameValue).trim();
document.title = trimmedName ? trimmedName : fallbackTitle;
const nextTitle = trimmedName ? trimmedName : fallbackTitle;
document.title = nextTitle;
if (trimmedName) {
localStorage.setItem(PANEL_TITLE_KEY, trimmedName);
} else {
localStorage.removeItem(PANEL_TITLE_KEY);
}
}
function applyCachedPanelTitle() {
const cachedTitle = localStorage.getItem(PANEL_TITLE_KEY);
if (cachedTitle && cachedTitle.trim()) {
document.title = cachedTitle.trim();
}
}
function rememberCurrentPage() {
localStorage.setItem(LAST_PAGE_KEY, isStatsPage ? "/stats" : "/app");
@@ -1017,6 +1030,7 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
window.location.replace("/");
}
rememberCurrentPage();
applyCachedPanelTitle();
function getPreferredTheme() {
const saved = localStorage.getItem("repeater-theme");
if (saved === "light" || saved === "dark") return saved;
@@ -1340,6 +1354,13 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
if (percent >= 35) return "warn";
return "bad";
}
function toneForLargestBlockPercent(percent) {
if (!Number.isFinite(percent)) return "bad";
if (percent >= 75) return "";
if (percent >= 55) return "ok";
if (percent >= 35) return "warn";
return "bad";
}
function colorForHeapFreePercent(percent) {
const tone = toneForHeapFreePercent(percent);
if (tone === "ok") return "#6ea43f";
@@ -1511,11 +1532,13 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
const psramFree = memory.psram_free || 0;
const psramMax = memory.psram_max || 0;
const heapFreePct = pctRange(heapFree, 0, 128 * 1024);
const heapLargestPct = pctRatio(heapMax, heapFree);
const psramLargestPct = pctRatio(psramMax, psramFree);
return `<section class="hud-card">
<h3>Memory</h3>
${renderMeter("Heap Free", formatBytes(heapFree), heapFreePct, "total free heap", toneForHeapFreePercent(heapFreePct))}
${renderMeter("Heap Largest Block", formatBytes(heapMax), pctRatio(heapMax, heapFree), "largest alloc vs free", false)}
${renderMeter("PSRAM Largest Block", formatBytes(psramMax), pctRatio(psramMax, psramFree), "largest alloc vs free", false)}
${renderMeter("Heap Largest Block", formatBytes(heapMax), heapLargestPct, "largest alloc vs free", toneForLargestBlockPercent(heapLargestPct))}
${renderMeter("PSRAM Largest Block", formatBytes(psramMax), psramLargestPct, "largest alloc vs free", toneForLargestBlockPercent(psramLargestPct))}
<div class="metric-grid">
${renderMetric("Heap Free", formatBytes(heapFree))}
${renderMetric("Heap Min", formatBytes(memory.heap_min || 0))}
@@ -1,6 +1,8 @@
[LilyGo_TBeam_1W]
extends = esp32_base
board = t_beam_1w
board_build.partitions = default_8MB.csv
board_upload.maximum_size = 8388608
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam_1w