Make Nightly index beautiful, commit nightly release_notes (#11816)

Link back to the Action, mention the commit, build date, make it pretty with CSS.

Also moves release notes into .github/nightly so they can be more easily edited. (Contents unchanged).
This commit is contained in:
Austin authored and GitHub committed 2026-09-11 01:53:15 +00:00
1 parent d4482a28a1
commit c3df4914b4
5 files changed
+362 -7

No files matched your search

+153
View File
@@ -0,0 +1,153 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<title>Meshtastic Nightly v%%VERSION%%</title>
<meta name="description" content="Nightly firmware builds from the tip of the Meshtastic develop branch.">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -22.5 100 100'%3E%3Cg fill='rgb(103,234,148)' transform='matrix(0.802386,0,0,0.460028,-421.748,-122.127)'%3E%3Cpath transform='matrix(0.579082,0,0,1.01004,460.975,-39.6867)' d='M250.908,330.267L193.126,415.005L180.938,406.694L244.802,313.037C246.174,311.024 248.453,309.819 250.889,309.816C253.326,309.814 255.606,311.015 256.982,313.026L320.994,406.536L308.821,414.869L250.908,330.267Z'/%3E%3Cpath transform='matrix(0.582378,0,0,1.01579,485.019,-211.182)' d='M87.642,581.398L154.757,482.977L142.638,474.713L75.523,573.134L87.642,581.398Z'/%3E%3C/g%3E%3C/svg%3E">
<style>
:root {
--bg: #ffffff;
--panel: #fbfbfc;
--fg: #2c2d3c;
--muted: #6b6d80;
--rule: #e3e4ea;
--accent: #0f9d58;
--logo: #2c2d3c;
--notice-bg: #fff9e8;
--notice-rule: #e8b931;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1b1c26;
--panel: #23242f;
--fg: #e7e8ee;
--muted: #9a9cb0;
--rule: #32343f;
--accent: #67ea94;
--logo: #ffffff;
--notice-bg: #2b2618;
--notice-rule: #b9902a;
}
}
* { box-sizing: border-box; }
body {
margin: 0;
padding: 2.5rem 1.25rem 4rem;
background: var(--bg);
color: var(--fg);
font: 15px/1.6 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
main { max-width: 62rem; margin: 0 auto; }
a { color: var(--accent); }
header { display: flex; align-items: center; gap: 0.85rem; }
header svg { width: 46px; height: auto; fill: var(--logo); flex: none; }
h1 {
margin: 0;
font-size: 1.6rem;
font-weight: 600;
letter-spacing: -0.015em;
line-height: 1.15;
}
h1 .sub {
display: block;
font-size: 0.82rem;
font-weight: 500;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--accent);
}
.lede { margin: 1.5rem 0 0; max-width: 46rem; color: var(--muted); }
code {
padding: 0.1em 0.35em;
background: var(--panel);
border: 1px solid var(--rule);
border-radius: 3px;
font: 0.88em ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
color: var(--fg);
}
dl.meta {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.3rem 1.25rem;
margin: 1.5rem 0 0;
font-size: 0.86rem;
}
dl.meta dt { color: var(--muted); }
dl.meta dd {
margin: 0;
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}
.notice {
margin: 1.75rem 0 0;
padding: 0.8rem 1rem;
background: var(--notice-bg);
border-left: 3px solid var(--notice-rule);
border-radius: 0 4px 4px 0;
font-size: 0.9rem;
}
h2 {
margin: 2.5rem 0 0.75rem;
font-size: 0.82rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted);
}
.tree {
padding: 1rem 1.15rem;
background: var(--panel);
border: 1px solid var(--rule);
border-radius: 6px;
overflow-x: auto;
white-space: nowrap;
font: 12.5px/1.75 ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
color: var(--muted);
}
.tree a { color: var(--fg); text-decoration: none; }
.tree a:hover { color: var(--accent); text-decoration: underline; }
footer {
margin: 2.5rem 0 0;
padding-top: 1.25rem;
border-top: 1px solid var(--rule);
font-size: 0.85rem;
color: var(--muted);
}
footer a { margin-right: 1.25rem; white-space: nowrap; }
</style>
</head>
<body>
<main>
<header>
<svg viewBox="0 0 100 55" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Meshtastic">
<g transform="matrix(0.802386,0,0,0.460028,-421.748,-122.127)">
<path transform="matrix(0.579082,0,0,1.01004,460.975,-39.6867)" d="M250.908,330.267L193.126,415.005L180.938,406.694L244.802,313.037C246.174,311.024 248.453,309.819 250.889,309.816C253.326,309.814 255.606,311.015 256.982,313.026L320.994,406.536L308.821,414.869L250.908,330.267Z"/>
<path transform="matrix(0.582378,0,0,1.01579,485.019,-211.182)" d="M87.642,581.398L154.757,482.977L142.638,474.713L75.523,573.134L87.642,581.398Z"/>
</g>
</svg>
<h1>Meshtastic<span class="sub">Nightly Firmware</span></h1>
</header>
<p class="lede">
Firmware built straight from the tip of <code>develop</code>, published every night.
Grab a <code>.bin</code>, <code>.uf2</code> or <code>.hex</code> for your board below, or point the
<a href="https://flasher.meshtastic.org">Web Flasher</a> at the nightly channel and let it pick for you.
</p>
<dl class="meta">
<dt>Version</dt><dd>%%VERSION%%</dd>
<dt>Commit</dt><dd><a href="https://github.com/meshtastic/firmware/commit/%%COMMIT%%">%%COMMIT_SHORT%%</a></dd>
<dt>Built</dt><dd>%%BUILD_DATE%%</dd>
<dt>Build log</dt><dd><a href="%%RUN_URL%%">run %%RUN_ID%%</a></dd>
</dl>
<p class="notice">
Nightlies are untested pre-release builds and can be unstable. Only flash hardware you can afford to
fully erase, and back up your config first. Start with the
<a href="./release_notes.md">release notes</a> &mdash; they cover what changed and how to report what you find.
</p>
<h2>Files</h2>
<div class="tree">
+11
View File
@@ -0,0 +1,11 @@
</div>
<footer>
<a href="https://meshtastic.org">meshtastic.org</a>
<a href="https://meshtastic.org/docs/getting-started/flashing-firmware/">Flashing guide</a>
<a href="https://github.com/meshtastic/firmware">Source</a>
<a href="https://github.com/meshtastic/firmware/issues">Report a bug</a>
</footer>
</main>
</body>
</html>
+161
View File
@@ -0,0 +1,161 @@
# Help Test 2.8 - Flash a Nightly, Send Feedback
We're preparing the **2.8** release, and we need your help shaking it out on real hardware. The web flasher now has a **built-in feedback form**. Flash a nightly, use your node like you normally would, and tell us what you find. Every report on a real board moves the release forward.
⚠️ 2.8 nightlies are **experimental, pre-release builds** and can be unstable. Please read the warnings and only flash hardware you can afford to fully erase. Back up your config first.
## Big changes
There are a number of fundamental changes to 2.8 that require a heads-up. Please review some of these higher profile changes so that you are aware of them before installing:
- Node numbers (ID) are now derived from the public-key identity of the node
- XEdDSA based packet signing
- Reduction of long-name to 25 bytes
- Precise position no longer allowed on known-keys (public mesh. Please use private channels for this)
- Telemetry and position are off-by-default and must be opted into
- Ground-up redesigned NodeDB storage and traffic management
- Completely new allocation of LoRa Regions and presets, including ham specific carve-outs
---
## How to help in 3 steps
1. **Flash a 2.8 nightly** from the web flasher onto supported hardware.
2. Make sure your apps / clients are up to date with the latest release in order to support the 2.8 firmware features like packet signing.
3. **Use it normally** for a while - send messages, move around, let it mesh, sleep, and wake. Try the features you actually rely on.
4. **Open the feedback form in the web flasher and tell us what happened** - good, bad, or broken. "Works great on my board" is genuinely useful data too.
---
## Where we most need coverage
The more different boards and setups we hear from, the better. Especially valuable:
- **A variety of supported boards**
- **Both radios and roles** - routers, clients, repeaters, and low-power/sleep configurations.
- **Different regions** and channel/modem-preset combinations.
- **Bluetooth pairing and reconnection** from Android and iOS.
- **Upgrade paths** - flashing 2.8 over an existing 2.x install and confirming your config/keys survive.
- **Peripherals** - GPS, screens (OLED/E-Ink/TFT), sensors, and buttons.
---
## What makes a feedback report actionable
The feedback form captures a lot automatically, but the more of the following you include, the faster we can act:
| Include | Why it helps |
| ------------------------- | --------------------------------------------------------------------------------------------- |
| **Exact board / variant** | Behavior is often board-specific (e.g. `rak4631`, `heltec-v3`, `t1000-e`). |
| **Build identifier** | The nightly version / commit / date you flashed, so we can reproduce against the right build. |
| **What you did** | Concrete steps leading up to the problem - the shorter the repro, the better. |
| **Expected vs. actual** | What you thought would happen, and what actually happened. |
| **How often** | Every time? Once? Only after a reboot or after X hours? |
| **Logs / screenshots** | Serial or app logs, and photos of the screen or error, when you have them. |
| **Environment** | Region, phone OS + app version, and anything unusual about your setup. |
### Especially flag these
- **Boot loops, hangs, watchdog resets, or unexpected reboots**
- **Config, channel, or key loss** after flashing or upgrading
- **Regressions** - something that worked on your previous (stable) firmware but is now broken
- **Meshing / DM problems** between a 2.8 node and nodes on other firmware
- **Power regressions** - noticeably worse battery life
---
## Good feedback vs. vague feedback
**Vague:** "It's broken, keeps rebooting."
**Actionable:** "On a `rak4631` flashed with the 2.8 nightly from <date/commit>, the node reboots every time I open the Android app (v2.7.15) and tap Position. Happens every time. Serial log attached, region US."
---
> [!NOTE]
> Thank you for testing. Reports from real hardware - including the boring "everything works" ones - are exactly what let us promote 2.8 from nightly preview to a stable release with confidence.
# Changes
### Radio & mesh protocol
- **Packet Signing via XEdDSA** (#10478) plus a **BaseUI signing status UI** (#10841), unsigned-packet policy hardening with test coverage (#10858), and runtime-toggleable `MESHTASTIC_LOCKDOWN` hardening for nRF52 (#10349, opt-in via #10712).
- **Traffic Management Module** for packet forwarding - dedup, rate limiting, role-aware policing (#9358 base, #10706 dedup/rate-limit expansion, #10745 next-hop cache overflow store, #9921 congestion-aware position interval/hop-exhaustion tuning).
- **Automatic variable hop limits** based on live mesh activity and message-size estimation (#10176).
- **Mesh beacon** feature and admin controls (#10618 base implementation, #10839 second pass adding beacon admin/config).
- **Noise floor** tracking with a sliding-window estimate (#9347).
- **Hash table index for O(1) packet history lookups** - improves routing/dedup performance on busy meshes (#9499).
- New amateur-radio regions: 70cm (#10627), 1.25m/125cm (#10638), 2m/~144MHz (#10623); EU regions merge plus Narrow/Lite region enablement for EU (#10675, #10120); LoRa region preset map for cleaner per-region defaults (#10736).
- **TinyFast and TinySlow modem presets** added to config and menu (#10597).
- LoRa config changes now apply live without a reboot (#9962); LoRa settings expansion and validation improvements (#9878).
- Position privacy: direct-send position packets are clamped to channel precision (#10383), and public/known-key position precision is clamped similarly (#10665) and honors explicit channel settings to prevent location leaks (#10513).
- Licensed operators are now prevented from rebroadcasting packets to/from unlicensed users, for regulatory compliance (#9958).
- Packets with missing/invalid `hop_start` (pre-hop firmware) are now deprecated/blocked (#9476).
- Spoof detection added for UDP multicast packets (#9905).
- Low-bandwidth conversion support added to MeshRadio (#10595).
- ATAK Plugin V2 implemented (drops legacy unishox2 compression) (#10105), including TAKTALK voice/text chat message and room data structures.
- Ethernet HTTP/HTTPS API server ported to RP2350 + W5500 boards (#10573), plus Ethernet OTA support for RP2350/W5500 (#10136).
- Optional `LED_LORA` indicator to show LoRa TX activity (#10465), and an LED indicator for LoRa RX (#10674).
- GPS time sync: device now sets its clock from GPS every 30 minutes (#10737); GPS is skipped at startup if the LoRa region is unset, to save battery (#10386); GPS model/baudrate now cached across reboots to skip a full sweep (#10544).
- Config: **position & telemetry broadcast are now opt-in** rather than always-on (#10929).
- **Extra-repeat tolerance** - device tolerates a configurable number of heard repeats before cancelling its own rebroadcast, with tolerance suppressed when the mesh is busy or dense (recent local branch work).
### UI / display - BaseUI
_BaseUI is the current default graphical UI (`src/graphics/Screen.cpp`, `draw/UIRenderer`, `draw/MenuHandler`, `draw/CompassRenderer`, `draw/NotificationRenderer`, `draw/NodeListRenderer`)._
- **"Ham Mode"** - first implementation (#10663).
- **Color support for TFT-equipped nodes** (#10233).
- Status-message display added to Favorite/NodeList screens (#9504, #10197).
- **Hex picker** UI added for entering hex values (#10650).
- Save/restore of frame visibility state across sessions (#10576).
- BLE pairing PIN now shown via a proper on-screen banner (#8902).
- Compass rendering/behavior improvements (#10166).
- Emote handling refactor (#9896).
### UI / display - InkHUD
_InkHUD is the e-ink-optimized UI (`src/graphics/niche/InkHUD`)._
- **Offline map tiles with zoom controls** (#10785) and general GPS UX improvements (#10846).
- **Full touch support** for the T5 E-Paper S3 (#10286) and a full InkHUD port for the LilyGo T5 E-Paper S3 Pro (#10211).
- **"Wipe all messages"** option (#10721).
- T-mini E-Ink S3 support added (#9856).
### UI / display - MUI
_MUI is the older/legacy graphical UI menu system, still selectable alongside BaseUI (`draw/MenuHandler`'s `MuiPicker`/`switchToMUIMenu`)._
- WiFi map-tile download adapted for Heltec V4 (#10011).
### UI / display - shared / cross-cutting
_Touches the display driver layer or more than one UI system at once._
- InkHUD and BaseUI **message store unified** into a shared implementation (#10596).
- T-mini E-Ink S3 support landed for both InkHUD and BaseUI (#9856).
- Board-specific TFT driver support and simplified TFT ifdef chains for easier porting (#10827, #10803); faster TFT color conversion (#10814); touchscreen variant flags (`VARIANT_TOUCHSCREEN`/`ENABLE_TOUCH_INT`) added for new touch boards (#10815).
## Backend / developer-facing features
### Memory & stability infrastructure
- **MemClass.h** - a central memory-class ladder providing fail-safe-small defaults across constrained platforms (#10901).
- **MemAudit** - per-subsystem heap accounting reported in the boot log (#10900).
- nRF52 heap tiers and SoftDevice RAM reservation right-sized, freeing an extra ~8KB heap arena (#10898, #10903).
- Native Portduino malloc shim added for more realistic memory behavior in simulation (#10677).
- Bluetooth memory freed automatically when Wi-Fi is enabled or Bluetooth is disabled (#10398); Bluetooth wait is skipped entirely when disabled (#10571).
- NodeDB "warm store" - new persistent warm-tier node storage layer (#10705 base, #10746/#10759 right-sizing for constrained platforms, #10809 fixing associated spiLock deadlocks).
- 2.8 NodeDB shrink/decoupling/restructuring to reduce per-node memory footprint (#10413).
- Flash hardening, filesystem platform unification, and a write-behind LFS cache for STM32WL/nRF52 - a storage-format break (#10171).
### New APIs / module-author infrastructure
- **MCP server** added for interacting with Meshtastic devices and driving a testing framework / TUI, later extracted to its own repo (#10194, #10861).
- Native "sensors" simulation support for Portduino (#10748); `PortduinoSetOptions` to override the `realhardware` flag for tests (#10157).
- Hardfault handler added for STM32, making crashes visibly obvious in logs (#10071).
- `BinarySemaphorePosix` implemented with proper pthread synchronization for native builds (#9895).
- NimBLE parameter overhaul, including a fix attempt for incompatible BLE bond cleanup (#10741).
- STM32 ADC support added to `AnalogBatteryLevel` (#9369).
- JSON library dependency removed from firmware builds while retaining full JSON support in meshtasticd (#10152) - reduces firmware footprint for module authors relying on the JSON path.
- Improved manual build flow / developer build ergonomics (#8839).- External Notifications module logic fully reworked for more flexible notification rules (#10006).
+31 -7
View File
@@ -731,7 +731,7 @@ jobs:
# Nightly publish: refresh the root of the meshtastic-firmware-nightly R2
# bucket with the current develop build. Runs on the cron schedule (or a manual
# nightly=true dispatch) and never creates a GitHub release. The bucket's
# release_notes.md is maintained by hand and deliberately left untouched.
# release_notes.md is published from .github/nightly/ in this repo.
publish-nightly:
runs-on: ubuntu-24.04
if: github.repository_owner == 'meshtastic' && (github.event_name == 'schedule' || github.event.inputs.nightly == 'true')
@@ -741,6 +741,11 @@ jobs:
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
r2_bucket: meshtastic-firmware-nightly
steps:
# Only the index templates and release notes are needed here.
- uses: actions/checkout@v7
with:
sparse-checkout: .github/nightly
- name: Get firmware artifacts
uses: actions/download-artifact@v8
with:
@@ -763,6 +768,10 @@ jobs:
'{version: $ver, id: ("v" + $ver), title: ("Meshtastic Firmware " + $ver + " Nightly"), commit: $sha}' \
> ./stage/index.json
# The notes are maintained in-tree and published to the bucket root.
- name: Stage the nightly release notes
run: cp .github/nightly/release_notes.md ./stage/release_notes.md
# For diagnostics
- name: Display structure of files to publish
run: ls -lR ./stage
@@ -782,18 +791,35 @@ jobs:
exit 1
fi
# tree renders the file listing; .github/nightly wraps it in the page
# chrome. tree silently skips an --hintro/--houtro file it cannot open, so
# the rendered page is checked for both markers below.
- name: Generate nightly html index
env:
VERSION: ${{ needs.version.outputs.long }}
COMMIT: ${{ github.sha }}
RUN_ID: ${{ github.run_id }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
working-directory: ./stage
run: |
tree -H "." -T "Meshtastic Nightly $VERSION" --noreport -I "index.html" --charset utf-8 > index.html
set -euo pipefail
# Substitute placeholders in the nightly index header template.
sed -e "s|%%VERSION%%|$VERSION|g" \
-e "s|%%COMMIT%%|$COMMIT|g" \
-e "s|%%COMMIT_SHORT%%|${COMMIT:0:7}|g" \
-e "s|%%BUILD_DATE%%|$(date -u +'%Y-%m-%d %H:%M UTC')|g" \
-e "s|%%RUN_ID%%|$RUN_ID|g" \
-e "s|%%RUN_URL%%|$RUN_URL|g" \
"$GITHUB_WORKSPACE/.github/nightly/hintro.html" > "$RUNNER_TEMP/hintro.html"
# Render the html index using tree, with custom header and footer templates.
tree -H "." -h --noreport -I "index.html" --charset utf-8 \
--hintro "$RUNNER_TEMP/hintro.html" \
--houtro "$GITHUB_WORKSPACE/.github/nightly/houtro.html" \
> index.html
# Mirror the staged directory to Cloudflare R2. --delete at the bucket root
# clears stale nightly binaries, and is in scope for the whole bucket because
# this bucket holds nothing but the nightly build. release_notes.md lives only
# in the bucket and is never staged, so it is excluded from the sync to keep
# --delete from removing it.
# this bucket holds nothing but the nightly build.
- name: Publish nightly to Cloudflare R2
env:
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
@@ -810,12 +836,10 @@ jobs:
set -euo pipefail
aws --version
# Cache for 1 hour in browser, 1 day on CDN.
# Preserve the release_notes.md (manually maintained)
aws s3 sync ./stage "s3://${r2_bucket}/" \
--endpoint-url "$R2_ENDPOINT" \
--no-progress \
--delete \
--exclude 'release_notes.md' \
--exclude 'index.json' \
--exclude 'index.html' \
--metadata "commit=${{ github.sha }},run=${{ github.run_id }}" \
+6
View File
@@ -161,6 +161,12 @@ lint:
- test/test_airtime/test_main.cpp
- test/test_throttle/test_main.cpp
- test/test_uptime_clock/test_main.cpp
# The nightly index templates are halves of one page, not whole documents:
# hintro.html stops mid-<div> and houtro.html starts with closing tags, so
# that `tree --hintro/--houtro` can splice the file listing between them.
- linters: [ALL]
paths:
- .github/nightly/*.html
runtimes:
enabled:
- python@3.14.4