Add repo scaffolding for Colorado-Mesh publish

Adds the project metadata and CI/release workflow needed to publish this
repo under Colorado-Mesh/meshcore-bot-firmware.

- LICENSE: MIT with attribution to upstream MeshCore (also MIT)
- README: rewritten with badges, supported boards, install paths (web
  flasher / PlatformIO / esptool), bot command table, layout map,
  development quickstart
- CONTRIBUTING: submodule + patch-queue workflow, what-goes-where,
  patch hygiene rules, PR expectations
- RELEASE: cmesh-bot-vX.Y.Z tag scheme + procedure
- CHANGELOG: Keep-a-Changelog format, seeded with the hop-coordination
  fix and patch-5 utility commands
- Issue templates: bug_report (with bot stats prompt), feature_request,
  config.yml (no blank issues, link to upstream + community)
- Pull request template: layer checklist, verification gates,
  prefs-schema impact prompt
- .github/workflows/firmware-build.yml: keep PR check on representative
  envs (Heltec V3, RAK 4631 USB+BLE), add concurrency cancellation for
  PRs, scope cache key to PIO config hash
- .github/workflows/release.yml: NEW; triggers on cmesh-bot-v* tag or
  manual dispatch, enumerates all 133 *_companion_radio_(usb|ble) envs
  from vendor/MeshCore/variants/, shards across 8 parallel matrix jobs,
  aggregates artifacts into a single draft release
- scripts/verify.sh: respect MESHCORE_SKIP_APPLY_PATCHES like
  build-representative.sh does, so verify works when vendor already has
  patches applied as commits
- .gitignore: add .forge.bak.*/ for forge backup directories
This commit is contained in:
cj-vana
2026-05-16 13:01:09 -06:00
parent d26979ed94
commit 15c7072d81
13 changed files with 727 additions and 17 deletions

61
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: Bug report
description: Something's broken in the firmware or tooling
labels: [bug]
body:
- type: markdown
attributes:
value: |
Thanks for the report. The more concrete, the faster we can chase it down.
- type: input
id: firmware_version
attributes:
label: Firmware version
description: From `bot` (no args) CLI command, the `version` chat command, or the filename you flashed.
placeholder: cmesh-bot-v1.2.3-abc1234
validations:
required: true
- type: dropdown
id: board
attributes:
label: Board
description: Which PlatformIO env / hardware?
options:
- Heltec V3 (USB)
- Heltec V3 (BLE)
- RAK 4631 (USB)
- RAK 4631 (BLE)
- LilyGo T-Echo
- LilyGo T-Deck
- Xiao S3 WIO
- Other (specify below)
validations:
required: true
- type: textarea
id: symptom
attributes:
label: What happened?
description: What did you observe? What did you expect instead?
validations:
required: true
- type: textarea
id: repro
attributes:
label: Reproduction steps
description: The shortest sequence of actions that reproduces the bug.
placeholder: |
1. Flash cmesh-bot-vX.Y.Z to Heltec V3
2. From another node 3 hops away, send `ping` on #bot
3. Observe: no reply within 30s
validations:
required: true
- type: textarea
id: bot_stats
attributes:
label: bot stats output (if available)
description: Output of `bot` and `bot stats` from the USB CLI rescue console, before and after the trigger.
render: shell
- type: textarea
id: other
attributes:
label: Anything else?
description: Logs, screenshots, hop diagrams, peer node names, etc.

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: MeshCore upstream
url: https://github.com/meshcore-dev/MeshCore/issues
about: Bugs that affect upstream MeshCore (not specific to the Colorado bot patches) should go upstream.
- name: Colorado Mesh community
url: https://github.com/Colorado-Mesh
about: General questions about Colorado Mesh — coverage, joining, hardware recommendations.

View File

@@ -0,0 +1,28 @@
name: Feature request
description: Suggest a new bot command, board, or capability
labels: [enhancement]
body:
- type: textarea
id: motivation
attributes:
label: What problem are you trying to solve?
description: Start with the use case, not the proposed solution.
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposal
description: What command, behavior, or board support would address the problem?
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives you've considered
description: Other commands, workflow changes, off-device tools, etc.
- type: textarea
id: scope
attributes:
label: Anything specific about scope or implementation?
description: e.g. should this be guarded by a CLI toggle? Does it need new bot prefs? Cross-bot coordination?

28
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,28 @@
<!--
Thanks for the PR. A few quick prompts to make review fast.
Delete sections that don't apply.
-->
## Summary
<!-- What changed and why. Lead with the why. -->
## Affected layer
- [ ] MeshCore submodule (`vendor/MeshCore/`) — patches re-exported
- [ ] Wrapper tooling (`scripts/`, `tests/`, `.github/`)
- [ ] Colorado overlay (`colorado/`)
- [ ] Docs only
## Verification
- [ ] `MESHCORE_SKIP_APPLY_PATCHES=1 bash scripts/verify.sh --no-build` passes locally
- [ ] (if firmware changed) Built a representative env and confirmed size impact in `out/size/summary.json`
- [ ] (if behavior changed on the radio) Flashed and tested on real hardware — note the board and what you tried:
> _e.g. Heltec V3, sent `ping`/`trace`/`path` at 0, 2, 4, 6 hops from another node on #bot_
## Bot-prefs schema impact
- [ ] No change to `BotPrefs` shape or default values
- [ ] Schema changed → `BOT_PREFS_VERSION` bumped accordingly
- [ ] N/A

View File

@@ -7,9 +7,15 @@ on:
- main - main
workflow_dispatch: workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs: jobs:
representative-build: representative-build:
name: Representative build (Heltec V3, RAK 4631)
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 30
steps: steps:
- name: Check out repository - name: Check out repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -22,7 +28,9 @@ jobs:
path: | path: |
~/.cache/pip ~/.cache/pip
~/.platformio/.cache ~/.platformio/.cache
key: ${{ runner.os }}-pio key: ${{ runner.os }}-pio-${{ hashFiles('vendor/MeshCore/platformio.ini', 'vendor/MeshCore/variants/**/platformio.ini') }}
restore-keys: |
${{ runner.os }}-pio-
- name: Install Python - name: Install Python
uses: actions/setup-python@v5 uses: actions/setup-python@v5
@@ -32,7 +40,7 @@ jobs:
- name: Install PlatformIO - name: Install PlatformIO
run: python3 -m pip install --upgrade platformio run: python3 -m pip install --upgrade platformio
- name: Run host and safety checks - name: Run host tests and safety checks
run: bash scripts/verify.sh --no-build run: bash scripts/verify.sh --no-build
- name: Build representative firmware - name: Build representative firmware

205
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,205 @@
name: Release
on:
push:
tags:
- 'cmesh-bot-v*'
workflow_dispatch:
inputs:
version:
description: 'Version label to embed (e.g. v1.2.3 or v1.2.3-rc.1). Required for manual runs.'
required: true
type: string
permissions:
contents: write
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
enumerate:
name: Enumerate companion targets
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
version: ${{ steps.version.outputs.version }}
shards: ${{ steps.shards.outputs.shards }}
env_count: ${{ steps.shards.outputs.env_count }}
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Resolve release version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
version="${{ inputs.version }}"
else
tag="${GITHUB_REF#refs/tags/}"
# cmesh-bot-vX.Y.Z[-...] -> vX.Y.Z[-...]
version="${tag#cmesh-bot-}"
fi
if [ -z "$version" ]; then
echo "Could not derive a version label." >&2
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Release version: $version"
- name: Enumerate companion USB+BLE environments and shard
id: shards
run: |
envs=$(grep -rhE '^\[env:' vendor/MeshCore/variants/ \
| sort -u \
| grep -E '_companion_radio_(usb|ble)\]$' \
| sed -e 's/\[env://' -e 's/\]//')
count=$(printf '%s\n' "$envs" | wc -l | tr -d ' ')
echo "env_count=$count" >> "$GITHUB_OUTPUT"
echo "Found $count companion USB+BLE environments."
shards=$(jq -nc '[range(0;8)]')
echo "shards=$shards" >> "$GITHUB_OUTPUT"
build:
name: Build shard ${{ matrix.shard }}/8
needs: enumerate
runs-on: ubuntu-latest
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
shard: ${{ fromJSON(needs.enumerate.outputs.shards) }}
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Cache PlatformIO
uses: actions/cache@v4
with:
path: |
~/.cache/pip
~/.platformio/.cache
~/.platformio/packages
key: ${{ runner.os }}-pio-release-${{ hashFiles('vendor/MeshCore/platformio.ini', 'vendor/MeshCore/variants/**/platformio.ini') }}
restore-keys: |
${{ runner.os }}-pio-release-
${{ runner.os }}-pio-
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install PlatformIO
run: python3 -m pip install --upgrade platformio
- name: Apply patches
run: bash scripts/apply-patches.sh
- name: Select envs for this shard
id: select
run: |
envs=$(grep -rhE '^\[env:' vendor/MeshCore/variants/ \
| sort -u \
| grep -E '_companion_radio_(usb|ble)\]$' \
| sed -e 's/\[env://' -e 's/\]//')
shard_envs=$(printf '%s\n' "$envs" \
| awk -v shard=${{ matrix.shard }} -v total=8 'NR%total==shard')
printf 'envs<<EOF\n%s\nEOF\n' "$shard_envs" >> "$GITHUB_OUTPUT"
shard_count=$(printf '%s\n' "$shard_envs" | grep -c . || true)
echo "Shard ${{ matrix.shard }}: building $shard_count envs"
printf '%s\n' "$shard_envs"
- name: Build firmware
env:
FIRMWARE_VERSION: ${{ needs.enumerate.outputs.version }}
run: |
set -e
mkdir -p out/firmware out/logs
cd vendor/MeshCore
while IFS= read -r env; do
[ -z "$env" ] && continue
log="../../out/logs/$env.log"
echo "::group::Building $env"
if /usr/bin/env bash build.sh build-firmware "$env" 2>&1 | tee "$log"; then
echo "::endgroup::"
if compgen -G "out/$env-*" >/dev/null; then
cp out/"$env"-* ../../out/firmware/
fi
else
echo "::endgroup::"
echo "::error::Build failed for $env (see logs artifact)"
exit 1
fi
done <<< "${{ steps.select.outputs.envs }}"
- name: Upload firmware shard
if: always()
uses: actions/upload-artifact@v4
with:
name: firmware-shard-${{ matrix.shard }}
path: out/firmware
if-no-files-found: warn
retention-days: 14
- name: Upload build logs
if: always()
uses: actions/upload-artifact@v4
with:
name: build-logs-shard-${{ matrix.shard }}
path: out/logs
if-no-files-found: warn
retention-days: 14
release:
name: Publish draft release
needs: [enumerate, build]
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Download all firmware shards
uses: actions/download-artifact@v4
with:
pattern: firmware-shard-*
merge-multiple: true
path: release-firmware
- name: List release artifacts
run: |
count=$(find release-firmware -maxdepth 1 -type f | wc -l | tr -d ' ')
echo "Aggregated $count release artifacts:"
ls -la release-firmware/
- name: Create draft release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
name: Colorado Mesh Bot Firmware ${{ needs.enumerate.outputs.version }}
tag_name: ${{ github.ref_name }}
draft: true
prerelease: ${{ contains(needs.enumerate.outputs.version, '-') }}
generate_release_notes: true
body: |
Companion-radio firmware for the Colorado Mesh.
**Built environments:** ${{ needs.enumerate.outputs.env_count }} companion USB+BLE targets across ESP32, NRF52, RP2040, and STM32 platforms.
See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md) for changes in this version.
### Install
Easiest: flash via [flasher.meshcore.io](https://flasher.meshcore.io) and drag in the right artifact for your board.
- ESP32 boards: `<board>-merged.bin`
- NRF52 boards: `<board>.uf2`
See the [README](https://github.com/${{ github.repository }}#install) for other install methods.
files: release-firmware/*

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.forge/ .forge/
.forge.bak.*/
out/ out/
.venv/ .venv/
__pycache__/ __pycache__/

35
CHANGELOG.md Normal file
View File

@@ -0,0 +1,35 @@
# Changelog
All notable changes to this firmware are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versioning
follows the `cmesh-bot-vX.Y.Z` scheme described in [RELEASE.md](RELEASE.md).
## [Unreleased]
### Added
- Hop-aware response coordination: bot delays its reply proportional to
the sender's hop count so the closest bot wins; far bots suppress.
- Utility commands: `time`, `lora`, `id`, `neighbors`.
- Neighbor tracking: bot remembers nodes heard directly within the last
hour for the `neighbors` command.
- `received_at_timestamp` field on bot messages; personalized ack target
in command context.
- Comprehensive repository scaffolding: README, CONTRIBUTING, LICENSE,
CHANGELOG, RELEASE doc, issue/PR templates, release workflow building
all 133 companion USB+BLE environments.
### Changed
- `BOT_HOP_STEP_MILLIS_DEFAULT` lowered from 5000 to 1500 ms per hop.
- Added `BOT_HOP_BIAS_MAX_MILLIS` cap of 8000 ms on the total hop bias.
- `BOT_RESPONSE_PENDING_TTL_MILLIS` raised from 15000 to 45000 ms.
- `BOT_PREFS_VERSION` bumped 2 → 3 to force re-default of in-the-wild
bots that saved the broken 5000 ms hop-step value.
### Fixed
- Multi-hop senders on `#bot` no longer get silently ignored. Previously
3+ hop responses scheduled past the 15 s TTL and were dropped by the
coordinator's `poll()` as `READY_EXPIRED`. Verified on a Heltec V3
bench bot replying at 2, 4, and 6 hops.

103
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,103 @@
# Contributing to Colorado Mesh Bot Firmware
Thanks for your interest. This repo is a thin wrapper around upstream
MeshCore: most firmware code lives in `vendor/MeshCore/` (a git submodule)
and is applied via the patch queue in `patches/meshcore/`. Colorado-only
overlay files, tests, and tooling live at the wrapper level.
## Quick reference
| Task | Command |
|---|---|
| Bootstrap | `git submodule update --init --recursive && bash scripts/apply-patches.sh` |
| Run host tests + safety checks | `MESHCORE_SKIP_APPLY_PATCHES=1 bash scripts/verify.sh --no-build` |
| Build representative firmwares | `bash scripts/build-representative.sh --baseline` |
| Export patch queue after edits | `bash scripts/export-patches.sh origin/main` |
## Development workflow
The submodule is a real git repo. Iterate inside it like normal:
1. **Bootstrap once** (clone with `--recurse-submodules`, or run
`git submodule update --init --recursive`).
2. **Apply patches** with `bash scripts/apply-patches.sh`. This commits the
patch queue on top of `origin/main` in the submodule, leaving you with
a clean tree pinned to a known state.
3. **Make changes inside `vendor/MeshCore/`** — edit files, run
`pio run -e <env>` to compile, commit your changes in the submodule
with descriptive messages.
4. **Re-export the patch queue** with
`bash scripts/export-patches.sh origin/main`. This deletes
`patches/meshcore/*.patch` and regenerates it from the submodule
commits since `origin/main`. Each patch corresponds to one submodule
commit, so keep commits small and focused.
5. **Run host tests** (`python3 tests/firmware_bot/run_tests.py`) — fast,
no hardware needed.
6. **Run safety checks** (`bash scripts/check-bot-safety.sh`) — verifies
the firmware doesn't expose private keys, network bridges, or other
debug-only features in release builds.
7. **(Optional) Build representative envs** with
`bash scripts/build-representative.sh --baseline` to confirm the
binaries still link and to inspect size impact in `out/size/summary.json`.
8. **Commit at the wrapper level** with the regenerated patches, any
test/script changes, and the updated submodule pointer. PR-ready.
## What goes where
- **Firmware/library code that MUST live inside MeshCore** for PlatformIO
builds — develop inside `vendor/MeshCore/`, export as a patch.
- **Test code (host-side C++ tests)** — `tests/firmware_bot/` at the
wrapper level. They `#include` MeshCore headers via the script's `-I`
flag.
- **Tooling, build scripts, CI** — `scripts/` and `.github/` at the
wrapper level.
- **Colorado-specific docs, fixtures, board notes** — `colorado/`.
## Patch hygiene
- One conceptual change per patch / submodule commit.
- Prefer additive changes (`#if CMESH_BOT_ENABLED` guards, new files in
`examples/companion_radio/`) over edits to broadly-used upstream code.
This keeps merges with upstream MeshCore manageable.
- When changing a stored format (e.g., bot prefs), bump
`BOT_PREFS_VERSION` so deployed bots reset to the new defaults
instead of loading broken legacy state.
- Add a host test for new behavior whenever it's testable without
hardware. The bot has 48+ host tests covering the registry, parser,
policy, coordinator, and command output strings.
## CI
PRs run `.github/workflows/firmware-build.yml`, which:
1. Runs host tests + safety checks (`scripts/verify.sh --no-build`).
2. Builds the four representative companion environments (Heltec V3 and
RAK 4631, USB + BLE).
3. Uploads firmware + size reports as workflow artifacts.
Releases run `.github/workflows/release.yml` on `cmesh-bot-v*` tags and
build all 133 companion USB+BLE environments — see [RELEASE.md](RELEASE.md).
## Pull request expectations
- One PR per logical change. Bundle related patches; keep unrelated work
in separate PRs.
- Describe the **why** as well as the what.
- If you touched response timing, coordination, or anything that could
silently drop messages, include a host test that exercises the
failure mode and explain how you verified on hardware (which boards,
what commands, what hop counts).
- CI must be green.
- Don't commit `.forge/` workflow artifacts, the `.venv/` directory, or
PlatformIO build output. They're gitignored.
## Reporting bugs
[Open an issue](https://github.com/Colorado-Mesh/meshcore-bot-firmware/issues/new/choose).
For firmware bugs, include the output of `bot stats` (over USB CLI rescue),
the firmware version, board, and a minimal reproduction.
## Code of conduct
Be respectful, be patient, assume good faith. We're all volunteers building
infrastructure for a mesh community.

26
LICENSE Normal file
View File

@@ -0,0 +1,26 @@
MIT License
Copyright (c) 2026 Colorado Mesh contributors
Portions of this repository are derived from MeshCore (https://github.com/meshcore-dev/MeshCore),
Copyright (c) 2025 Scott Powell / rippleradios.com, used under the MIT License. The
upstream MeshCore source is included as a git submodule under vendor/MeshCore and
retains its original license notice in vendor/MeshCore/license.txt.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

152
README.md
View File

@@ -1,15 +1,123 @@
# Colorado MeshCore Bot Firmware # Colorado Mesh Bot Firmware
Wrapper repository for Colorado Mesh firmware-only bot work on top of upstream MeshCore companion firmware. [![Firmware Build](https://github.com/Colorado-Mesh/meshcore-bot-firmware/actions/workflows/firmware-build.yml/badge.svg)](https://github.com/Colorado-Mesh/meshcore-bot-firmware/actions/workflows/firmware-build.yml)
[![Latest Release](https://img.shields.io/github/v/release/Colorado-Mesh/meshcore-bot-firmware?include_prereleases&sort=semver)](https://github.com/Colorado-Mesh/meshcore-bot-firmware/releases)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
Companion-radio firmware for the Colorado Mesh community, built on top of
[MeshCore](https://github.com/meshcore-dev/MeshCore). It adds an in-firmware
"firmware bot" that responds to chat commands like `ping`, `trace`, `path`,
`status`, `neighbors`, and `magic8`, with multi-bot response coordination so
nearby Colorado bots don't all reply at once.
The bot runs entirely on-device — no internet, no companion-app bridge, no
cloud. Useful as a low-friction probe / utility node on the Colorado mesh.
## What's different from upstream MeshCore
The release-built firmware applies a patch queue (`patches/meshcore/`) on top
of a pinned MeshCore commit. The patches add:
- A bot command registry (`help`, `cmd`, `ping`, `test`, `hello`, `about`,
`roll`, `dice`, `status`, `channels`, `version`, `stats`, `magic8`, `path`,
`trace`, `tracer`, `prefix`, `time`, `lora`, `id`, `neighbors`)
- Channel-aware response policy (`#bot`, `#testing` for normal commands;
`#emergency` for emergency forwards to `Public`; all other channels ignored)
- Multi-bot response coordinator with hop-aware delay, bounded TTL, and
fingerprint-based suppression so duplicates are avoided across the mesh
- Direct-message (DM) prefixless command parsing
- Two-byte path hash default for compact traces
- Private-key import/export disabled in release builds
- Host-side bot prefs (CLI tunable channels, delay, advert intervals,
known-bot list)
See `patches/meshcore/` for the full set; each patch is a standalone commit
re-exported from the submodule.
## Supported boards
The release workflow builds **every** `*_companion_radio_usb` and
`*_companion_radio_ble` PlatformIO environment exposed by upstream MeshCore
— 133 boards across ESP32, NRF52, RP2040, and STM32 platforms (Heltec V3,
RAK 4631, LilyGo T-Echo, T-Beam, T-Deck, Xiao S3, Nano G2, ThinkNode,
Meshtiny, Pico W, and many more). See the
[latest release assets](https://github.com/Colorado-Mesh/meshcore-bot-firmware/releases/latest)
for the full list.
PR CI builds a smaller "representative" matrix (Heltec V3 USB+BLE, RAK 4631
USB+BLE) on every push, so the most common boards get fast feedback.
## Install
Three ways to flash:
### MeshCore web flasher (easiest)
1. Open [flasher.meshcore.io](https://flasher.meshcore.io) in Chrome/Edge.
2. Pick "Custom firmware" and drag in the `*-merged.bin` (ESP32) or `*.uf2`
(NRF52) file from the
[latest release](https://github.com/Colorado-Mesh/meshcore-bot-firmware/releases/latest)
for your board.
3. Plug the board in, click "Connect", and flash.
### PlatformIO (from source)
```sh
git clone --recurse-submodules https://github.com/Colorado-Mesh/meshcore-bot-firmware.git
cd meshcore-bot-firmware
python3 -m venv .venv && .venv/bin/python -m pip install --upgrade platformio
bash scripts/apply-patches.sh
cd vendor/MeshCore
pio run -e Heltec_v3_companion_radio_usb -t upload --upload-port /dev/cu.usbserial-0001
```
Swap the env name for your board (see
`grep -rE '^\[env:' vendor/MeshCore/variants/`).
### esptool / nrfutil (manual)
ESP32 boards: `esptool.py write_flash 0x0 <board>-merged.bin`
NRF52 boards: drag the `.uf2` onto the bootloader mass-storage volume, or
use `adafruit-nrfutil dfu serial -pkg <board>.zip -p <port>`.
## Using the bot
Once flashed, the bot joins the channels configured in its prefs. By default
those are `#bot`, `#testing`, `#emergency`, and `Public`. Send commands on
`#bot` (or DM the bot directly) without any prefix — for example:
| Command | Response |
|---|---|
| `ping` | `Pong` |
| `hello` | `Hello @[<your-name>], from <bot-name>` |
| `path` | Compact route summary back to you, e.g. `Path 3h@2B SNR -6.25 \| 2751 -> ea4d -> 430d` |
| `trace` | Active trace request along your reverse path |
| `status` | Bot uptime, battery, storage, send counters |
| `neighbors` | Nodes heard directly within the last hour |
| `version` | Firmware version + build date |
| `magic8 <question>` | Classic 8-ball answer |
| `help` | List all commands |
In any other channel the bot stays silent (except `#emergency`, which it
re-forwards to `Public`).
If you're testing alongside other Colorado bots, the response coordinator
adds a hop-aware delay (~1.5 s per hop, capped at 8 s) so the closest bot
wins the race and others suppress. This avoids spam on the channel.
## Layout ## Layout
- `vendor/MeshCore/` — pinned upstream MeshCore submodule. - `vendor/MeshCore/` — pinned upstream MeshCore submodule.
- `patches/meshcore/` — ordered patch queue applied to the submodule. - `patches/meshcore/` — ordered patch queue applied to the submodule.
- `colorado/` — Colorado Mesh overlay files, fixtures, and notes. - `colorado/` — Colorado Mesh overlay files, fixtures, and notes.
- `scripts/` — wrapper scripts for patch and build workflows. - `scripts/` — wrapper scripts for patch, build, verify, and size-report
workflows.
- `tests/firmware_bot/` — host-side C++ unit tests for the bot code
(compile and run on your machine, no hardware required).
- `.github/workflows/` — PR CI (`firmware-build.yml`) and tag-driven release
(`release.yml`).
## Patch workflow ## Local development
Initialize the submodule and apply patches: Initialize the submodule and apply patches:
@@ -18,25 +126,41 @@ git submodule update --init --recursive
bash scripts/apply-patches.sh bash scripts/apply-patches.sh
``` ```
Develop firmware changes in `vendor/MeshCore`, commit them in that submodule worktree, then export the patch queue: Make firmware changes inside `vendor/MeshCore`, commit them in the submodule
worktree, then export the patch queue:
```sh ```sh
bash scripts/export-patches.sh origin/main bash scripts/export-patches.sh origin/main
``` ```
## Representative builds Build the four representative companion environments and write size reports:
Build the release-gate companion environments and write size reports:
```sh ```sh
bash scripts/build-representative.sh --baseline bash scripts/build-representative.sh --baseline
``` ```
The build writes PlatformIO logs and `summary.json` to `out/size/`, and copied firmware artifacts to `out/firmware/`. Run host tests + safety checks:
Representative companion build environments: ```sh
python3 tests/firmware_bot/run_tests.py
bash scripts/check-bot-safety.sh
# Or all in one go:
MESHCORE_SKIP_APPLY_PATCHES=1 bash scripts/verify.sh --no-build
```
- `Heltec_v3_companion_radio_usb` ## Releases
- `Heltec_v3_companion_radio_ble`
- `RAK_4631_companion_radio_usb` Releases are cut by pushing a `cmesh-bot-vX.Y.Z` tag. See
- `RAK_4631_companion_radio_ble` [RELEASE.md](RELEASE.md) for the full procedure.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). The short version: edit inside
`vendor/MeshCore`, re-export the patch queue, run `verify.sh`, open a PR.
Patches stay in `patches/meshcore/` so reviewers can see exactly what
deviates from upstream.
## License
MIT, including upstream MeshCore. See [LICENSE](LICENSE) and
[vendor/MeshCore/license.txt](vendor/MeshCore/license.txt).

81
RELEASE.md Normal file
View File

@@ -0,0 +1,81 @@
# Cutting a release
Releases are produced by pushing a `cmesh-bot-vX.Y.Z` tag. The
`.github/workflows/release.yml` workflow then:
1. Builds **every** companion USB+BLE environment exposed by the pinned
MeshCore submodule (133 boards as of this writing).
2. Splits the build across 8 parallel matrix shards for wall-time.
3. Embeds the tag version (`vX.Y.Z`) into the firmware via
`FIRMWARE_VERSION`.
4. Uploads each shard's artifacts.
5. Aggregates everything into a single GitHub Release in draft state,
ready for you to add release notes and publish.
## Prerequisites
- All PRs for the release are merged to `main`.
- CI on `main` is green (host tests + representative builds).
- You've updated `CHANGELOG.md` with notes for the new version.
- Your local branch is up to date with `origin/main`.
## Steps
```sh
git checkout main
git pull origin main
# Bump CHANGELOG.md, commit, push.
$EDITOR CHANGELOG.md
git commit -am "docs: prep cmesh-bot-vX.Y.Z release notes"
git push origin main
# Tag and push.
git tag -a cmesh-bot-vX.Y.Z -m "Colorado Mesh Bot Firmware vX.Y.Z"
git push origin cmesh-bot-vX.Y.Z
```
The `release.yml` workflow will start automatically. Track progress at
<https://github.com/Colorado-Mesh/meshcore-bot-firmware/actions>.
When the workflow finishes, a **draft** release will appear at
<https://github.com/Colorado-Mesh/meshcore-bot-firmware/releases>.
Review it, paste in the CHANGELOG entry as the description, and publish.
## Tag scheme
- `cmesh-bot-vX.Y.Z` — production release.
- `cmesh-bot-vX.Y.Z-rc.N` — release candidate (still publishes as draft).
- `cmesh-bot-vX.Y.Z-alpha.N` / `-beta.N` — pre-release, mark as
pre-release when publishing.
The leading `cmesh-bot-` namespace leaves room for future variants
(repeater, room-server) without colliding.
## Versioning
Semantic-ish: bump major for breaking pref/protocol changes, minor for
new commands or boards, patch for fixes. Bump `BOT_PREFS_VERSION` in
`vendor/MeshCore/examples/companion_radio/BotTypes.h` whenever an
existing pref field's meaning or default changes — that forces deployed
bots to reset prefs on first boot.
## Hotfix / unpublish
If a published release turns out to be broken:
1. Mark it as a pre-release (don't delete — flashed devices may still
reference the URL).
2. Tag and publish `cmesh-bot-vX.Y.(Z+1)` immediately.
3. Edit the broken release's notes to point at the fix.
If you tagged the wrong commit and the workflow hasn't finished:
```sh
git tag -d cmesh-bot-vX.Y.Z
git push --delete origin cmesh-bot-vX.Y.Z
# fix, re-tag, re-push
```
Avoid deleting tags after the workflow has published artifacts — users
may have already downloaded them.

View File

@@ -42,7 +42,9 @@ if [ ! -d "${MESHCORE_DIR}/.git" ] && [ ! -f "${MESHCORE_DIR}/.git" ]; then
exit 1 exit 1
fi fi
if ! git -C "${MESHCORE_DIR}" diff --quiet --cached || ! git -C "${MESHCORE_DIR}" diff --quiet || [ -n "$(git -C "${MESHCORE_DIR}" ls-files --others --exclude-standard)" ]; then if [ "${MESHCORE_SKIP_APPLY_PATCHES:-0}" = "1" ]; then
echo "Skipping MeshCore patch application; using current vendor/MeshCore tree."
elif ! git -C "${MESHCORE_DIR}" diff --quiet --cached || ! git -C "${MESHCORE_DIR}" diff --quiet || [ -n "$(git -C "${MESHCORE_DIR}" ls-files --others --exclude-standard)" ]; then
echo "MeshCore submodule is dirty; verify existing patched tree without applying patches." echo "MeshCore submodule is dirty; verify existing patched tree without applying patches."
else else
"${MESHCORE_FW_ROOT}/scripts/apply-patches.sh" "${MESHCORE_FW_ROOT}/scripts/apply-patches.sh"