Compare commits

..

16 Commits

Author SHA1 Message Date
Matthias Wientapper
3471b1c4e0 v0.1.5 build 2026-01-28 20:33:47 +01:00
Matthias Wientapper
ae7e9e9aee platformio.ini: Adjust defaults for LoRa frequncies 2026-01-28 18:12:31 +01:00
Matthias Wientapper
9fd74008c0 Integration of upstrem PR #1297 2026-01-28 18:10:54 +01:00
Matthias Wientapper
69a514fcaa Integration of upstrem PR #1338 2026-01-28 18:10:42 +01:00
Matthias Wientapper
49721ff05a Merge branch 'evo-build-scripts' into meshcore-evo_20260128 2026-01-28 18:10:21 +01:00
Matthias Wientapper
c571323813 Merge branch 'dev' into meshcore-evo 2026-01-28 18:09:47 +01:00
Matthias Wientapper
4a9137bf00 Remove PR-1199 as its functionality is part of dev now 2026-01-26 12:47:35 +01:00
Matthias Wientapper
864a0c0421 Set default to EU/UK narrow 2026-01-26 12:45:45 +01:00
Matthias Wientapper
4bcbd54964 Merge branch 'dev' into meshcore-evo 2026-01-26 12:16:06 +01:00
Matthias Wientapper
cb11809dff Merge branch 'dev' into meshcore-evo 2026-01-26 11:10:20 +01:00
Matthias Wientapper
58decb74b8 Fix fetching same PR twice under wrong name 2026-01-26 11:09:03 +01:00
Matthias Wientapper
e6cab77670 Add scripts to help automate the fw build process 2026-01-21 09:54:56 +01:00
Matthias Wientapper
7682f1085c Merge branch 'dev' of github.com:meshcore-dev/MeshCore into meshcore-evo 2026-01-17 14:08:39 +01:00
Matthias Wientapper
4fd7aa6ce8 Merge branch 'dev' into meshcore-evo 2026-01-13 23:21:57 +01:00
Matthias Wientapper
94d44eb47c Merge branch 'dev' into meshcore-evo 2026-01-10 20:37:27 +01:00
Matthias Wientapper
f8f9cddb47 Integrate pending PRs from upstream repository 2026-01-09 23:23:39 +01:00
26 changed files with 634 additions and 479 deletions

View File

@@ -1,36 +0,0 @@
name: Build and deploy Docs site to GitHub Pages
on:
workflow_dispatch:
push:
branches:
- main
permissions:
contents: write
jobs:
github-pages:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
ruby-version: 3.x
- name: Build
run: |
pip install mkdocs-material
mkdocs build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
cname: docs.meshcore.nz
publish_dir: ./site
publish_branch: 'gh-pages'

1
CNAME
View File

@@ -1 +0,0 @@
docs.meshcore.nz

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 139 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="M3.232,3.582C2.789,3.582 2.368,3.934 2.289,4.369L0.013,16.964C-0.066,17.399 0.229,17.751 0.671,17.751L3.087,17.751C3.529,17.751 3.951,17.399 4.03,16.964L4.935,11.951L6.592,17.293C6.672,17.572 6.923,17.751 7.235,17.751L10.434,17.751C10.746,17.751 11.062,17.572 11.243,17.293L14.835,11.925L13.924,16.964C13.844,17.399 14.14,17.751 14.583,17.751L16.998,17.751C17.44,17.751 17.862,17.399 17.941,16.964L20.217,4.369C20.298,3.934 20.002,3.582 19.56,3.582L16.46,3.582C16.147,3.582 15.831,3.761 15.65,4.04L9.76,12.872C9.668,13.013 9.446,12.975 9.397,12.81L6.976,4.04C6.895,3.761 6.645,3.582 6.332,3.582L3.232,3.582Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M20.853,17.751C20.853,17.751 32.797,17.751 32.797,17.751C33.063,17.751 33.317,17.538 33.364,17.278L33.863,14.504C33.91,14.242 33.733,14.031 33.467,14.031L25.166,14.031C25.077,14.031 25.019,13.96 25.034,13.873L25.281,12.508C25.296,12.421 25.38,12.35 25.469,12.35L32.146,12.35C32.411,12.35 32.665,12.137 32.712,11.877L33.157,9.421C33.204,9.159 33.027,8.949 32.761,8.949L26.085,8.949C25.996,8.949 25.938,8.877 25.953,8.79L26.216,7.328C26.232,7.241 26.316,7.17 26.405,7.17L34.706,7.17C34.971,7.17 35.226,6.957 35.272,6.695L35.756,4.021C35.804,3.761 35.627,3.548 35.361,3.548L23.417,3.548C22.975,3.548 22.551,3.902 22.473,4.337L20.191,16.962C20.114,17.397 20.409,17.751 20.853,17.751Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M45.291,17.749L45.291,17.751L45.705,17.751C47.783,17.751 49.767,16.095 50.136,14.052L50.375,12.727C50.744,10.685 49.359,9.029 47.28,9.029L40.882,9.029C40.617,9.029 40.44,8.818 40.487,8.556L40.649,7.664C40.696,7.402 40.95,7.191 41.215,7.191L49.87,7.191C50.313,7.191 50.735,6.839 50.814,6.404L51.183,4.368C51.262,3.931 50.966,3.579 50.523,3.579L41.063,3.579C38.985,3.579 37,5.235 36.631,7.278L36.37,8.723C36.001,10.767 37.386,12.422 39.465,12.422L45.863,12.422C46.128,12.422 46.305,12.633 46.258,12.895L46.138,13.565C46.091,13.826 45.837,14.037 45.571,14.037L36.675,14.037C36.233,14.037 35.811,14.389 35.732,14.824L35.346,16.962C35.267,17.397 35.562,17.749 36.005,17.749L45.291,17.749Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M67.068,3.575C67.068,3.575 64.393,3.575 64.393,3.575C63.951,3.575 63.529,3.927 63.45,4.361L62.654,8.766C62.639,8.853 62.554,8.923 62.466,8.923L57.282,8.923C57.193,8.923 57.135,8.853 57.15,8.766L57.946,4.361C58.023,3.927 57.73,3.575 57.287,3.575L54.613,3.575C54.17,3.575 53.748,3.927 53.669,4.361L51.392,16.964C51.313,17.399 51.608,17.751 52.05,17.751L54.725,17.751C55.168,17.751 55.589,17.399 55.668,16.964L56.48,12.478C56.495,12.392 56.58,12.32 56.668,12.32L61.852,12.32C61.941,12.32 61.999,12.39 61.984,12.478L61.174,16.964C61.096,17.399 61.391,17.751 61.834,17.751L64.508,17.751C64.951,17.751 65.372,17.399 65.451,16.964L67.729,4.361C67.804,3.927 67.511,3.575 67.068,3.575Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M71.102,17.751C71.102,17.751 78.96,17.751 78.96,17.751C79.402,17.751 79.824,17.399 79.903,16.964L80.288,14.824C80.367,14.389 80.072,14.037 79.629,14.037L72.808,14.037C72.542,14.037 72.365,13.826 72.412,13.565L73.48,7.686C73.527,7.426 73.781,7.213 74.045,7.213L80.866,7.213C81.309,7.213 81.73,6.861 81.81,6.427L82.188,4.335C82.267,3.9 81.971,3.548 81.529,3.548L73.691,3.548C71.618,3.548 69.638,5.197 69.265,7.234L68.011,14.046C67.639,16.091 69.022,17.751 71.102,17.751Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M95.833,3.529C95.833,3.529 87.654,3.529 87.654,3.529C85.576,3.529 83.592,5.186 83.223,7.228L81.99,14.052C81.621,16.094 83.006,17.751 85.084,17.751L93.263,17.751C95.341,17.751 97.326,16.095 97.695,14.052L98.928,7.228C99.297,5.186 97.911,3.529 95.833,3.529ZM93.488,13.567C93.44,13.828 93.186,14.039 92.921,14.039L86.762,14.039C86.496,14.039 86.319,13.828 86.366,13.567L87.434,7.663C87.481,7.402 87.735,7.191 88,7.191L94.157,7.191C94.423,7.191 94.6,7.402 94.553,7.663L93.488,13.567Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M99.884,17.751L102.557,17.751C102.999,17.751 103.421,17.399 103.5,16.965L103.973,14.348C103.988,14.261 104.073,14.19 104.161,14.19L107.397,14.186C107.557,14.186 107.69,14.265 107.756,14.395L109.281,17.37C109.458,17.722 109.78,17.764 110.751,17.749C111.32,17.756 112.184,17.713 113.577,17.713C114.025,17.713 114.3,17.244 114.079,16.853L112.413,13.953C112.37,13.876 112.417,13.772 112.509,13.727C113.795,13.102 114.814,11.889 115.068,10.487L115.649,7.262C116.02,5.218 114.635,3.562 112.557,3.562L102.448,3.562C102.006,3.562 101.584,3.914 101.505,4.349L99.225,16.964C99.146,17.399 99.442,17.751 99.884,17.751L99.884,17.751ZM105.255,7.268C105.27,7.181 105.354,7.11 105.443,7.11L110.674,7.11C111.069,7.11 111.331,7.424 111.261,7.812L110.877,9.933C110.806,10.319 110.431,10.634 110.038,10.634L104.806,10.634C104.718,10.634 104.66,10.564 104.675,10.475L105.255,7.268Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M116.642,17.751C116.642,17.751 128.586,17.751 128.586,17.751C128.851,17.751 129.105,17.538 129.152,17.278L129.651,14.504C129.698,14.242 129.521,14.031 129.256,14.031L120.955,14.031C120.866,14.031 120.808,13.96 120.823,13.873L121.069,12.508C121.084,12.421 121.169,12.35 121.257,12.35L127.934,12.35C128.2,12.35 128.454,12.137 128.501,11.877L128.945,9.421C128.992,9.159 128.815,8.949 128.55,8.949L121.873,8.949C121.785,8.949 121.726,8.877 121.741,8.79L122.005,7.328C122.02,7.241 122.105,7.17 122.193,7.17L130.495,7.17C130.76,7.17 131.014,6.957 131.061,6.695L131.545,4.021C131.592,3.761 131.415,3.548 131.15,3.548L119.206,3.548C118.763,3.548 118.34,3.902 118.261,4.337L115.98,16.962C115.902,17.397 116.198,17.751 116.642,17.751Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M134.674,0C134.674,0 132.059,0 132.059,0C131.965,0 131.877,0.074 131.86,0.166L131.783,0.594C131.766,0.686 131.828,0.76 131.921,0.76L132.745,0.76C132.764,0.76 132.776,0.775 132.773,0.793L132.406,2.819C132.39,2.91 132.452,2.984 132.545,2.984L133.108,2.984C133.201,2.984 133.29,2.91 133.307,2.819L133.673,0.793C133.676,0.775 133.694,0.76 133.713,0.76L134.536,0.76C134.629,0.76 134.718,0.686 134.735,0.594L134.812,0.166C134.828,0.074 134.767,0 134.674,0Z" style="fill:white;fill-rule:nonzero;"/>
<path d="M135.278,0.002C135.185,0.002 135.096,0.076 135.079,0.167L134.6,2.819C134.583,2.91 134.646,2.984 134.739,2.984L135.247,2.984C135.34,2.984 135.429,2.91 135.446,2.819L135.636,1.763L135.985,2.888C136.002,2.947 136.055,2.984 136.121,2.984L136.794,2.984C136.86,2.984 136.926,2.947 136.964,2.888L137.72,1.758L137.528,2.819C137.512,2.91 137.574,2.984 137.667,2.984L138.176,2.984C138.269,2.984 138.358,2.91 138.374,2.819L138.853,0.167C138.87,0.076 138.808,0.002 138.715,0.002L138.062,0.002C137.997,0.002 137.93,0.039 137.892,0.098L136.652,1.957C136.633,1.987 136.586,1.979 136.575,1.944L136.066,0.098C136.049,0.039 135.996,0.002 135.93,0.002L135.278,0.002Z" style="fill:white;fill-rule:nonzero;"/>
</svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -1,16 +0,0 @@
:root {
--md-primary-fg-color: #1F2937;
--md-primary-fg-color--light: #1F2937;
--md-primary-fg-color--dark: #1F2937;
--md-accent-fg-color: #1F2937;
}
/* hide git repo version */
.md-source__fact--version {
display: none;
}
/* underline links */
.md-typeset a {
text-decoration: underline;
}

View File

@@ -1,6 +1,4 @@
# CLI Commands
This document provides an overview of CLI commands that can be sent to MeshCore Repeaters, Room Servers and Sensors.
# MeshCore Repeater & Room Server CLI Commands
## Navigation

View File

@@ -1,13 +0,0 @@
# Local Documentation
This document explains how to build and view the MeshCore documentation locally.
## Building and viewing Docs
```
pip install mkdocs
pip install mkdocs-material
```
- `mkdocs serve` - Start the live-reloading docs server.
- `mkdocs build` - Build the documentation site.

View File

@@ -1,7 +1,12 @@
# Frequently Asked Questions
**MeshCore-FAQ**<!-- omit from toc -->
A list of frequently-asked questions and answers for MeshCore
The current version of this MeshCore FAQ is at https://github.com/meshcore-dev/MeshCore/blob/main/docs/faq.md.
This MeshCore FAQ is also mirrored at https://github.com/LitBomb/MeshCore-FAQ and might have newer updates if pull requests on Scott's MeshCore repo are not approved yet.
author: https://github.com/LitBomb<!-- omit from toc -->
---
- [1. Introduction](#1-introduction)
- [1.1. Q: What is MeshCore?](#11-q-what-is-meshcore)
- [1.2. Q: What do you need to start using MeshCore?](#12-q-what-do-you-need-to-start-using-meshcore)
@@ -107,15 +112,15 @@ Anyone is able to build anything they like on top of MeshCore without paying any
### 1.2. Q: What do you need to start using MeshCore?
**A:** Everything you need for MeshCore is available at:
Main web site: [https://meshcore.co.uk/](https://meshcore.co.uk/)
Firmware Flasher: https://flasher.meshcore.co.uk/
Phone Client Applications: https://meshcore.co.uk/apps.html
MeshCore Firmware GitHub: https://github.com/ripplebiz/MeshCore
- Main web site: [https://meshcore.co.uk](https://meshcore.co.uk)
- Firmware Flasher: [https://flasher.meshcore.co.uk](https://flasher.meshcore.co.uk)
- MeshCore Firmware on GitHub: [https://github.com/meshcore-dev/MeshCore](https://github.com/meshcore-dev/MeshCore)
- MeshCore Companion App: [https://meshcore.nz](https://meshcore.nz)
- MeshCore Map: [https://meshcore.co.uk/map.html](https://meshcore.co.uk/map.html)
- Andy Kirby has a very useful [intro video](https://www.youtube.com/watch?v=t1qne8uJBAc) for beginners.
NOTE: Andy Kirby has a very useful [intro video](https://www.youtube.com/watch?v=t1qne8uJBAc) for beginners.
You need LoRa hardware devices to run MeshCore firmware as clients or server (repeater and room server).
You need LoRa hardware devices to run MeshCore firmware as clients or server (repeater and room server).
#### 1.2.1. Hardware
MeshCore is available on a variety of 433MHz, 868MHz and 915MHz LoRa devices. For example, Lilygo T-Deck, T-Pager, RAK Wireless WisBlock RAK4631 devices (e.g. 19003, 19007, 19026), Heltec V3, Xiao S3 WIO, Xiao C3, Heltec T114, Station G2, Nano G2 Ultra, Seeed Studio T1000-E. More devices are being added regularly.
@@ -290,7 +295,7 @@ This is a very low cost operation. AGC reset is done by simply setting `state =
### 3.8 Q: How do I make my repeater an observer on the mesh
**A:** The observer instruction is available here: https://analyzer.letsmesh.net/observer/onboard
**A:** The observer instruction is available here: https://analyzer.letsme.sh/observer/onboard
---
@@ -530,7 +535,7 @@ MeshCore clients would need to reset path constantly and flood traffic across th
This could change in the future if MeshCore develops a client firmware that repeats.
[Source](https://discord.com/channels/826570251612323860/1330643963501351004/1354780032140054659)
### 5.12. Q: How do I add a node to the [MeshCore Map](https://meshcore.co.uk/map.html)
### 5.12. Q: How do I add a node to the [MeshCore Map]([url](https://meshcore.co.uk/map.html))
**A:**
To add a BLE Companion radio, connect to the BLE Companion radio from the MeshCore smartphone app. In the app, tap the `3 dot` menu icon at the top right corner, then tap `Internet Map`. Tap the `3 dot` menu icon again and choose `Add me to the Map`
@@ -607,7 +612,7 @@ From here, reference repeater and room server command line commands on MeshCore
**A:** Yes. See the following:
#### 5.14.1. meshcoremqtt
A Python script to send meshcore debug and packet capture data to MQTT for analysis. Cisien's version is a fork of Andrew-a-g's and is being used to to collect data for https://map.w0z.is/messages and https://analyzer.letsmesh.net/
A Python script to send meshcore debug and packet capture data to MQTT for analysis. Cisien's version is a fork of Andrew-a-g's and is being used to to collect data for https://map.w0z.is/messages and https://analyzer.letsme.sh/
https://github.com/Cisien/meshcoretomqtt
https://github.com/Andrew-a-g/meshcoretomqtt
@@ -632,7 +637,7 @@ pyMC_Core is a Python port of MeshCore, designed for Raspberry Pi and similar ha
https://github.com/rightup/pyMC_core
#### 5.14.7. MeshCore Packet Decoder
A TypeScript library for decoding MeshCore mesh networking packets with full cryptographic support. Uses WebAssembly (WASM) for Ed25519 key derivation through the orlp/ed25519 library. It powers the [MeshCore Packet Analyzer](https://analyzer.letsmesh.net/packets).
A TypeScript library for decoding MeshCore mesh networking packets with full cryptographic support. Uses WebAssembly (WASM) for Ed25519 key derivation through the orlp/ed25519 library. It powers the [MeshCore Packet Analyzer](https://analyzer.letsme.sh/packets).
https://github.com/michaelhart/meshcore-decoder
#### 5.14.8. meshcore-pi

View File

@@ -1,15 +0,0 @@
# Introduction
Welcome to the MeshCore documentation.
Below are a few quick start guides.
- [Frequently Asked Questions](./faq.md)
- [CLI Commands](./cli_commands.md)
- [Companion Protocol](./companion_protocol.md)
- [Packet Structure](./packet_structure.md)
- [QR Codes](./qr_codes.md)
If you find a mistake in any of our documentation, or find something is missing, please feel free to open a pull request for us to review.
- [Documentation Source](https://github.com/meshcore-dev/MeshCore/tree/main/docs)

View File

@@ -1,42 +1,26 @@
# Companion Protocol
# MeshCore Device Communication Protocol Guide
- **Last Updated**: 2026-01-03
- **Protocol Version**: Companion Firmware v1.12.0+
This document provides a comprehensive guide for communicating with MeshCore devices over Bluetooth Low Energy (BLE). It is platform-agnostic and can be used for Android, iOS, Python, JavaScript, or any other platform that supports BLE.
> NOTE: This document is still in development. Some information may be inaccurate.
## ⚠️ Important Security Note
This document provides a comprehensive guide for communicating with MeshCore devices over Bluetooth Low Energy (BLE).
**All secrets, hashes, and cryptographic values shown in this guide are EXAMPLE VALUES ONLY and are NOT real secrets.**
It is platform-agnostic and can be used for Android, iOS, Python, JavaScript, or any other platform that supports BLE.
## Official Libraries
Please see the following repos for existing MeshCore Companion Protocol libraries.
- JavaScript: [https://github.com/meshcore-dev/meshcore.js](https://github.com/meshcore-dev/meshcore.js)
- Python: [https://github.com/meshcore-dev/meshcore_py](https://github.com/meshcore-dev/meshcore_py)
## Important Security Note
All secrets, hashes, and cryptographic values shown in this guide are example values only.
- All hex values, public keys and hashes are for demonstration purposes only
- Never use example secrets in production
- Always generate new cryptographically secure random secrets
- Please implement proper security practices in your implementation
- This guide is for protocol documentation only
- The secret `9b647d242d6e1c5883fde0c5cf5c4c5e` used in examples is a made-up example value
- All hex values, public keys, and hashes in examples are for demonstration purposes only
- **Never use example secrets in production** - always generate new cryptographically secure random secrets
- This guide is for protocol documentation only - implement proper security practices in your actual implementation
## Table of Contents
1. [BLE Connection](#ble-connection)
2. [Packet Structure](#packet-structure)
2. [Protocol Overview](#protocol-overview)
3. [Commands](#commands)
4. [Channel Management](#channel-management)
5. [Message Handling](#message-handling)
6. [Response Parsing](#response-parsing)
7. [Example Implementation Flow](#example-implementation-flow)
8. [Best Practices](#best-practices)
9. [Troubleshooting](#troubleshooting)
5. [Secret Generation and QR Codes](#secret-generation-and-qr-codes)
6. [Message Handling](#message-handling)
7. [Response Parsing](#response-parsing)
8. [Example Implementation Flow](#example-implementation-flow)
---
@@ -44,111 +28,181 @@ All secrets, hashes, and cryptographic values shown in this guide are example va
### Service and Characteristics
MeshCore Companion devices expose a BLE service with the following UUIDs:
MeshCore devices expose a BLE service with the following UUIDs:
- **Service UUID**: `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
- **RX Characteristic** (App → Firmware): `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
- **TX Characteristic** (Firmware → App): `6E400003-B5A3-F393-E0A9-E50E24DCCA9E`
- **Service UUID**: `0000ff00-0000-1000-8000-00805f9b34fb`
- **RX Characteristic** (Device → Client): `0000ff01-0000-1000-8000-00805f9b34fb`
- **TX Characteristic** (Client → Device): `0000ff02-0000-1000-8000-00805f9b34fb`
### Connection Steps
1. **Scan for Devices**
- Scan for BLE devices advertising the MeshCore Service UUID
- Optionally filter by device name (typically contains "MeshCore" prefix)
- Note the device MAC address for reconnection
- Scan for BLE devices advertising the MeshCore service UUID
- Filter by device name (typically contains "MeshCore" or similar)
- Note the device MAC address for reconnection
2. **Connect to GATT**
- Connect to the device using the discovered MAC address
- Wait for connection to be established
- Connect to the device using the discovered MAC address
- Wait for connection to be established
3. **Discover Services and Characteristics**
- Discover the service with UUID `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
- Discover the RX characteristic `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
- Your app writes to this, the firmware reads from this
- Discover the TX characteristic `6E400003-B5A3-F393-E0A9-E50E24DCCA9E`
- The firmware writes to this, your app reads from this
- Discover the service with UUID `0000ff00-0000-1000-8000-00805f9b34fb`
- Discover RX characteristic (`0000ff01-...`) for receiving data
- Discover TX characteristic (`0000ff02-...`) for sending commands
4. **Enable Notifications**
- Subscribe to notifications on the TX characteristic to receive data from the firmware
- Subscribe to notifications on the RX characteristic
- Enable notifications/indications to receive data from the device
- On some platforms, you may need to write to a descriptor (e.g., `0x2902`) with value `0x01` or `0x02`
5. **Send Initial Commands**
- Send `CMD_APP_START` to identify your app to firmware and get radio settings
- Send `CMD_DEVICE_QEURY` to fetch device info and negotiate supported protocol versions
- Send `CMD_SET_DEVICE_TIME` to set the firmware clock
- Send `CMD_GET_CONTACTS` to fetch all contacts
- Send `CMD_GET_CHANNEL` multiple times to fetch all channel slots
- Send `CMD_SYNC_NEXT_MESSAGE` to fetch the next message stored in firmware
- Setup listeners for push codes, such as `PUSH_CODE_MSG_WAITING` or `PUSH_CODE_ADVERT`
- See [Commands](#commands) section for information on other commands
5. **Send AppStart Command**
- Send the app start command (see [Commands](#commands)) to initialize communication
- Wait for OK response before sending other commands
### Connection State Management
- **Disconnected**: No connection established
- **Connecting**: Connection attempt in progress
- **Connected**: GATT connection established, ready for commands
- **Error**: Connection failed or lost
**Note**: MeshCore devices may disconnect after periods of inactivity. Implement auto-reconnect logic with exponential backoff.
### BLE Write Type
When writing commands to the RX characteristic, specify the write type:
When writing commands to the TX characteristic, specify the write type:
- **Write with Response** (default): Waits for acknowledgment from device
- **Write without Response**: Faster but no acknowledgment
**Platform-specific**:
- **Android**: Use `BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT` or `WRITE_TYPE_NO_RESPONSE`
- **iOS**: Use `CBCharacteristicWriteType.withResponse` or `.withoutResponse`
- **Python (bleak)**: Use `write_gatt_char()` with `response=True` or `False`
**Recommendation**: Use write with response for reliability.
**Recommendation**: Use write with response for reliability, especially for critical commands like `SET_CHANNEL`.
### MTU (Maximum Transmission Unit)
The default BLE MTU is 23 bytes (20 bytes payload). For larger commands like `SET_CHANNEL` (66 bytes), you may need to:
1. **Request Larger MTU**: Request MTU of 512 bytes if supported
- Android: `gatt.requestMtu(512)`
- iOS: `peripheral.maximumWriteValueLength(for:)`
- Python (bleak): MTU is negotiated automatically
- Android: `gatt.requestMtu(512)`
- iOS: `peripheral.maximumWriteValueLength(for:)`
- Python (bleak): MTU is negotiated automatically
### Command Sequencing
2. **Handle Chunking**: If MTU is small, commands may be split automatically by the BLE stack
- Ensure all chunks are sent before waiting for response
- Responses may also arrive in chunks - buffer until complete
### Command Sequencing and Timing
**Critical**: Commands must be sent in the correct sequence:
1. **After Connection**:
- Wait for BLE connection to be established
- Wait for services/characteristics to be discovered
- Wait for notifications to be enabled
- Now you can safely send commands to the firmware
- Wait for GATT connection established
- Wait for services/characteristics discovered
- Wait for notifications enabled (descriptor write complete)
- **Wait 200-1000ms** for device to be ready (some devices need initialization time)
- Send `APP_START` command
- **Wait for `PACKET_OK` response** before sending any other commands
2. **Command-Response Matching**:
- Send one command at a time
- Wait for a response before sending another command
- Use a timeout (typically 5 seconds)
- Match response to command by type (e.g: `CMD_GET_CHANNEL``RESP_CODE_CHANNEL_INFO`)
- Send one command at a time
- Wait for response before sending next command
- Use timeout (typically 5 seconds)
- Match response to command by:
- Command type (e.g., `GET_CHANNEL``PACKET_CHANNEL_INFO`)
- Sequence number (if implemented)
- First-in-first-out queue
3. **Timing Considerations**:
- Minimum delay between commands: 50-100ms
- After `APP_START`: Wait 200-500ms before next command
- After `SET_CHANNEL`: Wait 500-1000ms for channel to be created
- After enabling notifications: Wait 200ms before sending commands
**Example Flow**:
```python
# 1. Connect and discover
await connect_to_device(device)
await discover_services()
await enable_notifications()
await asyncio.sleep(0.2) # Wait for device ready
# 2. Send AppStart
send_command(build_app_start())
response = await wait_for_response(PACKET_OK, timeout=5.0)
if response.type != PACKET_OK:
raise Exception("AppStart failed")
# 3. Now safe to send other commands
await asyncio.sleep(0.1) # Small delay between commands
send_command(build_device_query())
response = await wait_for_response(PACKET_DEVICE_INFO, timeout=5.0)
```
### Command Queue Management
For reliable operation, implement a command queue.
For reliable operation, implement a command queue:
**Queue Structure**:
1. **Queue Structure**:
- Maintain a queue of pending commands
- Track which command is currently waiting for response
- Only send next command after receiving response or timeout
- Maintain a queue of pending commands
- Track which command is currently waiting for a response
- Only send next command after receiving response or timeout
2. **Implementation**:
```python
class CommandQueue:
def __init__(self):
self.queue = []
self.waiting_for_response = False
self.current_command = None
async def send_command(self, command, expected_response_type, timeout=5.0):
if self.waiting_for_response:
# Queue the command
self.queue.append((command, expected_response_type, timeout))
return
self.waiting_for_response = True
self.current_command = (command, expected_response_type, timeout)
# Send command
await write_to_tx_characteristic(command)
# Wait for response
response = await wait_for_response(expected_response_type, timeout)
self.waiting_for_response = False
self.current_command = None
# Process next queued command
if self.queue:
next_cmd, next_type, next_timeout = self.queue.pop(0)
await self.send_command(next_cmd, next_type, next_timeout)
return response
```
**Error Handling**:
- On timeout, clear current command, process next in queue
- On error, log error, clear current command, process next
3. **Error Handling**:
- On timeout: Clear current command, process next in queue
- On error: Log error, clear current command, process next
- Don't block queue on single command failure
---
## Packet Structure
## Protocol Overview
The MeshCore protocol uses a binary format with the following structure:
- **Commands**: Sent from app to firmware via RX characteristic
- **Responses**: Received from firmware via TX characteristic notifications
- **All multi-byte integers**: Little-endian byte order (except CayenneLPP which is Big-endian)
- **Commands**: Sent from client to device via TX characteristic
- **Responses**: Received from device via RX characteristic (notifications)
- **All multi-byte integers**: Little-endian byte order
- **All strings**: UTF-8 encoding
### Packet Structure
Most packets follow this format:
```
[Packet Type (1 byte)] [Data (variable length)]
@@ -229,7 +283,7 @@ Byte 1: Channel Index (0-7)
Byte 0: 0x20
Byte 1: Channel Index (0-7)
Bytes 2-33: Channel Name (32 bytes, UTF-8, null-padded)
Bytes 34-65: Secret (32 bytes)
Bytes 34-65: Secret (32 bytes, see [Secret Generation](#secret-generation))
```
**Total Length**: 66 bytes
@@ -244,7 +298,7 @@ Bytes 34-65: Secret (32 bytes)
- Padded with null bytes (0x00) if shorter
**Secret Field** (32 bytes):
- For **private channels**: 32-byte secret
- For **private channels**: 32-byte secret (see [Secret Generation](#secret-generation))
- For **public channels**: All zeros (0x00)
**Example** (create channel "YourChannelName" at index 1 with secret):
@@ -326,33 +380,170 @@ Byte 0: 0x14
### Channel Types
1. **Public Channel**
- Uses a publicly known 16-byte key: `8b3387e9c5cdea6ac9e5edbaa115cd72`
- Anyone can join this channel, messages should be considered public
- Used as the default public group chat
2. **Hashtag Channels**
- Uses a secret key derived from the channel name
- It is the first 16 bytes of `sha256("#test")`
- For example hashtag channel `#test` has the key: `9cd8fcf22a47333b591d96a2b848b73f`
- Used as a topic based public group chat, separate from the default public channel
3. **Private Channels**
- Uses a randomly generated 16-byte secret key
- Messages should be considered private between those that know the secret
- Users should keep the key secret, and only share with those you want to communicate with
- Used as a secure private group chat
1. **Public Channels** (Index 0)
- No secret required
- Anyone with the channel name can join
- Use for open communication
2. **Private Channels** (Indices 1-7)
- Require a 16-byte secret
- Secret is expanded to 32 bytes using SHA-512 (see [Secret Generation](#secret-generation))
- Only devices with the secret can access the channel
### Channel Lifecycle
1. **Set Channel**:
- Fetch all channel slots, and find one with empty name and all-zero secret
- Generate or provide a 16-byte secret
- Send `CMD_SET_CHANNEL` with name and secret
2. **Get Channel**:
- Send `CMD_GET_CHANNEL` with channel index
- Parse `RESP_CODE_CHANNEL_INFO` response
1. **Create Channel**:
- Choose an available index (1-7 for private channels)
- Generate or provide a 16-byte secret
- Send `SET_CHANNEL` command with name and secret
- **Store the secret locally** (device does not return it)
2. **Query Channel**:
- Send `GET_CHANNEL` command with channel index
- Parse `PACKET_CHANNEL_INFO` response
- Note: Secret will be null in response (security feature)
3. **Delete Channel**:
- Send `CMD_SET_CHANNEL` with empty name and all-zero secret
- Or overwrite with a new channel
- Send `SET_CHANNEL` command with empty name and all-zero secret
- Or overwrite with a new channel
### Channel Index Management
- **Index 0**: Reserved for public channels
- **Indices 1-7**: Available for private channels
- If a channel exists at index 0 but should be private, migrate it to index 1-7
---
## Secret Generation and QR Codes
### Secret Generation
For private channels, generate a cryptographically secure 16-byte secret:
**Pseudocode**:
```python
import secrets
# Generate 16 random bytes
secret_bytes = secrets.token_bytes(16)
# Convert to hex string for storage/sharing
secret_hex = secret_bytes.hex() # 32 hex characters
```
**Important**: Use a cryptographically secure random number generator (CSPRNG). Do not use predictable values.
### Secret Expansion
When sending the secret to the device via `SET_CHANNEL`, the 16-byte secret must be expanded to 32 bytes:
**Process**:
1. Take the 16-byte secret
2. Compute SHA-512 hash: `hash = SHA-512(secret)`
3. Use the first 32 bytes of the hash as the secret field in the command
**Pseudocode**:
```python
import hashlib
secret_16_bytes = ... # Your 16-byte secret
sha512_hash = hashlib.sha512(secret_16_bytes).digest() # 64 bytes
secret_32_bytes = sha512_hash[:32] # First 32 bytes
```
This matches MeshCore's ED25519 key expansion method.
### QR Code Format
QR codes for sharing channel secrets use the following format:
**URL Scheme**:
```
meshcore://channel/add?name=<ChannelName>&secret=<32HexChars>
```
**Parameters**:
- `name`: Channel name (URL-encoded if needed)
- `secret`: 32-character hexadecimal representation of the 16-byte secret
**Example** (using example secret - NOT a real secret):
```
meshcore://channel/add?name=YourChannelName&secret=9b647d242d6e1c5883fde0c5cf5c4c5e
```
**Alternative Formats** (for backward compatibility):
1. **JSON Format**:
```json
{
"name": "YourChannelName",
"secret": "9b647d242d6e1c5883fde0c5cf5c4c5e"
}
```
*Note: The secret value above is an example only - generate your own secure random secret.*
2. **Plain Hex** (32 hex characters):
```
9b647d242d6e1c5883fde0c5cf5c4c5e
```
*Note: This is an example hex value - always generate your own cryptographically secure random secret.*
### QR Code Generation
**Steps**:
1. Generate or use existing 16-byte secret
2. Convert to 32-character hex string (lowercase)
3. URL-encode the channel name
4. Construct the `meshcore://` URL
5. Generate QR code from the URL string
**Example** (Python with `qrcode` library):
```python
import qrcode
from urllib.parse import quote
import secrets
channel_name = "YourChannelName"
# Generate a real cryptographically secure secret (NOT the example value)
secret_bytes = secrets.token_bytes(16)
secret_hex = secret_bytes.hex() # This will be a different value each time
# Example value shown in documentation: "9b647d242d6e1c5883fde0c5cf5c4c5e"
# DO NOT use the example value - always generate your own!
url = f"meshcore://channel/add?name={quote(channel_name)}&secret={secret_hex}"
qr = qrcode.QRCode(version=1, box_size=10, border=5)
qr.add_data(url)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
img.save("channel_qr.png")
```
### QR Code Scanning
When scanning a QR code:
1. **Parse URL Format**:
- Extract `name` and `secret` query parameters
- Validate secret is 32 hex characters
2. **Parse JSON Format**:
- Parse JSON object
- Extract `name` and `secret` fields
3. **Parse Plain Hex**:
- Extract only hex characters (0-9, a-f, A-F)
- Validate length is 32 characters
- Convert to lowercase
4. **Validate Secret**:
- Must be exactly 32 hex characters (16 bytes)
- Convert hex string to bytes
5. **Create Channel**:
- Use extracted name and secret
- Send `SET_CHANNEL` command
---
@@ -502,28 +693,28 @@ Use the `SEND_CHANNEL_MESSAGE` command (see [Commands](#commands)).
### Packet Types
| Value | Name | Description |
|-------|----------------------------|-------------------------------|
| 0x00 | PACKET_OK | Command succeeded |
| 0x01 | PACKET_ERROR | Command failed |
| 0x02 | PACKET_CONTACT_START | Start of contact list |
| 0x03 | PACKET_CONTACT | Contact information |
| 0x04 | PACKET_CONTACT_END | End of contact list |
| 0x05 | PACKET_SELF_INFO | Device self-information |
| 0x06 | PACKET_MSG_SENT | Message sent confirmation |
| 0x07 | PACKET_CONTACT_MSG_RECV | Contact message (standard) |
| 0x08 | PACKET_CHANNEL_MSG_RECV | Channel message (standard) |
| 0x09 | PACKET_CURRENT_TIME | Current time response |
| 0x0A | PACKET_NO_MORE_MSGS | No more messages available |
| 0x0C | PACKET_BATTERY | Battery level |
| 0x0D | PACKET_DEVICE_INFO | Device information |
| 0x10 | PACKET_CONTACT_MSG_RECV_V3 | Contact message (V3 with SNR) |
| 0x11 | PACKET_CHANNEL_MSG_RECV_V3 | Channel message (V3 with SNR) |
| 0x12 | PACKET_CHANNEL_INFO | Channel information |
| 0x80 | PACKET_ADVERTISEMENT | Advertisement packet |
| 0x82 | PACKET_ACK | Acknowledgment |
| 0x83 | PACKET_MESSAGES_WAITING | Messages waiting notification |
| 0x88 | PACKET_LOG_DATA | RF log data (can be ignored) |
| Value | Name | Description |
|-------|------|-------------|
| 0x00 | PACKET_OK | Command succeeded |
| 0x01 | PACKET_ERROR | Command failed |
| 0x02 | PACKET_CONTACT_START | Start of contact list |
| 0x03 | PACKET_CONTACT | Contact information |
| 0x04 | PACKET_CONTACT_END | End of contact list |
| 0x05 | PACKET_SELF_INFO | Device self-information |
| 0x06 | PACKET_MSG_SENT | Message sent confirmation |
| 0x07 | PACKET_CONTACT_MSG_RECV | Contact message (standard) |
| 0x08 | PACKET_CHANNEL_MSG_RECV | Channel message (standard) |
| 0x09 | PACKET_CURRENT_TIME | Current time response |
| 0x0A | PACKET_NO_MORE_MSGS | No more messages available |
| 0x0C | PACKET_BATTERY | Battery level |
| 0x0D | PACKET_DEVICE_INFO | Device information |
| 0x10 | PACKET_CONTACT_MSG_RECV_V3 | Contact message (V3 with SNR) |
| 0x11 | PACKET_CHANNEL_MSG_RECV_V3 | Channel message (V3 with SNR) |
| 0x12 | PACKET_CHANNEL_INFO | Channel information |
| 0x80 | PACKET_ADVERTISEMENT | Advertisement packet |
| 0x82 | PACKET_ACK | Acknowledgment |
| 0x83 | PACKET_MESSAGES_WAITING | Messages waiting notification |
| 0x88 | PACKET_LOG_DATA | RF log data (can be ignored) |
### Parsing Responses
@@ -890,6 +1081,33 @@ def on_notification_received(data):
send_command(tx_char, build_get_message())
```
### QR Code Sharing
```python
import secrets
from urllib.parse import quote
# 1. Generate QR code data
channel_name = "YourChannelName"
# Generate a real secret (NOT the example value from documentation)
secret_bytes = secrets.token_bytes(16)
secret_hex = secret_bytes.hex()
# Example value in documentation: "9b647d242d6e1c5883fde0c5cf5c4c5e"
# DO NOT use example values - always generate your own secure random secrets!
url = f"meshcore://channel/add?name={quote(channel_name)}&secret={secret_hex}"
# 2. Generate QR code image
qr = qrcode.QRCode(version=1, box_size=10, border=5)
qr.add_data(url)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
# 3. Display or save QR code
img.save("channel_qr.png")
```
---
## Best Practices
@@ -903,37 +1121,81 @@ def on_notification_received(data):
- Always use cryptographically secure random number generators
- Store secrets securely (encrypted storage)
- Never log or transmit secrets in plain text
- Device does not return secrets - you must store them locally
3. **Message Handling**:
- Send `CMD_SYNC_NEXT_MESSAGE` when `PUSH_CODE_MSG_WAITING` is received
- Implement message deduplication to avoid display the same message twice
- Poll `GET_MESSAGE` periodically or when `PACKET_MESSAGES_WAITING` is received
- Handle message chunking for long messages (>133 characters)
- Implement message deduplication to avoid processing the same message twice
4. **Channel Management**:
- Fetch all channel slots even if you encounter an empty slot
- Ideally save new channels into the first empty slot
5. **Error Handling**:
4. **Error Handling**:
- Implement timeouts for all commands (typically 5 seconds)
- Handle `RESP_CODE_ERR` responses appropriately
- Handle `PACKET_ERROR` responses appropriately
- Log errors for debugging but don't expose sensitive information
5. **Channel Management**:
- Avoid using channel index 0 for private channels
- Migrate channels from index 0 to 1-7 if needed
- Query channels after connection to discover existing channels
---
## Platform-Specific Notes
### Android
- Use `BluetoothGatt` API
- Request `BLUETOOTH_CONNECT` and `BLUETOOTH_SCAN` permissions (Android 12+)
- Enable notifications by writing to descriptor `0x2902` with value `0x01` or `0x02`
### iOS
- Use `CoreBluetooth` framework
- Implement `CBPeripheralDelegate` for notifications
- Request Bluetooth permissions in Info.plist
### Python
- Use `bleak` library for cross-platform BLE support
- Handle async/await for BLE operations
- Use `asyncio` for command-response patterns
### JavaScript/Node.js
- Use `noble` or `@abandonware/noble` for BLE
- Handle callbacks or promises for async operations
- Use `Buffer` for binary data manipulation
---
## Troubleshooting
### Connection Issues
- **Device not found**: Ensure device is powered on and advertising
- **Connection timeout**: Check Bluetooth permissions and device proximity
- **GATT errors**: Ensure proper service/characteristic discovery
### Command Issues
- **No response**: Verify notifications are enabled, check connection state
- **Error responses**: Verify command format and check error code
- **Timeout**: Increase timeout value or try again
- **Error responses**: Verify command format, check channel index validity
- **Timeout**: Increase timeout value or check device responsiveness
### Message Issues
- **Messages not received**: Poll `GET_MESSAGE` command periodically
- **Duplicate messages**: Implement message deduplication using timestamp/content as a unique id
- **Message truncation**: Send long messages as separate shorter messages
- **Duplicate messages**: Implement message deduplication using timestamps/hashes
- **Message truncation**: Split long messages into chunks
### Secret/Channel Issues
- **Secret not working**: Verify secret expansion (SHA-512) is correct
- **Channel not found**: Query channels after connection to discover existing channels
- **Channel index 0**: Migrate to index 1-7 for private channels
---
## References
- MeshCore Python implementation: `meshcore_py-main/src/meshcore/`
- BLE GATT Specification: Bluetooth SIG Core Specification
- ED25519 Key Expansion: RFC 8032
---
**Last Updated**: 2025-01-01
**Protocol Version**: Based on MeshCore v1.36.0+

View File

@@ -1,34 +0,0 @@
# QR Codes
This document provides an overview of QR Code formats that can be used for sharing MeshCore channels and contacts. The formats described below are supported by the MeshCore mobile app.
## Add Channel
**Example URL**:
```
meshcore://channel/add?name=Public&secret=8b3387e9c5cdea6ac9e5edbaa115cd72
```
**Parameters**:
- `name`: Channel name (URL-encoded if needed)
- `secret`: 16-byte secret represented as 32 hex characters
## Add Contact
**Example URL**:
```
meshcore://contact/add?name=Example+Contact&public_key=9cd8fcf22a47333b591d96a2b848b73f457b1bb1a3ea2453a885f9e5787765b1&type=1
```
**Parameters**:
- `name`: Contact name (URL-encoded if needed)
- `public_key`: 32-byte public key represented as 64 hex characters
- `type`: numeric contact type
- `1`: Companion
- `2`: Repeater
- `3`: Room Server
- `4`: Sensor

View File

@@ -1,96 +0,0 @@
# Terminal Chat CLI
Below are the commands you can enter into the Terminal Chat clients:
```
set freq {frequency}
```
Set the LoRa frequency. Example: set freq 915.8
```
set tx {tx-power-dbm}
```
Sets LoRa transmit power in dBm.
```
set name {name}
```
Sets your advertisement name.
```
set lat {latitude}
```
Sets your advertisement map latitude. (decimal degrees)
```
set lon {longitude}
```
Sets your advertisement map longitude. (decimal degrees)
```
set af {air-time-factor}
```
Sets the transmit air-time-factor.
```
time {epoch-secs}
```
Set the device clock using UNIX epoch seconds. Example: time 1738242833
```
advert
```
Sends an advertisement packet
```
clock
```
Displays current time per device's clock.
```
ver
```
Shows the device version and firmware build date.
```
card
```
Displays *your* 'business card', for other to manually _import_
```
import {card}
```
Imports the given card to your contacts.
```
list {n}
```
List all contacts by most recent. (optional {n}, is the last n by advertisement date)
```
to
```
Shows the name of current recipient contact. (for subsequent 'send' commands)
```
to {name-prefix}
```
Sets the recipient to the _first_ matching contact (in 'list') by the name prefix. (ie. you don't have to type whole name)
```
send {text}
```
Sends the text message (as DM) to current recipient.
```
reset path
```
Resets the path to current recipient, for new path discovery.
```
public {text}
```
Sends the text message to the built-in 'public' group channel

View File

@@ -8,11 +8,11 @@
#define FIRMWARE_VER_CODE 8
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "29 Jan 2026"
#define FIRMWARE_BUILD_DATE "30 Nov 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.12.0"
#define FIRMWARE_VERSION "v1.11.0"
#endif
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)

View File

@@ -69,11 +69,11 @@ struct NeighbourInfo {
};
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "29 Jan 2026"
#define FIRMWARE_BUILD_DATE "30 Nov 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.12.0"
#define FIRMWARE_VERSION "v1.11.0"
#endif
#define FIRMWARE_ROLE "repeater"

View File

@@ -26,11 +26,11 @@
/* ------------------------------ Config -------------------------------- */
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "29 Jan 2026"
#define FIRMWARE_BUILD_DATE "30 Nov 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.12.0"
#define FIRMWARE_VERSION "v1.11.0"
#endif
#ifndef LORA_FREQ

View File

@@ -33,11 +33,11 @@
#define PERM_RECV_ALERTS_HI (1 << 7) // high priority alerts
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "29 Jan 2026"
#define FIRMWARE_BUILD_DATE "30 Nov 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.12.0"
#define FIRMWARE_VERSION "v1.11.0"
#endif
#define FIRMWARE_ROLE "sensor"

View File

@@ -2,9 +2,7 @@
git branch -D pr-1297
git branch -D pr-1338
git branch -D pr-1398
# fetch PRs
git fetch upstream pull/1398/head:pr-1398
git fetch upstream pull/1338/head:pr-1338
git fetch upstream pull/1297/head:pr-1297

View File

@@ -1,19 +0,0 @@
site_name: MeshCore Docs
site_url: https://meshcore-dev.github.io/meshcore/
site_description: Documentation for the open source MeshCore firmware
repo_name: meshcore-dev/meshcore
repo_url: https://github.com/meshcore-dev/meshcore/
edit_uri: edit/main/docs/
theme:
name: material
logo: _assets/meshcore_tm.svg
features:
- content.action.edit
- content.code.copy
- search.highlight
- search.suggest
extra_css:
- _stylesheets/extra.css

View File

@@ -24,9 +24,10 @@ lib_deps =
melopero/Melopero RV3028 @ ^1.1.0
electroniccats/CayenneLPP @ 1.6.1
build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
-D LORA_FREQ=869.525
-D LORA_BW=250
-D LORA_SF=11
-D LORA_FREQ=869.618
-D LORA_BW=62.5
-D LORA_SF=8
-D LORA_CR=8
-D ENABLE_ADVERT_ON_BOOT=1
-D ENABLE_PRIVATE_KEY_IMPORT=1 ; NOTE: comment these out for more secure firmware
-D ENABLE_PRIVATE_KEY_EXPORT=1

View File

@@ -8,9 +8,7 @@
namespace mesh {
#define MAX_RX_DELAY_MILLIS 32000 // 32 seconds
#define MIN_TX_BUDGET_RESERVE_MS 100 // min budget (ms) required before allowing next TX
#define MIN_TX_BUDGET_AIRTIME_DIV 2 // require at least 1/N of estimated airtime as budget before TX
#define MAX_RX_DELAY_MILLIS 32000 // 32 seconds
#ifndef NOISE_FLOOR_CALIB_INTERVAL
#define NOISE_FLOOR_CALIB_INTERVAL 2000 // 2 seconds
@@ -41,15 +39,15 @@ void Dispatcher::updateTxBudget() {
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
unsigned long max_budget = (unsigned long)(getDutyCycleWindowMs() * duty_cycle);
unsigned long refill = (unsigned long)(elapsed * duty_cycle);
if (refill > 0) {
tx_budget_ms += refill;
if (tx_budget_ms > max_budget) {
tx_budget_ms = max_budget;
}
last_budget_update = now;
tx_budget_ms += refill;
if (tx_budget_ms > max_budget) {
tx_budget_ms = max_budget;
}
last_budget_update = now;
}
int Dispatcher::calcRxDelay(float score, uint32_t air_time) const {
@@ -96,9 +94,9 @@ void Dispatcher::loop() {
tx_budget_ms -= t;
}
if (tx_budget_ms < MIN_TX_BUDGET_RESERVE_MS) {
if (tx_budget_ms < 100) {
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
unsigned long needed = MIN_TX_BUDGET_RESERVE_MS - tx_budget_ms;
unsigned long needed = 100 - tx_budget_ms;
next_tx_time = futureMillis((unsigned long)(needed / duty_cycle));
} else {
next_tx_time = _ms->getMillis();
@@ -266,9 +264,9 @@ void Dispatcher::checkSend() {
updateTxBudget();
uint32_t est_airtime = _radio->getEstAirtimeFor(MAX_TRANS_UNIT);
if (tx_budget_ms < est_airtime / MIN_TX_BUDGET_AIRTIME_DIV) {
if (tx_budget_ms < est_airtime / 2) {
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
unsigned long needed = est_airtime / MIN_TX_BUDGET_AIRTIME_DIV - tx_budget_ms;
unsigned long needed = est_airtime / 2 - tx_budget_ms;
next_tx_time = futureMillis((unsigned long)(needed / duty_cycle));
return;
}

56
tools/maint/README.md Normal file
View File

@@ -0,0 +1,56 @@
# Maintenance Tools
This directory contains automation for managing our **Friendly Fork**. It allows us to integrate community-submitted Pull Requests from the upstream repository into our local development branches.
## Why this exists
In firmware development, critical bug fixes or hardware support often exist in the upstream "Pull Request" queue long before they are officially merged. This tool allows us to build an integrated firmware version that includes those necessary patches while remaining syncable with the official source.
## Usage
### 1. Prerequisites
You must have the original repository added as a remote named `upstream`:
```bash
git remote add upstream https://github.com/meshcore-dev/MeshCore.git
```
### 2. Basic Commands
**Apply specific patches:**
To pull in PR #1338 and PR #1400 from the upstream project:
```bash
./tools/maint/apply_patches.sh 1338 1400
```
**Start over (Reset):**
To wipe the integrated branch and reset it to match the official upstream `main` branch exactly:
```bash
./tools/maint/apply_patches.sh --reset
```
## Traceability
Every time this script runs, it updates `patch_manifest.log`. This file tracks:
* The date of the integration.
* The base commit SHA we started from.
* The specific commit SHA of every PR applied.
**This log is essential for debugging firmware regressions.** If the hardware fails, check the manifest to identify which experimental patch might be the cause.
---
### A Note on Merge Conflicts
If a PR cannot be applied automatically, the script will abort the merge. You will need to:
1. Manually merge the PR.
2. Resolve the conflicts in your editor.
3. Commit the result.
4. Manually update the `patch_manifest.log`.

65
tools/maint/apply_patches.sh Executable file
View File

@@ -0,0 +1,65 @@
#!/bin/bash
# Configuration
UPSTREAM_REMOTE="upstream"
BASE_BRANCH="main" # Change to 'master' if that's what upstream uses
TARGET_BRANCH="main-integrated"
MANIFEST_FILE="tools/maint/patch_manifest.log"
# Function to reset the branch
reset_to_upstream() {
echo "Warning: This will wipe all local changes on $TARGET_BRANCH."
read -p "Are you sure you want to reset to $UPSTREAM_REMOTE/$BASE_BRANCH? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
git fetch "$UPSTREAM_REMOTE"
git checkout -B "$TARGET_BRANCH" "$UPSTREAM_REMOTE/$BASE_BRANCH"
echo "--- Reset to Upstream: $(date) ---" > "$MANIFEST_FILE"
echo "Base Commit: $(git rev-parse HEAD)" >> "$MANIFEST_FILE"
echo "Reset successful. Branch is now clean."
else
echo "Reset aborted."
fi
}
# Check for reset flag
if [[ "$1" == "--reset" ]]; then
reset_to_upstream
exit 0
fi
# Standard PR application logic
PR_IDS=("$@")
if [ ${#PR_IDS[@]} -eq 0 ]; then
echo "Usage:"
echo " Apply PRs: $0 <PR_ID1> <PR_ID2> ..."
echo " Reset: $0 --reset"
exit 1
fi
# Ensure target branch exists and is checked out
git checkout -B "$TARGET_BRANCH"
echo "--- Patch Session: $(date) ---" >> "$MANIFEST_FILE"
for PR in "${PR_IDS[@]}"; do
echo "--------------------------------------"
echo "Fetching PR #$PR..."
if git fetch "$UPSTREAM_REMOTE" "pull/$PR/head:PR_TEMP_FETCH"; then
if git merge PR_TEMP_FETCH --no-edit -m "Integrate upstream PR #$PR"; then
echo "Successfully integrated PR #$PR"
echo "PR #$PR SHA: $(git rev-parse PR_TEMP_FETCH)" >> "$MANIFEST_FILE"
else
echo "Conflict in PR #$PR. Aborting merge."
git merge --abort
exit 1
fi
git branch -D PR_TEMP_FETCH
else
echo "Error: PR #$PR not found."
fi
done
echo "--------------------------------------"
echo "Done. See $MANIFEST_FILE for details."

View File

@@ -3,7 +3,7 @@
export PATH="$HOME/.platformio/penv/bin:$PATH"
LOGFILE="$PWD/meshcore-evo-fw.log"
FIRMWARE_VERSION="v1.12.0-evo_0.1.6"
FIRMWARE_VERSION="v1.11.0-evo_0.1.5"
FIRMWARE_BUILD_DATE=$(date '+%d-%b-%Y')
collect_bin_files(){

View File

@@ -4,6 +4,30 @@
#include <Arduino.h>
#include <helpers/NRF52Board.h>
// LoRa radio module pins for RAK13302
#define P_LORA_SCLK 3
#define P_LORA_MISO 29
#define P_LORA_MOSI 30
#define P_LORA_NSS 26
#define P_LORA_DIO_1 10
#define P_LORA_BUSY 9
#define P_LORA_RESET 4
#ifndef P_LORA_PA_EN
#define P_LORA_PA_EN 31
#endif
//#define PIN_GPS_SDA 13 //GPS SDA pin (output option)
//#define PIN_GPS_SCL 14 //GPS SCL pin (output option)
// #define PIN_GPS_TX 16 //GPS TX pin
// #define PIN_GPS_RX 15 //GPS RX pin
#define PIN_GPS_1PPS 17 //GPS PPS pin
#define GPS_BAUD_RATE 9600
#define GPS_ADDRESS 0x42 //i2c address for GPS
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// built-ins
#define PIN_VBAT_READ 5
#define ADC_MULTIPLIER (3 * 1.73 * 1.187 * 1000)
@@ -11,13 +35,9 @@
#define PIN_3V3_EN (34)
#define WB_IO2 PIN_3V3_EN
class RAK3401Board : public NRF52BoardDCDC {
protected:
#ifdef NRF52_POWER_MANAGEMENT
void initiateShutdown(uint8_t reason) override;
#endif
class RAK3401Board : public NRF52BoardDCDC, public NRF52BoardOTA {
public:
RAK3401Board() : NRF52Board("RAK3401_OTA") {}
RAK3401Board() : NRF52BoardOTA("RAK3401_OTA") {}
void begin();
#define BATTERY_SAMPLES 8

View File

@@ -141,6 +141,11 @@ static const uint8_t AREF = PIN_AREF;
#define EXTERNAL_FLASH_DEVICES IS25LP080D
#define EXTERNAL_FLASH_USE_QSPI
#define P_LORA_SCK PIN_SPI1_SCK
#define P_LORA_MISO PIN_SPI1_MISO
#define P_LORA_MOSI PIN_SPI1_MOSI
#define P_LORA_CS 26
#define USE_SX1262
#define SX126X_CS (26)
#define SX126X_DIO1 (10)
@@ -152,15 +157,6 @@ static const uint8_t AREF = PIN_AREF;
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define P_LORA_SCLK PIN_SPI1_SCK
#define P_LORA_MISO PIN_SPI1_MISO
#define P_LORA_MOSI PIN_SPI1_MOSI
#define P_LORA_NSS SX126X_CS
#define P_LORA_DIO_1 SX126X_DIO1
#define P_LORA_BUSY SX126X_BUSY
#define P_LORA_RESET SX126X_RESET
#define P_LORA_PA_EN 31
// enables 3.3V periphery like GPS or IO Module
// Do not toggle this for GPS power savings
#define PIN_3V3_EN (34)
@@ -177,10 +173,6 @@ static const uint8_t AREF = PIN_AREF;
#define PIN_GPS_RX PIN_SERIAL1_RX
#define PIN_GPS_TX PIN_SERIAL1_TX
#define PIN_GPS_1PPS PIN_GPS_PPS
#define GPS_BAUD_RATE 9600
#define GPS_ADDRESS 0x42 //i2c address for GPS
// Battery
// The battery sense is hooked to pin A0 (5)
#define BATTERY_PIN PIN_A0

View File

@@ -4,6 +4,27 @@
#include <Arduino.h>
#include <helpers/NRF52Board.h>
// LoRa radio module pins for RAK4631
#define P_LORA_DIO_1 47
#define P_LORA_NSS 42
#define P_LORA_RESET RADIOLIB_NC // 38
#define P_LORA_BUSY 46
#define P_LORA_SCLK 43
#define P_LORA_MISO 45
#define P_LORA_MOSI 44
#define SX126X_POWER_EN 37
//#define PIN_GPS_SDA 13 //GPS SDA pin (output option)
//#define PIN_GPS_SCL 14 //GPS SCL pin (output option)
//#define PIN_GPS_TX 16 //GPS TX pin
//#define PIN_GPS_RX 15 //GPS RX pin
#define PIN_GPS_1PPS 17 //GPS PPS pin
#define GPS_BAUD_RATE 9600
#define GPS_ADDRESS 0x42 //i2c address for GPS
#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// built-ins
#define PIN_VBAT_READ 5
#define ADC_MULTIPLIER (3 * 1.73 * 1.187 * 1000)

View File

@@ -144,19 +144,6 @@ extern "C"
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;
// LoRa radio module pins for RAK4631
#define P_LORA_DIO_1 (47)
#define P_LORA_NSS (42)
#define P_LORA_RESET (-1)
#define P_LORA_BUSY (46)
#define P_LORA_SCLK (43)
#define P_LORA_MISO (45)
#define P_LORA_MOSI (44)
#define SX126X_POWER_EN (37)
#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
/*
* Wire Interfaces
*/
@@ -168,23 +155,19 @@ extern "C"
#define PIN_WIRE1_SDA (24)
#define PIN_WIRE1_SCL (25)
// QSPI Pins
// QSPI occupied by GPIO's
#define PIN_QSPI_SCK 3 // 19
#define PIN_QSPI_CS 26 // 17
#define PIN_QSPI_IO0 30 // 20
#define PIN_QSPI_IO1 29 // 21
#define PIN_QSPI_IO2 28 // 22
#define PIN_QSPI_IO3 2 // 23
// QSPI Pins
// QSPI occupied by GPIO's
#define PIN_QSPI_SCK 3 // 19
#define PIN_QSPI_CS 26 // 17
#define PIN_QSPI_IO0 30 // 20
#define PIN_QSPI_IO1 29 // 21
#define PIN_QSPI_IO2 28 // 22
#define PIN_QSPI_IO3 2 // 23
// On-board QSPI Flash
// No onboard flash
#define EXTERNAL_FLASH_DEVICES IS25LP080D
#define EXTERNAL_FLASH_USE_QSPI
#define PIN_GPS_1PPS 17 //GPS PPS pin
#define GPS_BAUD_RATE 9600
#define GPS_ADDRESS 0x42 //i2c address for GPS
// On-board QSPI Flash
// No onboard flash
#define EXTERNAL_FLASH_DEVICES IS25LP080D
#define EXTERNAL_FLASH_USE_QSPI
#ifdef __cplusplus
}