From d88f1ff68ba7079a397bdfccba86220e802d905b Mon Sep 17 00:00:00 2001 From: Elektr0Vodka <211697683+Elektr0Vodka@users.noreply.github.com> Date: Mon, 14 Sep 2026 04:07:12 +0200 Subject: [PATCH] feat(ota): persist ota_channel selector in NodePrefs (cherry picked from commit db1db5b57ecce408c7441cb6aa70f29608b09603) --- src/helpers/CommonCLI.h | 2 ++ .../test_config_serializer.cpp | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index e0a0a71b8..db77ac8db 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -70,6 +70,7 @@ public: uint8_t path_hash_mode = 0; // which path mode to use when sending uint8_t loop_detect = 0; uint8_t cad_enabled = 0; // hardware Channel Activity Detection before TX (boolean) + uint8_t ota_channel = 0; // OTA release channel selector: 0=native, 1=stable, 2=dev uint8_t extra_sf[4]; // NOTE: observer settings (MQTT/WiFi/timezone/SNMP/alert) are not in NodePrefs. @@ -182,6 +183,7 @@ protected: def("lat", node_lat); def("lon", node_lon); def("disc_mod", discovery_mod_timestamp); // gates 'since'-filtered DISCOVER replies + def("ota_ch", ota_channel); // OTA release channel: 0=native, 1=stable, 2=dev def("radio", radio); def("bridge", bridge); def("gps", gps); diff --git a/test/test_config_serializer/test_config_serializer.cpp b/test/test_config_serializer/test_config_serializer.cpp index 27c3c8119..1fbe1c8ad 100644 --- a/test/test_config_serializer/test_config_serializer.cpp +++ b/test/test_config_serializer/test_config_serializer.cpp @@ -214,6 +214,35 @@ TEST(NodePrefs, FemGainSettingsRoundTrip) { EXPECT_EQ(1, loaded.radio_fem_txgain); } +TEST(NodePrefs, OtaChannelDefaultsToNative) { + NodePrefs prefs; + EXPECT_EQ(0, prefs.ota_channel); // 0 == native +} + +TEST(NodePrefs, OtaChannelRoundTrip) { + NodePrefs saved; + saved.ota_channel = 2; // dev + + MockPrintStream output; + ASSERT_TRUE(saved.saveSerial(output)); + std::string serialised(reinterpret_cast(output.getBytes()), output.getLength()); + EXPECT_NE(std::string::npos, serialised.find("ota_ch:2")); + + MockInputStream input(serialised.c_str()); + NodePrefs loaded; + loaded.ota_channel = 1; // start different + ASSERT_TRUE(loaded.loadSerial(input)) << serialised; + EXPECT_EQ(2, loaded.ota_channel); +} + +TEST(NodePrefs, OtaChannelMissingKeyKeepsDefault) { + // A /prefs.json written before this field existed has no ota_ch key. + MockInputStream input("{name:\"n\"}"); + NodePrefs loaded; // ota_channel default 0 (native) + ASSERT_TRUE(loaded.loadSerial(input)); + EXPECT_EQ(0, loaded.ota_channel); +} + // ── main ───────────────────────────────────────────────────────