Meshtastic 固件源代码实用教程
本教程面向刚开始接触 Meshtastic 固件源代码的用户,涵盖 Windows 和 macOS 的常见工作流程。目标很简单:克隆官方仓库,完成一次成功的构建,做一个简单的 UI 修改,并将修改后的固件烧录到设备上进行验证。
如果你已经熟悉 Git、Python 或 PlatformIO,可以跳过对应章节,直接进入上手实战部分。
本指南同时给出了 Windows 和 macOS 的常用命令。大部分截图仍然来自 Windows 环境,但在 macOS 上的整体流程非常相似。
前置准备
在开始之前,请先准备好以下工具:
- Git
- Python 3
- VS Code
- PlatformIO
1. 安装 Git
- Windows
- macOS
打开 Git for Windows 官方下载页面:
通常在你打开页面后,安装程序会自动开始下载。下载完成后,双击安装程序并按照安装向导进行操作。
在安装过程中,最重要的一步是调整 PATH 环境变量。请选择:
Git from the command line and also from 3rd-party software
其他选项一般保持默认即可,直接连续点击 Next。

等待安装完成。
安装完成后,关闭当前所有 PowerShell 和 VS Code 终端窗口,然后重新打开一个新的 PowerShell 窗口并运行:
& "C:\Program Files\Git\cmd\git.exe" --version

如果显示了 Git 版本号,说明 Git 已成功安装。
如果 git 命令仍然不可用
你可以先在 PowerShell 中运行以下命令,确认 Git 的默认安装路径:
$gitCmd = "C:\Program Files\Git\cmd"
$gitBin = "C:\Program Files\Git\bin"
Write-Host $gitCmd
Write-Host $gitBin

然后手动将 Git 添加到系统环境变量中。
图形界面修复步骤
- 按下
Win - 搜索“Edit the system environment variables”
- 打开后点击 Environment Variables
- 在 System variables 下找到
Path - 点击 Edit
- 点击 New,并添加以下两个路径:
C:\Program Files\Git\cmd
C:\Program Files\Git\bin
- 连续点击 OK 保存

保存之后,你仍然需要:
- 关闭所有 PowerShell 窗口
- 重新打开 PowerShell
然后运行:
git --version

如果出现版本号,说明安装已经完成。
在 macOS 上安装 Git 的方式不止一种,但使用 Homebrew 通常是最简单的选择:
- 先安装 Command Line Tools:
xcode-select --install
- 如果还没有安装 Homebrew,请先安装它:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- 安装 Git:
brew install git
- 检查已安装的版本:
git --version
如果终端已经返回了有效的 Git 版本信息,就不需要再次安装。
配置你的 Git 身份信息
接下来配置 Git 用户信息。请将示例值替换为你自己的姓名和邮箱地址:
git config --global user.name "your name"
git config --global user.email "your [email protected]"
然后运行:
git config --global --list
以确认配置已经生效。
2. 安装 Python 3
通过命令行安装 Python
- Windows
- macOS
在终端中运行以下命令:
winget search --id Python.Python.3.13 --source winget
winget install -e --id Python.Python.3.13 --source winget
如果第一个命令可以找到 Python,第二个命令通常就能直接安装它。
安装完成后,关闭终端并重新打开,然后运行:
python --version
pip --version

如果显示了版本号,说明 Python 和 pip 已经可以正常使用。
macOS 通常已经自带一个 Python 环境。在安装新版本之前,先检查是否已经可以使用 python3 和 pip3:
python3 --version
pip3 --version
如果它们不可用,或者你希望使用更新的版本,可以通过 Homebrew 安装 Python:
brew install python
安装完成后,重新打开终端并运行:
python3 --version
pip3 --version
如果你更习惯使用 python 和 pip,可以自行设置 shell 别名。不过在 macOS 上,使用 python3 和 pip3 通常更可靠。
3. 安装 PlatformIO
这一步对新手来说可能不太友好,因为 PlatformIO 会自动下载很多依赖,安装过程可能需要一些时间。如果安装过程中出现错误,通常最好耐心等待,并逐个排查问题。借助 AI 工具分析报错信息也能节省不少时间。
在 VS Code 扩展市场中搜索 PlatformIO 并进行安装。

安装完成后,左侧工具栏中通常会出现一个蚂蚁形状的图标。

4. 克隆 Meshtastic 固件仓库
Meshtastic 官方固件仓库为 meshtastic/firmware。
- Windows
- macOS
在你的工作目录终端中运行以下命令:
git clone https://github.com/meshtastic/firmware.git
cd firmware
git submodule update --init
如果你的项目目录在其他磁盘或不同路径下,请先切换到对应位置。


如果输出结果与上面的截图类似,说明仓库已经成功克隆。
在你的工作目录终端中运行以下命令:
cd ~/workplace
git clone https://github.com/meshtastic/firmware.git
cd firmware
git submodule update --init
如果 ~/workplace 目录尚不存在,请先创建它:
mkdir -p ~/workplace
如果命令能够正常执行完成,说明仓库已经成功克隆。
仓库准备好之后,你可以继续进行下面两个实践项目中的任意一个。项目 A 侧重于 Wio Tracker L1 的 UI 自定义;项目 B 侧重于基于 Meshtastic 的 XIAO ESP32S3 环境遥测。
项目 A:Wio Tracker L1 UI 自定义
实战练习
在这个阶段,不要急于修改代码。首先要确保项目能够完整地跑通一次构建流程。
建议从以下三个任务开始:
- 打开
firmware - 查看
platformio.ini - 找到目标开发板对应的构建环境
一个重要细节:不要只关注根目录下的 platformio.ini。它实际上还包含了额外的配置文件,例如:
extra_configs =
variants/*/*.ini
variants/*/*/platformio.ini
variants/*/diy/*/platformio.ini
这意味着真正的板级环境定义通常位于 variants/.../platformio.ini 下。
在确认目标开发板时,特别留意以下两个目录:
variants/boards/
这里我们以 Wio Tracker L1 Pro 作为示例目标。

这表明,在 Meshtastic 中,Wio Tracker L1 / L1 Pro 的构建目标是 seeed_wio_tracker_L1。
最小修改流程概览
如果你只想完成一次最小化的端到端实践,可以重点关注以下关键步骤:
- 安装 Git、Python 3、VS Code 和 PlatformIO。
- 克隆
meshtastic/firmware仓库并初始化子模块。 - 使用
pio run -e seeed_wio_tracker_L1确认原始项目可以成功构建。 - 修改
src/graphics/SharedUIDisplay.cpp中的显示逻辑。 - 重新构建固件,并将生成的 UF2 文件烧录到设备上进行验证。
步骤 1:确认项目可以成功构建
这里我们使用 PlatformIO Core CLI 进行构建。

对于第一次构建,建议运行以下命令:
- Windows
- macOS
cd D:\workplace\firmware # Adjust to your actual project path
pio run -e seeed_wio_tracker_L1
cd ~/workplace/firmware # Adjust to your actual project path
pio run -e seeed_wio_tracker_L1

如果界面看起来与上面的截图类似,说明构建过程已经正确开始。第一次构建通常会花费较长时间,请耐心等待。
如果构建失败
当构建失败时,你可以先让 PlatformIO 安装当前环境所需的依赖:
- Windows
- macOS
cd D:\workplace\firmware # Adjust to your actual project path
pio pkg install -e seeed_wio_tracker_L1
cd ~/workplace/firmware # Adjust to your actual project path
pio pkg install -e seeed_wio_tracker_L1
这种方式有几个好处:
- 它只安装依赖,而不会立即开始完整构建。
- 它可以更容易看出是哪个软件包导致了问题。
- 错误信息通常更集中,也更容易排查。
依赖安装完成后,运行:
- Windows
- macOS
pio run -e seeed_wio_tracker_L1 -v
pio run -e seeed_wio_tracker_L1 -v

依赖安装完成后,再次运行正常构建:
- Windows
- macOS
pio run -e seeed_wio_tracker_L1
pio run -e seeed_wio_tracker_L1

如果此时构建通过,说明你的固件输出已经成功生成。

步骤 2:修改代码
练习 1:修改 UI 显示
首先从板级配置开始追踪显示实现。你可以先查看:
variants/nrf52840/seeed_wio_tracker_L1/platformio.inivariants/nrf52840/seeed_wio_tracker_L1/variant.h

从这些配置文件中可以看到,L1 定义了 HAS_SCREEN 和 USE_SSD1306。这意味着它使用的是标准 OLED 显示管线,而不是无屏配置,也不是 E-Ink 方案。
如果继续追踪显示逻辑,大部分相关代码位于:
src/graphics/src/graphics/draw/
具体如何修改取决于你阅读源码的能力。这里我们从一个非常简单的例子开始:修改主屏幕 UI。
修改 1:记录电池文本的右边界
Before / After
// Before
int batteryX = 1;
int batteryY = HEADER_OFFSET_Y + 1;
// After
int batteryX = 1;
int batteryY = HEADER_OFFSET_Y + 1;
int batteryTextEndX = batteryX - 1;
src/graphics/SharedUIDisplay.cpp:157
这里增加了 batteryTextEndX,用于记录电池百分比文本的结束位置。这样后续在电池信息后追加自定义文本会更方便。
修改 2:在绘制电池百分比时计算右边界
// Before
if (chargePercent != 101) {
char chargeStr[4];
snprintf(chargeStr, sizeof(chargeStr), "%d", chargePercent);
int chargeNumWidth = display->getStringWidth(chargeStr);
display->drawString(batteryX, textY, chargeStr);
display->drawString(batteryX + chargeNumWidth - 1, textY, "%");
if (isBold) {
display->drawString(batteryX + 1, textY, chargeStr);
display->drawString(batteryX + chargeNumWidth, textY, "%");
}
}
// After
if (chargePercent != 101) {
char chargeStr[4];
snprintf(chargeStr, sizeof(chargeStr), "%d", chargePercent);
int chargeNumWidth = display->getStringWidth(chargeStr);
int percentWidth = display->getStringWidth("%");
display->drawString(batteryX, textY, chargeStr);
display->drawString(batteryX + chargeNumWidth - 1, textY, "%");
if (isBold) {
display->drawString(batteryX + 1, textY, chargeStr);
display->drawString(batteryX + chargeNumWidth, textY, "%");
}
batteryTextEndX = batteryX + chargeNumWidth + percentWidth - 1 + (isBold ? 1 : 0);
} else {
batteryTextEndX = batteryX - 1;
}
src/graphics/SharedUIDisplay.cpp:204
这段代码位于电池百分比绘制逻辑内部。除了正常显示电池电量外,它还会计算文本区域的右边界,以便在电池信息后放置自定义标签。
修改 3:为右侧图标区域预留边界
// Before
int iconRightEdge = timeX - 2;
// After
int iconRightEdge = timeX - 2;
int headerLabelRight = timeX - 4;
src/graphics/SharedUIDisplay.cpp:263
这部分处理右侧时间、邮件、静音等图标所占用的区域。我添加了 headerLabelRight 来限制中间文本的最右边界,防止与右侧内容重叠。
修改 4:在标题为空时绘制自定义标签
// Newly added core logic
#if defined(SEEED_WIO_TRACKER_L1) && !defined(SEEED_WIO_TRACKER_L1_EINK)
if (titleStr && titleStr[0] == '\0') {
static const char *yclLabel = "made by AE";
int labelWidth = display->getStringWidth(yclLabel);
int labelLeft = batteryTextEndX + 4;
if (labelLeft + labelWidth <= headerLabelRight) {
int labelX = labelLeft + ((headerLabelRight - labelLeft) - labelWidth) / 2;
display->drawString(labelX, textY, yclLabel);
if (isBold)
display->drawString(labelX + 1, textY, yclLabel);
}
}
#endif
src/graphics/SharedUIDisplay.cpp:350
这是本次修改的核心逻辑。它只适用于 SEEED_WIO_TRACKER_L1,并显式排除了 E-Ink 版本。它会在电池信息与时间显示之间的空白区域,将 made by AE 文本居中显示。
修改 5:处理不显示时间的分支
// Add the same boundary control for the no-time branch
int iconRightEdge = screenW - xOffset;
int headerLabelRight = screenW - xOffset - 2;
src/graphics/SharedUIDisplay.cpp:377
这是在没有时间值显示时使用的分支。这里同样需要加入相同的边界控制。
#if defined(SEEED_WIO_TRACKER_L1) && !defined(SEEED_WIO_TRACKER_L1_EINK)
if (titleStr && titleStr[0] == '\0') {
static const char *yclLabel = "made by AE";
int labelWidth = display->getStringWidth(yclLabel);
int labelLeft = batteryTextEndX + 4;
if (labelLeft + labelWidth <= headerLabelRight) {
int labelX = labelLeft + ((headerLabelRight - labelLeft) - labelWidth) / 2;
display->drawString(labelX, textY, yclLabel);
if (isBold)
display->drawString(labelX + 1, textY, yclLabel);
}
}
#endif
src/graphics/SharedUIDisplay.cpp:426
这是在无时间分支中绘制 made by AE 的实现。
你可以在这里找到完整代码:
步骤 3:构建你自己的固件
完成修改后,返回项目根目录,再次构建相同的目标:
- Windows
- macOS
cd D:\workplace\firmware # Adjust to your actual project path
pio run -e seeed_wio_tracker_L1
cd ~/workplace/firmware # Adjust to your actual project path
pio run -e seeed_wio_tracker_L1
显示逻辑已经改变,但构建目标仍然相同:
seeed_wio_tracker_L1
构建成功后,输出通常位于:
- Windows
- macOS
D:\workplace\firmware\.pio\build\seeed_wio_tracker_L1\
~/workplace/firmware/.pio/build/seeed_wio_tracker_L1/
你需要确认已被更新的文件是:
firmware-seeed_wio_tracker_L1-*.uf2
烧录固件
构建完成后,打开官方烧录页面:
在大多数情况下,你应该先执行擦除操作。

然后选择你刚刚构建的固件文件,并将其烧录到设备上。


至此,Meshtastic 源码实战练习已经完成。你已经走完了完整流程:环境搭建、仓库克隆、板卡配置探索、固件编译、显示逻辑修改以及最终烧录验证。
如果你想更进一步,可以继续探索以下方向:
- 修改主屏幕上的更多元素
- 调整按键、GPS、蓝牙等模块的行为
- 为你自己的板卡添加一个独立的
variant - 继续追踪
src/、variants/和boards/之间的关系
如果你想要一个更偏向功能的源码级示例,请继续查看下面的项目 B。它使用 XIAO ESP32S3 + Wio-SX1262 + SHT40 构建一个专用的环境遥测节点。与上面 Wio Tracker L1 的 UI 修改相比,这一部分更关注默认配置、遥测节奏以及两个节点之间的真实 Mesh 验证。
项目 B:XIAO ESP32S3 环境遥测节点
项目目标
这个进阶示例会在同一个 Mesh 中使用两个 Meshtastic 设备。
远程传感器节点
- 从
SHT40读取温度和湿度 - 使用 Meshtastic 环境遥测
- 将遥测数据发送到 Mesh 中
- 将 Mesh 发送间隔改为
60s - 跳过首次启动时的交互式区域设置
- 将默认区域设置为
US
附近网关节点
- 以
CLIENT身份加入 Meshtastic 网络 - 通过 LoRa 接收远程
TELEMETRY_APP数据包 - 解析
environmentMetrics.temperature - 解析
environmentMetrics.relativeHumidity
通信路径
XIAO ESP32S3 + Wio-SX1262 + SHT40 -> Meshtastic LoRa -> XIAO ESP32S3 + Wio-SX1262 (or any other device on the same mesh)
硬件准备
远程节点硬件
- Seeed
XIAO ESP32S3 Wio-SX1262SHT40
网关节点硬件
附近节点可以是任何加入同一网络的 Meshtastic 设备。在下面的示例中,我仍然使用另一块 XIAO ESP32S3 + Wio-SX1262 设备。
SHT40 接线
VCC -> 3V3GND -> GNDSDA -> GPIO5SCL -> GPIO6
已确认可用的设置:
I2C address = 0x44GPIO5 / GPIO6是当前使用的 I2C 接线对
下图展示了远程节点上实际使用的接线:

本项目使用的模块和 SKU
Seeeduino XIAO Expansion Board(SKU: 103030356)XIAO ESP32S3 & Wio-SX1262 Kit for Meshtastic & LoRa(SKU: 102010611)

修改远程节点的 Meshtastic 固件
本项目的目标环境为:
seeed-xiao-s3
主要文件为:
variants/esp32s3/seeed_xiao_s3/platformio.inisrc/modules/Telemetry/EnvironmentTelemetry.hsrc/modules/Telemetry/EnvironmentTelemetry.cpp
在本部分中,只需更新 variants/esp32s3/seeed_xiao_s3/platformio.ini 中的 build_flags 部分。其余上游文件保持不变。
build_flags =
${esp32s3_base.build_flags}
-D SEEED_XIAO_S3
-D ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE=1 ; enable environmental telemetry by default
-D USERPREFS_CONFIG_LORA_REGION=meshtastic_Config_LoRaConfig_RegionCode_US ; set the default region to US
-D USERPREFS_CONFIG_DEVICE_ROLE=meshtastic_Config_DeviceConfig_Role_SENSOR ; set the default role to SENSOR
-I variants/esp32s3/seeed_xiao_s3
-DBOARD_HAS_PSRAM
-DARDUINO_USB_MODE=0
build_flags 的更改应类似如下:

这三个标志的作用如下:
- 默认启用环境遥测
- 将默认区域设置为
US,因此首次启动不再停在区域选择界面 - 将默认设备角色设置为
SENSOR
遥测时序的更改是在 EnvironmentTelemetry.h 和 EnvironmentTelemetry.cpp 中实现的,而不是在 platformio.ini 中。
完成全部修改后,行为变为:
- 环境遥测默认启用
- 设备以区域
US启动 - 设备以角色
SENSOR启动 - Mesh 环境遥测每
60s发送一次 path=phone和path=mesh分别记录日志- 仅在实际 mesh 发送成功后才更新 mesh 发送时间戳
预期的 mesh 分发日志如下所示:
Environment telemetry dispatch path=mesh dest=0xffffffff interval_mesh_s=60
配置附近的网关节点
使用附近的 Meshtastic 设备作为同一 mesh 上的 CLIENT。在远程节点开始发送遥测后,确认网关可以接收:
TELEMETRY_APPenvironmentMetrics.temperatureenvironmentMetrics.relativeHumidity
如果网关在测试期间一直尝试连接 Wi-Fi,请使用 Meshtastic CLI 禁用 Wi-Fi。将 <gateway_port> 替换为你实际的串口,例如 Windows 上的 COMx 或 macOS 上的 /dev/cu.usbmodem...。
meshtastic --port <gateway_port> --set network.wifi_enabled false
构建、烧录并验证
步骤 1:复制修改后的文件
在构建之前,将三个修改后的文件复制到 Meshtastic 2.7.20 或 2.7.21 源码树中:
| 压缩包中的文件 | 替换 Meshtastic 源码树中的这个文件 |
|---|---|
meshtastic-2.7.20-s3-files/variants/esp32s3/seeed_xiao_s3/platformio.ini | <your Meshtastic directory>/variants/esp32s3/seeed_xiao_s3/platformio.ini |
meshtastic-2.7.20-s3-files/src/modules/Telemetry/EnvironmentTelemetry.h | <your Meshtastic directory>/src/modules/Telemetry/EnvironmentTelemetry.h |
meshtastic-2.7.20-s3-files/src/modules/Telemetry/EnvironmentTelemetry.cpp | <your Meshtastic directory>/src/modules/Telemetry/EnvironmentTelemetry.cpp |
直接下载链接:
如果你使用图形文件管理器复制文件,替换提示应类似如下:

步骤 2:构建远程固件
在 Meshtastic 固件根目录下运行:
pio run -e seeed-xiao-s3

步骤 3:上传到远程节点
- Windows
- macOS
pio device list
pio run -e seeed-xiao-s3 -t upload --upload-port COMx
如果你需要手动进入下载模式:
- 按住
BOOT - 轻按
RESET - 松开
RESET - 松开
BOOT
pio device list
pio run -e seeed-xiao-s3 -t upload --upload-port /dev/cu.usbmodemXXXX
先使用 pio device list,以便识别正确的串口:

上传完成后,PlatformIO 应该会报告烧录成功:

步骤 4:监控串口日志
使用 PlatformIO 的串口监视器检查远程节点和附近网关的日志。
- Windows
- macOS
pio device monitor -p COMx -b 115200
pio device monitor -p COMy -b 115200
pio device monitor -p /dev/cu.usbmodemE072A1D89EB81 -b 115200
pio device monitor -p /dev/cu.usbmodem3030F917FF281 -b 115200
查找类似如下的日志:
Environment telemetry dispatch path=mesh dest=0xffffffff interval_mesh_s=60
Send: relative_humidity=...
Send: ... temperature=...
步骤 5:使用 Meshtastic CLI 验证
首先安装 CLI:
- Windows
- macOS
pip install meshtastic
pip3 install meshtastic
安装完成后,重新打开终端并确认 meshtastic --help 可以正常运行。
在下面的命令中,将 <gateway_port> 替换为你实际的网关串口:
- Windows 示例:
COMx - macOS 示例:
/dev/cu.usbmodem3030F917FF281
meshtastic --port <gateway_port> --listen --debug
meshtastic --port <gateway_port> --nodes --show-fields user.id,user.longName,user.shortName
meshtastic --port <gateway_port> --get bluetooth.enabled --get bluetooth.mode --get bluetooth.fixed_pin --get power.wait_bluetooth_secs --get power.is_power_saving
meshtastic --port <gateway_port> --set network.wifi_enabled false
重点关注:
TELEMETRY_APPenvironmentMetrics.temperatureenvironmentMetrics.relativeHumidity
步骤 6:在手机应用中确认
烧录完成后,使用 Meshtastic 手机应用连接远程节点,确认可以看到环境数据。然后将应用连接到同一 mesh 上的另一台设备,在 Nodes 视图中检查是否通过 mesh 收到了传感器数值。
在远程传感器节点上,你应该可以在应用中直接看到环境遥测数值:

在附近节点上,这些读数在通过 mesh 转发后,应出现在 Nodes 视图中:

常见问题
git 命令不可用
- 在 Windows 上,先检查 Git 是否已添加到
PATH。 - 在 macOS 上,先运行
git --version。如果系统提示安装 Command Line Tools,请按提示操作。
python3 或 pip3 不可用
- 在 Windows 上,确认安装 Python 时已添加到
PATH,或者重新打开终端再试一次。 - 在 macOS 上,先检查是否已存在
python3/pip3,仅在需要时使用 Homebrew 安装 Python。
pio 命令不可用
- 先运行
pio --version。 - 如果命令仍不可用,重启 VS Code 和终端,然后再试一次。
- 如有必要,重新安装 PlatformIO 扩展,并确认 PlatformIO Core 已正确初始化。
运行 git submodule update --init 后代码仍然不完整
- 首先确保你位于
firmware仓库的根目录。 - 如果网络连接不稳定,请使用以下命令重试:
git submodule update --init --recursive
第一次构建耗时过长
- 第一次构建下载大量依赖是正常现象。
- 如果看起来长时间卡住,请先单独安装这些软件包:
pio pkg install -e seeed_wio_tracker_L1
然后再次运行构建。
Web 客户端未显示完整的环境遥测数据
- Meshtastic Web 客户端目前尚未为远程环境遥测提供完整的 UI。
Messages/Broadcast页面用于聊天流量,而不是专门的遥测页面。- 如果数值没有出现在那里,并不自动意味着 mesh 链路已经失败。
在手机上看到数据并不能证明 mesh 转发已生效
- 在直接连接的手机上看到刷新后的数值,只能证明本地手机到设备的连接是正常的。
- 这并不能自动证明环境遥测数据已经被转发进 mesh。
- 要确认真正的 mesh 转发,请在日志中检查以下条目:
Environment telemetry dispatch path=mesh ...TELEMETRY_APPenvironmentMetrics.temperatureenvironmentMetrics.relativeHumidity
seeed-xiao-s3 构建在首次设置时失败
- 第一次安装依赖可能需要很长时间,这是正常现象。
- 如果目标环境失败,请先安装依赖包,然后运行详细输出的构建:
pio pkg install -e seeed-xiao-s3
pio run -e seeed-xiao-s3 -v
- 依赖准备好之后,再回到正常构建:
pio run -e seeed-xiao-s3