- добавлен ручной workflow Gitea Actions (.gitea/workflows/build-mqtt-firmwares.yml): сборка MQTT-прошивок на сервере и публикация релиза - добавлен posadmesh-tools/publish-gitea-release.sh для выгрузки собранных файлов в релиз Gitea (идемпотентно, фильтр по треку) - README: происхождение проекта переписано (форк EastMesh, доработка энтузиастов из Сергиева Посада, ориентация на meshcoretel.ru), добавлены раздел «Отличия от upstream MeshCore» и журнал «Изменения в проекте» - убраны упоминания Австралии, ссылки на eastmesh.au и региональные материалы; руководство по прошивке переведено на файлы релизов и esptool.py - posadmesh-build.sh: вывод PlatformIO очищается от \r — на Windows групповые команды сборки не находили ни одной цели; companion-команды удалены, добавлены build-mqtt-firmwares и list-mqtt - release-notes.yml: треки repeater-mqtt*, запись 2026.10.0 дополнена удалением companion и исправлением сборки, companion-wifi помечен как снятый с выпуска - AGENTS.md: правило дописывать изменения в README - .gitignore: .pio-home
369 lines
11 KiB
Bash
Executable File
369 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
require_uv() {
|
|
if ! command -v uv >/dev/null 2>&1; then
|
|
echo "uv is required. Install it from https://docs.astral.sh/uv/" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
sync_python_tooling() {
|
|
uv sync --locked --no-group docs >/dev/null
|
|
uv venv --allow-existing --seed >/dev/null
|
|
}
|
|
|
|
run_python() {
|
|
uv run --no-sync python "$@"
|
|
}
|
|
|
|
run_pio() {
|
|
uv run --no-sync pio "$@"
|
|
}
|
|
|
|
global_usage() {
|
|
cat - <<EOF
|
|
Usage:
|
|
sh posadmesh-build.sh <command> [target]
|
|
|
|
Commands:
|
|
help|usage|-h|--help: Shows this message.
|
|
list|-l: List firmwares available to build.
|
|
list-mqtt: List only the PosadMesh MQTT build targets.
|
|
build-firmware <target>: Build the firmware for the given build target.
|
|
build-firmwares: Build all PosadMesh MQTT firmwares.
|
|
build-mqtt-firmwares: Build all MQTT firmwares (uplink, ESP-NOW bridge and MQTT bridge).
|
|
build-matching-firmwares <build-match-spec>: Build all firmwares for build targets containing the string given for <build-match-spec>.
|
|
build-repeater-mqtt-firmwares: Build the MQTT uplink firmwares.
|
|
build-repeater-mqtt-espnow-firmwares: Build the MQTT uplink firmwares that also run a local ESP-NOW bridge.
|
|
build-repeater-mqtt-bridge-firmwares: Build the MQTT bridge firmwares.
|
|
build-repeater-firmwares: Build all upstream repeater firmwares.
|
|
build-repeater-bridge-espnow-firmwares: Build all repeater ESP-NOW bridge firmwares.
|
|
build-room-server-firmwares: Build all chat room server firmwares.
|
|
|
|
Examples:
|
|
Build firmware for the "heltec_v4_repeater_mqtt" device target
|
|
$ sh posadmesh-build.sh build-firmware heltec_v4_repeater_mqtt
|
|
|
|
Build all MQTT firmwares
|
|
$ sh posadmesh-build.sh build-mqtt-firmwares
|
|
|
|
Build the MQTT uplink firmwares
|
|
$ sh posadmesh-build.sh build-repeater-mqtt-firmwares
|
|
|
|
Build the MQTT uplink firmwares with the local ESP-NOW bridge
|
|
$ sh posadmesh-build.sh build-repeater-mqtt-espnow-firmwares
|
|
|
|
Build the MQTT bridge firmwares
|
|
$ sh posadmesh-build.sh build-repeater-mqtt-bridge-firmwares
|
|
|
|
Build all firmwares for device targets containing the string "Xiao"
|
|
$ sh posadmesh-build.sh build-matching-firmwares Xiao
|
|
|
|
Environment Variables:
|
|
DISABLE_DEBUG=1: Disables all debug logging flags (MESH_DEBUG, MESH_PACKET_LOGGING, etc.)
|
|
If not set, debug flags from variant platformio.ini files are used.
|
|
|
|
Examples:
|
|
Build without debug logging:
|
|
$ export FIRMWARE_VERSION=v1.0.0
|
|
$ export DISABLE_DEBUG=1
|
|
$ sh posadmesh-build.sh build-firmware RAK_4631_repeater
|
|
|
|
Build with debug logging (default, uses flags from variant files):
|
|
$ export FIRMWARE_VERSION=v1.0.0
|
|
$ sh posadmesh-build.sh build-firmware RAK_4631_repeater
|
|
EOF
|
|
}
|
|
|
|
# get a list of pio env names that start with "env:"
|
|
get_pio_envs() {
|
|
run_pio project config --json-output | run_python -c "
|
|
import json
|
|
import sys
|
|
|
|
for section, _options in json.load(sys.stdin):
|
|
if section.startswith('env:'):
|
|
print(section[4:])
|
|
" | tr -d '\r'
|
|
}
|
|
|
|
# Catch cries for help before doing anything else.
|
|
case $1 in
|
|
help|usage|-h|--help)
|
|
global_usage
|
|
exit 1
|
|
;;
|
|
list|-l)
|
|
require_uv
|
|
sync_python_tooling
|
|
get_pio_envs
|
|
exit 0
|
|
;;
|
|
list-mqtt)
|
|
require_uv
|
|
sync_python_tooling
|
|
get_pio_envs | grep -E '_(repeater_mqtt|repeater_mqtt_espnow|repeater_mqtt_bridge)$' | sort
|
|
exit 0
|
|
;;
|
|
esac
|
|
|
|
# cache project config json for use in get_platform_for_env()
|
|
require_uv
|
|
sync_python_tooling
|
|
|
|
PIO_CONFIG_JSON=$(run_pio project config --json-output)
|
|
|
|
# $1 should be the string to find (case insensitive)
|
|
get_pio_envs_containing_string() {
|
|
shopt -s nocasematch
|
|
envs=($(get_pio_envs))
|
|
for env in "${envs[@]}"; do
|
|
if [[ "$env" == *${1}* ]]; then
|
|
echo $env
|
|
fi
|
|
done
|
|
}
|
|
|
|
# $1 should be the string to find (case insensitive)
|
|
get_pio_envs_ending_with_string() {
|
|
shopt -s nocasematch
|
|
envs=($(get_pio_envs))
|
|
for env in "${envs[@]}"; do
|
|
if [[ "$env" == *${1} ]]; then
|
|
echo $env
|
|
fi
|
|
done
|
|
}
|
|
|
|
# get platform flag for a given environment
|
|
# $1 should be the environment name
|
|
get_platform_for_env() {
|
|
local env_name=$1
|
|
echo "$PIO_CONFIG_JSON" | run_python -c "
|
|
import sys, json, re
|
|
data = json.load(sys.stdin)
|
|
for section, options in data:
|
|
if section == 'env:$env_name':
|
|
for key, value in options:
|
|
if key == 'build_flags':
|
|
for flag in value:
|
|
match = re.search(r'(ESP32_PLATFORM|NRF52_PLATFORM|STM32_PLATFORM|RP2040_PLATFORM)', flag)
|
|
if match:
|
|
print(match.group(1))
|
|
sys.exit(0)
|
|
" | tr -d '\r'
|
|
}
|
|
|
|
# disable all debug logging flags if DISABLE_DEBUG=1 is set
|
|
disable_debug_flags() {
|
|
if [ "$DISABLE_DEBUG" == "1" ]; then
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -UBLE_DEBUG_LOGGING -UWIFI_DEBUG_LOGGING -UBRIDGE_DEBUG -UGPS_NMEA_DEBUG -UCORE_DEBUG_LEVEL -UESPNOW_DEBUG_LOGGING -UDEBUG_RP2040_WIRE -UDEBUG_RP2040_SPI -UDEBUG_RP2040_CORE -UDEBUG_RP2040_PORT -URADIOLIB_DEBUG_SPI -UCFG_DEBUG -URADIOLIB_DEBUG_BASIC -URADIOLIB_DEBUG_PROTOCOL"
|
|
fi
|
|
}
|
|
|
|
get_firmware_build_date() {
|
|
local env_name="$1"
|
|
local header="examples/simple_repeater/MyMesh.h"
|
|
|
|
if [[ "$env_name" == *room_server* ]]; then
|
|
header="examples/simple_room_server/MyMesh.h"
|
|
elif [[ "$env_name" == *sensor* ]]; then
|
|
header="examples/simple_sensor/SensorMesh.h"
|
|
fi
|
|
|
|
sed -n 's/^[[:space:]]*#define[[:space:]][[:space:]]*FIRMWARE_BUILD_DATE[[:space:]][[:space:]]*"\([^"]*\)".*/\1/p' "$header" | head -n 1 | tr -d '\r'
|
|
}
|
|
|
|
# build firmware for the provided pio env in $1
|
|
build_firmware() {
|
|
# get env platform for post build actions
|
|
ENV_PLATFORM=($(get_platform_for_env $1))
|
|
|
|
# get git commit sha
|
|
COMMIT_HASH=$(git rev-parse --short HEAD)
|
|
|
|
# use the same fallback build date as direct PlatformIO builds
|
|
FIRMWARE_BUILD_DATE=$(get_firmware_build_date "$1")
|
|
if [ -z "$FIRMWARE_BUILD_DATE" ]; then
|
|
echo "FIRMWARE_BUILD_DATE could not be read for $1"
|
|
exit 1
|
|
fi
|
|
|
|
# get FIRMWARE_VERSION, which should be provided by the environment
|
|
if [ -z "$FIRMWARE_VERSION" ]; then
|
|
echo "FIRMWARE_VERSION must be set in environment"
|
|
exit 1
|
|
fi
|
|
|
|
# set artifact version string
|
|
# e.g: v1.2.3-posadmesh-v1.0.1-abcdef
|
|
FIRMWARE_VERSION_BASE="${FIRMWARE_VERSION}"
|
|
if [ -n "$POSADMESH_VERSION" ]; then
|
|
FIRMWARE_VERSION_BASE="${FIRMWARE_VERSION_BASE}-posadmesh-${POSADMESH_VERSION}"
|
|
fi
|
|
FIRMWARE_VERSION_STRING="${FIRMWARE_VERSION_BASE}-${COMMIT_HASH}"
|
|
CLIENT_VERSION_STRING="PosadMesh/${COMMIT_HASH}"
|
|
if [ -n "$POSADMESH_VERSION" ]; then
|
|
CLIENT_VERSION_STRING="PosadMesh/${POSADMESH_VERSION}-${COMMIT_HASH}"
|
|
fi
|
|
|
|
# craft filename
|
|
# e.g: RAK_4631_Repeater-v1.0.0-SHA
|
|
FIRMWARE_FILENAME="$1-${FIRMWARE_VERSION_STRING}"
|
|
|
|
# add build metadata to end of existing platformio build flags in environment vars
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION}\"' -DCLIENT_VERSION='\"${CLIENT_VERSION_STRING}\"' -DCLIENT_ENV='\"${1}\"'"
|
|
|
|
# disable debug flags if requested
|
|
disable_debug_flags
|
|
|
|
# build firmware target
|
|
run_pio run -e $1
|
|
|
|
# build merge-bin for esp32 fresh install, copy .bins to out folder (e.g: Heltec_v3_room_server-v1.0.0-SHA.bin)
|
|
if [ "$ENV_PLATFORM" == "ESP32_PLATFORM" ]; then
|
|
run_pio run -t mergebin -e $1
|
|
cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true
|
|
cp .pio/build/$1/firmware-merged.bin out/${FIRMWARE_FILENAME}-merged.bin 2>/dev/null || true
|
|
fi
|
|
|
|
# build .uf2 for nrf52 boards, copy .uf2 and .zip to out folder (e.g: RAK_4631_Repeater-v1.0.0-SHA.uf2)
|
|
if [ "$ENV_PLATFORM" == "NRF52_PLATFORM" ]; then
|
|
run_python bin/uf2conv/uf2conv.py .pio/build/$1/firmware.hex -c -o .pio/build/$1/firmware.uf2 -f 0xADA52840
|
|
cp .pio/build/$1/firmware.uf2 out/${FIRMWARE_FILENAME}.uf2 2>/dev/null || true
|
|
cp .pio/build/$1/firmware.zip out/${FIRMWARE_FILENAME}.zip 2>/dev/null || true
|
|
fi
|
|
|
|
# for stm32, copy .bin and .hex to out folder
|
|
if [ "$ENV_PLATFORM" == "STM32_PLATFORM" ]; then
|
|
cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true
|
|
cp .pio/build/$1/firmware.hex out/${FIRMWARE_FILENAME}.hex 2>/dev/null || true
|
|
fi
|
|
|
|
# for rp2040, copy .bin and .uf2 to out folder
|
|
if [ "$ENV_PLATFORM" == "RP2040_PLATFORM" ]; then
|
|
cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true
|
|
cp .pio/build/$1/firmware.uf2 out/${FIRMWARE_FILENAME}.uf2 2>/dev/null || true
|
|
fi
|
|
|
|
}
|
|
|
|
# firmwares containing $1 will be built
|
|
build_all_firmwares_matching() {
|
|
envs=($(get_pio_envs_containing_string "$1"))
|
|
for env in "${envs[@]}"; do
|
|
build_firmware $env
|
|
done
|
|
}
|
|
|
|
# firmwares ending with $1 will be built
|
|
build_all_firmwares_by_suffix() {
|
|
envs=($(get_pio_envs_ending_with_string "$1"))
|
|
for env in "${envs[@]}"; do
|
|
build_firmware $env
|
|
done
|
|
}
|
|
|
|
build_repeater_firmwares() {
|
|
|
|
# # build specific repeater firmwares
|
|
# build_firmware "Heltec_v2_repeater"
|
|
# build_firmware "Heltec_v3_repeater"
|
|
# build_firmware "Xiao_C3_Repeater_sx1262"
|
|
# build_firmware "Xiao_S3_WIO_Repeater"
|
|
# build_firmware "LilyGo_T3S3_sx1262_Repeater"
|
|
# build_firmware "RAK_4631_Repeater"
|
|
|
|
# build all repeater firmwares
|
|
build_all_firmwares_by_suffix "_repeater"
|
|
|
|
}
|
|
|
|
build_repeater_bridge_espnow_firmwares() {
|
|
|
|
build_all_firmwares_by_suffix "_repeater_bridge_espnow"
|
|
|
|
}
|
|
|
|
build_repeater_mqtt_firmwares() {
|
|
|
|
build_all_firmwares_by_suffix "_repeater_mqtt"
|
|
|
|
}
|
|
|
|
build_repeater_mqtt_espnow_firmwares() {
|
|
|
|
build_all_firmwares_by_suffix "_repeater_mqtt_espnow"
|
|
|
|
}
|
|
|
|
build_repeater_mqtt_bridge_firmwares() {
|
|
|
|
build_all_firmwares_by_suffix "_repeater_mqtt_bridge"
|
|
|
|
}
|
|
|
|
# every MQTT firmware track: uplink, uplink with ESP-NOW bridge, and MQTT bridge
|
|
build_mqtt_firmwares() {
|
|
|
|
build_repeater_mqtt_firmwares
|
|
build_repeater_mqtt_espnow_firmwares
|
|
build_repeater_mqtt_bridge_firmwares
|
|
|
|
}
|
|
|
|
build_room_server_firmwares() {
|
|
|
|
# # build specific room server firmwares
|
|
# build_firmware "Heltec_v3_room_server"
|
|
# build_firmware "RAK_4631_room_server"
|
|
|
|
# build all room server firmwares
|
|
build_all_firmwares_by_suffix "_room_server"
|
|
|
|
}
|
|
|
|
build_firmwares() {
|
|
build_mqtt_firmwares
|
|
}
|
|
|
|
# clean build dir
|
|
rm -rf out
|
|
mkdir -p out
|
|
|
|
# handle script args
|
|
if [[ $1 == "build-firmware" ]]; then
|
|
TARGETS=${@:2}
|
|
if [ "$TARGETS" ]; then
|
|
for env in $TARGETS; do
|
|
build_firmware $env
|
|
done
|
|
else
|
|
echo "usage: $0 build-firmware <target>"
|
|
exit 1
|
|
fi
|
|
elif [[ $1 == "build-matching-firmwares" ]]; then
|
|
if [ "$2" ]; then
|
|
build_all_firmwares_matching $2
|
|
else
|
|
echo "usage: $0 build-matching-firmwares <build-match-spec>"
|
|
exit 1
|
|
fi
|
|
elif [[ $1 == "build-firmwares" ]]; then
|
|
build_firmwares
|
|
elif [[ $1 == "build-mqtt-firmwares" ]]; then
|
|
build_mqtt_firmwares
|
|
elif [[ $1 == "build-repeater-firmwares" ]]; then
|
|
build_repeater_firmwares
|
|
elif [[ $1 == "build-repeater-bridge-espnow-firmwares" ]]; then
|
|
build_repeater_bridge_espnow_firmwares
|
|
elif [[ $1 == "build-repeater-mqtt-firmwares" ]]; then
|
|
build_repeater_mqtt_firmwares
|
|
elif [[ $1 == "build-repeater-mqtt-espnow-firmwares" ]]; then
|
|
build_repeater_mqtt_espnow_firmwares
|
|
elif [[ $1 == "build-repeater-mqtt-bridge-firmwares" ]]; then
|
|
build_repeater_mqtt_bridge_firmwares
|
|
elif [[ $1 == "build-room-server-firmwares" ]]; then
|
|
build_room_server_firmwares
|
|
fi
|