From 32664499f3af5437b5ba470c742573d5c4111df5 Mon Sep 17 00:00:00 2001 From: Florian Date: Sat, 10 Jan 2026 11:59:41 -0600 Subject: [PATCH] [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> --- main/gatewayLORA.cpp | 45 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/main/gatewayLORA.cpp b/main/gatewayLORA.cpp index b37763e..d389fa0 100644 --- a/main/gatewayLORA.cpp +++ b/main/gatewayLORA.cpp @@ -44,6 +44,7 @@ LORAConfig_s LORAConfig; void LORAConfig_fromJson(JsonObject& LORAdata); +void LORAConfig_apply(); String stateLORAMeasures(); # ifdef ZmqttDiscovery @@ -320,23 +321,7 @@ byte hexStringToByte(const String& hexString) { return (byte)strtol(hexString.c_str(), NULL, 16); } -void LORAConfig_fromJson(JsonObject& LORAdata) { - Config_update(LORAdata, "frequency", LORAConfig.frequency); - Config_update(LORAdata, "txpower", LORAConfig.txPower); - Config_update(LORAdata, "spreadingfactor", LORAConfig.spreadingFactor); - Config_update(LORAdata, "signalbandwidth", LORAConfig.signalBandwidth); - Config_update(LORAdata, "codingrate", LORAConfig.codingRateDenominator); - Config_update(LORAdata, "preamblelength", LORAConfig.preambleLength); - Config_update(LORAdata, "onlyknown", LORAConfig.onlyKnown); - // Handle syncword separately - if (LORAdata.containsKey("syncword")) { - String syncWordStr = LORAdata["syncword"].as(); - LORAConfig.syncWord = hexStringToByte(syncWordStr); - THEENGS_LOG_NOTICE(F("Config syncword changed: %d" CR), LORAConfig.syncWord); - } - Config_update(LORAdata, "enablecrc", LORAConfig.crc); - Config_update(LORAdata, "invertiq", LORAConfig.invertIQ); - +void LORAConfig_apply() { LoRa.setFrequency(LORAConfig.frequency); LoRa.setTxPower(LORAConfig.txPower); LoRa.setSpreadingFactor(LORAConfig.spreadingFactor); @@ -346,6 +331,29 @@ void LORAConfig_fromJson(JsonObject& LORAdata) { LoRa.setSyncWord(LORAConfig.syncWord); LORAConfig.crc ? LoRa.enableCrc() : LoRa.disableCrc(); LORAConfig.invertIQ ? LoRa.enableInvertIQ() : LoRa.disableInvertIQ(); +} + +void LORAConfig_fromJson(JsonObject& LORAdata) { + Config_update(LORAdata, "frequency", LORAConfig.frequency); + Config_update(LORAdata, "txpower", LORAConfig.txPower); + Config_update(LORAdata, "spreadingfactor", LORAConfig.spreadingFactor); + Config_update(LORAdata, "signalbandwidth", LORAConfig.signalBandwidth); + Config_update(LORAdata, "codingrate", LORAConfig.codingRateDenominator); + Config_update(LORAdata, "preamblelength", LORAConfig.preambleLength); + Config_update(LORAdata, "onlyknown", LORAConfig.onlyKnown); + // Handle syncword separately as it requires hex string conversion + if (LORAdata.containsKey("syncword")) { + String syncWordStr = LORAdata["syncword"].as(); + byte newSyncWord = hexStringToByte(syncWordStr); + if (newSyncWord != LORAConfig.syncWord) { + LORAConfig.syncWord = newSyncWord; + THEENGS_LOG_NOTICE(F("Config syncword changed: %d" CR), LORAConfig.syncWord); + } else { + THEENGS_LOG_NOTICE(F("Config syncword unchanged, currently: %d" CR), LORAConfig.syncWord); + } + } + Config_update(LORAdata, "enablecrc", LORAConfig.crc); + Config_update(LORAdata, "invertiq", LORAConfig.invertIQ); if (LORAdata.containsKey("erase") && LORAdata["erase"].as()) { // Erase config from NVS (non-volatile storage) @@ -409,6 +417,7 @@ void setupLORA() { THEENGS_LOG_ERROR(F("gatewayLORA setup failed!" CR)); while (1); } + LORAConfig_apply(); LoRa.receive(); THEENGS_LOG_NOTICE(F("LORA_SCK: %d" CR), LORA_SCK); THEENGS_LOG_NOTICE(F("LORA_MISO: %d" CR), LORA_MISO); @@ -505,6 +514,7 @@ void XtoLORA(const char* topicOri, JsonObject& LORAdata) { // json object decodi const char* message = LORAdata["message"]; const char* hex = LORAdata["hex"]; LORAConfig_fromJson(LORAdata); + LORAConfig_apply(); if (message || hex) { LoRa.beginPacket(); uint8_t deviceId = _determineDevice(LORAdata); @@ -547,6 +557,7 @@ void XtoLORA(const char* topicOri, JsonObject& LORAdata) { // json object decodi // Load config from json if available LORAConfig_fromJson(LORAdata); + LORAConfig_apply(); stateLORAMeasures(); } }