Author SHA1 Message Date
chriz 02a8732318 Fix build action.
Build and Release OpenMQTTGateway Firmware / Build Firmware & Publish Gitea Release (push) Successful in 15m16s
2026-10-29 21:42:09 +01:00
chriz b1e2301ea1 Release package as part of build action.
Build and Release OpenMQTTGateway Firmware / Build Firmware & Publish Gitea Release (push) Failing after 8m2s
2026-10-29 20:53:36 +01:00
chriz 0d8a8b35f0 disable some decoders.
Build and Release OpenMQTTGateway Firmware / Build Firmware & Publish Gitea Release (push) Canceled after 3m53s
2026-10-29 20:49:24 +01:00
chriz d686cf71fc enable oled.
Build and Release OpenMQTTGateway Firmware / Build Firmware & Publish Gitea Release (push) Successful in 15m42s
2026-10-29 18:58:25 +01:00
chriz 86ecf4e5be ESA energy enable patch during build.
Build and Release OpenMQTTGateway Firmware / Build Firmware & Publish Gitea Release (push) Successful in 15m51s
2026-10-27 22:41:03 +01:00
chriz a11f3b9990 Merge remote-tracking branch 'origin/development' into development
# Conflicts:
#	.github/workflows/build.yml
#	.github/workflows/build_and_docs_to_dev.yml
#	.github/workflows/manual_docs.yml
#	.github/workflows/release.yml
#	platformio.ini
2026-10-27 22:31:36 +01:00
dependabot[bot] 1d865aa881 Bump source-map-js from 1.2.1 to 1.2.2 (#2411)
Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2.
- [Release notes](https://github.com/7rulnik/source-map-js/releases)
- [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/7rulnik/source-map-js/compare/v1.2.1...v1.2.2)

---
updated-dependencies:
- dependency-name: source-map-js
  dependency-version: 1.2.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-18 10:43:39 -05:00
dependabot[bot] 4cdce23d2a Bump @vue/server-renderer and vue (#2413)
Bumps [@vue/server-renderer](https://github.com/vuejs/core/tree/HEAD/packages/server-renderer) to 3.5.44 and updates ancestor dependency [vue](https://github.com/vuejs/core). These dependencies need to be updated together.


Updates `@vue/server-renderer` from 3.5.31 to 3.5.44
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/commits/v3.5.44/packages/server-renderer)

Updates `vue` from 3.5.31 to 3.5.44
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.5.31...v3.5.44)

---
updated-dependencies:
- dependency-name: "@vue/server-renderer"
  dependency-version: 3.5.44
  dependency-type: indirect
- dependency-name: vue
  dependency-version: 3.5.44
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-18 10:43:19 -05:00
Zhaoqi Xu 60aa84841d [INA226] Read the shunt voltage as a signed value (#2410)
The shunt voltage register is a 16-bit two's complement value. The
old conversion tested `shuntvolt && 0x8000` (always true for a
non-zero reading) and then negated the complement of the zero-extended
value, which gives back the raw register value. Positive readings came
out right by accident, but a reverse current was published as a large
positive current (0xFFF0 -> 1.638 A instead of -0.4 mA with the
default 0.1 ohm shunt).

Cast the register to int16_t instead.

Fixes #2395

Signed-off-by: Zhaoqi Xu <lzy00419@outlook.com>
2026-10-15 05:20:38 -05:00
7b9d32b765 [BT] Update Theengs Decoder to v2.5.0 (#2409)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:21:23 -05:00
pwshandClaude Opus 5.5 f06b4b1de6 [DISC] Fix empty unique_id suffix for gateway entities (#2401)
createDiscoveryFromList() used column [2] as the unique id suffix of
gateway entities whenever it was non null. The gateway sensors (RF, RF2,
IR, Pilight, SRFB, RFM69, LORA, 2G, hcsr501...) pass "" there, so they
all got the unique_id "<MAC>-": entities of a multi module gateway
collide in Home Assistant, and the ids changed from the
"<MAC>-gatewayLORA" form used by v1.8.1, duplicating entities on
upgrade. Treat an empty suffix like a null one and fall back to the
name, as already done for column [11].

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:52:18 -05:00
pwshandClaude Opus 5.5 3986d9d1f7 [LORA] Fix buffer overflow when converting binary packets to hex (#2402)
TheengsUtils::_rawToHex() formats each byte with "%02X\r", so the last
sprintf writes two bytes past the 2 * size hex digits (the '\r' and the
terminating null). LORAtoX() sized its buffer 2 * packetSize + 1, one
byte short, overflowing the stack for every binary LoRa packet.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:51:09 -05:00
pwshandClaude Opus 5.5 3ec01a72fd [WebUI] Show the active modules as text in the page heading (#2406)
Every page heading printed the modules JSON array as is
(["LilyGo_SSD1306","WebUI","LORA"]). Show it as a comma separated list.
The heading buffer was also filled with serializeJson(modules, jsonChar,
measureJson(modules) + 1), i.e. the size of the text rather than of the
100 bytes buffer, which overflows when many modules are enabled; the new
helper (and the boot log) use the buffer size.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:50:14 -05:00
pwshandClaude Opus 5.5 eb1e7c71e6 [WebUI] Fix dangling pointer when saving the gateway password (#2408)
server.arg() returns a String by value, so the pointer from c_str()
pointed into a temporary that was destroyed before strlen()/strcpy().

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:47:46 -05:00
Shad107 9795527b34 [BOARD] Add ISNO Super build environment (ESP32-S3, dual CC1101 433 + 868/915 MHz) (#2378)
The ISNO Super is an open-hardware ESP32-S3 board carrying two CC1101
sub-GHz radios (433 MHz and 868/915 MHz) combined on a single antenna
through a passive LC diplexer. This environment builds on the
esp32dev-multi_receiver RF stack; it drives the 868/915 MHz radio (868
in the EU, 915 in the US) and parks the 433 MHz one using the existing
RF_MODULE_SECONDARY_CS hook in commonRF.cpp.

Signed-off-by: Olivier Delafosse <olshad@gmail.com>
2026-10-02 05:39:46 -05:00
FlorianandClaude Opus 5 827c37542a [OTA] Report the version actually requested after a successful update (#2374)
On HTTP_UPDATE_OK the pre-reboot RLStoMQTT reported
`installed_version = latestVersion` unconditionally. That is only correct for
a "latest" request: "dev" installs from RELEASE_LINK_DEV, "vX.Y.Z" installs
that tag, and a caller-supplied URL installs an arbitrary image whose
`version` field is just a label (the WebUI sends "test"). On ESP8266
latestVersion is never populated, so every successful OTA there published an
empty installed_version.

Report the version that was actually requested when the URL was derived from
it, and omit the field for a caller-supplied URL rather than publish a label
as a version. The decision is keyed on systemUrl (non-empty only on the
derived branches) rather than on `version`, because `{"url": ...,
"version": "latest"}` takes the url branch and must not be reported as the
latest release. The value is stored as a String so ArduinoJson 6.18.5 copies
it into the document instead of referencing the caller's buffer.

Scope and evidence, stated plainly: this corrects the message when it lands,
and on current development it usually does not. ESPRestart(6) clears
jsonQueue before the drain task publishes, so the pre-reboot "Update success
!" message was dropped on 3 of 3 successful OTAs on a Theengs Bridge,
including one where this code was certified to be the firmware performing the
update. The change is therefore verified by inspection and by clean builds
(theengs-bridge-v11 on ESP32, nodemcuv2-rf on ESP8266, no new warnings), not
by observing the corrected field on hardware. The authoritative
installed_version is republished from OMG_VERSION after the reboot, which was
correct in every run. Making the pre-reboot message survive the restart, or
dropping it in favour of that republish, is a separate change.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 19:46:59 -05:00
mgerczukandMartin 4e49049b27 Replace dtostrf() with safer Arduino String constructor call (#2368)
* Replace dtostrf() with safer Arduino String constructor call

* Fix code formatting

* Replace dtostrf() / atoi() calls with buffer safe local functions

* Removed duplicate code

* Replace remaining itoa() calls with buffer safe function

---------

Co-authored-by: Martin <martin@gerczuk.de>
2026-09-13 08:02:05 -05:00
FlorianandClaude Opus 5 050ba3e827 [SYS] Fix erase command leaving MQTT credentials in SPIFFS (#2372)
eraseConfig() passed SPIFFS.format() as an argument to THEENGS_LOG_TRACE,
which expands to ((void)0) below LOG_LEVEL_TRACE and discards its arguments
along with the call. On every build using the default LOG_LEVEL_NOTICE the
format therefore never ran, so {"cmd":"erase"} only performed
nvs_flash_erase(): the WiFi credentials were cleared but /config.json
survived and restored the MQTT server, port, user, password, broker and
client certificates, connection index, topic, gateway name, OTA password
and BLE AES keys on the next boot.

Call SPIFFS.format() on its own statement and report a failed format at
ERROR level, so the failure is visible at the default log level.

This was introduced in #2232, which converted the original runtime-checked
Log.trace() call to the compile-time macro. It affects the SYS erase
command, the WebUI erase button and the GPIO factory-reset hold alike,
since all three go through eraseConfig().

Reproduced on a Theengs Plug built at the default log level: after
{"cmd":"erase"} the NVS namespaces are gone ("SYS config not found",
"ONOFF config not found") and the saved APs are empty, yet the same boot
still logs "Config loaded from flash" and restores the OTA server cert.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 16:36:47 -05:00
3b8496e323 [BT] Update Theengs Decoder to v2.4.5 (#2371)
Pin the decoder library to the v2.4.5 release archive instead of the
moving development branch.

Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 12:56:54 -05:00
Northern Man 5b839aadd3 [RF] rtl_433_ESP 6.2 (#2369) 2026-09-11 21:04:52 -05:00
7945a42d06 [RF] Update rtl_433_ESP to v0.6.1 (#2366)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-07 17:53:36 -05:00
4e3ed19827 [NET] ESP32 Ethernet: PHY cold-cycle at boot, default on Theengs Bridge (#2364)
Power ETH_PHY_POWER down for 200 ms and back up 200 ms before ETH.begin()
so the PHY always gets a true cold start. A warm PHY left in a stale state
(reproduced on Theengs Bridge v1.1 with PSRAM enabled after an NVS erase)
can flap the link until a manual power cycle: it reports up for one poll,
then down for several seconds, forever, so DHCP never completes. The short
reset the Ethernet driver performs on its own does not clear that state; a
power cycle with a settle window before begin() does. On a hardware-in-the-
loop bench the same provocation went from flapping every trial to flapping
in none of them (4/4).

Enabled via -DETH_PHY_COLD_CYCLE, only active when ETH_PHY_POWER is a valid
pin, at the cost of ~400 ms added boot time. Set by default on both Theengs
Bridge environments.

Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 08:39:39 -05:00
1dfa2f17fb [RF] Fix RTL_433 duplicate detection swallowing rapid transmissions with differing payloads (#2357)
* Initial plan

* Fix RTL_433 duplicate detection to hash full payload instead of id+temperature_C

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NorthernMan54 <19808920+NorthernMan54@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-30 06:14:46 -05:00
FlorianandClaude Opus 5 77754a1fe9 [RF] Deselect a secondary CC1101 chip-select on shared-SPI boards (#2363)
Boards that carry two radios on one SPI bus need the unused radio's CS held
high, or it answers on MISO and corrupts every transfer to the radio that is
actually in use. Add an optional RF_MODULE_SECONDARY_CS: when defined, drive
that pin high before probing the CC1101.

Bench-proven on a dual-CC1101 ESP32 board where one radio is faulty and the
other is the working one: without the deselect the shared bus is unreliable;
with it, the working module probes cleanly on the first attempt and decodes
live 433 MHz sensors.

No effect on single-radio boards: the whole block compiles out unless
RF_MODULE_SECONDARY_CS is set.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 08:17:15 -05:00
Florian 98ae55cd7b [DOCS] Modify README for Theengs bridge and plug information (#2362)
Updated image path for Theengs bridge and removed Theengs plug details.
2026-08-24 07:26:27 -05:00
47da455246 [BLE] Fix esp32dev-ble-idf: bump esp-nimble-cpp 2.1.1 -> 2.5.0 (#2361)
esp-nimble-cpp 2.1.1 no longer exists: the PlatformIO registry pruned it
(2.3.2 is now the oldest available) and the upstream 2.1.1 git tag was
deleted as well. Dependency resolution therefore fails before any
compilation, breaking every build of esp32dev-ble-idf:

  UnknownPackageError: Could not find the package with
  'h2zero/esp-nimble-cpp @ 2.1.1' requirements

Pin 2.5.0, matching the NimBLE-Arduino 2.5.0 already used by the Arduino
ESP32 environments, and reference the GitHub archive rather than the
registry so future registry pruning cannot break the build again.

No source changes are needed: esp32dev-ble-idf builds clean with the
newer API, blufi.cpp included.

Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 17:25:34 -05:00
FlorianandClaude Opus 5 b6b23bd423 [RF] Move RTL_433 / SX127x envs to the shipped ESP32 platform (#2360)
Eight environments were still pinned to espressif32@6.1.0 (arduino-esp32
2.0.7 / IDF 4.4) while the rest of the tree had moved to the shared
${com.esp32_platform} definition. Align them so they build against the
platform that actually ships, rather than silently keeping an old
toolchain alive:

  esp32doitv1-aithinker-r01-sx1278
  esp32dev-rtl_433, esp32dev-rtl_433-fsk
  heltec-rtl_433, heltec-rtl_433-fsk
  lilygo-rtl_433, lilygo-rtl_433-fsk
  esp32dev-multi_receiver

The stray "* copy.c" duplicate in rtl_433_ESP that previously blocked
these envs on a modern toolchain is gone as of rtl_433_ESP v0.6.0, which
development already pulls in, so no build workaround is needed.

The move alone is not sufficient: the newer core leaves ~35 KB less heap
on BT-less ESP32 builds, which pushes the memory-constrained RTL_433
boards into a boot loop at the first TLS handshake. That is fixed here
too, in main.cpp.

On ESP32-classic builds without ZgatewayBT, arduino-esp32 3.x leaves most
of the Bluetooth controller's reserved DRAM (CONFIG_BTDM_RESERVE_DRAM =
0xdb5c, 56156 B) stranded. arduino-esp32 2.x released the whole BTDM
region unconditionally in initArduino():

    if (!btInUse()) esp_bt_controller_mem_release(ESP_BT_MODE_BTDM);

3.x releases CLASSIC and BLE separately, and the CLASSIC pass silently
short-circuits. cores/esp32/esp32-hal-bt.c has:

    #if defined(CONFIG_BT_CLASSIC_ENABLED)
    static bool _classicMemReleased = false;
    #else
    static bool _classicMemReleased = true;  // "No Classic BT on this chip"
    #endif

With a BLE-only controller build CONFIG_BT_CLASSIC_ENABLED is unset, so
_classicMemReleased starts true and btMemRelease(BT_MODE_CLASSIC_BT)
returns "already released" without reaching IDF. Only the ~5 KB BLE slice
is freed. The guard is wrong for this part: ESP32 does have Classic BT
hardware (CONFIG_SOC_BT_CLASSIC_SUPPORTED) and the DRAM is reserved
regardless of the controller's configured mode; the correct guard would be
CONFIG_SOC_BT_CLASSIC_SUPPORTED. Reported upstream separately.

Release the whole BTDM region explicitly. esp_bt_mem_release() is used
rather than esp_bt_controller_mem_release() because it is a superset that
also frees the linker _bt_data / _bt_controller_* sections. The guard is
compile-time and authoritative: OMG knows via ZgatewayBT whether it uses
BT, whereas the core infers it from link-time flags that NimBLE-Arduino
does not set. Safe no-op if the memory was already released or once the
core is fixed. Note this makes btStart() permanently unavailable in these
builds, which is already the case for a !ZgatewayBT build.

Measured on a Heltec WiFi LoRa32 V2 running heltec-rtl_433 (WiFi + MQTT +
TLS + rtl_433 + SSD1306, no BT), pioarduino 55.03.39 / esp32-arduino-libs
0.1.8:

  BT DRAM reclaimed: 209928 -> 245048        (+35120 B)
  Update check, free heap: 49868 -> 89484

Without it, the boot-time HTTPS update check fails its TLS handshake
("Dynamic Impl: alloc(4437 bytes) failed", then X509 -9984) because the
largest free block is too small, and the MinimumMemory watchdog then
reboots the board in a loop. With it: no allocation failure, handshake
succeeds, freemem ~85 KB / minmem 53432 against the 40000 threshold,
0 reboots over a 3 min soak with live RTL_433 decodes.

The memory fix affects every ESP32-classic env without ZgatewayBT, not
just the ones moved here. The RTL_433 envs fail loudly because they carry
the MinimumMemory watchdog; others (esp32dev-ir, esp32dev-pilight,
ttgo-lora32-v21, heltec-wifi-lora-32, ...) simply run ~35 KB short.
Builds with ZgatewayBT are unaffected.

Hardware validation, two boards:

  heltec-rtl_433 (OOK 433.92 MHz, Heltec WiFi LoRa32 V2)
    boots, joins WiFi/MQTT, RadioLib/SX127x RSSI calibration completes,
    HA discovery publishes, decodes live ambient sensors
    (Ambientweather-F007TH, Prologue-TH, WEC-2103).

  heltec-rtl_433-fsk (FSK 915 MHz, second Heltec)
    same boot path, decodes a live Fineoffset-WH51 soil sensor.

The other six envs have no matching board on hand and are compile-only.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 14:15:48 -05:00
Northern Man e30b65ee6f [RF] Update rtl_433_ESP to 0.6.0 (#2358)
This refreshes the bundled rtl_433 decoder set to the latest development snapshot available on August 14, 2026: 25.12-346-g91b2ebdb, commit 91b2ebdb.

Refresh rtl_433 device decoders, supporting utilities, headers, and generated registration files.
Expand the supported set to 223 OOK and 153 FSK protocol decoders.
Regenerate the README protocol lists directly from the registered decoder set.
Update the decoder-generation tooling for the refreshed upstream layout.
Add Vivint DW11/DW21R, PIR2, and GB2 decoding with automatic 16-bit seed discovery.
Support compile-time Vivint seed lists through VIVINT_SEEDS.
Add optional Vivint seed-discovery diagnostics and OUTPUT_VIVINT_DECODE=0 to omit them.
Make the Vivint sensor count, sample cache size, and required sample count configurable.
Refresh the README and PlatformIO examples.
Update the RadioLib dependency and library metadata for Beta 0.6.0.
2026-08-20 08:20:05 -05:00
FlorianandClaude Opus 5 d8ffa3f1dd [SYS] Migrate M5 boards to M5Unified + M5GFX (modern platform) (#2355)
The per-board libs (M5Stack/M5StickC/M5StickC-Plus/M5Tough) don't build on
Arduino core 3.x, which kept the five M5 BLE envs pinned to espressif32@6.1.0.
Port board support to M5Unified + M5GFX so they run ${com.esp32_platform} like
the rest of the tree.

- environments.ini: 5 M5 envs -> modern platform + m5unified. m5stick-c uses the
  pico32 variant (m5stick_c variant absent upstream) and no_coredump partitions
  (M5Unified overflows min_spiffs).
- boardM5.cpp / config_M5.h: single <M5Unified.h>; M5.Lcd aliases M5.Display;
  unified brightness/sleep/wake.
- main.cpp / mqttDiscovery.cpp: battery telemetry via M5.Power; AXP192-only
  Vin/VBus/temp fields dropped (no portable equivalent).

All five M5 envs build; M5Stack Core hardware-verified.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 16:45:35 -05:00
Camilo Duque 7df23d4e3e [FIX] ESP32 Ethernet: make NetworkAdvancedSetup work, and skip WiFiManager when Ethernet is up (#2351)
Static IP over Ethernet on ESP32 was unusable, and a fresh board with a
working Ethernet link still brought up the WiFi radio.

setup_ethernet_esp32() did not compile with NetworkAdvancedSetup defined: it
declared ip_adress/gateway_adress/subnet_adress/dns_adress but then called
fromString() on ip/gateway/subnet/Dns, which are declared nowhere. The WiFi
path a few hundred lines above does the same thing correctly, so this looks
like an incomplete copy of it.

Once that compiles, the static IP was still ignored. ETH.config() was called
before ETH.begin(), but NetworkInterface::config() returns false immediately
while _esp_netif is NULL, and the netif is only created inside begin(). The
call was a silent no-op and the board kept asking for DHCP. Swapping the order
is safe: the client branch of config() stops the running DHCP client itself
and sets the static-IP status bit. The return value is now checked and logged
instead of being discarded.

Separately, the "no config in flash" branch of setup() called
setupWiFiManager() guarded only by !failSafeMode, while the "config loaded"
branch a few lines above correctly also checks !ethConnected. So a
factory-fresh board with Ethernet already up would still start the WiFi
manager. Beyond being unnecessary, it powers up the 2.4GHz radio and competes
with BLE on gateways that run both.

Verified on an Olimex ESP32-POE-ISO: the board now takes its static address
immediately with no DHCP wait, does not fall back to the WiFi manager, and
reaches the broker. Formatting checked with clang-format against .clang-format.
2026-08-15 14:26:44 -05:00
FlorianandClaude Opus 5 5fdaddadaf [RF] Fix CC1101 on Arduino core 3.x: bump SmartRC to V3.0.2 + init before probe (#2353)
On the platform we ship (pioarduino 55.03.39 / arduino-esp32 3.3.9) the pinned
SmartRC-CC1101-Driver-Lib v2.5.7 does not work with the CC1101 at all. Core 3.x's
peripheral manager owns SCK/MISO/MOSI once SPI.begin() has run, so the driver's
digitalWrite() calls on those pins become silent no-ops, and it starts and stops
the SPI bus around every single register access (LSatan/SmartRC-CC1101-Driver-Lib#176).

Bench result on an ESP32 DevKit + CC1101 running esp32dev-pilight-cc1101: setup
hangs in the driver's unbounded `while(digitalRead(MISO_PIN));` before any C1101
log line is emitted, and TG1WDT reboots the board in a loop. The same build on
espressif32@6.8.1 (core 2.0.17) initialises normally, so this is the core, not
the wiring. Every ZradioCC1101 ESP32 environment is affected: Pilight, RF, RF2
and Somfy. The RTL_433 CC1101 path goes through RadioLib and is unaffected.

V3.0.x re-engineered the SPI core for ESP32: gpio_get_level() with a timeout
instead of the unbounded digitalRead() wait, SPI.begin() once instead of per
transaction, and no digitalWrite() on peripheral-owned pins. It also moved
SPI.begin() out of getCC1101() and into Init(), so the connection probe has to
run after Init() rather than before it — reported in #2348.

Both changes are needed together: the reorder alone does not help on core 3.x,
and V3 cannot work without it.

Verified on the bench, core 3.3.9, esp32dev-pilight-cc1101:
  N: C1101 SPI connection OK on attempt 1
  N: C1101 tuned RX to 433.92 MHz
plus a live round trip — an arctech_switch frame published to MQTTtoPilight was
transmitted and decoded back by the board's own receiver on PilighttoMQTT.

Note for review: this bumps the pin for the ESP8266 CC1101 environments too.
They are not affected by the core 3.x breakage and V3 is untested there, so the
pin may be worth splitting per environment before this lands.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 14:10:00 -05:00
FlorianandClaude Opus 5 4462ac94bf [SYS] esp32-arduino-libs: bump 0.1.7 -> 0.1.8 (restores RISC-V -march) (#2352)
0.1.7 shipped esp32c3 flags with no -march at all, so every ESP32-C2/C3 build
fell back to the compiler default (rv32imafdc) and emitted atomic and
hardware-FP instructions the core does not implement. The firmware panicked
with "Illegal instruction" during C++ static init — on the first
std::shared_ptr refcount, inside the Arduino core's global SPIFFS constructor —
so the board boot-looped before printing a single line of OMG output. That is
issue #2336: esp32c3-dev-c2-ble dev builds boot-loop while 1.8.1 (built on
arduino-esp32 2.x, which passed -march=rv32imc explicitly) is fine.

The flag was lost in packaging, not in the compiler: ESP-IDF >= 5.5.2 moved the
toolchain base flags into @response files and the lib-builder's flag extraction
silently dropped them. The precompiled libs were always correct RV32IMC code.
0.1.8 restores -march across c_flags/cpp_flags/S_flags/ld_flags and
pioarduino-build.py, and fails the lib build if a target's ISA flag ever goes
missing again (theengs/esp32-arduino-lib-builder#9).

Xtensa targets were never affected — each core has its own GCC driver whose
default multilib already matches — but they are rebuilt from the same bundle,
so esp32/esp32s3 want a smoke test alongside the C3.

Bench-verified on an ESP32-C3 rev v0.4: boot-loops on 0.1.7 (30 panics in 20 s,
MTVAL 0x06f7202f), boots and decodes BLE on 0.1.8 with no project-level flags.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 14:03:47 -05:00
FlorianandClaude Opus 5 65d0998278 [OTA] Resolve the offered version per build environment (#2350)
checkForUpdates() reads an optional "envs" map from the update manifest and,
when it holds an entry for this build's ENV_NAME, offers that version instead
of the global latest_version. Boards with no entry are unaffected.

This lets the OTA server hold a specific product at an older release while the
rest of the fleet advances, with no per-board build flags. The resolved value
is republished as latest_version so the Home Assistant update entity compares
against it, and the map itself is dropped from the retained state topic to
keep it small.

Backward compatible both ways: old firmware ignores "envs", and a manifest
without "envs" behaves exactly as before.

OTA_JSON_URL is also guarded with #ifndef so a build environment can point the
update check at another OTA server. It was defined unconditionally, so a -D
build flag could not retarget it (the header definition always won). This is
needed to exercise the check against a test manifest, and is useful for
self-hosted OTA servers. No behaviour change without an override.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 06:33:13 -05:00
b9e8821b17 [DOCS] Fix responsive layout on phones and tablets (#2349)
The home hero image overlapped the hero title on phones: the default theme
pulls the stacked image up with negative margins (-76px -24px -48px), which
only works because it normally sits absolutely positioned inside a fixed
320px box. custom.css lets the image flow to enlarge it, so those margins
made it bleed off-screen and collide with the title. Reset them below 960px,
and hide the image entirely under 640px -- at phone size it is a wall of
unreadable logos that pushes the title, tagline and call-to-action buttons
below the fold.

Also fixes, found while sweeping every page at 360/400/900px:

- Nav bar: the shared Theengs nav has seven top-level entries and the theme
  swaps to the desktop nav bar at 768px, where it does not fit. From 768px to
  ~1180px, Shop, Sponsor, the appearance switch and the GitHub link were
  clipped or off-screen and the page scrolled sideways. Keep the hamburger +
  full-screen menu until the full menu genuinely fits.
- upload/binaries: indented (non-fenced) code blocks render as a bare <pre>,
  which the theme only makes scrollable inside a language-* wrapper, so the
  long esptool.py commands pushed the page sideways.
- use/lora: the YouTube embed is raw HTML with width="560", wider than a
  phone. Make video embeds fluid at a 16/9 ratio.
- OmgPipeline: stack below a 680px container instead of 480px -- in between,
  the "OpenMQTTGateway" label spilled out of its node and over the arrows.
  Drop the media query in index.md that meant to do this: it was scoped to
  index.md and could never match an element inside the child component.

No horizontal overflow remains on any of the 50 pages at 360px, 400px or
900px; desktop is unchanged.


Claude-Session: https://claude.ai/code/session_01Nj6xa5Mk5wi8XWtgJG7w5D

Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 21:22:35 -05:00
f5b33104ef [DOCS] Overhaul new-user onboarding, home page, and upload flow (#2347)
Getting started:
- New 15-minute Getting Started guide featuring the two most popular
  tracks (BLE on esp32dev-ble, RF on lilygo-rtl_433), with broker setup
  and a verification step
- Sidebar restructured around the new-user journey; upload options
  numbered by ease; Gitpod upload method removed

Home page:
- VitePress hero with clear actions, larger hero image
- How-it-works pipeline diagram shared as a component (responsive via
  container queries), use-case grid, bigger video tiles without the
  image lightbox, refreshed press coverage list, functions pills
- Support section pointing to Theengs Bridge and
  github.com/sponsors/1technophile

Upload flow:
- Decision-oriented upload landing page (journey strip, method cards,
  comparison table)
- Pre-flight checklist and driver troubleshooting on the web installer
- Guided environment picker (bridge + hardware wizard) replacing the
  filter chips, with manifest-verified recommendations
- Post-flash next-steps card linking to the portal and verification

Board images:
- custom_img key in environments.ini and board photos for all
  web-flashable environments (licenses recorded); private prod_env.ini
  environments excluded from boards-info.json

Corrections:
- RF frequency coverage stated as 433/315/868/915MHz
- Removed references to the retired compatible.openmqttgateway.com
  site (BLE list is decoder.theengs.io), the discontinued Theengs
  Plug, and the private sponsor forum


Claude-Session: https://claude.ai/code/session_01TYysQW8tpmt1dWWuzKhTLi

Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 10:23:43 -05:00
Florian 382aae8353 [DOCS] Fix image link in README.md (#2346) 2026-08-01 07:45:03 -05:00
a33010c068 [FIX] Restore GET route for /wi so the WiFi scan link works (#2345)
handleWI() dispatches internally on the "scan" query arg, so the same
handler serves both the scan link and the save form. #2037 narrowed the
route to POST-only, which orphaned the scan hyperlink (a GET) in
config_WebContent.h. Re-register /wi for HTTP_GET alongside HTTP_POST;
the credential Save form stays method=post, so no secrets move to GET.

Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-01 07:30:26 -05:00
f76d04b613 [SERIAL] Make SERIAL gateway frame format (data/parity/stop bits) configurable (#2342)
Serial.begin() was hardcoded to SERIAL_8N1 across all four UART init paths
(UART0/1/2/3), with no way to override it via a build flag -- unlike SERIALBaud,
which already is. Devices using non-8N1 framing (e.g. even-parity RS232 sources)
currently can't be read correctly at all, not just unreliably: a parity mismatch
misaligns the frame, not just adds occasional noise.

Adds SERIAL_CONFIG following the existing #ifndef/#define override pattern used
throughout this codebase, defaulting to SERIAL_8N1 so existing environments are
unaffected byte-for-byte. Verified: default (SERIAL_8N1) and an override
(SERIAL_CONFIG=SERIAL_8E1) both build successfully on ESP32.

Co-authored-by: simowilso <simowilso@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 19:05:18 -05:00
dependabot[bot] 3c33431fe5 Bump postcss from 8.5.13 to 8.5.23 (#2341)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.13 to 8.5.23.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.13...8.5.23)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 19:03:16 -05:00
FlorianandClaude Opus 4.8 77b588fb60 Keep WiFiManager portal available when saved WiFi credentials are lost (#2340)
setupWiFiManager() disables the config portal whenever /config.json exists
(a security measure to avoid exposing the config data + OTA page). But if the
saved WiFi credentials are lost while config.json remains -- e.g. the NVS
partition is erased ({"cmd":"erase"}, or corruption) -- the gateway can no
longer connect AND the portal is suppressed: autoConnect() fails immediately
and the failure path calls ESPRestart(3). The device then reboot-loops
forever, un-onboardable, its SoftAP flickering up ~1s per cycle.

Only suppress the portal when config.json exists AND saved STA credentials
are still present (WiFi.SSID() non-empty). With no credentials the portal
stays enabled, so the gateway raises a stable onboarding AP and can be
re-provisioned instead of reboot-looping. The original security intent is
preserved for provisioned gateways (which always have saved credentials).

Reproduced + verified on a Theengs Plug (esp32dev, min_spiffs): with NVS
erased and config.json present, the SoftAP is now stable and accepts
provisioning via the captive portal, rejoining the broker normally.


Claude-Session: https://claude.ai/code/session_01MbmZRv67fnNvzpyvqPi6vx

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 09:55:28 -05:00
FlorianandClaude Opus 4.8 b493dddb97 [SYS] esp32-arduino-libs: bump 0.1.6 -> 0.1.7 for no-PSRAM TLS (MBEDTLS_DYNAMIC_BUFFER) (#2335)
The 0.1.7 bundle enables MBEDTLS_DYNAMIC_BUFFER (dynamic TX/RX TLS record
buffers) by disabling the unused DTLS proto that was gating it. mbedTLS now
sizes the ~32 KB record buffers per-record and frees them between records
instead of holding them for the whole session lifetime.

On no-PSRAM ESP32 (e.g. the Theengs Plug) this is the difference between MQTT
TLS (8883) being viable or not: steady-state free heap goes from ~36 KB to
~71 KB (minmem ~18 KB -> ~30 KB), the boot HTTPS update-check and the HA
discovery burst no longer OOM/crash-loop, and flash drops ~19 KB from removing
the DTLS code. Boards with PSRAM (Theengs Bridge) are unaffected.

Bundle: theengs/esp32-arduino-lib-builder 0.1.6 -> 0.1.7 (libs-only rebuild,
same IDF v5.5.4 / arduino-esp32 pin; no platform-espressif32 bump).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 03:53:33 -05:00
FlorianandClaude Opus 4.8 b01240330a [ONOFF] Fix ACTUATOR_TRIGGER build flag: missing -D prefix (#2334)
Several envs pass '-ACTUATOR_TRIGGER=true' instead of
'-DACTUATOR_TRIGGER=true', so the ACTUATOR_TRIGGER macro is never defined
and the physical-button -> relay toggle in sensorGPIOInput.cpp
(#if defined(ZactuatorONOFF) && defined(ACTUATOR_TRIGGER)) is compiled out.

Verified on a Theengs Plug: with the -D added, a button press now toggles the
relay and emits ONOFFtoMQTT. Same one-character fix applied to the other envs
carrying the identical typo.

Affected envs: theengs-plug, esp32dev-all-test, sonoff-basic, sonoff-basic-rfr3.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 06:09:04 -05:00
FlorianandClaude Opus 4.8 268b879239 [BT] Bump NimBLE-Arduino 2.3.2 -> 2.5.0 to fix BLE scan regression on Arduino core 3.3.7+ (#2333)
The esp32_platform 55.03.39 bump (#2329) ships Arduino-ESP32 core >=3.3.7,
whose NimBLE integration enables mesh scan-filtering. NimBLE-Arduino 2.3.2
(pinned since 2025-06-28) handles this incorrectly and stops reporting
advertisements on scan restart, so continuously-scanning gateways (e.g. the
Theengs Bridge) decode nothing.

Upstream fix: h2zero/NimBLE-Arduino 98548470f "[Bugfix] Scan duplicate filter
not resetting on scan restart" (released in 2.3.9). Bumping to the latest 2.5.0
also picks up the Arduino 3.3.7 "controller invalid state" init fix (2.3.8/2.3.9)
and a scan-response timer for long-duration scans.

HIL-validated on a Theengs Bridge v11 with esp32_platform 55.03.39:
  - NimBLE 2.3.2: BLE decode 0/3
  - NimBLE 2.5.0: BLE decode 3/3, reachability 2/2, builds clean

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 16:22:53 -05:00
0bbc00cfa0 [SYS] esp32_platform: update to 55.03.39 (#2329)
* 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>
2026-06-28 09:38:12 -05:00
FlorianandClaude 4b7d3f6589 [RTL_433] Update rtl_433_ESP library to v0.5.1 (#2328)
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>
2026-06-20 20:27:14 -05:00
FlorianandClaude Opus 4.8 94aa6ae443 [SYS] Update esp32-arduino-libs to 0.1.4 (BLE-only controller) (#2327)
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>
2026-06-20 20:18:55 -05:00
FlorianandClaude Opus 4.7 0b6780678f [SYS] Bound remaining MQTT/HTTP/BLE/RF inputs into fixed buffers (#2324)
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>
2026-06-14 17:20:24 -05:00
Florian 2459e1c29b [RF] Change ESP8266 default RF_RECEIVER_GPIO from 0 to 4 (#2240) (#2323)
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.
2026-06-14 16:28:01 -05:00
Florian 9f5bf3ec57 [DOCS] Remove dead compatible.openmqttgateway.com links (#2205) (#2322)
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.
2026-06-14 15:26:02 -05:00
c027dd225d [SYS] Fix heap overflows from unbounded strcpy of MQTT input (#2321)
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>
2026-06-06 09:35:27 -05:00
FlorianandClaude 4d945851ce [SYS] Add WiFi reconnect watchdog to self-heal from wedged WiFi stack (#2319)
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>
2026-06-01 08:50:12 -05:00
FlorianandClaude Opus 4.7 cf27d0e3e7 [BT] Omit state_class/unit_of_measurement for enum sensors in HA discovery (#2316)
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>
2026-05-23 15:33:44 -05:00
FlorianandClaude Opus 4.7 6d64dbcd8c [BT] Emit hex-valued BLE properties as text sensors (no state_class) (#2315)
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>
2026-05-23 15:33:26 -05:00
FlorianandClaude Opus 4.7 e7411d2000 [BT] Reset BTProcessLock when immediateBTAction can't take the device semaphore (#2314)
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>
2026-05-23 15:33:06 -05:00
FlorianandClaude Opus 4.7 7904d49dbe Fix/wifimanager portal defaults (#2312)
* [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>
2026-05-23 14:01:48 -05:00
FlorianandClaude Opus 4.7 319c05af5c [BT] Default BLE AES key empty, skip decryption without a key (#2310)
* [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>
2026-05-16 10:26:49 -05:00
dependabot[bot] 647e437382 Bump postcss from 8.5.8 to 8.5.13 (#2307)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.8 to 8.5.13.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.8...8.5.13)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-10 12:33:29 -05:00
FlorianandClaude Opus 4.7 9e93e37506 [DOCS] Restore dev-version banner gate after VitePress migration (#2305)
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>
2026-05-01 07:31:13 -05:00
ddd05ebe50 [CI] Pin SmartRC-CC1101-Driver-Lib via GitHub URL (#2304)
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>
2026-04-27 06:20:50 -05:00
7551ed9e22 [MEM] Enable PSRAM on Theengs Bridge v1.1 (ESP32-WROVER-IE) (#2303)
- 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>
2026-04-26 15:59:12 -05:00
FlorianandClaude Opus 4.7 23fc99f0fe [MEM] Heap-allocate createDiscovery JsonDocuments (#2302)
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>
2026-04-25 12:00:13 -05:00
9e8098964c [MEM] Reduce NimBLE max connections from 3 to 1 (#2300)
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>
2026-04-25 11:59:49 -05:00
DigiH a5158c503b Revert "Delete build_and_docs_to_dev.yml" (#2301)
This reverts commit 079c987450.
2026-04-21 18:56:50 +02:00
DigiH 079c987450 Delete build_and_docs_to_dev.yml 2026-04-07 05:08:09 +02:00
8273617c17 [DOCS] Migrate documentation from VuePress 1.x to VitePress (#2299)
- 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>
2026-03-30 07:00:20 -05:00
dependabot[bot] 600d48dc48 Bump picomatch from 2.3.1 to 2.3.2 (#2296)
Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-29 17:21:26 -05:00
3b2b8a333a [WebUI] Fix BLE config page connection reset on load (#2295)
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>
2026-03-25 07:23:06 -05:00
3a4eb55a79 [MEM] Reduce ESP32 BLE firmware RAM usage (#2294)
- Fix addLog buffer overflow; reduce LOG_BUFFER_SIZE 6096→3072, ROW_LENGTH 1024→512
- Lazy-allocate web console log buffer (saves ~3.5KB when console not active)
- Stream WebUI responses in chunks to eliminate String heap allocations
- NimBLE buffer tuning: ACL bufs 20→12, HCI hi bufs 30→15, MSYS1 blocks 12→8, MTU 256→185
- BLE adv report flow control 100→50, LWIP sockets 16→10
- BLE scan duplicate cache 200→100 (align with sdkconfig)
- procBLETask stack 9500→8000 (788B headroom over measured peak)
- Cap BLE device vector at 80 with LRU eviction of non-listed devices
- Disable unused LWIP components: PPP, IPv6 autoconfig/DHCPv6
- Disable unused Arduino libs: SD, SD_MMC, FFat, LittleFS, NetBIOS

Measured over 30 min A/B test vs development:
  freemem: 58,805 → 68,755 avg (+10KB)
  minmem:  5,988 → 15,780 (+9.8KB)
  msgprc/scnct: identical (656 msgs, 26 scans)
  msgblck: 0 on both branches
  No crashes or errors

Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 19:05:44 -05:00
7d6a019699 [WebUI] Add full BLE configuration page and MQTT Discovery toggle (#2293)
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>
2026-03-22 18:12:31 -05:00
dependabot[bot] 31f949c80b [DOCS] Bump qs from 6.14.1 to 6.14.2 (#2292)
Bumps [qs](https://github.com/ljharb/qs) from 6.14.1 to 6.14.2.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 10:52:55 -05:00
8b3aa1d981 [DOCS] Add search and filter bar to board selection page (#2291)
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>
2026-03-10 07:54:11 -05:00
c58ead0a35 [CI] Skip nightly dev build when no changes in the last 24 hours (#2290)
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>
2026-03-10 07:37:28 -05:00
883e9318cf [DOCS] Fix dev docs deploying to /dev/dev/ instead of /dev/ (#2289)
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>
2026-03-09 09:31:27 -05:00
Alessandro Staniscia 98481c5145 [SITE] Renew the web board presentation and the ESP32 web upload + [SYS] Security checks (#2277)
* 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
2026-03-09 07:47:30 -05:00
dependabot[bot] 5f0966c2c1 Bump minimatch from 3.1.2 to 3.1.5 (#2287)
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-04 07:06:04 -06:00
Florian cd9d6ecb96 [DOCS] Remove build and code format badges (#2284)
Removed build and code format badges from README.
2026-02-15 15:58:27 -06:00
5fe77e9c85 [CI] Remove Claude Code GitHub Actions workflows (#2283)
* [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>
2026-02-15 15:56:44 -06:00
Ben Fulton df1204d92f [DISC] Add HASS_UNIT_PPM to availableHASSUnits array (#2279)
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.
2026-02-15 15:35:22 -06:00
Alessandro Staniscia 134c03362c [CI] Refactor GitHub Actions workflows for build, documentation, and linting (#2260)
* 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.
2026-02-15 14:58:58 -06:00
fd433c220e [BLE] Add BM6 Battery Monitor connection support (#2274)
* [BLE] Add BM6 Battery Monitor connection support

Implement BLE connection support for BM6 Battery Monitor devices,
following the BM2 pattern with BM6-specific protocol handling.

Key features:
- Encrypted command/response using AES-128 CBC
- Read voltage, temperature, and State of Charge (SoC)
- Home Assistant MQTT Discovery support
- Device tracker integration

Technical implementation:
- Add BM6_connect class with encrypted command handling
- Encryption key (static const): "leagend\xff\xfe0100009"
- Parse hex string positions for voltage (15-17), temp (8-9), SoC (12-13)
- Add discovery with 3 sensors (voltage, temperature, battery %)
- Validate message signature (D15507)
- Add canWrite() check before writing to characteristic
- Empty stub for non-ESP32 builds

Code quality improvements:
- Extract AES key as static constant to avoid duplication
- Use shared jsonVoltBM template for both BM2 and BM6
- Clean up commented-out reasoning in parsing logic

Based on reverse engineering from:
https://github.com/JeffWDH/bm6-battery-monitor

Files modified:
- main/gatewayBLEConnect.h: Add BM6_connect class
- main/gatewayBLEConnect.cpp: Implement BM6 connection logic
- main/gatewayBT.cpp: Add detection, connection, and discovery handlers
- main/config_mqttDiscovery.h: Rename jsonVoltBM2 to jsonVoltBM

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Add BM6 to exceptions

---------

Co-authored-by: Florian <1technophile@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-24 17:16:03 -06:00
dependabot[bot] 497dc878f5 Bump lodash from 4.17.21 to 4.17.23 (#2275)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-22 07:16:34 -06:00
f52bc6c11e [SYS] Fix: Set WiFi hostname to gateway name (#2272)
* 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>
2026-01-21 08:22:00 -06:00
32664499f3 [LORA] Fix syncword not persisting after reset (#2271)
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>
2026-01-10 11:59:41 -06:00
e01b22695a [RF] Fix CC1101 initialization on boot with saved RF config (#2269)
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>
2026-01-06 05:47:49 -06:00
0c2884c392 [CI] Configure Claude GitHub Actions to use Opus model (#2267)
* [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>
2026-01-05 07:58:05 -06:00
dependabot[bot] 07d048f1c3 [DOCS] Bump qs and express (#2265)
Bumps [qs](https://github.com/ljharb/qs) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `qs` from 6.13.0 to 6.14.1
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.13.0...v6.14.1)

Updates `express` from 4.21.1 to 4.22.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.1...v4.22.1)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: indirect
- dependency-name: express
  dependency-version: 4.22.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-03 11:11:48 -06:00
FlorianandFlorian 5c401f6d02 [CI] Add Claude GitHub actions (#2266)
* "Claude PR Assistant workflow"

* "Claude Code Review workflow"

* Add CLAUDE md for context

---------

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2026-01-03 10:54:31 -06:00
e91086a9bd [DOC] Sort firmware dropdown lists alphabetically (#2258)
Sort the web uploader firmware selection dropdowns alphabetically
for better user experience. Applies to both dev and release builds.

🤖 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>
2025-12-07 16:45:07 -06:00
5f969bf26b [CI] Fix nightly build failures (#2257)
- 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>
2025-12-07 16:03:30 -06:00
Northern Man 50ff9f535f [RF] Update to rtl_433_ESP 0.5.0 2025-12-07 10:16:22 -06:00
Alessandro Staniscia c6b2aae965 Refactor RF Configuration Management (#2245)
- 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.
2025-12-07 09:56:15 -06:00
dependabot[bot] 401be5f10c Bump min-document from 2.19.0 to 2.19.1 (#2249)
Bumps [min-document](https://github.com/Raynos/min-document) from 2.19.0 to 2.19.1.
- [Commits](https://github.com/Raynos/min-document/compare/v2.19.0...v2.19.1)

---
updated-dependencies:
- dependency-name: min-document
  dependency-version: 2.19.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-21 19:15:46 -06:00
dependabot[bot] 593f25ff59 Bump js-yaml from 3.14.1 to 3.14.2 (#2251)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.14.1 to 3.14.2.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.14.1...3.14.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 3.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-21 19:15:23 -06:00
75f9d30919 [SYS] Update to Arduino 3.3.3 and use custom libs (#2248)
* Update Arduino core to v3.3.2 and use custom Arduino libs

* Update Python version and install uv in build.yml (#2247)

Updated Python version and added uv installation step.

---------

Co-authored-by: Ryan Powell <ryan@nable-embedded.io>

* fix builds

* Update scripts/add_c_flags.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fetch archives instead of cloning libraries

* Update to Arduino 3.3.3

---------

Co-authored-by: h2zero <powellperalata@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-10 07:36:09 -06:00
Northern Man 382fa5e9f2 [SYS] Fix for build error with MDNS_SD (#2239)
* Fix for build error with MDNS_SD

* Update environments.ini
2025-09-16 05:38:43 -05:00
dependabot[bot] 226297ba5b Bump sha.js from 2.4.11 to 2.4.12 (#2236)
Bumps [sha.js](https://github.com/crypto-browserify/sha.js) from 2.4.11 to 2.4.12.
- [Changelog](https://github.com/browserify/sha.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/sha.js/compare/v2.4.11...v2.4.12)

---
updated-dependencies:
- dependency-name: sha.js
  dependency-version: 2.4.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-06 08:42:29 -05:00
dependabot[bot] f8f96a0383 Bump cipher-base from 1.0.4 to 1.0.6 (#2235)
Bumps [cipher-base](https://github.com/crypto-browserify/cipher-base) from 1.0.4 to 1.0.6.
- [Changelog](https://github.com/browserify/cipher-base/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/cipher-base/compare/v1.0.4...v1.0.6)

---
updated-dependencies:
- dependency-name: cipher-base
  dependency-version: 1.0.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-06 08:42:16 -05:00
FlorianandFlorian e495b61216 [SYS] Fix ESP8266 local builds (#2234)
Following #2232

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2025-08-20 06:16:47 -05:00
FlorianandFlorian 32174e37a5 [SYS] Reduce Logs flash footprint (#2232)
By building only the log level required into LOG_LEVEL

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2025-08-19 09:15:41 -05:00
FlorianandFlorian 6e6b54b05e [DISC] Ram usage and flash size optimization (#2223)
Fix duplicate W and keep units and classes in flash
Use macro for discovery classes and units
[BREAKING] change gateway sensor unique id
module - parameter
Standardize the use of createDiscoveryFromList

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2025-08-17 06:27:42 -05:00
DigiH 51bdc2d080 [BT] Victron decryption adjustments (#2228) 2025-08-16 15:43:54 +02:00
DigiH 14ceba5bee [BT] Consistent checking for BLEDecryptor as a Boolean (#2230)
Consistent checking for BLEDecryptor as a Boolean, not just as a Define, so that
…
…

also behaves correctly when set to false.
2025-08-16 15:03:19 +02:00
DigiH 5add388fbc [BT] Typo fix to actually have Victron devices decrypted (#2226) 2025-08-13 14:34:00 +02:00
FlorianandFlorian 6d7e4fd8f1 [BOARD] Remove Theengs Bridge self test (#2225)
Not needed for web or OTA update. It will enable to save flash

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2025-08-13 07:14:30 -05:00
Peter Lambrechtsen 75b3a3657e Add RSSI as diagnostic entity_category (#2224) 2025-08-12 07:11:42 -05:00
Peter Lambrechtsen 6d1b7935c4 [DISC] Replace Home Assistant Auto Discovery MQTT keys with shortened abbreviations (#2221) 2025-08-10 10:34:17 -05:00
Peter Lambrechtsen ddb9cc67cc [DISC] Fix cosmetic issue in Home Assistant where devices don't link to gateway (#2220)
* Fix cosmetic issue in HA where devices don't link to gateway

* Update via_device to use getMacAddress() to get the OMG device mac address
2025-08-07 06:52:38 -05:00
Peter Lambrechtsen 2d29ee4524 [BLE] Add support for decrypting PVVX, BTHome v2 and Victron BLE frames (#2219)
* Changing WebUI to include display device name, and change it to select drop down rather than checkbox

* Fix mqttDiscovery to require WebUI and ESP32 for displayDeviceName

* Fix mqttDiscovery to require WebUI and ESP32 and ESP8266 for displayDeviceName and ForceDeviceName

* Changing WebUI to include display device name, and change it to select drop down rather than checkbox

* Fixes for WebUI and BT for supporting custom setting Display name

* Fixes for WebUI and BT for supporting custom setting Display name

* Move DISPLAY_DEVICE_NAME to User_config.h

* Update docs to include change for Display temperature

* Update docs to include change for Display temperature

* Fix minor cosmetic bug where devices were not linking in HA to the gateway using via_device as it should be the gateway mac address not name

* Add support for decrypting BTHome v2 frames

* Add support for decrypting BTHome v2 frames

* Add support for decrypting BTHome v2 frames

* BTHome fix issue with theengs-plug

* BTHome fix issue with theengs-plug

* Adding support for all BLE encrypted methods, support in UI and gatewayBT for specific MACAddress AES Keys

* Fix lint

* Fix build issue with theengs-bridge-v11 and esp32dev-all-test and revert the documentation to Units of measurement displayed

* Revert docs

* Revert displayDeviceName and Units of measurement

* Revert displayDeviceName and Units of measurement

* Revert displayDeviceName and Units of measurement

* Revert minor typo

* Revert minor typo

* Revert minor typo

* Bug in Victron as nonce should be 16 bytes

* Shortened the client side javascript for BLE key validation that is commented out due to image constrains on theengs-bridge-v11
2025-08-06 19:59:33 -05:00
Ryan Powell a0d5b7d181 [BLE] Fix crash if BLE stack is not initialized when setting advertising. (#2212) 2025-08-05 07:08:03 -05:00
dependabot[bot] 4166d2ab68 [CI] Bump on-headers and compression (#2214)
---
updated-dependencies:
- dependency-name: on-headers
  dependency-version: 1.1.0
  dependency-type: indirect
- dependency-name: compression
  dependency-version: 1.8.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-05 07:07:16 -05:00
Ryan Powellandh2zero 27a6ec592b [BLE] Add status to Blufi advertising. (#2198)
* blufi status

* Make the manufacturer ID configurable at build time.

* fix missing break.

* Update blufi gateway state when changed

---------

Co-authored-by: h2zero <powellperalata@gmail.com>
2025-07-07 22:54:52 +02:00
peshovec 162a4d3ae9 [RF] RF2, Pilight : fixups to RF2 transmit when using CC1100; fixups to Pilight when raw enabled (#2207) 2025-06-28 14:51:15 -05:00
Tom Roush b8b427555a [BOARD] Support lilygo-t3-s3 (#2160)
* Support lilygo-t3-s3

* Add to CI list

* Use espressif32@6.10.0 platform
2025-06-28 14:42:12 -05:00
Ryan Powell 3f569b9de3 [BLE] Update NimBLE-Arduino to 2.3.2 (#2201) 2025-06-28 14:40:10 -05:00
dependabot[bot] fff05ee2e4 Bump pbkdf2 from 3.1.2 to 3.1.3 (#2206)
Bumps [pbkdf2](https://github.com/crypto-browserify/pbkdf2) from 3.1.2 to 3.1.3.
- [Changelog](https://github.com/browserify/pbkdf2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/pbkdf2/compare/v3.1.2...v3.1.3)

---
updated-dependencies:
- dependency-name: pbkdf2
  dependency-version: 3.1.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-28 14:39:42 -05:00
jaal2001 f634f1f204 [DOCS] Update binaries.md for the use with Mac (#2203)
The baud rate seems to a common problem, so this may be a nice hint to Apple users.
2025-06-22 06:25:39 -05:00
PLCHome 9b6e835afb [RF] An FSK version for esp32dev-rtl_433 has been added (#2195)
* An FSK version for esp32dev-rtl_433 has been added to handle the Bresser 5-in-1 weather station with a standard 868 MHz c1101

* Change platform and DGateway_Name
2025-05-23 19:29:14 -05:00
DigiH e47c145bad [RF] Fix discovery for negative Ids (#2194) (#2196) 2025-05-23 19:27:34 -05:00
DigiH a4ba937553 [DOCS] image optimisation (#2192) 2025-05-21 16:30:29 +02:00
DigiH 828f0a226e [DISC] device class added and Units sorted (#2189)
device class added and Units sorted alphabetically for easier lookup and adding missing units
2025-05-18 20:35:44 +02:00
Ryan Powell 301b3eecd8 [SYS] Misc bug fixes with strict compilation (#2188) 2025-05-17 17:36:07 -05:00
DigiH 6175e03bc8 [DISC] Additional device classes (#2185) 2025-05-17 01:42:40 +02:00
DigiH f0491e188c [BT] MQTT corruption fix (#2183)
Storing a copy of the ID instead of a pointer to a local variable to avoid MQTT publishing id topic and id property corruption.
2025-05-16 22:15:57 +02:00
Ryan Powell 585df9a420 [SYS] Update arduino core to 3.1.1 + refactor ino to cpp (#2177)
* Update arduino core to 3.1.1

* Fix Blufi build

* Update arduinojson, fix build errors with idf

* Fix narrowing

* fix RF builds

* WIP-Convert ino files to cpp

* Fix pilight build

* Fix Somfy actuator build.

* Update esp32dev-rf partition

* Fix Weatherstation build

* Fix GFSunInverter build

* Fix esp32dev-ir build

* Fix ble-aws build

* Fix eth builds

* Fix m5Stack missing pins_arduino.h

* Fix build errors for M5 stack/tough, others are upstream issues.

* Fix RTL 433 build - remaining errors are from radolib

* Fix nodemcu build

* fix 2g builds

* Fix serial build

* Fix actuator on off builds

* Fix SSD1306 build - remaining errors are from radiolib

* Fix multiple definition of OTAserver_cert

* Fix nodemcu rf2 build

* Fix ADC builds

* Fix sensor builds

* Fix LORA builds

* Fix multi-receiver builds - remaining errors are in radiolib

* Fix fastled builds

* Fix theegns board builds

* Fix broker builds

* Update fastled - old version failed all-test build

* Fix RN8209 builds

* Fix max temp actuator builds

* Fix PWM builds

* Fix C37 sensor builds

* Fix HTU21 builds

* Fix INA266 builds

* Fix undefined variables in mqtt discovery

* Fix webui build

* Fix fastled invalid pin error

* Fix wifi manual setup builds

* Fix onewire/all-test build - bin too big error remaining

* Fix theengs plug build

* Fix rfbridge builds

* Fix blufi builds

* Fix undefined functions in serial

* Fix preprocessor definition checks

* Set IDF log level to erre

* Add delay in loop to prevent watchdog timeout

* Use xTaskCreateUniveral to support single core processors

* Remove old HTTPUpdate files - upsteam fixed.

* Cleanup and move common declarations to header file

* Use custom partiton table to fix builds where bin is too large

* Update M5StickC - fixs esp32-m5stick-c-ble build

* Revert to Arduino core 2.x for builds with incompatible libs

* Remove "Z" from file names and rename omg_common to TheengsCommon

* Fix gateway name when using MAC with new Arduino core

* Update IDF config to reduce loop task stack use

* Update esp-nimble-cpp version, corrects BLE uppercase ID's

* Update wifi manager to fix watchdog timeout error
2025-05-06 19:35:50 -05:00
DigiH 6e77efb11b "ohdiscovery" back in obsoleteEntities 2025-04-28 17:14:40 +02:00
Florian bb135aa0bf [DOCS] Remove hits (#2175) 2025-04-09 05:36:23 -05:00
dependabot[bot] 037ee88528 [CI] Bump prismjs from 1.29.0 to 1.30.0 (#2169)
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.29.0 to 1.30.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.29.0...v1.30.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-04 07:28:47 -05:00
peshovec 7f542c8347 [RF] ZgatewatPilight: toggle RawEnabled only if Pilight is active receiver (#2159) 2025-03-07 16:48:15 -06:00
Alessandro Staniscia e683fbbd18 [RF] Proposal fix for issue #2139 + Extra documentation (#2157)
* Refactor announceDeviceTrigger function to improve parameter handling and documentation for optional device information
Fix null pointer references in RFtoMQTTdiscovery and update logging levels for RF signal handling
Refactor RF to MQTT discovery functions for improved clarity and parameter handling

* Update documentation for RF auto discovery and MQTT integration, correcting terminology and enhancing clarity

* Refactor enableRFReceive function to accept parameters for frequency and GPIOs, enhancing flexibility
2025-03-07 16:47:33 -06:00
dependabot[bot] e6443143bb [CI] Bump elliptic from 6.6.0 to 6.6.1 (#2167)
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.6.0 to 6.6.1.
- [Commits](https://github.com/indutny/elliptic/compare/v6.6.0...v6.6.1)

---
updated-dependencies:
- dependency-name: elliptic
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 16:42:37 -06:00
peshovec e2ada763ec [RF2] fix json formatted sending, when the active receiver is not RF2 (#2158) 2025-02-04 07:39:26 -06:00
Ryan Powell d03795d0bf [BT] Update NimBLE-Arduino to 2.2.1 (#2140)
* Update NimBLE-Arduino to 2.2.1

* Add BLE OTA update capability.
2025-02-01 12:21:40 -06:00
DigiH 4bf43f5695 [DISC] Removal of openHAB specific MQTT discovery patch (#2153)
Removal of openHAB specific MQTT discovery patch "ohdisc", as it is no longer required with openHAB 4.3 and later, and with openHAB before 4.3 MQTT discovery never was fully implemented anyway.
2025-01-25 14:14:22 -06:00
peshovec d837dfd32a [RF] HA: RF modules as sensors. Subscribe topic, according valueAsATopic (#2134) 2025-01-25 12:53:24 -06:00
FlorianandFlorian cd35520bb0 [BT] Increase again procBLEtask stack size (#2152)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2025-01-14 07:23:57 -06:00
FlorianandFlorian 5b6cf44662 [CI] Update python version to 3.11 (#2151)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2025-01-14 07:23:41 -06:00
FlorianandFlorian bead01347e [BT] Increase procBLEtask stack size to avoid reset when adapting the scan parameters (#2148)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2025-01-10 13:47:34 -06:00
DigiH d8c0f0f9c5 [BT] Small typo fix (#2147) 2025-01-07 17:14:49 +01:00
DanEmord 4d6e7f4afa [RF] Allow configuration of CC1101 SPI pins (#2141)
If all CC1101 SPI pins are defined, use them to create the SPI device. Otherwise, default to the platform's SPI.
2025-01-03 09:29:26 -06:00
DigiH 5e1860abd9 [DISC] rtl_433 UV amendments (#2144) 2025-01-02 14:56:18 +01:00
Northern Man 3db54b4266 Update to rtl_433_esp - for testing of the integrated package (#2125) 2024-12-18 07:55:14 -06:00
benzok 312b4bcf17 [DISC] Whitelist immediate change (#2133)
* When updating a device from UNKNOWN force a new scan

* update the sensorModel_id and handle if white-list is updated

* Restore unduly deleted documentation
2024-12-18 07:53:32 -06:00
melyux 7fa00dd593 Pilight: Handle when 'value' is not a string (#2129) 2024-12-13 16:42:39 -06:00
DigiH 1b50c8ec02 [WEBUI] Fix for TH1 external probe in display routine (#2127)
Fix for TH1 external probe in display routine only actually showing when connected.
2024-12-05 15:33:28 +01:00
DigiH 2cce06ed4e [DISC] Defined boolean values (#2126)
Defined boolean values in discovery message for cross platform discovery in HA and OH for binary_sensors.
2024-12-04 01:04:56 +01:00
DigiH 9bb7751b8d [BT] Decoder development link (#2120) 2024-11-24 13:13:57 +01:00
FlorianandFlorian 1f45a7711b [SYS] Avoid queue overloading at start (#2114)
Give one cycle of the loop without starting BT

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-15 10:37:20 -06:00
FlorianandFlorian 8bad846d94 [BT] Update Theengs decoder to v1.8.0 (#2113)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-15 09:47:38 -06:00
FlorianandFlorian b5adf1f5ac [BROKER] Fix BT start (#2112)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-13 07:42:44 -06:00
FlorianandFlorian bbea094438 [LORA][BREAKING] Update LoRa env partition (#2110)
Not enough flash memory with the regular one

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-13 07:28:56 -06:00
FlorianandFlorian 18cfbb759a [SYS] Remove Multi Gateway Sync from idf example env (#2109)
To avoid consuming procBLEtask stack memory when using esp idf framework

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-12 09:55:17 -06:00
FlorianandFlorian 3bcfdee712 [BLUFI] Fix SSID return (#2108)
The filter on NTWK_CONNECTED was too restrictive when asking for WiFi status.
Get the WiFi name and BSSID from the WiFi object

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-12 08:50:24 -06:00
FlorianandFlorian 379312a127 [BLUFI] Enable larger notifications (#2107)
by replacing esp_blufi_send_notify by esp_blufi_send_custom_data

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-12 08:37:51 -06:00
FlorianandFlorian fdc7435079 [SYS] Fix capacity to onboard ethernet board without WiFi AP (#2106)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-12 08:26:55 -06:00
FlorianandFlorian f5fe3ed223 [DISC] Remove unnecessary discovery publication (#2105)
They are not anymore needed as we keep the scan and presence parameters always displayed

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-12 08:26:29 -06:00
FlorianandFlorian 921488359e [BT] Fix BT command triggering a stack trace due to conflict (#2104)
related to the vector between BLE scanning and BLE control

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-12 08:26:15 -06:00
FlorianandFlorian bb05011bdc [SYS] Fix webUI OTA update free memory (#2103)
When doing an OTA update we deinit BT to free enough memory for the update

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-11 17:27:26 -06:00
FlorianandFlorian 87228b5f29 [SYS] Bump ESP8266 framework version to 4.2.1 (#2102)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-10 08:24:31 -06:00
FlorianandFlorian 3cd7c92d8f [SYS] Fix ESP8266 discovery publications (#2100)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-10 08:24:13 -06:00
FlorianandFlorian 742945906d [SYS] Fix erase function for ESP8266 (#2101)
And remove restart parameter as it is not used (the ESP always restart after erase for our use cases)

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-11-10 08:23:53 -06:00
peshovec e2641f49e7 [RF] Disable the active RF receive when transmitting with RC-Switch and NewRemoteTransmitter\n (#2084)
Pilight RF transmit is behaving this way already.
2024-11-07 07:55:30 -06:00
JamesandJames Carey f5bca0054e [RF] Improve Home Assistant auto discoverability (#2057)
* add '-DvalueAsATopic=true' to RF based environments
add '-DvalueAsATopic=true' to RF based environments. Required to support changes in zgatewayRF.ino for Home Assistant discoverability

* Modify gatewayRF to improve Home Assistant auto discoverability
Pass "recieved" as the type argument and switchRF[0] as the subtype argument to announceDeviceTrigger() which will cause recieved codes to be picked up by home assistant as triggers, i.e. When setting up automations in Home Assistant, selecting a `device` trigger and an OMG device will allow the user to select a code picked up during the autoDiscover window as the trigger for the automation, for example "1394004" recieved. In order to support this, the `'-DvalueAsATopic=true'` argument must be added to all environments using the RF Library

Also change getUniqueId() call to remove leading '-' which will prevent MQTT topics having '--' in them

---------

Co-authored-by: James Carey <james.carey@uws.ac.uk>
2024-11-07 07:54:50 -06:00
dependabot[bot] ac1ad10240 Bump elliptic from 6.5.7 to 6.6.0 (#2095)
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.7 to 6.6.0.
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.7...v6.6.0)

---
updated-dependencies:
- dependency-name: elliptic
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 07:53:11 -06:00
DigiH ba9506c022 [DISC] Additional HA discovery device class (#2097) 2024-11-04 00:17:56 +01:00
DigiH 044182460c [DOCS] SwitchBot Curtain clarification & device tracker updates (#2096)
• SwitchBot Curtain clarification, as these commands work with all three - original, 2 and 3 - versions of the SwitchBot Curtain.

• Device tracker updates.
2024-11-03 18:06:51 +01:00
DigiH 67e50642dd [BT] Device Tracker sync across gateways (#2094)
Device Tracker sync across gateways - OpenMQTTGateway & Theengs Gateway
2024-10-28 11:25:38 -05:00
FlorianandFlorian 952a65dd0f [DISC] Fix device name discovery (#2093)
Fix issue introduced by #1936

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-10-25 13:24:31 -05:00
Alessandro Staniscia f30960566c [DISC] Fix Mqtt Device Trigger announcement message (#2091) 2024-10-25 13:24:10 -05:00
Michael HaberlerandMichael Haberler f86d89db85 [BOARD] add esp32s3-m5stack-stamps3 (#2088)
* [BOARD] add esp32s3-m5stack-stamps3

https://docs.m5stack.com/en/core/StampS3

* [BOARD] add esp32c3u-m5stamp

button long-press reset verified to work

* add build environments for addional M5Stack targets

esp32s3-m5stack-stamps3
esp32c3u-m5stamp

---------

Co-authored-by: Michael Haberler <git@mah.priv.at>
2024-10-15 06:42:58 -05:00
dependabot[bot] 3b3fe3eabe Bump cookie and express (#2087)
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)

Updates `express` from 4.21.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.0...4.21.1)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-13 08:38:40 -05:00
peshovec 258e3b3f6a [SYS] Implement changes to build against ArduinoJson@7.2.0. (#2083)
In ArduinoJson@6.20 a deprecation (naked char) is enforced. The deprecation origins from ArduionoJson@6.18.0
2024-10-08 12:11:35 -05:00
puterboy 4f26d39b93 [RF] Bumped rtl_433_ESP to v0.3.3 to increases rtl_433_Decoder_Stack size to prevent OOM crash (#2082) 2024-10-06 18:19:46 -05:00
puterboy 5f80fea88d [RF] Add 'rtl433_stack' size reporting to RFtoMQTT topic (#2081)
* Added reporting of rtl433_stack size as part of RFtoMQTT

* Fixed formatting
2024-10-06 14:13:10 -05:00
peshovec c98ac731b4 [DOCS] RF Gateway receiver mode change, HA integration example to view/change the RF mode (#2072)
* Update rf.md

* Update home_assistant.md
2024-10-04 17:04:01 -05:00
FlorianandFlorian 898b5e6213 [ONB] Fix failsafe mode (#2080)
Erasing the nvs before the start of WM prevent WM from starting, revert a part of #2075
Also remove the erase from setupWiFiManager method

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-10-04 17:02:50 -05:00
FlorianandFlorian 4e090eda3c [SERIAL] Improve communication robustness (#2079)
-Add a semaphore to avoid msg overlap
-Clean partial buffer
-Enable erase and restart of the secondary module from the primary

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-10-03 09:47:22 -05:00
FlorianandFlorian fcc09df02c [DISC] Fix via device discovery when using secondary module(#2077)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-10-01 20:02:18 -05:00
FlorianandFlorian e390aca43b [SYS] Erase secondary module flash when button is pressed on primary module (#2076)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-10-01 16:29:03 -05:00
FlorianandFlorian c234afa9c8 [SYS] Fix connection validation on unknown indexes and improve erase method (#2075)
Before this fix, connections with Index 1 and 2 were supposed valid when not present in the configuration, generating attempts to connect with those indexes.
Also improve the erase config by adding an erase when the config file is not present (ESP is connected to WiFi without the config file). This way the ESP will not reconnect to the WiFi AP.

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-10-01 11:48:39 -05:00
FlorianandFlorian 9e5f56580d [SYS] Detect IDF environnement with USE_ESP_IDF (#2074)
Rather than USE_BLUFI only, as IDF can be used without BLUFI

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-10-01 11:42:11 -05:00
FlorianandFlorian 88e09092d6 [SERIAL] Add Serial Heartbeat ack (#2073)
And enable to launch the loop when offline: false and serial communication layer is activated

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-10-01 10:47:55 -05:00
FlorianandFlorian 3187ed6154 [SERIAL] Enable SERIAL to X communication (#2068)
Add Serial as a communication layer so as to transmit data to/from serial
Enable discovery of BT sensors through serial
Add serial heartbeat

Change discovery principle for interval and intervalacts, keep them always discovered and deactivate adaptivescan when changed. Instead of removing their discovery when adaptive scan is activated

Increase JSON_MSG_BUFFER_MAX as we are now using const char* and it requires more memory for Arduino Json Deserialization

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-26 06:55:26 -05:00
Northern Man a89ff43900 [DISC] Warning message for discovery prefix change (#2066)
* discovery_Topic

* Remove  Log.notice(F("type: %s" CR), type.c_str());
2024-09-25 12:09:29 -05:00
Northern Man 6fa725d633 [DOCS] Touch Blanking Docs (#2067) 2024-09-24 16:56:31 -05:00
FlorianandFlorian 026fb4a337 [BOARD] Add Theengs Plug environment (#2065)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-24 10:11:05 -05:00
FlorianandFlorian 0d338cc5c5 [LED] Add LED STRIP macros and a third Addressable pin (#2063)
* [LED] Add LED STRIP macros and a third Addressable pin

---------

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-19 20:36:46 -05:00
FlorianandFlorian 0b4c6ef107 [BT] Clean KnownBTAction function (#2062)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-17 09:58:21 -05:00
FlorianandFlorian 4b20976a08 [BLUFI] Add Blufi activation and deactivation at runtime (#2058)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-17 09:32:20 -05:00
FlorianandFlorian 776ed6568d [BT] Fix crash when sending multiple BT commands at the same time (#2059)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-17 07:29:36 -05:00
dependabot[bot] eab1354d7a Bump serve-static and express (#2060)
Bumps [serve-static](https://github.com/expressjs/serve-static) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `serve-static` from 1.15.0 to 1.16.2
- [Release notes](https://github.com/expressjs/serve-static/releases)
- [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md)
- [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2)

Updates `express` from 4.19.2 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0)

---
updated-dependencies:
- dependency-name: serve-static
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-17 07:16:13 -05:00
dependabot[bot] 32e01cdc96 Bump send and express (#2061)
Bumps [send](https://github.com/pillarjs/send) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `send` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/pillarjs/send/releases)
- [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md)
- [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0)

Updates `express` from 4.19.2 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0)

---
updated-dependencies:
- dependency-name: send
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-17 07:16:04 -05:00
FlorianandFlorian ed0b683754 [LED] Add power pin to addressable LED (#2056)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-13 11:21:41 -05:00
FlorianandFlorian 435b8ca3d9 [LED] Refactor LED handling (#2051)
Refactor LED handling into a library
Use a task instead of relying on the loop for precise timing

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-13 09:55:56 -05:00
DigiH 20af9ccf11 HOBOMX2001 added to UNIQ Level display routine (#2055) 2024-09-13 16:52:04 +02:00
FlorianandFlorian 5d6f735058 [SYS} Improve queue performance whenb Using Ethernet and low interval between scan (#2052)
Add also a msgrcv (messages received) indicators into SYStoMQTT to measure the performances

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-10 16:33:46 -05:00
DigiH caea021ca9 "ctrl" key included in Advanced Data (#2050) 2024-09-07 02:30:15 +02:00
FlorianandFlorian 00fe36f426 [BT] Add Switchbot curtain (#2049)
Add SB curtain commands and add stop to SB tilt

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-05 08:54:53 -05:00
FlorianandFlorian 2b958ae363 [SYS] Externalize utils function keep cmpToMainTopic (#2048)
And fill generateHash

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-04 13:18:41 -05:00
FlorianandFlorian 5e65e807b7 [SYS] Externalize utils functions (#2046)
To declutter main.ino code

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-04 10:31:51 -05:00
FlorianandFlorian 0999563095 [CI] Update Github actions versions (#2047)
* [CI] Update Github actions

* Update setup-node

---------

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-04 10:30:05 -05:00
FlorianandFlorian 220e2fe164 [BLUFI] Add Bluetooth timer, notifications and AP scan list (#2045)
Add a Bluetooth timer to automatically disconnect the Bluetooth client
Add custom data notifications
Add AP Scan list
Change MQTTtoSYS API to accept server or port alone

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-09-04 08:37:17 -05:00
puterboy c5b9bcb4cb [DISPLAY] Removed obsolete pubOled stub and calls (#2039) 2024-08-29 10:40:03 -05:00
FlorianandFlorian 719976b652 [SYS] Remove handleJsonQueue wrapper and use std::string (#2038)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-29 09:44:05 -05:00
puterboy cb824e2ee4 [RTL_433] Revert ZgatewayRTL_433 to use handleJsonEnqueue (#2036) 2024-08-29 07:46:30 -05:00
puterboy 1f42075ec8 [SYS] Fixed data corruption associated with jsonQueue enqueueing and dequeuing (#2035)
* Changed jsonQueue to use json String rather than json Object
Added Mutex protection to emptyQueue()
Move Mutex protection to within enqueueJsonObject to shorten lock time
2024-08-29 07:45:56 -05:00
puterboy 830d58f98e [SYS] Add Mutex to potect mqtt->publish() from concurrent… (#2034)
Protecting mqtt->publish() fixed the problem with corruption of MQTT discovery config messages #2012
2024-08-29 07:10:46 -05:00
puterboy 5564ed531c [DISC] Remove restartesp from discovery_prefix 2024-08-29 07:09:16 -05:00
puterboy f34e549d59 [WEBUI] Changed from GET to POST method for config forms with passwords (#2037) 2024-08-29 07:05:58 -05:00
FlorianandFlorian 5492e334dc [SERIAL] Add the capability send info to Serial instead of/added MQTT (#2030)
* [SERIAL] Add the capability send info to Serial instead of/added MQTT

Add the capability to send json data to Serial as a communication layer, added/instead of MQTT

* Use delay rather than vTaskDelay

---------

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-27 13:23:42 -05:00
FlorianandFlorian 3d6d9baeaf [SYS} Fix disconnection detection (#2031)
Fix #2029
Introduced by #2020

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-27 13:23:04 -05:00
FlorianandFlorian 18461b9ef8 [BT] Add capability to remove the decoder when using BT (#2028)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-27 12:31:40 -05:00
puterboy a07bbe5c63 Update ZwebUI.ino - Convert WiFi.SSID() to c_string (JJK) (#2021) 2024-08-25 05:05:03 -05:00
FlorianandFlorian f9a5c6961a [SYS][BREAKING] Add gateway states, Offline mode and refactor sleep (#2020)
Gaterway states to improve LED management
Make the sleep function accessible outside BT
BREAKING remove sleep for ESP8266
BREAKING lowpowermode API changed to powermode and new mode definition

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-23 16:55:04 -05:00
FlorianandFlorian 068c2e457a [LED] Avoid gpio error message at start and fix led macro (#2017)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-22 14:09:49 -05:00
FlorianandFlorian 11ea8210a2 [CM] Ignore pycache folder (#2019)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-22 13:28:37 -05:00
FlorianandFlorian b2ebf670d6 [CM] Git Ignore certificates (#2018)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-22 13:26:43 -05:00
puterboyandFlorian 57fbca8f88 [DISC] Add ability to change Discovery Prefix via WebUI or via mosquitto_pub (#2007)
Add discovery_prefix change at runtime

---------

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-22 13:22:08 -05:00
Northern Man 36945dae42 [DISPLAY] Touch Based Display Blanking (#2015) 2024-08-22 13:21:29 -05:00
FlorianandFlorian b0cf3c1dc7 [BT][BREAKING] Change Switchbot API and add new commands (#2003)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-22 13:04:52 -05:00
Florian 761e3e34f3 [LED] Add ON Led status (#2016)
ON per default at start, never OFF unless the board loose power or the program does not start
2024-08-20 09:02:51 -05:00
FlorianandFlorian a2fa86eef6 [SYS] Fix Ethernet network check on MQTT failure (#2013)
Missing the check

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-16 19:56:41 -05:00
FlorianandFlorian f655f4fda0 [LED] Add ON Led status (#2011)
ON per default at start, never OFF unless the board loose power or the program does not start

Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-16 16:49:14 -05:00
dependabot[bot] 1f5e5006c2 Bump elliptic from 6.5.4 to 6.5.7 (#2010)
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.4 to 6.5.7.
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.4...v6.5.7)

---
updated-dependencies:
- dependency-name: elliptic
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-16 12:34:34 -05:00
Florian 8fd672de45 [LED] Add capability to change second RGB led function (#2009)
When using different pins for each RGB led add the capability to change the function assignment to led2
2024-08-16 11:27:16 -05:00
Florian 8a28bb2cf8 [SERIAL][BREAKING] RS232 change to SERIAL GATEWAY (#2008)
Make the RS232 more generic by converting it to a Serial Gateway
Add the capability to decode BLE data coming through Serial
2024-08-16 11:23:39 -05:00
Florian 25c3da7ee9 [DOCS] Fix image path (#2006)
* [DOCS] Fix image path

Those images are directly stored into the assets directory now for optimization purposes

* Add back the images
2024-08-15 18:52:00 -05:00
FlorianandFlorian 1c942a06cc [SYS] Refine json buffer maximum size (#2005)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-15 07:57:13 -05:00
Florian 04c3e7ef95 Add Switchbot Blind Tilt control (#2002)
close_up, close_down, open, and percentage command
Add auto-discovery with HA and cover component
2024-08-14 14:55:15 -05:00
Florian 4ec577d6af [BT] Switchbot Bot control fix (#2001)
* Fix Canary stack trace error during connection attempt

* Fix discovery

* Fix documentation tip
2024-08-13 13:23:59 -05:00
FlorianandFlorian d43d93f151 [WEBUI] Fix index (#1992)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-13 13:05:07 -05:00
FlorianandFlorian 6441175262 [BOARD] Activate WebUI for the bridge (beta) (#2000)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-12 19:31:35 -05:00
FlorianandFlorian ad74cf9c3c [DOCS] Adaptive scan condition to change intervals (#1999)
Co-authored-by: Florian <1technophile@users.noreply.github.com>
2024-08-12 19:31:21 -05:00
Grégoire Seux c911ec08dc [DOCS] Fix capitalization of rssithreshold in documentation (#1993)
See https://github.com/1technophile/OpenMQTTGateway/blob/8537b7498d887da910733da1818720361b585b25/main/ZcommonRF.ino#L208
2024-07-30 12:48:40 -05:00
Michał Leśniewski 8537b7498d [SYS] Introduce MQTT Broker mode (#1988) 2024-07-27 17:40:47 -05:00
James Coleman ada83bf227 [IR] Fix errors noticed when sending IR codes (#1991) 2024-07-17 10:26:41 -05:00
Florian 35124f2af8 [LORA] Fix save function for parameters that are not frequency (#1987) 2024-07-04 17:09:44 -05:00
Florian b67016bd05 [BT] Default BT enable as a build time parameter (#1985) 2024-07-03 15:02:52 -05:00
Florian 3c0140f57b [SYS] Clean queue before restart (#1986) 2024-07-03 15:02:32 -05:00
Florian cd04c5b92a [BT] Increase BLE task stack (#1984)
To allow to be above 500 free
2024-07-03 11:47:30 -05:00
Michał Leśniewski 9257433a50 [SYS] Use PicoMQTT for MQTT communication (#1954)
* Update Arduino core for selected configurations

* Use PicoMQTT for MQTT communication
2024-07-03 11:39:58 -05:00
Florian b20f2c4819 [ONB] Enable BluFi onboarding with other modules than BT gateway (#1982) 2024-06-24 12:01:55 -05:00
Florian 77d0d14af3 [SYS] Detect instable MQTT connection with AWS (#1979)
and restart directly if the connection parameters does not work, instead of taking into account other parameters like xtomqtt
2024-06-23 16:07:48 -05:00
Florian b1b4bddcbc [SYS] Improve max buffer (#1981)
* [SYS] Reduce the usage scope of json maximum buffer usage

* Reduce procBLETask stack size
2024-06-23 15:28:52 -05:00
Florian 2d5b8b403e [BT] Enable to define MinimumRSSI from a macro in ini files (#1977) 2024-06-21 14:03:34 -05:00
Florian 9af5a2aca0 [ONB] Remove Blufi password visibility in the logs (#1976) 2024-06-21 08:24:08 -05:00
dependabot[bot] 7a2dc8b074 Bump ws from 6.2.2 to 6.2.3 (#1974)
Bumps [ws](https://github.com/websockets/ws) from 6.2.2 to 6.2.3.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/6.2.2...6.2.3)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-18 12:52:26 -05:00
Florian 6a5d3a3da7 [RN8209] Enable RN8209 task size override (#1973) 2024-06-18 12:52:08 -05:00
Florian aa5fd3cb0b [ONB] Fix max buffer size (#1972) 2024-06-18 12:51:48 -05:00
DigiH 4bb7c5502d [DISC] reorder UVI for correct auto-discovery (#1968)
To avoid auto-discovery issues due to substring comparison at
https://github.com/1technophile/OpenMQTTGateway/blob/development/main/ZgatewayRTL_433.ino#L128

strcmp instead of substring only strstr
2024-06-17 13:37:39 -05:00
DigiH 57d1105ba8 [DISC] build flag dependant discovery of HTTP firmware update UI (#1969) 2024-06-13 12:25:43 -05:00
Florian e4e4814c28 [CERTS] Remove certificate display on WiFi manager and enable memory certificate usage for update check (#1967)
* [SYS] Do not display certificates on WiFi Manager

And save them only if the size is more than the minimum

* Enable to use memory cert for update checks
2024-06-12 13:53:24 -05:00
Florian 0a1ee69a72 [SYS] Fix default connection (#1966) 2024-06-12 12:17:12 -05:00
Florian 676a62fecb [OTA] Add Github Digicert cert hash check (#1965)
to avoid loading a deprecated certificate
2024-06-12 12:16:48 -05:00
Florian a74a6ebc06 [SYS] Add serial self test feature (#1964)
Add self testing for Theengs Bridge v1.1 (TBRIDGE02)
This feature enables factory testing
2024-06-12 08:02:34 -05:00
Florian e321448db0 [OTA] Switch OTA server to ota.openmqttgateway.com (#1962)
due to Github cert change
2024-06-12 07:50:41 -05:00
riegelbrau 23b3123b97 [RTL] Correct string handling for type key in NAMING_KEYS (#1960)
* Correct string handling for type key in NAMING_KEYS

Extend class structure RTL_433device and modify code to create correct state topic in discovery message to support sensors, that send type key as well as sensors, that don't. Actually only TPMS sensors use type=TPMS.

* Try to correct format failure.

* Remove trailing spaces
2024-06-12 06:11:02 -05:00
Florian db8e850570 [SYS] Fix wrong connection index record during onboarding (#1961)
and no connection validation if CNT_DEFAULT_INDEX is different than 0
2024-06-10 12:46:24 -05:00
DigiH d538316e03 [DISC] always auto-discover Presence/Tracker timeout (#1959)
auto-discover Presence/Tracker timeout even when HASS presence is not active

Also inject an additional placeholder rssi key and value into the BM2 voltage connection message to avoid the message being registered as a device tracker AWAY

https://community.openmqttgateway.com/t/bm2-home-and-away/3315
2024-06-10 11:50:08 -05:00
DigiH 6e906702ed [DISC] battery_ok discovery differentiation (#1958)
Differentiation between 0%-100% float battery_ok devices' discovery and binary_sensor devices battery_ok
2024-06-10 11:49:43 -05:00
DigiH 417d28fb20 [DISC] Consistent upper case discovery property names (#1957)
And property name change of 'light' and 'lux' to Illuminance
2024-05-30 19:52:33 +02:00
DigiH 33511b5b25 [DISC] Nexa additional auto-discovery properties (#1953) (#1955)
* [DISC] Nexa additional discovery properties (#1953)

* State as binary_sensor ON/OFF

* Alphabetical sorting
2024-05-29 21:55:56 +02:00
Florian 07d9ed9df5 [BOARD][BREAKING] Change of partition for esp32dev-pilight (#1952) 2024-05-24 22:07:48 -04:00
Florian 0db67f75aa [SYS] Add connection fallback capability (#1950)
This feature enable to rotate among the connection parameters index to find a valid one when the current MQTT connection is not working
2024-05-22 05:48:48 -05:00
Florian 819d3c2d91 [SYS] Change log level when publication is canceled (#1949) 2024-05-20 17:03:10 -05:00
Florian f98474bed0 [SYS] Multiple connections management (#1947)
Enable the management of different connections at runtime with a set of certs for each.
Add parameters to the WiFi Manager onboarding, client certificates, and certificate validation
2024-05-20 09:30:49 -05:00
Florian 743083cbfe [ONBOARD] Use Gateway short name macro (#1943) 2024-05-06 11:29:52 -05:00
Vito Ammirata bae4364e41 [LORA] Add water counter sensor with example (#1941)
* Add water counter example
2024-05-05 14:45:33 -05:00
DigiH b5e0223602 [WebUI] Specific Gravity SG added to BLE display routine (#1939) 2024-05-05 14:43:45 -05:00
DigiH f27855527e [DOCS] RETAIN option clarification only for white/black-list (#1937) 2024-04-25 07:11:28 -05:00
Florian 68fd4dc17e [DISC] Add the capability to use the device BLE name (#1936) 2024-04-25 07:11:02 -05:00
Florian 55d9d87a77 [SYS] Do not check idle task on cpu 1 to be consistent with Arduino configuration (#1935) 2024-04-17 09:14:11 -05:00
Sami Salonen d721567adb [DISC] Do not deactive autodiscovery on reconnect-repub (#1933)
Specifically, do not deactive autodiscovery in certain cases
when discovery_republish_on_reconnect is enabled

Signed-off-by: Sami Salonen <ssalonen@gmail.com>
2024-04-17 08:34:21 -05:00
DigiH 115a17cbcc [BT] Prevent intervalacts from being lower than interval (#1932)
Prevent intervalacts from being lower than interval to avoid untrue non-sensical intervalacts values.
2024-04-17 08:32:27 -05:00
DigiH c85f5bec37 Differentiation between OOK and FSK modulation in default environments (#1934) 2024-04-16 20:40:10 +02:00
Florian 2645928dbd [SYS] Remove unnecessaries ESP8266 ESP32 macros (#1931) 2024-04-12 17:13:11 -05:00
Florian 2065d57e11 [BOARDS] Remove Arduino boards (#1929) 2024-04-10 15:48:05 -05:00
ayetee 30f8264878 [BT] Update PublishDeviceData to run presenceUseBeaconUuid check when device is close (#1915) 2024-04-10 13:46:25 -05:00
Florian 0929fa23a8 [DOCS] Remove Arduino IDE support (#1928) 2024-04-10 13:15:16 -05:00
DigiH a52296a97d [DOCS] BLE compatible devices clarification (#1921)
BLE compatible devices clarification and link to listing
2024-04-08 10:18:20 -05:00
Florian a845d772f9 [DOCS] Fix image sizing and path (#1926) 2024-04-08 07:18:52 -05:00
DigiH b884ee8883 [DISC] Additional RF discovery keys and device classes (#1927) 2024-04-05 17:34:02 +02:00
Florian bf70508318 [DOCS] Use Node 16 (#1925)
* [DOCS] Downgrade Node to 16.x and page speed criteria to 60
2024-04-04 20:04:06 -05:00
DigiH 781f7af90c [DISC] uv/uvi discovery fix and device classes added (#1923) 2024-04-04 20:00:14 +02:00
Florian 6c62858093 [DOCS] Page speed optimizations (#1922)
* [DOCS] Page speed optimizations

* Fix img path
2024-04-04 11:38:41 -05:00
FlorianandDigiH 369eb0447b [DOCS] Page Speed criteria update (#1924)
* [CI] Page speed test adjustment

Page speed test adjustment to 65, to avoid development build and artifacts upload fails

* Update build_and_docs_to_dev.yml

---------

Co-authored-by: DigiH <github@digih.net>
2024-04-04 11:37:49 -05:00
dependabot[bot] 3a9193497d Bump express from 4.18.2 to 4.19.2 (#1918)
Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.2...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-31 15:23:31 -05:00
431 changed files with 27492 additions and 38990 deletions

No files matched your search

+41 -12
View File
@@ -10,6 +10,7 @@ on:
permissions:
contents: write
packages: write
jobs:
build-and-release:
@@ -58,7 +59,7 @@ jobs:
if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
TAG_NAME="${GITHUB_REF_NAME}"
else
BASE_VERSION="$(git describe --tags --abbrev=0 2>/dev/null || echo v1.7.0)"
BASE_VERSION="$(git describe --tags --abbrev=0 --exclude '*-b*' 2>/dev/null || echo v1.7.0)"
TAG_NAME="${BASE_VERSION}-b${GITHUB_RUN_NUMBER}-${SHORT_SHA}"
fi
@@ -67,16 +68,13 @@ jobs:
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
- name: Set version tag in sources
env:
TAG_NAME: ${{ steps.prep.outputs.tag_name }}
run: |
sed -i "s/version_tag/${TAG_NAME}/g" main/User_config.h scripts/latest_version.json
- name: Build OpenMQTTGateway Firmware (${{ steps.prep.outputs.pio_env }})
env:
PIO_ENV: ${{ steps.prep.outputs.pio_env }}
TAG_NAME: ${{ steps.prep.outputs.tag_name }}
run: |
# Inject the firmware version (same mechanism as upstream scripts/ci_build_firmware.sh)
export PLATFORMIO_BUILD_FLAGS="-DOMG_VERSION=\\\"${TAG_NAME}\\\""
mkdir -p ".pio/build/${PIO_ENV}"
pio run -e "${PIO_ENV}"
@@ -90,14 +88,16 @@ jobs:
cp ".pio/build/${PIO_ENV}/firmware.bin" "dist/OpenMQTTGateway-${PIO_ENV}-${TAG_NAME}.bin"
ls -lA dist
- name: Create Gitea Release and Upload Binaries
- name: Create Gitea Release and Publish Package
env:
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITEA_PKG_TOKEN: ${{ secrets.GITEATOKEN }}
PIO_ENV: ${{ steps.prep.outputs.pio_env }}
TAG_NAME: ${{ steps.prep.outputs.tag_name }}
SHORT_SHA: ${{ steps.prep.outputs.short_sha }}
run: |
python3 - << 'EOF'
import base64
import json
import os
import subprocess
@@ -106,7 +106,10 @@ jobs:
server_url = os.environ["GITHUB_SERVER_URL"].rstrip("/")
repo = os.environ["GITHUB_REPOSITORY"]
owner, repo_name = repo.split("/", 1)
actor = os.environ.get("GITHUB_ACTOR") or owner
token = os.environ["GITEA_TOKEN"]
pkg_token = os.environ.get("GITEA_PKG_TOKEN") or token
tag_name = os.environ["TAG_NAME"]
sha = os.environ["GITHUB_SHA"]
short_sha = os.environ["SHORT_SHA"]
@@ -156,7 +159,12 @@ jobs:
release_id = data["id"]
print(f"Created release ID {release_id} for tag {tag_name}")
# Upload firmware binaries in dist/
# Upload firmware binary to Release and Gitea Package Registry
# Note: Gitea's Generic Package Registry upload router is at /api/packages/ (not /api/v1/packages/)
package_name = f"{repo_name}-{pio_env}"
pkg_base = f"{server_url}/api/packages/{owner}/generic/{package_name}/{tag_name}"
basic_auth = base64.b64encode(f"{actor}:{pkg_token}".encode("utf-8")).decode("ascii")
for filename in sorted(os.listdir("dist")):
if filename in existing_assets:
del_req = urllib.request.Request(
@@ -166,12 +174,33 @@ jobs:
)
urllib.request.urlopen(del_req).close()
filepath = os.path.join("dist", filename)
print(f"Uploading {filename}...")
print(f"Uploading {filename} to Release...")
subprocess.run([
"curl", "--fail", "-sS", "-X", "POST",
"curl", "--fail", "-sS", "-o", "/dev/null", "-X", "POST",
"-H", f"Authorization: token {token}",
"-F", f"attachment=@{filepath}",
f"{api_base}/releases/{release_id}/assets?name={filename}"
], check=True)
print(f"Uploaded {filename} successfully.")
print(f"Uploaded {filename} to Release successfully.")
# Publish to Gitea Generic Package Registry (delete existing file first if re-running)
pkg_file_url = f"{pkg_base}/{filename}"
try:
del_pkg_req = urllib.request.Request(
pkg_file_url,
headers={"Authorization": f"Basic {basic_auth}"},
method="DELETE",
)
urllib.request.urlopen(del_pkg_req).close()
except urllib.error.HTTPError as e:
if e.code != 404:
raise
print(f"Publishing {filename} to Gitea Package {package_name}/{tag_name}...")
subprocess.run([
"curl", "--fail", "-sS", "-o", "/dev/null", "-X", "PUT",
"--user", f"{actor}:{pkg_token}",
"--upload-file", filepath,
pkg_file_url,
], check=True)
print(f"Published {filename} to Gitea Package Registry successfully.")
EOF
+37
View File
@@ -1,13 +1,50 @@
.pio
.vscode
*_env.ini
*.pem
**/.DS_Store
node_modules
*.ps1
main/certs/private*
lib/*
!lib/esp32-bt-lib
!lib/TheengsUtils
!lib/LEDManager
CMakeLists.txt
dependencies.lock
sdkconfig.*
!sdkconfig.defaults
__pycache__
*.pem
managed_components
.github/chatmodes
.github/prompts
.github/*instructions.md
.github/workflows/_docs
# CI/CD Generated outputs
docs/.vitepress/dist/
docs/.vitepress/cache/
docs/.vitepress/public/boards-info.json
docs/.vitepress/public/commonConfig.js
docs/.vitepress/public/firmware_build
# Generated site/firmware/reports files
generated/
# Generated ssl for testing
.ssl
# Generated JSON files from templates
scripts/latest_version.json
scripts/latest_version_dev.json
# Generated configuration files
docs/.vitepress/meta.json
# Generated full documentation pages
docs/prerequisites/board-full.md
docs/upload/web-install-full.md
.superpowers/
docs/superpowers/
+1
View File
@@ -0,0 +1 @@
disable=SC1091
+319
View File
@@ -0,0 +1,319 @@
# OpenMQTTGateway - Claude Code Context
This document provides essential context about the OpenMQTTGateway project for AI assistants working on the codebase.
## Project Overview
OpenMQTTGateway is a unified firmware that bridges various wireless technologies (RF 433MHz, IR, BLE, LoRa, etc.) to MQTT protocol, enabling home automation integration with platforms like Home Assistant, OpenHAB, and Node-RED.
**Key Features:**
- Multi-protocol gateway (BLE, RF 433MHz, IR, LoRa, RTL_433, Pilight, etc.)
- ESP8266/ESP32 and Arduino support
- MQTT-based communication
- Web UI for configuration
- Home Assistant MQTT Discovery support
- Over 100 supported BLE sensors via Theengs Decoder
**Main Branch:** `development` (not master/main)
## Architecture
### Modular Design
The firmware uses a modular architecture where each protocol/sensor/actuator is implemented as a separate "gateway" or "sensor" module:
- **Gateways**: Receive and transmit signals (e.g., `gatewayBT.cpp`, `gatewayRF.cpp`, `gatewayIR.cpp`)
- **Sensors**: Read physical sensor data (e.g., `sensorBME280.cpp`, `sensorDHT.cpp`)
- **Actuators**: Control outputs (e.g., `actuatorONOFF.cpp`, `actuatorPWM.cpp`)
Each module has:
- A config file (e.g., `config_BT.h`, `config_RF.h`)
- An implementation file (e.g., `gatewayBT.cpp`, `gatewayRF.cpp`)
### Configuration System
Configuration is managed through:
1. **User_config.h** - Main configuration file with defaults
2. **config_*.h** - Module-specific configurations
3. **platformio.ini & environments.ini** - Build-time configurations
4. **prod_env.ini** - User-specific environments (gitignored)
Build flags in `environments.ini` can override User_config.h parameters.
## Directory Structure
```
OpenMQTTGateway/
├── main/ # Main source code (Arduino convention)
│ ├── main.cpp # Main application entry point
│ ├── User_config.h # Global configuration
│ ├── config_*.h # Module configurations
│ ├── gateway*.cpp # Gateway implementations
│ ├── sensor*.cpp # Sensor implementations
│ ├── actuator*.cpp # Actuator implementations
│ ├── webUI.cpp # Web interface
│ ├── mqttDiscovery.cpp # Home Assistant discovery
│ └── rf/ # RF-specific modules
├── lib/ # Custom libraries
├── scripts/ # Build and automation scripts
├── docs/ # VuePress documentation
├── tests/ # Test configurations
├── environments.ini # PlatformIO environment definitions
├── platformio.ini # PlatformIO configuration
└── prod_env.ini.example # Example production environment
Note: src_dir is set to "main" in platformio.ini
```
## Key Concepts
### Environment-Based Builds
The project supports 80+ hardware configurations defined in `environments.ini`. Examples:
- `esp32dev-ble` - ESP32 with BLE gateway
- `esp32dev-pilight` - ESP32 with Pilight RF
- `esp32dev-rtl_433` - ESP32 with RTL_433 decoder
- `nodemcuv2-ir` - NodeMCU with IR
- `rfbridge` - Sonoff RF Bridge
### MQTT Topics
Standard topic structure:
- Base: `home/` (configurable via Base_Topic)
- Gateway name: `OpenMQTTGateway` or `OMG` (configurable)
- Example: `home/OpenMQTTGateway/BTtoMQTT`
### Module Activation
Modules are activated via build flags in environments.ini:
```ini
build_flags =
'-DZgatewayBT="BT"' # Enable BLE gateway
'-DZgatewayRF="RF"' # Enable RF gateway
'-DZsensorBME280="BME280"' # Enable BME280 sensor
```
### Web UI & WiFi Manager
- ESP32/ESP8266 boards include a WiFiManager for initial setup
- Access point: SSID = `WifiManager_ssid`, Password = `WifiManager_password`
- Web UI provides runtime configuration and control
- Can disable WiFiManager with `ESPWifiManualSetup` flag
## Important Files
### Core Files
- **main/main.cpp** - Main application loop, MQTT handling, module coordination
- **main/User_config.h** - Global configuration defaults
- **main/webUI.cpp** - Web interface implementation
- **main/mqttDiscovery.cpp** - Home Assistant MQTT discovery
### Gateway Files
- **main/gatewayBT.cpp** - BLE gateway (uses Theengs Decoder)
- **main/gatewayRF.cpp** - RF 433MHz gateway (RCSwitch library)
- **main/gatewayRF2.cpp** - Alternative RF implementation
- **main/gatewayPilight.cpp** - Pilight protocol gateway
- **main/gatewayRTL_433.cpp** - RTL_433 decoder integration
- **main/gatewayIR.cpp** - Infrared gateway
- **main/gatewayLORA.cpp** - LoRa gateway
### Configuration Files
All in `main/` directory:
- **config_RF.h** - RF gateway configuration
- **config_BT.h** - BLE gateway configuration
- **config_IR.h** - IR gateway configuration
- etc.
### Build System
- **platformio.ini** - Main PlatformIO config
- **environments.ini** - All environment definitions (~3000+ lines)
- **scripts/** - Python scripts for build automation
## Common Patterns
### Adding a New Gateway Module
1. Create `gateway[NAME].cpp` in `main/`
2. Create `config_[NAME].h` in `main/`
3. Add build flag in `environments.ini`: `-DZgateway[NAME]="[NAME]"`
4. Include conditional compilation: `#ifdef Zgateway[NAME]`
5. Implement setup function: `setup[NAME]()`
6. Implement loop function: `[NAME]toMQTT()`
7. Optionally implement MQTT callback: `MQTTto[NAME]()`
### Adding a New Sensor Module
Similar to gateways, but prefix with `sensor` instead of `gateway` and `Z` becomes `Zsensor`.
### Configuration Override Pattern
```cpp
#ifndef PARAM_NAME
# define PARAM_NAME default_value
#endif
```
This allows platformio.ini build flags to override defaults.
### MQTT Publishing Pattern
```cpp
pub(subjectToMQTT, data); // Basic publish
pub_custom_topic(topic, data, retain); // Custom topic with retain
```
## Development Workflow
### Building
```bash
# List all environments
pio run --list-targets
# Build specific environment
pio run -e esp32dev-ble
# Upload to device
pio run -e esp32dev-ble -t upload
# Monitor serial
pio device monitor
```
### Code Formatting
- Uses clang-format with config in `.clang-format`
- CI checks formatting automatically
- Format before committing
### Testing
- Unit tests in `tests/` directory
- CI runs builds for all environments
- Nightly builds test comprehensive environment matrix
### Documentation
- Documentation uses VuePress, located in `docs/`
- Hosted at https://docs.openmqttgateway.com
## CI/CD
### GitHub Actions Workflows
Located in `.github/workflows/`:
- **build.yml** - Build validation on PRs
- **nightly.yml** - Nightly builds of all environments
- **format-check.yml** - Code formatting validation
### Build Matrix
The nightly build tests configurations:
- ESP32 variants (ESP32, ESP32-S3, ESP32-C3)
- ESP8266 variants (NodeMCU, Sonoff)
- Different gateway combinations
- Board-specific builds (M5Stack, Heltec, TTGO, etc.)
## Common Issues & Solutions
### Memory Constraints
- ESP8266 has limited RAM (~40KB free)
- Use `PROGMEM` for constants
- Minimize module combinations on ESP8266
- ESP32 has more headroom (~200KB+ free)
### RF Module Conflicts
- Some RF implementations (RF, RF2, Pilight, RTL_433) may conflict
- Use separate environments for different RF approaches
- Check GPIO pin assignments in config files
### BLE on ESP32
- BLE stack uses significant RAM
- Limit simultaneous BLE connections
## Related Projects
- **Theengs Decoder** - BLE device decoder library
- **Theengs Gateway** - Python version for Raspberry Pi/PC
- **RTL_433_ESP** - ESP32 port of RTL_433
## Resources
- **Documentation**: https://docs.openmqttgateway.com
- **Community Forum**: https://community.openmqttgateway.com
- **GitHub**: https://github.com/1technophile/OpenMQTTGateway
- **Web Installer**: https://docs.openmqttgateway.com/upload/web-install.html
## Products
- **Theengs Bridge** - ESP32 BLE gateway with Ethernet
- **Theengs Plug** - Smart plug with BLE gateway
## Conventions
### Naming
- Gateways: `gateway[NAME].cpp` with `Zgateway[NAME]` flag
- Sensors: `sensor[NAME].cpp` with `Zsensor[NAME]` flag
- Actuators: `actuator[NAME].cpp` with `Zactuator[NAME]` flag
- Config files: `config_[NAME].h`
### Code Style
- 2-space indentation
- Follow existing patterns in similar modules
- Use preprocessor directives for module isolation
- Comment complex RF protocols or BLE parsing
### Git Workflow
- Main branch: `development`
- Feature branches from `development`
- PRs target `development`
- Squash commits when appropriate
- Descriptive commit messages
## Quick Start for Contributors
1. Fork the repository
2. Create `prod_env.ini` for your local environments
3. Choose an environment from `environments.ini`
4. Build: `pio run -e [environment-name]`
5. Make changes following existing patterns
6. Test build with your environment
7. Run format check
8. Submit PR to `development` branch
## Platform-Specific Notes
### ESP32
- Preferred platform for new development
- More RAM and Flash
- Supports BLE natively
- Can use Ethernet via add-on boards
### ESP8266
- Legacy support
- Memory constrained
- No native BLE
- Good for simple RF/IR gateways
## Tips for AI Assistants
1. **Check environments.ini** when modifying build configurations
2. **Follow existing module patterns** when adding new features
3. **Test on relevant environments** - changes may affect multiple boards
4. **Memory is precious** especially on ESP8266
5. **MQTT topic structure** is critical for Home Assistant integration
6. **Config headers** allow user customization without code changes
7. **Use conditional compilation** to keep builds modular
8. **WebUI changes** need both backend (webUI.cpp) and frontend (config_WebUI.h)
9. **RF protocols** often need precise timing - be careful with changes
10. **The main branch is `development`** - always target PRs there
+10 -24
View File
@@ -1,8 +1,5 @@
[![Community forum](https://img.shields.io/badge/community-forum-brightgreen.svg)](https://community.openmqttgateway.com)
![Build](https://github.com/1technophile/OpenMQTTGateway/workflows/Build/badge.svg?branch=development)
![Check Code Format](https://github.com/1technophile/OpenMQTTGateway/workflows/Check%20Code%20Format/badge.svg?branch=development)
[![OpenMQTTGateway capabilities](https://github.com/1technophile/OpenMQTTGateway/blob/development/docs/img/OpenMQTTGateway.png)](https://community.openmqttgateway.com)
OpenMQTTGateway aims to unify various technologies and protocols into a single firmware. This reduces the need for multiple physical bridges and streamlines diverse technologies under the widely-used [MQTT](http://mqtt.org/) protocol.
@@ -15,49 +12,39 @@ OpenMQTTGateway aims to unify various technologies and protocols into a single f
The documentation is [here](https://docs.openmqttgateway.com)
New to OpenMQTTGateway? Follow the [Getting Started guide](https://docs.openmqttgateway.com/getting-started.html) to flash a board from your browser and see your first sensor data in about 15 minutes.
The reference sheet, with the list of all functions, pinouts is [here](https://docs.google.com/spreadsheets/d/1_5fQjAixzRtepkykmL-3uN3G5bLfQ0zMajM9OBZ1bx0/edit#gid=0)
## Upload
Upload OpenMQTTGateway directly from the [upload page](https://docs.openmqttgateway.com/upload/web-install.html) (no additional software required) or [build your own configuration](https://docs.openmqttgateway.com/upload/builds.html) with [PlatformIO](https://platformio.org/) or [Arduino IDE](https://www.arduino.cc/en/software)
Upload OpenMQTTGateway directly from the [upload page](https://docs.openmqttgateway.com/upload/web-install.html) (no additional software required) or [build your own configuration](https://docs.openmqttgateway.com/upload/builds.html) with [PlatformIO](https://platformio.org/).
## Using OpenMQTTGateway ?
Support open-source development through sponsorship and gain exclusive access to our private forum. Your questions, issues, and feature requests will receive priority attention, plus you'll gain insider access to our roadmap.
Support open-source development through sponsorship, it helps keep the project healthy and evolving.
[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/theengs)
[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/1technophile)
## Products powered by OpenMQTTGateway
### Theengs Bridge, Bluetooth gateway (BLE) with external antenna
[Theengs bridge](https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna) is a powerfull BLE to MQTT gateway for over [90 sensors](https://decoder.theengs.io/devices/devices.html). Equipped with an Ethernet port, and external antenna, ensuring an enhanced range for your BLE sensors. It supports also WiFi connectivity.
[Theengs bridge](https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna) is a powerfull BLE to MQTT gateway for over [100 sensors](https://decoder.theengs.io/devices/devices.html). Equipped with an Ethernet port, and external antenna, ensuring an enhanced range for your BLE sensors. It supports also WiFi connectivity.
[![Theengs bridge view](./docs/img/Theengs-Bridge-ble-gateway.png)](https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna)
### Theengs Plug, Bluetooth gateway (BLE) gateway and Smart Plug
[Theengs plug](https://shop.theengs.io/products/theengs-plug-smart-plug-ble-gateway-and-energy-consumption) brings the following features:
* BLE to MQTT gateway, tens of [Bluetooth devices](https://compatible.openmqttgateway.com/index.php/devices/ble-devices/) supported thanks to Theengs Decoder library. The plug uses an ESP32 acting as a BLE to Wifi gateway to scan, decode and forward the data of the nearby sensors,
* Smart plug that can be controlled remotely,
* Energy consumption monitoring,
* Device tracker,
* Presence detection (beta),
* Local connectivity first.
[![Theengs plug view](./docs/img/Theengs-Plug-OpenMQTTGateway.png)](https://shop.theengs.io/products/theengs-plug-smart-plug-ble-gateway-and-energy-consumption)
Support the project by purchasing the [Theengs bridge](https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna) or the [Theengs plug](https://shop.theengs.io/products/theengs-plug-smart-plug-ble-gateway-and-energy-consumption)
Support the project by purchasing the [Theengs bridge](https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna)
## Compatible items
* [List of supported devices](https://compatible.openmqttgateway.com/index.php/devices/), door/window sensors, PIR sensors, smoke detectors, weather stations...
* [List of supported BLE devices](https://decoder.theengs.io/devices/devices.html), thermometers, scales, plant sensors, beacons...
* [List of compatible boards (Off the shelf or DIY) is available](https://compatible.openmqttgateway.com/index.php/boards/), RF Bridge, IR, BLE gateways...
* [Boards guide](https://docs.openmqttgateway.com/prerequisites/board.html), RF Bridge, IR, BLE gateways...
*Running on a computer*
If you want to use the BLE decoding capabilities of OpenMQTTGateway with a Raspberry Pi, Windows or Unix PC you can now leverage [Theengs Gateway](https://theengs.github.io/gateway/).
* [List of compatible components to build your gateway](https://compatible.openmqttgateway.com/index.php/parts/), DHT, RF, IR emitters and receivers...
* [Parts to build your gateway](https://docs.openmqttgateway.com/prerequisites/parts.html), DHT, RF, IR emitters and receivers...
## Compatible controllers, saas or software
@@ -82,7 +69,6 @@ For Questions or Support please don't open an issue, first go to the [docs](http
If you like the project and/or used it please consider supporting it! It can be done in different ways:
* Helping other users in the [community](https://community.openmqttgateway.com)
* [Contribute](development) to the [code](https://github.com/1technophile/OpenMQTTGateway) or the [documentation](https://docs.openmqttgateway.com)
* Buy devices, boards or parts from the [compatible web site](https://compatible.openmqttgateway.com), the devices and parts linked use affiliated links.
* Donate or sponsor the project [developers](https://github.com/1technophile/OpenMQTTGateway/graphs/contributors)
* Make a video or a blog article about what you have done with [OpenMQTTGateway](https://docs.openmqttgateway.com) and share it to the [community](https://community.openmqttgateway.com)
+41
View File
@@ -0,0 +1,41 @@
// docs/.vitepress/commonConfig.mts
// Adapter that loads the shared Theengs commonConfig.js (CommonJS) downloaded
// by CI from https://www.theengs.io/commonConfig.js, and re-exports the nav
// and head arrays in a format VitePress can consume.
//
// This keeps theengs.io as the single source of truth for nav/head until all
// Theengs docs sites are migrated to VitePress.
import { createRequire } from 'module'
import { existsSync } from 'fs'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const require = createRequire(import.meta.url)
const commonConfigPath = resolve(__dirname, 'public/commonConfig.js')
let sharedConfig: any = null
if (existsSync(commonConfigPath)) {
sharedConfig = require(commonConfigPath)
} else {
console.warn(
'commonConfig.js not found in .vitepress/public/. ' +
'Using fallback nav/head. Run CI or download from https://www.theengs.io/commonConfig.js'
)
}
// Re-export nav from shared config, or use a minimal fallback
export const commonNav = sharedConfig?.themeConfig?.nav ?? [
{ text: 'Home', link: 'https://www.theengs.io' },
{ text: 'Community', link: 'https://community.openmqttgateway.com' },
{ text: 'Shop', link: 'https://shop.theengs.io/' }
]
// Re-export head from shared config, or use a minimal fallback
export const commonHead = sharedConfig?.head ?? [
['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1' }],
['meta', { name: 'theme-color', content: '#3eaf7c' }]
]
@@ -0,0 +1,926 @@
<template>
<div class="board-environment-list">
<div v-if="loading" class="custom-block tip">
<p class="custom-block-title">
<span class="loading-spinner" aria-label="Loading"></span>
Loading supported environments...
</p>
</div>
<div v-if="error" class="custom-block danger">
<p class="custom-block-title">Error</p>
<p>{{ error }}</p>
</div>
<div v-if="!loading && !error">
<!-- Guided picker -->
<div class="wizard">
<span class="wizard-title">Help me choose</span>
<div class="wizard-row">
<span class="filter-group__label">I want to bridge:</span>
<div class="filter-chips">
<button
v-for="b in bridgeOptions"
:key="b.key"
:class="['filter-chip', { 'filter-chip--active': wizardBridge === b.key }]"
@click="wizardBridge = wizardBridge === b.key ? null : b.key">
{{ b.label }}
</button>
</div>
</div>
<div class="wizard-row">
<span class="filter-group__label">My hardware:</span>
<div class="filter-chips">
<button
v-for="h in hardwareOptions"
:key="h.key"
:class="['filter-chip', { 'filter-chip--active': wizardHardware === h.key }]"
@click="wizardHardware = wizardHardware === h.key ? null : h.key">
{{ h.label }}
</button>
</div>
</div>
<div v-if="wizardBridge && recommendedBoard" class="wizard-result">
<div class="wizard-result__text">
<span>Recommended: <code>{{ recommendedBoard.environment }}</code></span>
<span v-if="recommendedBoard.description" class="wizard-result__desc" v-html="recommendedBoard.description"></span>
<span v-if="wizardHardware === 'none' && shoppingHint" class="wizard-result__desc">🛒 {{ shoppingHint }}</span>
</div>
<button class="wizard-result__cta" @click="openSelector(recommendedBoard.environment)">Flash it →</button>
</div>
<div v-else-if="wizardBridge && !recommendedBoard" class="wizard-result wizard-result--none">
No pre-built environment matches this combination<template v-if="wizardBridge === 'ble' && wizardHardware === 'esp8266'"> — Bluetooth needs an ESP32</template>. Try another hardware choice, or <a :href="buildsUrl">build from source</a>.
</div>
</div>
<!-- Search and Filter Bar -->
<div class="filter-bar">
<div class="search-box">
<svg class="search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input
v-model="searchQuery"
type="text"
placeholder="Search by name, description, module..."
class="search-input"
aria-label="Search boards">
<button
v-if="searchQuery"
class="search-clear"
@click="searchQuery = ''"
aria-label="Clear search">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div v-if="hasActiveFilters" class="filter-status">
<span>Showing {{ filteredBoards.length }} of {{ boards.length }} boards</span>
<button class="filter-clear" @click="clearFilters">Clear all filters</button>
</div>
</div>
<!-- No Results -->
<div v-if="filteredBoards.length === 0" class="no-results">
<p>No boards match your filters.</p>
<button class="filter-clear" @click="clearFilters">Clear all filters</button>
</div>
<div class="boards-grid">
<article
v-for="board in filteredBoards"
:key="board.environment"
class="board-card"
@click="openSelector(board.environment)">
<div class="board-card__image">
<span v-if="popularEnvironments.includes(board.environment)" class="popular-badge">Popular</span>
<img
:src="getBoardImageUrl(board)"
:alt="board.environment"
loading="lazy">
</div>
<div class="board-card__content">
<div class="board-card__header">
<h3 class="board-card__title">
<code>{{ board.environment }}</code>
</h3>
<span v-if="board.microcontroller" class="board-card__chip">
{{ board.microcontroller }}
</span>
</div>
<p v-if="board.description" class="board-card__description" v-html="board.description">
</p>
<!-- Modules Section with expand/collapse -->
<div v-if="Array.isArray(board.modules) && board.modules.length" class="board-card__libraries">
<div class="modules-label-row">
<span class="libraries-label">Modules:</span>
<span
v-if="board.modules.length > 2"
class="expand-icon-btn"
@click.stop="toggleModules(board.environment)"
:title="expandedModules[board.environment] ? 'Hide' : 'Show all'">
<svg :class="{rotated: expandedModules[board.environment]}" width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 6 15 12 9 18"/></svg>
</span>
</div>
<Transition name="expand-fade">
<div class="libraries-badges"
:style="expandedModules[board.environment] ? '' : 'max-height: 2.2em; overflow: hidden;'">
<span
v-for="(mod, index) in board.modules"
:key="index"
class="lib-badge">
{{ mod }}
</span>
</div>
</Transition>
</div>
<!-- Libraries Section with expand/collapse -->
<div v-if="Array.isArray(board.libraries) && board.libraries.length" class="board-card__libraries">
<div class="modules-label-row">
<span class="libraries-label">Libraries:</span>
<span
v-if="board.libraries.length > 2"
class="expand-icon-btn"
@click.stop="toggleLibraries(board.environment)"
:title="expandedLibraries[board.environment] ? 'Hide' : 'Show all'">
<svg :class="{rotated: expandedLibraries[board.environment]}" width="19" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 6 15 12 9 18"/></svg>
</span>
</div>
<Transition name="expand-fade">
<div class="libraries-badges"
:style="expandedLibraries[board.environment] ? '' : 'max-height: 2.2em; overflow: hidden;'">
<span
v-for="(lib, index) in board.libraries"
:key="index"
class="lib-badge">
{{ lib }}
</span>
</div>
</Transition>
</div>
<div class="board-card__action">
<span class="action-text">More info →</span>
</div>
</div>
</article>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
interface Board {
environment: string
description?: string
microcontroller?: string
modules?: string[]
libraries?: string[]
customImg?: string
CustomImg?: string
}
const props = withDefaults(defineProps<{
boardsUrl?: string
selectorPath?: string
}>(), {
boardsUrl: '/boards-info.json',
selectorPath: '/upload/board-selector.html'
})
const boards = ref<Board[]>([])
const loading = ref(false)
const error = ref<string | null>(null)
const expandedModules = reactive<Record<string, boolean>>({})
const expandedLibraries = reactive<Record<string, boolean>>({})
const searchQuery = ref('')
const wizardBridge = ref<string | null>(null)
const wizardHardware = ref<string | null>(null)
const bridgeOptions = [
{ key: 'ble', label: 'Bluetooth devices' },
{ key: 'rf433', label: 'RF devices (433/868/915MHz)' },
{ key: 'ir', label: 'Infrared' },
{ key: 'lora', label: 'LoRa' }
]
const hardwareOptions = [
{ key: 'esp32dev', label: 'Generic ESP32' },
{ key: 'esp32c3', label: 'ESP32-C3' },
{ key: 'esp32s3', label: 'ESP32-S3' },
{ key: 'lilygo', label: 'LilyGo / Heltec / TTGO' },
{ key: 'm5', label: 'M5Stack' },
{ key: 'esp8266', label: 'ESP8266 / NodeMCU' },
{ key: 'none', label: "I don't have hardware yet" }
]
const popularEnvironments = [
'esp32dev-ble',
'theengs-bridge-v11',
'lilygo-rtl_433',
'lilygo-rtl_433-fsk',
'esp32dev-ir'
]
function buildUrl(path: string): string {
const base = import.meta.env.BASE_URL || '/'
const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base
const cleanPath = path.startsWith('/') ? path : `/${path}`
return `${cleanBase}${cleanPath}`
}
const resolvedBoardsUrl = computed(() => buildUrl(props.boardsUrl))
const resolvedSelectorUrl = computed(() => buildUrl(props.selectorPath))
function getMcuFamily(mcu: string | undefined): string | null {
if (!mcu) return null
const m = mcu.toLowerCase()
if (m.includes('esp32-s3') || m.includes('esp32s3') || m.includes('atoms3') || m.includes('lilygo-t3-s3')) return 'ESP32-S3'
if (m.includes('esp32-c3') || m.includes('esp32c3') || m.includes('lolin_c3') || m.includes('airm2m')) return 'ESP32-C3'
if (m.includes('esp32') || m.includes('m5st') || m.includes('heltec') || m.includes('ttgo') || m.includes('lolin32') || m.includes('pico32') || m.includes('tinypico') || m.includes('feather')) return 'ESP32'
if (m.includes('esp8') || m.includes('nodemcu')) return 'ESP8266'
return 'Other'
}
function matchesBridge(board: Board, bridge: string): boolean {
const mods = (board.modules || []).map(m => m.toLowerCase())
switch (bridge) {
case 'ble': return mods.some(m => m.includes('bt'))
case 'rf433': return mods.some(m => m.includes('rf') || m.includes('rtl_433') || m.includes('pilight'))
case 'ir': return mods.some(m => m.includes('ir'))
case 'lora': return mods.some(m => m.includes('lora'))
default: return true
}
}
function matchesHardware(board: Board, hardware: string): boolean {
const haystack = `${board.environment} ${board.microcontroller || ''}`.toLowerCase()
switch (hardware) {
case 'esp32dev': return board.environment.toLowerCase().includes('esp32dev')
case 'esp32c3': return getMcuFamily(board.microcontroller) === 'ESP32-C3'
case 'esp32s3': return getMcuFamily(board.microcontroller) === 'ESP32-S3'
case 'lilygo': return /lilygo|heltec|ttgo/.test(haystack)
case 'm5': return haystack.includes('m5')
case 'esp8266': return getMcuFamily(board.microcontroller) === 'ESP8266'
default: return true // 'none': no hardware constraint
}
}
// Preferred defaults per bridge choice, consulted before the generic
// popular-first order. All entries must be web-flashable environments.
const preferredByBridge: Record<string, string[]> = {
ble: ['esp32dev-ble', 'esp32c3-dev-c2-ble', 'esp32s3-dev-c1-ble', 'esp32-m5atom-lite', 'heltec-ble', 'lilygo-ble'],
rf433: ['lilygo-rtl_433', 'esp32dev-rtl_433', 'heltec-rtl_433', 'nodemcuv2-rf'],
ir: ['esp32dev-ir', 'nodemcuv2-ir', 'esp32-m5atom-lite'],
lora: ['ttgo-lora32-v21', 'heltec-wifi-lora-32', 'ttgo-lora32-v1', 'ttgo-t-beam']
}
const recommendedBoard = ref<Board | null>(null)
const manifestCache = new Map<string, boolean>()
// Not every environment in boards-info.json has a pre-built firmware
// manifest; only recommend ones that can actually be web-flashed.
async function hasManifest(env: string): Promise<boolean> {
const cached = manifestCache.get(env)
if (cached !== undefined) return cached
let ok = false
try {
const response = await fetch(buildUrl(`/firmware_build/${env}.manifest.json`), { method: 'HEAD' })
ok = response.ok
} catch {
ok = false
}
manifestCache.set(env, ok)
return ok
}
let recommendationToken = 0
watch([wizardBridge, wizardHardware, boards], async () => {
const token = ++recommendationToken
const bridge = wizardBridge.value
if (!bridge) {
recommendedBoard.value = null
return
}
const candidates = boards.value.filter(b =>
matchesBridge(b, bridge) &&
(!wizardHardware.value || matchesHardware(b, wizardHardware.value))
)
const preferred = preferredByBridge[bridge] || []
const ordered = [...candidates].sort((a, b) => {
const ai = preferred.indexOf(a.environment)
const bi = preferred.indexOf(b.environment)
return (ai === -1 ? preferred.length : ai) - (bi === -1 ? preferred.length : bi)
})
for (const candidate of ordered.slice(0, 8)) {
if (await hasManifest(candidate.environment)) {
if (token === recommendationToken) recommendedBoard.value = candidate
return
}
}
if (token === recommendationToken) recommendedBoard.value = null
})
const shoppingHint = computed<string>(() => {
switch (wizardBridge.value) {
case 'ble':
case 'ir': return 'Any ESP32 development board will do.'
case 'rf433': return 'A LILYGO LoRa32 or Heltec LoRa V2 board matching your devices\' frequency (433/868/915MHz) needs no soldering.'
case 'lora': return 'Get a LILYGO LoRa32 or Heltec LoRa board matching the frequency used in your region.'
default: return ''
}
})
const buildsUrl = computed(() => buildUrl('/upload/builds.html'))
const hasActiveFilters = computed(() =>
searchQuery.value || wizardBridge.value || wizardHardware.value
)
const filteredBoards = computed<Board[]>(() =>
boards.value.filter(board => {
if (wizardBridge.value && !matchesBridge(board, wizardBridge.value)) return false
if (wizardHardware.value && wizardHardware.value !== 'none' && !matchesHardware(board, wizardHardware.value)) return false
if (searchQuery.value) {
const q = searchQuery.value.toLowerCase()
const haystack = [
board.environment,
board.description || '',
board.microcontroller || '',
(board.modules || []).join(' ')
].join(' ').toLowerCase()
if (!haystack.includes(q)) return false
}
return true
})
)
function clearFilters() {
searchQuery.value = ''
wizardBridge.value = null
wizardHardware.value = null
}
async function loadBoards() {
loading.value = true
error.value = null
try {
const response = await fetch(resolvedBoardsUrl.value)
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
const data = await response.json()
if (!Array.isArray(data)) {
throw new Error('boards-info.json must be an array')
}
boards.value = data
.filter((board: Board) => board && typeof board.environment === 'string')
.sort((a: Board, b: Board) => {
const aPopular = popularEnvironments.includes(a.environment)
const bPopular = popularEnvironments.includes(b.environment)
if (aPopular && !bPopular) return -1
if (!aPopular && bPopular) return 1
return a.environment.localeCompare(b.environment)
})
} catch (err: unknown) {
console.error('Failed to load boards-info:', err)
error.value = err instanceof Error ? err.message : 'Unable to load board information'
} finally {
loading.value = false
}
}
function toggleModules(env: string) {
expandedModules[env] = !expandedModules[env]
}
function toggleLibraries(env: string) {
expandedLibraries[env] = !expandedLibraries[env]
}
function openSelector(environment: string) {
if (!environment) return
const url = `${resolvedSelectorUrl.value}?env=${encodeURIComponent(environment)}`
window.location.href = url
}
function getBoardImageUrl(board: Board): string {
const customImg = board.customImg || board.CustomImg
if (customImg) {
if (customImg.startsWith('http')) {
return customImg
}
return buildUrl(customImg)
}
return buildUrl('/img/microcontroller.gif')
}
onMounted(() => {
// Preset the guided picker from query parameters, e.g. ?bridge=ble&hardware=esp32dev
const params = new URLSearchParams(window.location.search)
const bridgeParam = params.get('bridge')
if (bridgeParam && bridgeOptions.some(b => b.key === bridgeParam)) {
wizardBridge.value = bridgeParam
}
const hardwareParam = params.get('hardware')
if (hardwareParam && hardwareOptions.some(h => h.key === hardwareParam)) {
wizardHardware.value = hardwareParam
}
loadBoards()
})
</script>
<style scoped>
.board-environment-list {
margin: 2rem 0;
}
/* Guided picker */
.wizard {
display: flex;
flex-direction: column;
gap: 10px;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
padding: 16px;
margin-bottom: 1.25rem;
}
.wizard-title {
font-weight: 600;
font-size: 0.95rem;
}
.wizard-row {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.wizard-result {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
border-top: 1px dashed var(--vp-c-divider);
padding-top: 12px;
font-size: 0.9rem;
}
.wizard-result__text {
display: flex;
flex-direction: column;
gap: 2px;
}
.wizard-result__desc {
color: var(--vp-c-text-2);
font-size: 0.85rem;
}
.wizard-result__cta {
background: var(--vp-c-brand-1);
color: var(--vp-c-white, #fff);
border: none;
border-radius: 20px;
padding: 8px 18px;
font-weight: 600;
font-size: 0.9rem;
cursor: pointer;
transition: background 0.2s ease;
}
.wizard-result__cta:hover {
background: var(--vp-c-brand-2);
}
.wizard-result--none {
display: block;
color: var(--vp-c-text-2);
}
.wizard-result--none a {
color: var(--vp-c-brand-1);
}
/* Search and Filter Bar */
.filter-bar {
margin-bottom: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.search-box {
position: relative;
display: flex;
align-items: center;
}
.search-icon {
position: absolute;
left: 12px;
color: var(--vp-c-text-2);
pointer-events: none;
}
.search-input {
width: 100%;
padding: 0.6rem 2.2rem 0.6rem 2.4rem;
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
font-size: 0.9rem;
background: var(--vp-c-bg);
color: var(--vp-c-text-1);
transition: border-color 0.2s;
}
.search-input:focus {
outline: none;
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 0 3px rgba(62, 175, 124, 0.15);
}
.search-input::placeholder {
color: var(--vp-c-text-3);
}
.search-clear {
position: absolute;
right: 8px;
background: none;
border: none;
cursor: pointer;
padding: 4px;
color: var(--vp-c-text-2);
border-radius: 50%;
display: flex;
align-items: center;
}
.search-clear:hover {
background: var(--vp-c-bg-soft);
}
.filter-groups {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.filter-group {
display: flex;
align-items: center;
gap: 0.5rem;
}
.filter-group__label {
font-size: 0.8rem;
font-weight: 600;
color: var(--vp-c-text-2);
white-space: nowrap;
}
.filter-chips {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.filter-chip {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
border: 1px solid var(--vp-c-divider);
padding: 0.25rem 0.7rem;
border-radius: 16px;
font-size: 0.78rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.filter-chip:hover {
border-color: var(--vp-c-brand-1);
color: var(--vp-c-brand-1);
}
.filter-chip--active {
background: var(--vp-c-brand-1);
color: #ffffff;
border-color: var(--vp-c-brand-1);
}
.filter-chip--active:hover {
color: #ffffff;
opacity: 0.9;
}
.filter-status {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.filter-clear {
background: none;
border: none;
color: var(--vp-c-brand-1);
cursor: pointer;
font-size: 0.85rem;
font-weight: 500;
padding: 0;
}
.filter-clear:hover {
text-decoration: underline;
}
.no-results {
text-align: center;
padding: 3rem 1rem;
color: var(--vp-c-text-2);
}
.no-results p {
margin-bottom: 1rem;
}
/* Grid Layout */
.boards-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-top: 1.5rem;
}
/* Card Design */
.board-card {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
flex-direction: column;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.board-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
border-color: var(--vp-c-brand-1);
}
/* Image Section */
.board-card__image {
background: var(--vp-c-bg-soft);
padding: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
min-height: 120px;
border-bottom: 1px solid var(--vp-c-divider);
position: relative;
}
.popular-badge {
position: absolute;
top: 8px;
right: 8px;
background: #ff9800;
color: #ffffff;
font-size: 0.65rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 0.2rem 0.5rem;
border-radius: 4px;
}
.board-card__image img {
max-width: 100px;
max-height: 100px;
object-fit: contain;
}
/* Content Section */
.board-card__content {
padding: 1.25rem;
flex: 1;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
/* Header */
.board-card__header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 0.75rem;
margin-bottom: 0.25rem;
}
.board-card__title {
margin: 0;
font-size: 1rem;
font-weight: 600;
line-height: 1.4;
flex: 1;
}
.board-card__title code {
background: transparent;
color: var(--vp-c-brand-1);
font-size: 0.9em;
padding: 0;
font-weight: 600;
}
.board-card__chip {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-2);
padding: 0.3rem 0.8rem;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
white-space: nowrap;
flex-shrink: 0;
border: 1px solid var(--vp-c-divider);
}
/* Description */
.board-card__description {
margin: 0;
font-size: 0.9rem;
line-height: 1.5;
color: var(--vp-c-text-2);
}
/* Libraries Section */
.board-card__libraries {
margin-top: 0.5rem;
padding-top: 0.25rem;
border-top: 1px solid var(--vp-c-divider);
}
.modules-label-row {
display: flex;
align-items: center;
gap: 0.2em;
margin-bottom: 0.5rem;
}
.libraries-label {
font-size: 0.8rem;
font-weight: 600;
color: var(--vp-c-text-2);
display: inline-block;
}
.libraries-badges {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.lib-badge {
display: inline-block;
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
padding: 0.2rem 0.6rem;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 500;
border: 1px solid var(--vp-c-divider);
}
/* Action Footer */
.board-card__action {
padding-top: 0.75rem;
margin-top: 0.5rem;
border-top: 1px solid var(--vp-c-divider);
}
.action-text {
color: var(--vp-c-brand-1);
font-size: 0.85rem;
font-weight: 600;
display: flex;
align-items: center;
gap: 0.25rem;
}
.board-card:hover .action-text {
text-decoration: underline;
}
/* Loading Spinner */
.loading-spinner {
display: inline-block;
width: 16px;
height: 16px;
min-width: 16px;
border: 2px solid #cfd8dc;
border-top-color: var(--vp-c-brand-1);
border-radius: 50%;
animation: spin 0.8s linear infinite;
vertical-align: middle;
margin-right: 0.5rem;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Responsive */
@media (max-width: 768px) {
.filter-groups {
flex-direction: column;
gap: 0.5rem;
}
.filter-group {
flex-wrap: wrap;
}
.boards-grid {
grid-template-columns: 1fr;
}
.board-card__image {
min-height: 100px;
padding: 1rem;
}
.board-card__image img {
max-width: 80px;
max-height: 80px;
}
}
@media (max-width: 480px) {
.board-card__header {
flex-direction: column;
align-items: flex-start;
}
.board-card__chip {
align-self: flex-start;
}
}
/* Espansione animata per badge */
.expand-fade-enter-active, .expand-fade-leave-active {
transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s;
}
.expand-fade-enter-from, .expand-fade-leave-to {
opacity: 0;
max-height: 0;
}
.expand-fade-enter-to, .expand-fade-leave-from {
opacity: 1;
max-height: 500px;
}
.expand-icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
background: none;
border: none;
color: var(--vp-c-brand-1);
cursor: pointer;
margin-top: 0.3em;
margin-left: 0.2em;
padding: 0.1em 0.2em;
border-radius: 50%;
transition: background 0.2s;
}
.expand-icon-btn:hover {
background: rgba(62, 175, 124, 0.08);
}
.expand-icon-btn svg {
transition: transform 0.25s cubic-bezier(0.4,0,0.2,1);
vertical-align: middle;
}
.expand-icon-btn svg.rotated {
transform: rotate(90deg);
}
</style>
@@ -0,0 +1,730 @@
<template>
<div class="flash-selector">
<!-- Loading State -->
<div v-if="loading" class="custom-block tip">
<p class="custom-block-title">
<span class="loading-spinner"></span>
Loading environments...
</p>
</div>
<!-- Error State -->
<div v-if="error" class="custom-block danger">
<p class="custom-block-title">Error</p>
<p>{{ error }}</p>
</div>
<!-- Board Details (when selected) -->
<Transition name="fade">
<div v-if="currentEnvironment && !loading" class="board-details">
<!-- Hero Section - Clean and Focused -->
<div class="board-hero">
<div class="board-hero__content">
<!-- Inline Board Switcher -->
<h2>
<div class="board-switcher">
<label for="envSelect" class="switcher-label">Environment:</label>
<div class="switcher-select-wrapper">
<select
id="envSelect"
v-model="selectedEnvironment"
class="switcher-select">
<option
v-for="env in environments"
:key="env.environment"
:value="env.environment">
{{ env.environment }}
</option>
</select>
<span class="switcher-icon">⚙️</span>
</div>
</div>
</h2>
<div v-if="currentEnvironment.microcontroller" class="board-hero__meta">
<span class="meta-label">MCU:</span>
<span class="meta-value">{{ currentEnvironment.microcontroller }}</span>
</div>
<p v-if="currentEnvironment.description" class="board-hero__description">
<span class="meta-label">Description:</span> <span v-html="currentEnvironment.description"></span>
</p>
<!-- Primary Action -->
<div class="hero-action">
<esp-web-install-button
v-if="manifestUrl"
:manifest="manifestUrl"
aria-label="Flash firmware to device">
</esp-web-install-button>
<button v-else class="connect-button connect-button--disabled" disabled>
CONNECT
</button>
</div>
</div>
<!-- Image Optional -->
<div v-if="boardImageUrl && !imageError" class="board-hero__image">
<img
:src="boardImageUrl"
:alt="currentEnvironment.environment"
loading="lazy"
@error="handleImageError">
</div>
</div>
<!-- Technical Details - Collapsible -->
<details class="tech-details" open>
<summary class="tech-details__summary">
<span class="tech-details__icon">📋</span>
<span class="tech-details__title">Technical Information</span>
<span class="tech-details__toggle">▼</span>
</summary>
<div class="tech-details__content">
<div class="tech-grid">
<!-- Libraries -->
<div v-if="currentEnvironment.libraries && currentEnvironment.libraries.length" class="tech-section">
<h4 class="tech-section__title">Libraries</h4>
<div class="tech-section__content">
<div class="chip-group">
<span v-for="(lib, index) in currentEnvironment.libraries" :key="index" class="chip">
{{ lib }}
</span>
</div>
</div>
</div>
<!-- Gateway Modules -->
<div v-if="currentEnvironment.modules && currentEnvironment.modules.length" class="tech-section">
<h4 class="tech-section__title">Gateway Modules</h4>
<div class="tech-section__content">
<div class="chip-group">
<span v-for="(mod, index) in currentEnvironment.modules" :key="index" class="chip">
{{ mod }}
</span>
</div>
</div>
</div>
<!-- Hardware -->
<div v-if="currentEnvironment.hardware" class="tech-section">
<h4 class="tech-section__title">Hardware</h4>
<div class="tech-section__content" >
<span class="chip" v-html="currentEnvironment.hardware"></span>
</div>
</div>
<!-- Partitions -->
<div v-if="currentEnvironment.partitions" class="tech-section">
<h4 class="tech-section__title">Partitions</h4>
<div class="tech-section__content">
<code class="code-inline">{{ currentEnvironment.partitions }}</code>
</div>
</div>
<!-- Build Options -->
<div v-if="currentEnvironment.options" class="tech-section tech-section--full">
<h4 class="tech-section__title">Build Options</h4>
<div class="tech-section__content">
<pre class="code-block">{{ formatOptions(currentEnvironment.options) }}</pre>
</div>
</div>
</div>
</div>
</details>
<!-- Post-flash next steps -->
<div class="next-steps">
<h3 class="next-steps__title">✅ After flashing</h3>
<ol class="next-steps__list">
<li>Keep the board powered — it starts a WiFi access point named <code>OpenMQTTGateway</code> or starting with <code>OMG_</code>.</li>
<li>From your phone or computer, connect to that WiFi network and follow the <a :href="portalUrl">configuration portal guide</a> to enter your WiFi and MQTT broker credentials.</li>
<li>The gateway restarts, joins your network and connects to your broker — <a :href="verifyUrl">check that it works</a>.</li>
</ol>
</div>
</div>
</Transition>
<!-- Board Detail not selected message -->
<Transition name="fade">
<div v-if="!currentEnvironment && !loading && !error" class="custom-block info">
<p class="custom-block-title">Need to select one environment...</p>
</div>
</Transition>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
interface Environment {
environment: string
description?: string
microcontroller?: string
modules?: string[]
libraries?: string[]
hardware?: string
partitions?: string
options?: string | string[]
customImg?: string
CustomImg?: string
}
const props = withDefaults(defineProps<{
boardsUrl?: string
firmwareBaseUrl?: string
}>(), {
boardsUrl: '/boards-info.json',
firmwareBaseUrl: '/firmware_build/'
})
const environments = ref<Environment[]>([])
const selectedEnvironment = ref<string>('')
const loading = ref<boolean>(true)
const error = ref<string | null>(null)
const imageError = ref<boolean>(false)
const currentEnvironment = computed<Environment | undefined>(() => {
return environments.value.find(env => env.environment === selectedEnvironment.value)
})
const resolvedBoardsUrl = computed<string>(() => buildUrl(props.boardsUrl))
const resolvedFirmwareBaseUrl = computed<string>(() => buildUrl(props.firmwareBaseUrl))
const manifestUrl = computed<string | null>(() => {
if (!selectedEnvironment.value) return null
return `${resolvedFirmwareBaseUrl.value}${selectedEnvironment.value}.manifest.json`
})
const portalUrl = computed<string>(() => buildUrl('/upload/portal.html'))
const verifyUrl = computed<string>(() => buildUrl('/getting-started.html#step-4-check-that-it-works'))
const boardImageUrl = computed<string | null>(() => {
if (!currentEnvironment.value) return null
const customImg = currentEnvironment.value.customImg || currentEnvironment.value.CustomImg
if (customImg && !imageError.value) {
if (customImg.startsWith('http')) {
return customImg
}
return buildUrl(customImg)
}
return buildUrl('/img/microcontroller.gif')
})
watch(selectedEnvironment, () => {
imageError.value = false
error.value = null
})
onMounted(() => {
const script = document.createElement('script')
script.type = 'module'
script.src = 'https://unpkg.com/esp-web-tools@10/dist/web/install-button.js?module'
document.head.appendChild(script)
loadEnvironments()
})
function buildUrl(path: string): string {
const base = import.meta.env.BASE_URL || '/'
const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base
const cleanPath = path.startsWith('/') ? path : `/${path}`
return `${cleanBase}${cleanPath}`
}
function getQueryParam(param: string): string | null {
const params = new URLSearchParams(window.location.search)
return params.get(param)
}
async function loadEnvironments(): Promise<void> {
loading.value = true
error.value = null
try {
const response = await fetch(resolvedBoardsUrl.value)
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
const data = await response.json()
if (!Array.isArray(data)) {
throw new Error('Invalid data format: expected an array')
}
const validEnvironments = data.filter((env: unknown) =>
env &&
typeof env === 'object' &&
(env as Environment).environment &&
typeof (env as Environment).environment === 'string'
) as Environment[]
if (validEnvironments.length === 0) {
throw new Error('No valid environments found in data')
}
environments.value = validEnvironments
const envParam = getQueryParam('env')
if (envParam) {
const matchingEnv = validEnvironments.find(env => env.environment === envParam)
if (matchingEnv) {
selectedEnvironment.value = envParam
} else {
console.warn(`Environment '${envParam}' not found in available environments`)
}
}
} catch (err) {
console.error('Failed to load environments:', err)
error.value = (err instanceof Error ? err.message : null) || 'Failed to load environments'
} finally {
loading.value = false
}
}
function formatOptions(optionsText: string | string[]): string {
if (!optionsText) return ''
let optionsTextMap: string[] = []
if (typeof optionsText === 'string') {
optionsTextMap = optionsText.split('\n')
} else if (Array.isArray(optionsText)) {
optionsTextMap = optionsText
}
return optionsTextMap.map(line => line.trim())
.filter(line => line.length > 0)
.join('\n')
}
function handleImageError(): void {
imageError.value = true
}
</script>
<style scoped>
/* Post-flash next steps */
.next-steps {
margin-top: 16px;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
padding: 20px 24px;
}
.next-steps__title {
margin: 0 0 8px;
font-size: 16px;
font-weight: 600;
}
.next-steps__list {
margin: 0;
padding-left: 20px;
}
.next-steps__list li {
margin: 6px 0;
line-height: 1.6;
}
.next-steps__list a {
color: var(--vp-c-brand-1);
font-weight: 500;
}
/* Main Container */
.flash-selector {
max-width: 1200px;
margin: 2rem auto;
padding: 0 1rem;
}
/* Board Details Container */
.board-details {
margin-top: 2rem;
}
/* Hero Section - Material Design 3 */
.board-hero {
display: grid;
grid-template-columns: 1fr auto;
gap: 24px;
background: var(--vp-c-bg);
border-radius: 12px;
padding: 32px;
margin-bottom: 16px;
box-shadow: 0 1px 2px 0 var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
}
.board-hero__content {
display: flex;
flex-direction: column;
gap: 16px;
min-width: 0;
}
.board-hero__title {
margin: 0 0 8px 0;
font-size: 1.75rem;
font-weight: 400;
color: var(--vp-c-brand-1);
font-family: 'Monaco', 'Courier New', monospace;
line-height: 1.2;
letter-spacing: -0.01em;
}
/* Board Switcher - Material Chip Style */
.board-switcher {
display: flex;
align-items: center;
gap: 8px;
margin: 0;
min-width: 0;
}
.switcher-label {
font-size: 0.75rem;
text-transform: uppercase;
font-weight: 500;
letter-spacing: 0.1em;
color: var(--vp-c-text-2);
}
.switcher-select-wrapper {
position: relative;
display: inline-flex;
align-items: center;
min-width: 0;
max-width: 100%;
}
.switcher-select {
appearance: none;
max-width: 100%;
text-overflow: ellipsis;
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
border: none;
padding: 6px 32px 6px 12px;
border-radius: 16px;
font-size: 0.875rem;
font-weight: 500;
font-family: 'Monaco', 'Courier New', monospace;
cursor: pointer;
transition: background 0.2s cubic-bezier(0.4, 0, 0.2, 1);
min-height: 32px;
min-width: 280px;
width: auto;
}
.switcher-select:hover {
background: var(--vp-c-bg-soft);
}
.switcher-select:focus {
outline: 2px solid var(--vp-c-brand-1);
outline-offset: 2px;
}
.switcher-icon {
position: absolute;
right: 8px;
pointer-events: none;
font-size: 1rem;
opacity: 0.6;
}
.board-hero__meta {
display: flex;
align-items: baseline;
gap: 8px;
margin: 0;
}
.meta-label {
font-size: 0.75rem;
text-transform: uppercase;
font-weight: 500;
letter-spacing: 0.1em;
color: var(--vp-c-text-2);
}
.meta-value {
font-size: 0.875rem;
font-weight: 500;
color: var(--vp-c-text-1);
font-family: 'Monaco', 'Courier New', monospace;
}
.board-hero__description {
margin: 0;
font-size: 1rem;
line-height: 1.5;
color: var(--vp-c-text-1);
max-width: 600px;
}
.board-hero__image {
display: flex;
align-items: flex-start;
justify-content: center;
min-width: 0;
max-width: 200px;
}
.board-hero__image img {
max-width: 100%;
max-height: 180px;
object-fit: contain;
}
/* Primary Action - Material Filled Button */
.hero-action {
margin-top: 8px;
}
.connect-button {
background: #1976d2;
color: #ffffff;
border: none;
padding: 10px 24px;
border-radius: 20px;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3), 0 1px 3px 1px rgba(0, 0, 0, 0.15);
text-transform: uppercase;
letter-spacing: 0.125em;
height: 40px;
min-width: 120px;
}
.connect-button:hover:not(:disabled) {
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3), 0 2px 6px 2px rgba(0, 0, 0, 0.15);
}
.connect-button:active:not(:disabled) {
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3), 0 1px 3px 1px rgba(0, 0, 0, 0.15);
}
.connect-button--disabled {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-3);
cursor: not-allowed;
box-shadow: none;
}
/* Technical Details - Material Surface */
.tech-details {
background: var(--vp-c-bg);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 1px 2px 0 var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
}
.tech-details__summary {
display: flex;
align-items: center;
gap: 12px;
padding: 16px 24px;
cursor: pointer;
user-select: none;
background: var(--vp-c-bg-alt);
transition: background 0.2s cubic-bezier(0.4, 0, 0.2, 1);
list-style: none;
}
.tech-details__summary::-webkit-details-marker {
display: none;
}
.tech-details__summary:hover {
background: var(--vp-c-bg-soft);
}
.tech-details__icon {
font-size: 1.25rem;
opacity: 0.6;
}
.tech-details__title {
font-size: 1rem;
font-weight: 500;
color: var(--vp-c-text-1);
flex: 1;
letter-spacing: 0.01em;
}
.tech-details__toggle {
font-size: 0.875rem;
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
opacity: 0.6;
}
.tech-details[open] .tech-details__toggle {
transform: rotate(180deg);
}
.tech-details__content {
padding: 24px;
}
/* Tech Grid */
.tech-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
}
.tech-section {
display: flex;
flex-direction: column;
gap: 12px;
}
.tech-section--full {
grid-column: 1 / -1;
}
.tech-section__title {
margin: 0;
font-size: 0.75rem;
text-transform: uppercase;
font-weight: 500;
letter-spacing: 0.1em;
color: var(--vp-c-text-2);
}
.tech-section__content {
font-size: 0.875rem;
line-height: 1.5;
color: var(--vp-c-text-1);
}
/* Chips - Material Design */
.chip-group {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.chip {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
padding: 6px 12px;
border-radius: 8px;
font-size: 0.875rem;
font-weight: 400;
border: none;
height: 32px;
display: inline-flex;
align-items: center;
}
/* Code Styles - Material Surface */
.code-inline {
background: var(--vp-c-bg-soft);
padding: 2px 6px;
border-radius: 4px;
font-size: 0.875rem;
font-family: 'Monaco', 'Courier New', monospace;
color: var(--vp-c-text-1);
}
.code-block {
background: var(--vp-c-bg-soft);
padding: 16px;
border-radius: 8px;
font-size: 0.8125rem;
line-height: 1.5;
overflow-x: auto;
margin: 0;
border: 1px solid var(--vp-c-divider);
white-space: pre-wrap;
word-break: break-word;
font-family: 'Monaco', 'Courier New', monospace;
color: var(--vp-c-text-1);
}
/* Loading Spinner */
.loading-spinner {
display: inline-block;
width: 18px;
height: 18px;
border: 2px solid rgba(62, 175, 124, 0.3);
border-top-color: var(--vp-c-brand-1);
border-radius: 50%;
animation: spin 0.8s linear infinite;
vertical-align: middle;
margin-right: 0.5rem;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Fade Transition */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
/* Accessibility */
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
/* Responsive Design */
@media (max-width: 968px) {
.board-hero {
grid-template-columns: 1fr;
}
.board-hero__image {
order: -1;
max-width: 150px;
margin: 0 auto;
}
.tech-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.selector-card {
padding: 1.5rem;
}
.board-hero {
padding: 1.5rem;
}
.board-hero__title {
font-size: 1.5rem;
}
.connect-button {
width: 100%;
padding: 0.9rem 2rem;
}
}
</style>
+124
View File
@@ -0,0 +1,124 @@
<template>
<div class="omg-pipeline-wrap">
<div class="omg-pipeline">
<div class="omg-node">
<span class="omg-node-icon">🌡️</span>
<strong>Your devices</strong>
<span class="omg-node-sub">BLE · RF · IR · LoRa</span>
</div>
<span class="omg-arrow">⇄</span>
<div class="omg-node omg-node-brand">
<span class="omg-node-icon">📟</span>
<strong>OpenMQTTGateway</strong>
<span class="omg-node-sub">ESP32 / ESP8266</span>
</div>
<span class="omg-arrow">⇄</span>
<div class="omg-node">
<span class="omg-node-icon">🔀</span>
<strong>MQTT broker</strong>
<span class="omg-node-sub">Mosquitto...</span>
</div>
<span class="omg-arrow">⇄</span>
<div class="omg-node">
<span class="omg-node-icon">🏠</span>
<strong>Your controller</strong>
<span class="omg-node-sub">Home Assistant, OpenHAB...</span>
</div>
</div>
</div>
</template>
<style scoped>
.omg-pipeline-wrap {
container-type: inline-size;
margin: 24px 0;
}
.omg-pipeline {
display: flex;
align-items: stretch;
gap: 8px;
}
.omg-node {
flex: 1 1 0;
min-width: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
gap: 4px;
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
padding: 20px 10px;
}
.omg-node-brand {
border-color: var(--vp-c-brand-1);
box-shadow: 0 0 0 1px var(--vp-c-brand-1);
}
.omg-node-icon {
font-size: 28px;
}
.omg-node strong {
font-size: 15px;
line-height: 1.3;
}
.omg-node-sub {
color: var(--vp-c-text-2);
font-size: 13px;
}
.omg-arrow {
align-self: center;
flex-shrink: 0;
color: var(--vp-c-brand-1);
font-size: 20px;
font-weight: 700;
}
/* Narrow containers (doc column, tablets): tighten the nodes, keep one row */
@container (max-width: 760px) {
.omg-pipeline {
gap: 6px;
}
.omg-node {
padding: 12px 6px;
}
.omg-node strong {
font-size: 13px;
}
.omg-node-sub {
font-size: 11px;
}
.omg-node-icon {
font-size: 22px;
}
.omg-arrow {
font-size: 16px;
}
}
/* Narrow (phones, small tablets): stack vertically. Below ~680px the four nodes
no longer leave room for the longest label ("OpenMQTTGateway"), which spilled
out of its box and over the arrows. */
@container (max-width: 680px) {
.omg-pipeline {
flex-direction: column;
}
.omg-arrow {
transform: rotate(90deg);
}
.omg-node strong {
font-size: 15px;
}
.omg-node-sub {
font-size: 13px;
}
}
</style>
+147
View File
@@ -0,0 +1,147 @@
// docs/.vitepress/config.mts
import { defineConfig } from 'vitepress'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
import { commonNav, commonHead } from './commonConfig.mts'
const __dirname = dirname(fileURLToPath(import.meta.url))
// Load metadata with override support
import defaults from './defaults.json'
let meta = { ...defaults }
try {
const overrides = await import('./meta.json')
meta = { ...meta, ...overrides.default }
} catch {
console.warn('meta.json not found or not valid. Using default configuration.')
}
export default defineConfig({
title: `${meta.title} - ${meta.version}`,
description: 'One gateway, many technologies: MQTT gateway for ESP8266 or ESP32 with bidirectional 433mhz/315mhz/868mhz/915mhz RF, Infrared communications, BLE, LoRa, beacons detection, mi flora / mi jia / LYWSD02/ Mi Scale compatibility, SMS & LORA.',
base: meta.url_prefix as '/' | `/${string}/`,
outDir: resolve(__dirname, '../../', meta.dest),
// Internal working documents, not part of the published site
srcExclude: ['superpowers/**'],
head: commonHead,
ignoreDeadLinks: [
/localhost/,
/LoraTemperature/
],
lastUpdated: true,
markdown: {
lineNumbers: true
},
themeConfig: {
siteTitle: 'OpenMQTTGateway',
// @ts-expect-error custom fields consumed by index.md to render the dev-version banner
mode: meta.mode,
// @ts-expect-error
version: meta.version,
// @ts-expect-error
repo: meta.theme_config_repo,
nav: commonNav,
socialLinks: [
{ icon: 'github', link: `https://github.com/${meta.theme_config_repo}` }
],
editLink: {
pattern: `https://github.com/${meta.theme_config_repo}/edit/development/docs/:path`
},
sidebar: [
{ text: 'What is it for', link: '/' },
{ text: 'Getting Started', link: '/getting-started' },
{
text: '1 - Prerequisites',
collapsed: true,
items: [
{ text: 'Devices', link: '/prerequisites/devices' },
{ text: 'Board', link: '/prerequisites/board' },
{ text: 'Parts', link: '/prerequisites/parts' },
{ text: 'Broker', link: '/prerequisites/broker' },
{ text: 'Controller', link: '/prerequisites/controller' }
]
},
{
text: '2 - Upload',
collapsed: true,
link: '/upload/',
items: [
{ text: '1. Web installer (easiest)', link: '/upload/web-install' },
{ text: '2. Ready-to-go binaries', link: '/upload/binaries' },
{ text: '3. Build from source', link: '/upload/builds' },
{ text: 'Configuration portal', link: '/upload/portal' },
{ text: 'Portal HTTP API', link: '/upload/portal-api' },
{ text: 'Advanced Configuration', link: '/upload/advanced-configuration' },
{ text: 'Troubleshoot', link: '/upload/troubleshoot' }
]
},
{
text: '3 - Hardware setup',
collapsed: true,
items: [
{ text: 'RF', link: '/setitup/rf' },
{ text: 'BLE', link: '/setitup/ble' },
{ text: 'IR', link: '/setitup/ir' },
{ text: 'LoRa', link: '/setitup/lora' },
{ text: 'GSM', link: '/setitup/gsm' },
{ text: 'Serial', link: '/setitup/serial' },
{ text: 'Sensors', link: '/setitup/sensors' },
{ text: 'Actuators', link: '/setitup/actuators' }
]
},
{
text: '4 - Use',
collapsed: true,
items: [
{ text: 'RF', link: '/use/rf' },
{ text: 'BLE', link: '/use/ble' },
{ text: 'IR', link: '/use/ir' },
{ text: 'LoRa', link: '/use/lora' },
{ text: 'GSM', link: '/use/gsm' },
{ text: 'Serial', link: '/use/serial' },
{ text: 'RFM69', link: '/use/rfm69' },
{ text: 'Sensors', link: '/use/sensors' },
{ text: 'Actuators', link: '/use/actuators' },
{ text: 'Boards', link: '/use/boards' },
{ text: 'Displays', link: '/use/displays' },
{ text: 'Gateway', link: '/use/gateway' },
{ text: 'WebUI', link: '/use/webui' }
]
},
{
text: '5 - Integrate',
collapsed: true,
items: [
{ text: 'OpenHAB 2', link: '/integrate/openhab2' },
{ text: 'OpenHAB 3', link: '/integrate/openhab3' },
{ text: 'Home Assistant', link: '/integrate/home_assistant' },
{ text: 'Node-RED', link: '/integrate/node_red' },
{ text: 'AWS IoT', link: '/integrate/aws_iot' },
{ text: 'Jeedom', link: '/integrate/jeedom' }
]
},
{
text: '6 - Participate',
collapsed: true,
link: '/participate/',
items: [
{ text: 'Contributor Quick Start', link: '/participate/quick_start' },
{ text: 'Support', link: '/participate/support' },
{ text: 'Development', link: '/participate/development' },
{ text: 'Adding Protocols', link: '/participate/adding-protocols' },
{ text: 'Community', link: '/participate/community' },
{ text: 'License', link: meta.url_license_file }
]
}
],
search: {
provider: 'local'
}
},
sitemap: {
hostname: meta.hostname
},
vite: {
publicDir: '.vitepress/public'
}
})
+12
View File
@@ -0,0 +1,12 @@
{
"title": "Theengs OpenMQTTGateway",
"version": "edge",
"url_prefix": "/",
"dest": "generated/site",
"mode": "prod",
"url_license_file": "https://github.com/1technophile/OpenMQTTGateway/blob/development/LICENSE.txt",
"url_community_forum": "https://community.openmqttgateway.com",
"hostname": "https://docs.openmqttgateway.com",
"repo": "1technophile/OpenMQTTGateway",
"theme_config_repo": "1technophile/OpenMQTTGateway"
}
File renamed without changes.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 603 B

After

Width:  |  Height:  |  Size: 603 B

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

File renamed without changes.
+123
View File
@@ -0,0 +1,123 @@
/* docs/.vitepress/theme/custom.css */
/* Prevent long site title from overlapping sidebar/nav */
.VPNavBarTitle .title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* The shared Theengs nav has seven top-level entries, and the default theme
switches from the hamburger to the full nav bar at 768px -- far too early for
this menu. Between 768px and ~1180px the entries overflowed: Shop, Sponsor,
the appearance switch and the GitHub link ended up clipped or off-screen, and
the page picked up a horizontal scrollbar. Keep the compact nav (hamburger +
full-screen menu, which already lists every entry plus the appearance switch
and social links) until the full menu genuinely fits. */
@media (min-width: 768px) and (max-width: 1199px) {
.VPNav .VPNavBar .VPNavBarMenu.menu,
.VPNav .VPNavBar .VPNavBarExtra.extra {
display: none;
}
.VPNav .VPNavBar .VPNavBarHamburger.hamburger {
display: flex;
}
header.VPNav .VPNavScreen {
display: block;
}
}
/* Widen the entire content column on pages without aside (board/flash pages) */
.VPDoc:not(.has-aside) .content-container,
.VPDoc:not(.has-aside) .container {
max-width: 100% !important;
}
.VPDoc:not(.has-aside) .vp-doc {
max-width: 100% !important;
}
/* Enlarge the home hero image beyond the theme's ~320px default cap */
.VPHome .VPHero .image-container {
transform: none;
width: 100%;
height: auto;
margin: 0 auto;
}
.VPHome .VPHero .image-bg {
display: none;
}
.VPHome .VPHero .image-src {
position: static;
transform: none;
width: 100%;
max-width: 420px;
max-height: none;
}
/* Below the desktop breakpoint the default theme stacks the image on top of the
hero text and pulls it with negative margins (-76px -24px -48px), which only
works because the image is normally absolutely positioned inside a fixed
320px box. Since we let it flow, those margins made it bleed off-screen and
collide with the hero title -- reset them. */
@media (max-width: 959px) {
.VPHome .VPHero .image {
margin: 0 0 16px;
}
}
/* On phones the stacked image is a wall of unreadable logos that pushes the
title, tagline and call-to-action buttons below the fold. Drop it and let the
hero lead with the text. */
@media (max-width: 639px) {
.VPHome .VPHero .image {
display: none;
}
}
@media (min-width: 960px) {
.VPHome .VPHero .image-src {
max-width: 520px;
}
}
/* Indented (non-fenced) markdown code blocks render as a bare <pre>; the default
theme only makes code scroll inside its language-* wrapper, so long lines such
as the esptool.py commands pushed the whole page sideways on phones. */
.vp-doc pre {
overflow-x: auto;
}
/* Embeds are written as raw HTML in markdown with fixed width/height attributes
(e.g. <iframe width="560" height="315"> for YouTube), which pushes the whole
page sideways on phones. */
.vp-doc iframe {
max-width: 100%;
}
.vp-doc iframe[src*="youtube.com/embed"],
.vp-doc iframe[src*="youtube-nocookie.com/embed"],
.vp-doc iframe[src*="player.vimeo.com"] {
display: block;
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
}
/* Gray backdrop when ESP Web Tools install dialog is open */
ewt-install-dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
+36
View File
@@ -0,0 +1,36 @@
// docs/.vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import mediumZoom from 'medium-zoom'
import { onMounted, watch, nextTick } from 'vue'
import { useRoute } from 'vitepress'
import './custom.css'
import BoardEnvironmentTable from '../components/BoardEnvironmentTable.vue'
import FlashEnvironmentSelector from '../components/FlashEnvironmentSelector.vue'
import OmgPipeline from '../components/OmgPipeline.vue'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('BoardEnvironmentTable', BoardEnvironmentTable)
app.component('FlashEnvironmentSelector', FlashEnvironmentSelector)
app.component('OmgPipeline', OmgPipeline)
},
setup() {
const route = useRoute()
const initZoom = () => {
mediumZoom('.vp-doc img:not(.no-zoom)', {
background: 'var(--vp-c-bg)'
})
}
onMounted(() => {
initZoom()
})
watch(
() => route.path,
() => nextTick(() => initZoom())
)
}
}
-117
View File
@@ -1,117 +0,0 @@
const commonConfig = require('./public/commonConfig');
module.exports = {
...commonConfig,
title: 'Theengs OpenMQTTGateway version_tag',
base: '/',
description: 'One gateway, many technologies: MQTT gateway for ESP8266, ESP32, Sonoff RF Bridge or Arduino with bidirectional 433mhz/315mhz/868mhz, Infrared communications, BLE, beacons detection, mi flora / mi jia / LYWSD02/ Mi Scale compatibility, SMS & LORA.',
head: [
...commonConfig.head,
['script', {type: 'module', src: 'https://unpkg.com/esp-web-tools@9.4.3/dist/web/install-button.js?module'}]
],
themeConfig: {
repo: '1technophile/OpenMQTTGateway',
docsDir: 'docs',
...commonConfig.themeConfig,
sidebar: [
['/','0 - What is it for 🏠'],
{
title: '1 - Prerequisites🧭', // required
//collapsable: true, // optional, defaults to true
sidebarDepth: 1, // optional, defaults to 1
children: [
'prerequisites/devices',
'prerequisites/board',
'prerequisites/parts',
'prerequisites/broker',
'prerequisites/controller']
},
{
title: '2 - Set it up 🔨', // required
sidebarDepth: 1, // optional, defaults to 1
children: [
'setitup/rf',
'setitup/ble',
'setitup/ir',
'setitup/lora',
'setitup/gsm',
'setitup/rs232',
'setitup/sensors',
'setitup/actuators'
]
},
{
title: '3 - Upload ➡️', // required
sidebarDepth: 1, // optional, defaults to 1
children: [
'upload/web-install',
'upload/binaries',
'upload/builds',
'upload/gitpod',
'upload/portal',
'upload/advanced-configuration',
'upload/troubleshoot'
]
},
{
title: '4 - Use ✈️', // required
sidebarDepth: 1, // optional, defaults to 1
children: [
'use/rf',
'use/ble',
'use/ir',
'use/lora',
'use/gsm',
'use/rs232',
'use/rfm69',
'use/sensors',
'use/actuators',
'use/boards',
'use/displays',
'use/gateway',
'use/webui'
]
},
{
title: '5 - Integrate 🎉', // required
sidebarDepth: 1, // optional, defaults to 1
children: [
'integrate/openhab2',
'integrate/openhab3',
'integrate/home_assistant',
'integrate/node_red',
'integrate/aws_iot',
'integrate/jeedom'
]
},
{
title: '6 - Participate 💻', // required
sidebarDepth: 1, // optional, defaults to 1
children: [
'participate/support',
'participate/development',
'participate/adding-protocols',
'participate/community',
['https://github.com/1technophile/OpenMQTTGateway/blob/development/LICENSE.txt','License']
]
}
]
},
plugins: {
'sitemap': {
hostname: 'https://docs.openmqttgateway.com',
urls: [
'https://decoder.theengs.io/devices/devices.html',
'https://community.openmqttgateway.com/',
'https://shop.theengs.io/',
'https://shop.theengs.io/products/theengs-plug-smart-plug-ble-gateway-and-energy-consumption',
'https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna',
'https://app.theengs.io/',
'https://gateway.theengs.io/',
'https://decoder.theengs.io/',
'https://parser.theengs.io/',
'https://www.theengs.io/'
],
},
}
}
-13
View File
@@ -1,13 +0,0 @@
div.table-generated-page
main
div.content__default,
footer.page-edit,
div.page-nav
// Display full with the API pages
max-width: 65%
.sidebar
z-index 6
.navbar
z-index 6
-113
View File
@@ -1,113 +0,0 @@
OpenMQTTGateway aims to unify various technologies and protocols into a single firmware. This reduces the need for multiple physical bridges and streamlines diverse technologies under the widely-used [MQTT](http://mqtt.org/) protocol.
![Overview of the protocols and compatible controllers](./img/OpenMQTTGateway.png)
# What is an MQTT gateway or bridge ?
MQTT, short for Message Queuing Telemetry Transport, is a lightweight messaging protocol ideal for IoT devices.
An MQTT gateway or bridge plays a pivotal role in the MQTT ecosystem:
* Protocol Translation: It converts non-MQTT protocols (like LoRa or Bluetooth) into MQTT, enabling broader network communication.
* Data Aggregation: Combines data from multiple devices into single messages, optimizing network use.
* Security: Incorporates features like SSL/TLS encryption to safeguard data during transmission.
* Device Management: Handles tasks like firmware updates and remote configuration changes.
In essence, an MQTT gateway ensures smooth communication between devices and MQTT brokers, enhancing the efficiency and security of IoT systems.
# What OpenMQTTGateway can do ?
OpenMQTTGateway integrates with established technologies, such as 433mhz/315mhz protocols and infrared (IR), allowing you to upgrade and repurpose older devices. Additionally, OMG is compatible with modern technologies like Bluetooth Low Energy (BLE) and LoRa.
To have an overview of the supported PIR, door, water, temperature, smoke sensors, sirens, rings, beacons, switches & weather stations you can take a look to the
[compatible devices list](https://compatible.openmqttgateway.com/index.php/devices)
You can run OpenMQTTGateway on a wide variety of [boards](https://compatible.openmqttgateway.com/index.php/boards/), ESP32, ESP8266, Arduino MEGA, UNO (with limitation).
BLE to MQTT gateway can also run on Raspberry Pi, Windows or Unix computers thanks to [Theengs Gateway](https://theengs.github.io/gateway/).
Using MQTT, you can seamlessly integrate with home automation platforms such as OpenHAB, Home Assistant, and others, or with IoT software like Node-Red.
# Use cases
Leveraging OpenMQTTGateway with a controller allows you to:
* Monitor a garden with a Mi Flora BLE sensor and control an irrigation valve depending on the soil moisture,
* Trigger a fan depending on the temperature and humidity thanks to a Mi Jia/LYWSD03MMC BLE sensor,
* Follow your meat temperature when cooking with an Inkbird IBBQ
* Alert yourself by a controller notification if the temperature of a fridge or freezer is too high,
* Detect a beacon/smartwatch so as to trigger a special scenario when you come home,
* [Lose weight with the help of a complete log system](https://www.youtube.com/watch?v=noUROhtf0E0&t=18s), video from [@Andreas Spiess](https://www.youtube.com/channel/UCu7_D0o48KbfhpEohoP7YSQ)
* Detect opened door or windows through 433mhz or BLE and alert yourself when leaving
* Detect water leakage or smoke remotely
* Actionate a siren if something is going wrong
* Detect if your far mailbox has been opened by the postman with LoRa
* Make smart your old TV or AC system through infrared control
* Monitor vehicle tire pressure
The limit is your imagination 😀
# Functions
Under the hood, OpenMQTTGateway offers features such as:
* Deduplication
* Simple and lite API
* Strong integrations with libraries used
* Signal forward/repeat
* Wifi web portal onboarding
* Web portal configuration
* Whitelist & Blacklist management
* Secure connections
* Over the air updates
* Local or cloud, your choice
## Using OpenMQTTGateway ?
Support open-source development through sponsorship and gain exclusive access to our private forum. Your questions, issues, and feature requests will receive priority attention, plus you'll gain insider access to our roadmap.
<div style="text-align: center;">
<iframe src="https://github.com/sponsors/theengs/button" title="Sponsor Theengs" height="32" width="228" style="border: 0; border-radius: 6px;"></iframe>
</div>
## Products powered by OpenMQTTGateway
### Theengs Bridge, BLE gateway with external antenna
[Theengs bridge](https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna) is a powerfull BLE to MQTT gateway for over [90 sensors](https://decoder.theengs.io/devices/devices.html). Equipped with an Ethernet port, and external antenna, ensuring an enhanced range for your BLE sensors. It supports also WiFi connectivity.
[![Theengs bridge view](./img/Theengs-Bridge-ble-gateway.png)](https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna)
### Theengs Plug, BLE gateway and Smart Plug
[Theengs plug](https://shop.theengs.io/products/theengs-plug-smart-plug-ble-gateway-and-energy-consumption) brings the following features:
* BLE to MQTT gateway, tens of [Bluetooth devices](https://compatible.openmqttgateway.com/index.php/devices/ble-devices/) supported thanks to Theengs Decoder library. The plug uses an ESP32 acting as a BLE to Wifi gateway to scan, decode and forward the data of the nearby sensors,
* Smart plug that can be controlled remotely,
* Energy consumption monitoring,
* Device tracker,
* Presence detection (beta),
* Local connectivity first.
[![Theengs plug view](./img/Theengs-Plug-OpenMQTTGateway.png)](https://shop.theengs.io/products/theengs-plug-smart-plug-ble-gateway-and-energy-consumption)
Support the project by purchasing the [Theengs bridge](https://shop.theengs.io/products/theengs-bridge-esp32-ble-mqtt-gateway-with-ethernet-and-external-antenna) or the [Theengs plug](https://shop.theengs.io/products/theengs-plug-smart-plug-ble-gateway-and-energy-consumption)
## Media
* [Hackaday - ARDUINO LIBRARY BRINGS RTL_433 TO THE ESP32](https://hackaday.com/2023/01/13/arduino-library-brings-rtl_433-to-the-esp32)
* [CNX Software - 433 MHz is not dead! Using an ESP32 board with LoRa module to talk to 433 MHz sensors](https://www.cnx-software.com/2023/01/14/esp32-board-with-lora-433-mhz-sensors/)
* [RTL_433 PORTED TO ESP32 MICROCONTROLLERS WITH CC1101 OR SX127X TRANSCEIVER CHIPS](https://www.rtl-sdr.com/rtl_433-ported-to-esp32-microcontrollers-with-cc1101-or-sx127x-transceiver-chips/)
* [Using low-cost wireless sensors in the unlicensed bands](https://lwn.net/Articles/921497/)
* [SMART PLUG ESP32 OPENMQTTGATEWAY SERVING AS AN BLE MQTT GATEWAY AND A POWER METER](https://www.electronics-lab.com/smart-plug-esp32-openmqttgateway-serving-as-an-ble-mqtt-gateway-and-a-power-meter/)
### Theengs Plug
[![Theengs Plug video ElektroMaker](https://img.youtube.com/vi/nUwMt9p2U7o/0.jpg)](https://www.youtube.com/watch?v=nUwMt9p2U7o&t=427s)
### 433Mhz and BLE
[![433Mhz and BLE gateway video by Andreas Spiess](https://img.youtube.com/vi/_gdXR1uklaY/0.jpg)](https://www.youtube.com/watch?v=_gdXR1uklaY)
### BLE
[![BLE gateway video by Andreas Spiess](https://img.youtube.com/vi/noUROhtf0E0/0.jpg)](https://www.youtube.com/watch?v=noUROhtf0E0)
### 433Mhz
[![RTL_433 video by TECH MIND](https://img.youtube.com/vi/H-JXWbWjJYE/0.jpg)](https://www.youtube.com/watch?v=H-JXWbWjJYE)
### LORA
[![LORA video by Priceless Toolkit](https://img.youtube.com/vi/6DftaHxDawM/0.jpg)](https://www.youtube.com/watch?v=6DftaHxDawM)
::: warning Note
The material and information contained in this documentation is for general information purposes only. You should not rely upon the material or information on this documentation as a basis for making any business, legal or any other decisions. There is no warranty given on this documentation content. If you decide to follow the information and materials given it is at your own risk. I will not be liable for any false, inaccurate, inappropriate or incomplete information presented on this website.
:::
+73
View File
@@ -0,0 +1,73 @@
# Getting Started
This guide walks you through the two most popular setups from start to finish, flashed **from your browser** and integrated with **Home Assistant**. No soldering, no development environment, about 15 minutes:
* **Bluetooth sensors** — any ESP32 board reading thermometers, plant sensors, scales...
* **RF devices (433/315/868/915MHz)** — a LILYGO LoRa32 board receiving weather stations, door sensors, PIR sensors...
Using another controller (OpenHAB, Node-RED...) or another technology (IR, LoRa)? Follow the same steps and take the detours linked along the way.
## How the pieces fit together
OpenMQTTGateway (OMG) is a firmware for your board that translates signals from your devices (Bluetooth sensors, RF remotes, weather stations...) into MQTT messages, and the other way around:
<OmgPipeline />
The **broker** is the message hub; the **controller** is the home automation software where you see and use the data.
## What you need
* **A board** — for **Bluetooth**, any ESP32 development board. For **RF**, a LILYGO® LoRa32 V2.1 or a Heltec LoRa V2 matching your devices' frequency — 433MHz for most European devices, 915MHz in North America (no soldering needed). See the [board guide](prerequisites/board.md) for other cases, or get a pre-flashed [Theengs Bridge](https://shop.theengs.io/) and skip the flashing step.
* **A data USB cable** — some cables are charge-only and won't work.
* **An MQTT broker** — see Step 1.
* **A device to observe** — e.g. a [compatible Bluetooth sensor](https://decoder.theengs.io/devices/devices.html) such as a Mi Flora, LYWSD03MMC, Govee or Inkbird thermometer, or any RF sensor around you (weather station, door or PIR sensor...).
## Step 1 — Set up the MQTT broker
If you use **Home Assistant**, the simplest option is the Mosquitto add-on:
1. In Home Assistant go to **Settings → Add-ons → Add-on store**, install **Mosquitto broker** and start it.
2. Install the **MQTT integration** (**Settings → Devices & services → Add integration → MQTT**) if it isn't set up already.
3. Create a dedicated user for the gateway in **Settings → People → Users** (e.g. `omg` — it doesn't need to be an administrator). The gateway will log in with it.
No Home Assistant? Install [Mosquitto](https://mosquitto.org/) on any always-on machine, or see the [broker page](prerequisites/broker.md) for alternatives.
## Step 2 — Flash the firmware from your browser
1. Open the [web installer](upload/web-install.md) in **Chrome, Edge or Opera** (Firefox and Safari don't support web flashing).
2. Connect the board to your computer with the USB cable.
3. Pick the firmware matching your board and use case — the two most flashed:
* **Bluetooth** on a generic ESP32: <a href="./upload/board-selector.html?env=esp32dev-ble"><strong>esp32dev-ble</strong></a>
* **RF** on a LILYGO LoRa32: <a href="./upload/board-selector.html?env=lilygo-rtl_433"><strong>lilygo-rtl_433</strong></a> (the radio frequency is configurable afterwards)
4. Click **Connect**, select the board's USB port, and let the installer finish.
Prefer a desktop tool, or need a custom configuration? See the other [upload options](upload/index.md).
## Step 3 — Connect the gateway to your WiFi and broker
After flashing, the gateway starts its own WiFi access point:
1. From your phone or computer, connect to the WiFi network named **OpenMQTTGateway** or starting with **OMG_** (no password, except for Theengs devices — see the [portal page](upload/portal.md)).
2. A configuration page opens (on Android, accept "stay connected without internet"). Click **Configure WiFi**.
3. Select your WiFi network and enter its password.
4. Enter your broker's address as MQTT server (for the Home Assistant add-on, `homeassistant.local` or the server IP), keep port `1883`, and fill in the MQTT username and password from Step 1.
5. Click **Save**. The gateway restarts and joins your network.
The full list of portal fields is described on the [configuration portal page](upload/portal.md).
## Step 4 — Check that it works
* In Home Assistant, go to **Settings → Devices & services → MQTT**: after a minute you should see a device named **OpenMQTTGateway**, created automatically through MQTT discovery.
* **Bluetooth**: bring a compatible sensor nearby — it appears as its own device with its measurements as entities. Some devices only advertise on an event: press a button or trigger a reading if nothing shows up.
* **RF**: supported devices appear automatically as soon as they transmit — weather stations send every minute or two, door and PIR sensors on an event, so trigger one to see it arrive.
* You can also watch the raw messages with [MQTT Explorer](https://mqtt-explorer.com/): connect to your broker and look for `home/OpenMQTTGateway/LWT` = `online` and messages under `home/OpenMQTTGateway/`.
Something not right? Head to the [troubleshooting page](upload/troubleshoot.md) or ask on the [community forum](https://community.openmqttgateway.com).
## Where to go next
* **More RF options** — other <a href="./upload/web-install.html?bridge=rf433">compatible boards and firmwares</a>, transmitting, frequency tuning, and protocol details in [RF hardware setup](setitup/rf.md) and [RF usage](use/rf.md).
* **Infrared** — wire an IR emitter/receiver following the [IR hardware setup](setitup/ir.md).
* **Tune the gateway** — the [WebUI](use/webui.md) and [gateway commands](use/gateway.md) let you configure it at runtime over MQTT.
* **Other controllers** — [OpenHAB](integrate/openhab3.md), [Node-RED](integrate/node_red.md), [Jeedom](integrate/jeedom.md), [AWS IoT](integrate/aws_iot.md).
* **Full Home Assistant details** — [Home Assistant integration](integrate/home_assistant.md).
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Loaded 100 of 431 files, more files were not shown because too many files have changed in this diff. Show more