* esp32_platform: update to 55.03.39
## Summary
- Add support for Python 3.14
- Improve ESP32 platform and framework compatibility.
- Update board support and toolchain integrations.
- Fix stability and hardware-specific issues across supported ESP32 targets.
- Release notes:
- [55.03.39](https://github.com/pioarduino/platform-espressif32/releases/tag/55.03.39)
- [55.03.38](https://github.com/pioarduino/platform-espressif32/releases/tag/55.03.38)
- [55.03.37](https://github.com/pioarduino/platform-espressif32/releases/tag/55.03.37)
- [55.03.36](https://github.com/pioarduino/platform-espressif32/releases/tag/55.03.36)
- [55.03.35](https://github.com/pioarduino/platform-espressif32/releases/tag/55.03.35)
- [55.03.34](https://github.com/pioarduino/platform-espressif32/releases/tag/55.03.34)
* update build to use python 3.14 with platformio 6.1.19
* Update esp32-arduino-lib-builder to v1.5
* [CI] Fix call8 link overflow on large Xtensa builds (IDF 5.5.4)
The 55.03.39 / IDF 5.5.4 bump enlarges the precompiled libs enough that
large Xtensa images (esp32 / esp32s3) overflow the call8 reach and fail to
link with "dangerous relocation: call8: call target out of range".
-mlongcalls (which makes calls linker-relaxable) is injected by
esp32-arduino-libs into the framework compile but NOT into lib_deps
(NimBLE-Arduino, ArduinoJson) or project sources.
Add a project pre: extra_script (scripts/add_mlongcalls.py) that applies
-mlongcalls to CCFLAGS/ASFLAGS, gated on the Xtensa MCUs (RISC-V c3 has no
call8 and rejects the flag). Wired into [env]; the four esp32dev-*pilight*
envs that set their own extra_scripts list it explicitly too, since
PlatformIO replaces rather than merges extra_scripts.
Also bump esp32-arduino-libs 0.1.5 -> 0.1.6, which restores the
framework-side -mdisable-hardware-atomics / -fno-builtin-* flags that 0.1.5
dropped under IDF 5.5.4 (separate from the lib_deps call8 issue).
Verified clean (0 call8): esp32dev-all-test, esp32dev-ble, theengs-bridge,
theengs-plug, esp32dev-pilight (+cc1101); esp32c3 unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Florian <florian@theengs.io>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Updates the NorthernMan54/rtl_433_ESP dependency from v0.5.0 to v0.5.1,
which guards vdata_make() against strdup(NULL) for DATA_FORMAT.
Co-authored-by: Claude <noreply@anthropic.com>
Bumps the precompiled framework-arduinoespressif32-libs bundle from 0.1.3
to 0.1.4, which builds the esp32 BT controller in BLE-only mode (classic
BR/EDR + A2DP/SPP/HFP dropped). OMG's BT stack is NimBLE (a BLE-only host)
and never uses classic Bluetooth, so it was unreachable dead weight.
Measured on a no-PSRAM Theengs Plug (esp32, NimBLE, MQTT over TLS):
- flash 89.5% -> 86.7% (-54 KB)
- runtime freemem +~10 KB: the dual-mode controller reserved heap for the
classic BR/EDR baseband + 2 classic ACL connections at
esp_bt_controller_init(); BLE-only skips it
- BLE scan/decode and GATT connect (BM2/BM6 battery reads, SwitchBot
control) validated working
esp32-arduino-lib-builder change: theengs/esp32-arduino-lib-builder
mem/esp32-ble-only-controller (in 0.1.4).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to #2321. That PR fixed five strcpy sites in XtoSYS/createOrUpdateDevice
but left adjacent attack surfaces using the same pattern (strncpy with the
destination's own size, leaving the buffer non-NUL-terminated when the source
is at the limit; or strcpy of WiFiManager/HTTP form values that bypass the
client-side maxlength). The over-long string then flows into saveConfig() and
back into a strcpy on next boot, corrupting heap/.bss on every reload.
main/main.cpp - XtoSYS: length-check before copying mqtt_topic, discovery_prefix,
gateway_name, gw_pass (ota_pass), and ble_aes. Reject over-length with
THEENGS_LOG_WARNING, preserving existing values.
main/main.cpp - loadConfigFromFlash: new loadStrField() helper applies the same
guard to every SPIFFS-loaded string (mqtt_server/port/user/pass per slot,
mqtt_topic, discovery_prefix, gateway_name, ota_pass, ble_aes). Defense in
depth in case a pre-fix build left an over-length value in /config.json.
main/main.cpp - WiFiManager save: bound mqtt_topic against the 150-byte portal
buffer overflowing the 66-byte destination (HTML maxlength is client-side
only; a raw POST bypasses it).
main/webUI.cpp - handleCG /gw save: bound gateway-password form input before
the strncpy that previously left ota_pass non-NUL-terminated.
main/blufi.cpp - ESP_BLUFI_EVENT_RECV_STA_SSID/PASSWD: clamp the wire-supplied
ssid_len/passwd_len before the memcpy and the trailing NUL so a crafted
BluFi provisioning frame cannot overrun gl_sta_ssid[32]/gl_sta_passwd[64].
main/gatewayBT.cpp - BLEDecryptor (Victron, encr==3): remove `nonce[16] = {0}`,
a one-byte stack-OOB write reachable from any BLE adv. The line was dead
(the memset two lines later zeroes the whole array); deleting it eliminates
the OOB write.
main/gatewaySRFB.cpp - SRFBtoX: bound the _uartbuf writer so a 433 MHz frame
with no STOP can no longer let _uartpos grow past sizeof(_uartbuf).
main/gatewaySRFB.cpp - _rfbSend: the hex output buffer was sized RF_MESSAGE_SIZE
(9) but _rawToHex writes 2*N+2 bytes per call. Resize to fit.
Tested on a Theengs Bridge: built theengs-bridge-v11 env, OTA-flashed, and
verified that publishing {"discovery_prefix":"Z"*200} to MQTTtoSYS/config
leaves discovery_prefix unchanged (no Z*65 truncation in subsequent discovery
topics), bridge keeps decoding BLE adverts, and SYStoMQTT/LWT stay healthy.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GPIO0 (D3) is the ESP8266 boot strapping pin: an RF receiver holding the
data line low at reset forces the board into flash mode, so a stock
nodemcuv2-rf build never starts after a restart with the receiver wired
to the documented default pin. Default to GPIO4 (D2) instead, which the
docs already recommend as the workaround. Environments that need other
pins (srfb-direct, sonoff-rfr3, rf-wifi-gateway) already override the
value explicitly and are unaffected.
The compatible.openmqttgateway.com site is offline (TLS connection reset),
leaving 38 dead links across the docs and README. Repoint BLE device lists
to the canonical Theengs Decoder devices page already used by the navbar,
point boards/devices/parts references to the corresponding docs pages, and
drop the affiliate-site mentions and 'Where to Buy' links that have no live
equivalent. Also fix a malformed markdown link in docs/use/ble.md.
Guard createOrUpdateDevice() in gatewayBT.cpp against null or >17-char MAC
strings before the strcpy into the 18-byte BLEdevice::macAdr buffer. An
MQTT client could previously publish a crafted white-list/black-list/id
field to MQTTtoBT/config (and related topics) and corrupt the heap.
Apply the same defense to the XtoSYS config branch in main.cpp: mqtt_user,
mqtt_pass, mqtt_server, and mqtt_port are now length-checked against their
destination buffer sizes before strcpy. The mqtt_port destination is only
6 bytes, so this path was particularly easy to overflow via MQTTtoSYS/config.
Oversized fields are now rejected with a warning log; existing values are
preserved and the device does not crash.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the network drops at runtime and the WiFi stack is wedged (e.g. the
ESP32 driver getting stuck after a long uptime, see #2276), the main loop
kept calling wifi_reconnect_bypass() forever with no recovery: the device
stayed stale until a manual reboot. The reboot watchdog only existed in the
ESPWifiManualSetup path, which the default WiFiManager build doesn't compile.
Count consecutive reconnection failures in the runtime loop and ESPRestart(2)
once they exceed maxRetryWatchDog, mirroring the existing manual-setup
watchdog. Gated behind the new WifiReconnectWatchDog flag (default on) so
environments where an unexpected reboot is undesirable can opt out; disabled
for theengs-plug to avoid interrupting the relay state.
Co-authored-by: Claude <noreply@anthropic.com>
Home Assistant rejects an MQTT discovery payload that carries `options`
(an enum sensor) together with `state_class` or `unit_of_measurement`:
these fields are mutually exclusive. createDiscovery() was emitting all
three for Mi Body Composition Scale (XMTZC0x) weighing_mode/unit sensors,
so HA discarded the discovery message.
Gate the stat_cla and unit_of_meas writes on enum_options == nullptr so
enum sensors no longer carry the conflicting fields.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
iBeacon uuid/mfid (and any decoder property with unit "hex") were built
as HA sensors with state_class "measurement" and unit "hex". Home
Assistant rejects a measurement sensor whose value is non-numeric, so it
logged "non-numeric value" errors on every iBeacon decode. Route "hex"
units through the same path as "string" units: plain text sensor, no
state_class, no unit_of_measurement.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
immediateBTAction() sets BTProcessLock=true and stops the scan before an
outbound BLE action, and resets it on the success path and the
"BLE busy" path — but the branch where semaphoreCreateOrUpdateDevice
can't be taken left it true. Under scan contention that wedges the BLE
scanner/connect subsystem until a restart (same BTProcessLock-mishandling
family as the long-uptime NimBLE scanner hang). Reset it on that branch
too.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [SYS] Don't clobber MQTT/portal defaults with empty form fields
The /wifisave handler unconditionally strcpy'd every form value into the
persisted config, even when WiFiManager surfaced an empty string for a
field the caller omitted. A partial provisioning POST (e.g. only s/p)
silently wiped the compile-time MQTT defaults so the DUT joined WiFi but
never reached the broker.
Mirror the mqtt_pass sentinel guard with strlen() > 0 checks for the
remaining textual fields (server, port, user, topic, name, ota). The
boolean checkboxes and certificate fields already had non-empty guards.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [DOCS] Document /wifisave provisioning portal API
Add a reference page enumerating the HTTP form fields accepted by the
on-device configuration portal so companion apps and provisioning scripts
can integrate without reading firmware source. Documents the empty-field
ignore semantics introduced in the previous commit and the AP-teardown
response race that callers must tolerate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [SYS] Also length-guard the MQTT password sentinel branch
The sentinel-only check (form-value != MQTT_PASS) was meant to protect
the stored password against accidental re-saves of the form default,
but it also persists an empty string from a partial / programmatic POST
that omits the `pass` field — empty differs from the sentinel, so the
broker password gets wiped. Add a strlen() > 0 precondition so partial
POSTs preserve the existing password.
Verified on the HIL bench (test_sys/test_wifimanager_portal_partial):
without this commit the DUT joined WiFi but never reached the broker;
with it, LWT-online lands within the reconnect budget.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [DOCS] Reflect length-guard in /wifisave mqtt_pass semantics
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [BT] Default BLE AES key empty, skip decryption without a key
Shipping a non-empty default key caused fresh installs to attempt
decryption of every encrypted PVVX/BTHome v2/Victron advertisement with
the placeholder string from User_config.h. Frames that didn't happen to
share that key were silently dropped at the CCM auth step, masking
otherwise-decodable devices (notably Victron MPPT) until users found and
entered a per-MAC key.
Initialise ble_aes[] to "" and treat an empty default as "no default
configured" in the decryption path - mirroring Theengs Gateway, which
has no default and skips frames whose MAC has no bindkey. Per-MAC keys
in ble_aes_keys still take precedence; the BLE_AES macro remains as the
WebUI placeholder hint.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [BT] clang-format: move BLE_AES default comment above #define
clang-format-9 rejected the trailing-comment continuation on the empty
BLE_AES default line. Move the explanation to a leading // block above
the #ifndef so the directive line is comment-free.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [BT] Use THEENGS_LOG_TRACE for missing-AES-key skip log
Previous commit referenced THEENGS_LOG_DEBUG, which OMG does not define
(only VERBOSE/TRACE/NOTICE/WARNING/ERROR exist), breaking every BLE
firmware build. Switch to THEENGS_LOG_TRACE — same level as the adjacent
"Custom AES key" / "Default AES key" trace lines.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The VuePress->VitePress migration replaced the `themeConfig.mode === 'dev'`
gate with a heuristic on `site.title`. CI overrides version with a short
SHA (dev) or git tag (prod), so the title never contains "edge"/"dev" and
the banner never renders on live deploys. Surface `meta.mode` in
`themeConfig` and check it directly, mirroring the original behaviour.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The PlatformIO library registry can no longer resolve
SmartRC-CC1101-Driver-Lib@2.5.7:
Library Manager: Installing SmartRC-CC1101-Driver-Lib @ 2.5.7
Warning! Could not find the package with 'SmartRC-CC1101-Driver-Lib @ 2.5.7'
requirements for your system 'linux_x86_64'
This breaks every CC1101-based environment in the nightly build:
esp32dev-rtl_433, esp32dev-pilight-cc1101, esp32dev-multi_receiver,
esp32dev-somfy-cc1101, nodemcuv2-rf2-cc1101, and others fail with:
main/commonRF.cpp:30:14: fatal error: ELECHOUSE_CC1101_SRC_DRV.h: No such file
Switch to the upstream GitHub release URL, matching how other
removed-from-registry libs in this file are pinned (m5tough, stl,
shtc3, etc). The v2.5.7 tag still exists in the upstream repo.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Switch Ethernet RMII clock from GPIO16 to GPIO0 output mode,
freeing GPIO16 for PSRAM chip select (SPICS1) on WROVER-IE
- Enable PSRAM with QIO flash mode and cache workaround flags
- Add PHY pre-power support for ETH_CLOCK_GPIO0_IN mode
- Report PSRAM status and free memory in SYS MQTT topic
Requires Theengs lib-builder update: remove LIBTIME from IRAM
cache workaround (CONFIG_SPIRAM_CACHE_LIBTIME_IN_IRAM=n) to
free ~3.5KB IRAM for the -mfix-esp32-psram-cache-issue flag.
Tested on Theengs Bridge v1.1: 4MB PSRAM detected, Ethernet
100Mbps on GPIO0, BLE scanning nominal.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
createDiscovery sits at the bottom of the discovery call chain
(loop → launchBTDiscovery → <device>Discovery → createDiscoveryFromList
(9-col, VLA) → createDiscoveryFromList(13-col) → here). Keeping
2×1024 B StaticJsonDocuments on the stack burned loopTask headroom
down to ~100 B free under a full BLE + WebUI load. Moving the two
buffers to the heap drops that 2 KB off the stack peak.
Measured over the full test_perf + test_webui suite on
esp32dev-ble-hil-fastsys (dev HEAD):
freestck_min_bytes: 292 → 2324 B (+2032, target was ≥1500)
minmem_soak_bytes: 18200 → 20652 B (+2452)
all 17 tests still pass
The docs are function-scoped, so net heap usage is unchanged long-term
(free-on-return), and the soak heap floor actually improved.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The BLE gateway only connects to one device at a time sequentially,
so 3 connection slots are unnecessary. This saves ~4-8KB of RAM.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace VuePress 1.9.10 with VitePress 1.6.4
- Convert config from CommonJS to ESM TypeScript (config.mts)
- Convert shared Theengs nav config to ESM (commonConfig.mts)
- Rewrite BoardEnvironmentTable in Vue 3 Composition API
- Rewrite FlashEnvironmentSelector in Vue 3 Composition API
- Enable built-in local search and dark mode
- Add medium-zoom for image zoom
- Use VitePress CSS variables for dark mode compatibility
- Update CI script paths from .vuepress to .vitepress
- Update .gitignore for VitePress build artifacts
- Rename README.md files to index.md (VitePress convention)
- Fix markdown compatibility (angle-bracket escaping, image paths)
- Drop PWA plugin (not needed)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ble_script is defined as "" (empty string). Passing it to
server.sendContent("") signals end of HTTP chunked transfer,
closing the response prematurely. All subsequent chunks then
fail with errno 104 "Connection reset by peer".
Guard the call with a length check so the empty string is
never sent as a chunk terminator.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Expand the BLE config page from encryption-only (BLEDecryptor) to a
comprehensive settings page available for all ZgatewayBT builds, covering
scan, publish, presence, external decoder, and encryption settings.
Add MQTT Discovery checkbox to the gateway configuration page.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a search input and filter chips to the web-install board grid,
allowing users to quickly find boards by name, MCU family (ESP32,
ESP32-S3, ESP32-C3, ESP8266), or gateway type (BLE, RF, IR, LoRa,
RTL_433, Pilight). Filters are derived dynamically from the board
data. Shows result count and a clear-all button when filters are
active.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The prepare job now checks for commits in the last 24 hours before
proceeding. If there are no changes, the firmware build and docs
deploy are skipped, saving CI minutes. Manual triggers always run.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The ci_site.sh script was overriding the VuePress dest to
"generated/site/dev" in dev mode. Since task-docs.yml already sets
destination_dir: "dev" in the GitHub Pages deploy step, this caused
the site to be nested at /dev/dev/ on gh-pages, leaving
docs.openmqttgateway.com/dev/ empty.
Remove the dest override and let the deploy action handle the
subdirectory placement.
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Refactor GitHub Actions workflows for build, documentation, and linting
- Consolidated build logic into reusable workflows (`task-build.yml` and `task-docs.yml`) to reduce duplication across multiple workflows.
- Introduced `environments.json` to centralize the list of PlatformIO build environments, improving maintainability and clarity.
- Updated `build.yml` and `build_and_docs_to_dev.yml` to utilize the new reusable workflows and environment definitions.
- Enhanced `release.yml` to streamline the release process and integrate documentation generation.
- Created reusable linting workflow (`task-lint.yml`) to standardize code formatting checks across the repository.
- Simplified manual documentation workflow by leveraging the new reusable documentation workflow.
- Improved artifact management and retention policies across workflows.
- Updated dependencies and versions in workflows to ensure compatibility and performance.
CI/CD pipeline agnostic of Workflow Engine and integrated on github actions
- Implemented ci.sh for orchestrating the complete build pipeline.
- Created ci_00_config.sh for centralized configuration of build scripts.
- Created ci_build_firmware.sh for building firmware for specified PlatformIO environments.
- Created ci_prepare_artifacts.sh for preparing firmware artifacts for upload or deployment.
- Created ci_set_version.sh for updating version tags in firmware configuration files.
- Created ci_build.sh to orchestrate the complete build pipeline.
- Created ci_qa.sh for code linting and formatting checks using clang-format.
- Created ci_site.sh for building and deploying VuePress documentation with version management.
- Implemented checks for required tools and dependencies in the new scripts.
- Improved internal scripts for better error handling and logging.
UPDATE the web installer manifest generation and update documentation structure
- Enhanced ci_list-env.sh to list environments from a JSON file.
- Replaced common_wu.py and gen_wu.py scripts with new npm scripts for site generation and previewing on docsgen/gen_wu.js
- Replaced generate_board_docs.py with docsgen/generated_board_docs.js
- Added new npm scripts for integration of site generation on build phase.
- Created preview_site.js to serve locally generated site over HTTPS with improved error handling.
- Added new CI environments for CI builds in environments.json.
- Deleted lint.yml as part of workflow cleanup.
- Enhanced task-build.yml to include linting as a job and added support for specifying PlatformIO version.
- Improved task-docs.yml to handle versioning more effectively and added clean option.
Enhance documentation
- ADD CLEAR Mark of development version of site
- Updated README.md to include detailed workflow dependencies and relationships using mermaid diagrams.
- Improved development.md with a quick checklist for contributors and clarified the code style guide.
- Enhanced quick_start.md with tips for contributors and streamlined the workflow explanation.
LINT FIX
- Refined User_config.h for better formatting consistency.
- Adjusted blufi.cpp and gatewayBT.cpp for improved code readability and consistency in formatting.
- Updated gatewaySERIAL.cpp and mqttDiscovery.cpp to enhance logging error messages.
- Improved sensorDS1820.cpp for better logging of device information.
Add security scan workflows for vulnerability detection
Add SBOM generation and upload to release workflow; update security scan summary handling
Add shellcheck suppor + FIX shellcheck warning
Enhance documentation for CI/CD scripts and workflows, adding details for security scanning and SBOM generation processes
Fix formatting and alignment in BLE connection handling
Reviewed the full web board presentation and the ESP32 web upload. The project uses a modern pattern where data is divided from the presentation layer.
- Removed the `generate_board_docs` script.
- Updated the `gen_wu` script in order to generate `boards-info.json`: the fail that containe all information about the configuration
- Created and isolate the file `boards-info.js` to streamline the parsing of PlatformIO dependencies, modules, environments and improve the handling of library information.
- Introduced vuepress component `BoardEnvironmentTable.vue` that render `boards-info.json` as UI card component
- Introduced vuepress component `FlashEnvironmentSelector.vue` that render a selectred environment from `boards-info.json` and provide esp-web-upload feature on it
- Introduced a new board page `board-selector.md` for improved firmware selection.
- Updated `web-install.md` to enhance the firmware upload process, including a new board environment table.
- Enhanced custom descriptions in `environments.ini` to include HTML links for better user guidance and board image link
Add CC1101 initialization improvements and logging enhancements
Add installation step for PlatformIO dependencies in documentation workflow
Remove ci_set_version.sh script and associated versioning functionality
* Fix comment provisined
Fix PlatformIO version input reference in documentation workflow
Remove outdated Squeezelite-ESP32 installer documentation
* [CI] Fix Claude review action failing on fork PRs
Use pull_request_target instead of pull_request so OIDC tokens and
secrets are available when reviewing PRs from external contributors.
Explicitly checkout the PR head SHA to review the actual changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [CI] Harden review workflow against prompt injection from forks
Checkout the base branch instead of the PR head to prevent CLAUDE.md
poisoning and code-level prompt injection. Claude uses gh pr diff to
review changes without exposing the runner to untrusted fork code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [CI] Remove Claude auto-review workflow on PRs
Remove the pull_request_target review workflow due to prompt injection
risks from fork PRs. Claude can still be invoked on-demand via @claude
mentions through the claude.yml workflow, which is safer as it requires
a trusted maintainer to trigger.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [CI] Restrict @claude trigger to repo owner only
Add actor check so only 1technophile can invoke Claude via @claude
mentions. Prevents untrusted users from triggering the action and
consuming API credits or attempting prompt injection via comments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* [CI] Remove Claude @mention workflow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
HASS_UNIT_PPM is defined in config_mqttDiscovery.h but was missing from
the availableHASSUnits validation array in mqttDiscovery.cpp. This caused
unit_of_measurement to be silently dropped for CO2 sensors (like the
Govee H5140) during MQTT discovery, resulting in Home Assistant warnings
about invalid units.
* Refactor GitHub Actions workflows for build, documentation, and linting
- Consolidated build logic into reusable workflows (`task-build.yml` and `task-docs.yml`) to reduce duplication across multiple workflows.
- Introduced `environments.json` to centralize the list of PlatformIO build environments, improving maintainability and clarity.
- Updated `build.yml` and `build_and_docs_to_dev.yml` to utilize the new reusable workflows and environment definitions.
- Enhanced `release.yml` to streamline the release process and integrate documentation generation.
- Created reusable linting workflow (`task-lint.yml`) to standardize code formatting checks across the repository.
- Simplified manual documentation workflow by leveraging the new reusable documentation workflow.
- Improved artifact management and retention policies across workflows.
- Updated dependencies and versions in workflows to ensure compatibility and performance.
* CI/CD pipeline agnostic of Workflow Engine and integrated on github actions
- Implemented ci.sh for orchestrating the complete build pipeline.
- Created ci_00_config.sh for centralized configuration of build scripts.
- Created ci_build_firmware.sh for building firmware for specified PlatformIO environments.
- Created ci_prepare_artifacts.sh for preparing firmware artifacts for upload or deployment.
- Created ci_set_version.sh for updating version tags in firmware configuration files.
- Created ci_build.sh to orchestrate the complete build pipeline.
- Created ci_qa.sh for code linting and formatting checks using clang-format.
- Created ci_site.sh for building and deploying VuePress documentation with version management.
- Implemented checks for required tools and dependencies in the new scripts.
- Updated common_wu.py, compressFirmware.py, gen_wu.py, generate_board_docs.py, and prepare_deploy.sh with descriptive comments.
Refactor CI/CD scripts for improved modularity and clarity
- Consolidated build steps in task-build.yml to utilize ci.sh for version tagging, building, and artifact preparation.
- Updated task-lint.yml to use ci.sh for code formatting checks instead of ci_qa.sh.
- Enhanced CI_SCRIPTS.md documentation to reflect changes in script usage, command structure, and output organization.
- Improved internal scripts for better error handling and logging.
- Streamlined the output structure for build artifacts and documentation.
* Fix: Set WiFi hostname to gateway name
Add WiFi.setHostname() calls to ensure the ESP's WiFi hostname matches
the configured gateway name instead of using the default ESP hostname.
- Add wifiManager.setHostname(gateway_name) in setupWiFiManager() for
WiFiManager-based setups
- Add WiFi.setHostname(gateway_name) in setupWiFiFromBuild() for manual
WiFi setup configurations (ESPWifiManualSetup)
This matches the existing behavior for Ethernet connections where
ETH.setHostname(gateway_name) is already called.
Fixes#2150
Co-authored-by: Florian <1technophile@users.noreply.github.com>
* Change WiFi mode position
* Fix setHostname when using WiFi Manager
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Florian <1technophile@users.noreply.github.com>
The bug was a race condition where saved configuration was applied
to the LoRa hardware BEFORE LoRa.begin() was called, causing settings
like syncword to be lost after reset/power cycle.
Changes:
- Created LORAConfig_apply() to centralize hardware configuration
- Removed hardware application from LORAConfig_fromJson() (now only
updates struct values)
- Call LORAConfig_apply() after LoRa.begin() in setupLORA()
- Call LORAConfig_apply() after LORAConfig_fromJson() in runtime
handlers (MQTT/WebUI) since hardware is already initialized
- Fixed syncword logging to properly show 'unchanged' vs 'changed'
Fixes#2270
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Florian <1technophile@users.noreply.github.com>
When a saved RF configuration exists in NVS, loadFromStorage() was loading
the config but not calling iRFReceiver.enable(), which meant initCC1101()
was never invoked during boot. This caused the CC1101 to not receive signals
until the user manually toggled the RF receiver via the WebUI.
This fix adds a reinitReceiver parameter to loadFromStorage() that controls
whether to disable/enable the receiver after loading config. By default it's
true (for boot-time initialization), but loadFromMessage() passes false to
avoid double initialization when loading config from MQTT messages.
Fixes#2264
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Odyno <odyno@users.noreply.github.com>
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
* [CI] Configure Claude GitHub Actions to use Opus model
- Add --model opus flag to claude.yml workflow
- Add --model opus flag to claude-code-review.yml workflow
- Ensures advanced reasoning capabilities for complex firmware codebase
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix model ID to use full Claude Opus identifier
---------
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Convert nightly workflow to matrix builds to fix FRAMEWORK_DIR issues
caused by platform_packages conflicts when building sequentially
- Each environment now builds on its own runner, matching build.yml
- Add deploy job that collects all artifacts and deploys docs
- Add extra_scripts to esp32dev-pilight environment to fix implicit
function declaration error with newer GCC toolchain
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Introduced RFConfiguration class to encapsulate RF settings and operations.
- Replaced direct usage of RFConfig structure with iRFConfig instance across multiple files.
- Updated frequency handling in actuatorSomfy, gatewayPilight, gatewayRF, and gatewayRF2 to use iRFConfig.
- Modified webUI to interact with iRFConfig for RF settings management.
- Removed deprecated RFConfig structure and related functions.
- Enhanced JSON handling for RF configuration loading and saving.
- Improved logging for RF configuration operations.