diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile index a769a976d..54b5cda0f 100644 --- a/.clusterfuzzlite/Dockerfile +++ b/.clusterfuzzlite/Dockerfile @@ -20,7 +20,7 @@ ENV PIP_ROOT_USER_ACTION=ignore RUN apt-get update && apt-get install --no-install-recommends -y \ cmake git zip libgpiod-dev libbluetooth-dev libi2c-dev \ libunistring-dev libmicrohttpd-dev libgnutls28-dev libgcrypt20-dev \ - libusb-1.0-0-dev libssl-dev pkg-config && \ + libusb-1.0-0-dev libssl-dev pkg-config libsqlite3-dev && \ apt-get clean && rm -rf /var/lib/apt/lists/* && \ pip install --no-cache-dir -U \ platformio==6.1.16 \ diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 12e6696c0..9d563a39a 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,14 +9,14 @@ plugins: lint: enabled: - checkov@3.2.497 - - renovate@42.81.8 + - renovate@42.84.2 - prettier@3.8.0 - - trufflehog@3.92.4 + - trufflehog@3.92.5 - yamllint@1.38.0 - - bandit@1.9.2 + - bandit@1.9.3 - trivy@0.68.2 - taplo@0.10.0 - - ruff@0.14.11 + - ruff@0.14.13 - isort@7.0.0 - markdownlint@0.47.0 - oxipng@10.0.0 @@ -26,7 +26,7 @@ lint: - hadolint@2.14.0 - shfmt@3.6.0 - shellcheck@0.11.0 - - black@25.12.0 + - black@26.1.0 - git-diff-check - gitleaks@8.30.0 - clang-format@16.0.3 diff --git a/Dockerfile b/Dockerfile index 111dd69fc..91d3f7796 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ curl wget g++ zip git ca-certificates pkg-config \ libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \ libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev \ - libx11-dev libinput-dev libxkbcommon-x11-dev \ + libx11-dev libinput-dev libxkbcommon-x11-dev libsqlite3-dev \ && apt-get clean && rm -rf /var/lib/apt/lists/* \ && pip install --no-cache-dir -U platformio \ && mkdir /tmp/firmware diff --git a/alpine.Dockerfile b/alpine.Dockerfile index b3b384101..64c281788 100644 --- a/alpine.Dockerfile +++ b/alpine.Dockerfile @@ -11,7 +11,7 @@ RUN apk --no-cache add \ bash g++ libstdc++-dev linux-headers zip git ca-certificates libbsd-dev \ libgpiod-dev yaml-cpp-dev bluez-dev \ libusb-dev i2c-tools-dev libuv-dev openssl-dev pkgconf argp-standalone \ - libx11-dev libinput-dev libxkbcommon-dev \ + libx11-dev libinput-dev libxkbcommon-dev sqlite-dev \ && rm -rf /var/cache/apk/* \ && pip install --no-cache-dir -U platformio \ && mkdir /tmp/firmware diff --git a/debian/control b/debian/control index 679a444c9..46c932a80 100644 --- a/debian/control +++ b/debian/control @@ -25,7 +25,8 @@ Build-Depends: debhelper-compat (= 13), liborcania-dev, libx11-dev, libinput-dev, - libxkbcommon-x11-dev + libxkbcommon-x11-dev, + libsqlite3-dev Standards-Version: 4.6.2 Homepage: https://github.com/meshtastic/firmware Rules-Requires-Root: no diff --git a/meshtasticd.spec.rpkg b/meshtasticd.spec.rpkg index 0819d5f8d..fc14ede7f 100644 --- a/meshtasticd.spec.rpkg +++ b/meshtasticd.spec.rpkg @@ -39,6 +39,7 @@ BuildRequires: pkgconfig(bluez) BuildRequires: pkgconfig(libusb-1.0) BuildRequires: libi2c-devel BuildRequires: pkgconfig(libuv) +BuildRequires: pkgconfig(sqlite3) # Web components: BuildRequires: pkgconfig(openssl) BuildRequires: pkgconfig(liborcania) diff --git a/platformio.ini b/platformio.ini index 4c19136af..8daad1fb3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -119,7 +119,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/5a870c623a4e9ab7a7abe3d02950536f107d1a31.zip + https://github.com/meshtastic/device-ui/archive/3480b731d28b10d73414cf0dd7975bff745de8cf.zip ; Common libs for environmental measurements in telemetry module [environmental_base] diff --git a/protobufs b/protobufs index 4b9f104a1..bbde30a0b 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 4b9f104a18ea43b1b2091ee2b48899fe43ad8a0b +Subproject commit bbde30a0b98b485df8ccc1058facc7d31477f16d diff --git a/src/configuration.h b/src/configuration.h index eb258651c..59bffe7be 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -445,18 +445,6 @@ along with this program. If not, see . #endif #endif -// BME680 BSEC2 support detection -#if !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED) -#if defined(RAK_4631) || defined(TBEAM_V10) - -#define MESHTASTIC_BME680_BSEC2_SUPPORTED 1 -#define MESHTASTIC_BME680_HEADER -#else -#define MESHTASTIC_BME680_BSEC2_SUPPORTED 0 -#define MESHTASTIC_BME680_HEADER -#endif // defined(RAK_4631) -#endif // !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED) - // ----------------------------------------------------------------------------- // Global switches to turn off features for a minimized build // ----------------------------------------------------------------------------- diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index 75b65c65f..2dca38d66 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -438,7 +438,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, if (currentResolution == ScreenResolution::UltraLow) { snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz (%d)", freqStr, config.lora.channel_num); } else { - snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %sMHz (%d)", freqStr, config.lora.channel_num); + snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %sMHz (%d)", freqStr, config.lora.channel_num); } } size_t len = strlen(frequencyslot); diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index 5c459d984..c5a4106e7 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -65,12 +65,12 @@ uint8_t test_count = 0; void menuHandler::loraMenu() { - static const char *optionsArray[] = {"Back", "Device Role", "Radio Preset", "LoRa Region"}; - enum optionsNumbers { Back = 0, device_role_picker = 1, radio_preset_picker = 2, lora_picker = 3 }; + static const char *optionsArray[] = {"Back", "Device Role", "Radio Preset", "Frequency Slot", "LoRa Region"}; + enum optionsNumbers { Back = 0, device_role_picker = 1, radio_preset_picker = 2, frequency_slot = 3, lora_picker = 4 }; BannerOverlayOptions bannerOptions; bannerOptions.message = "LoRa Actions"; bannerOptions.optionsArrayPtr = optionsArray; - bannerOptions.optionsCount = 4; + bannerOptions.optionsCount = 5; bannerOptions.bannerCallback = [](int selected) -> void { if (selected == Back) { // No action @@ -78,6 +78,8 @@ void menuHandler::loraMenu() menuHandler::menuQueue = menuHandler::device_role_picker; } else if (selected == radio_preset_picker) { menuHandler::menuQueue = menuHandler::radio_preset_picker; + } else if (selected == frequency_slot) { + menuHandler::menuQueue = menuHandler::frequency_slot; } else if (selected == lora_picker) { menuHandler::menuQueue = menuHandler::lora_picker; } @@ -248,6 +250,113 @@ void menuHandler::DeviceRolePicker() screen->showOverlayBanner(bannerOptions); } +void menuHandler::FrequencySlotPicker() +{ + + enum ReplyOptions : int { Back = -1 }; + constexpr int MAX_CHANNEL_OPTIONS = 202; + static const char *optionsArray[MAX_CHANNEL_OPTIONS]; + static int optionsEnumArray[MAX_CHANNEL_OPTIONS]; + static char channelText[MAX_CHANNEL_OPTIONS - 1][12]; + int options = 0; + optionsArray[options] = "Back"; + optionsEnumArray[options++] = Back; + optionsArray[options] = "Slot 0 (Auto)"; + optionsEnumArray[options++] = 0; + + // Calculate number of channels (copied from RadioInterface::applyModemConfig()) + meshtastic_Config_LoRaConfig &loraConfig = config.lora; + double bw = loraConfig.bandwidth; + if (loraConfig.use_preset) { + switch (loraConfig.modem_preset) { + case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO: + bw = (myRegion->wideLora) ? 1625.0 : 500; + break; + case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST: + bw = (myRegion->wideLora) ? 812.5 : 250; + break; + case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW: + bw = (myRegion->wideLora) ? 812.5 : 250; + break; + case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST: + bw = (myRegion->wideLora) ? 812.5 : 250; + break; + case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW: + bw = (myRegion->wideLora) ? 812.5 : 250; + break; + case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO: + bw = (myRegion->wideLora) ? 1625.0 : 500; + break; + default: + bw = (myRegion->wideLora) ? 812.5 : 250; + break; + case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE: + bw = (myRegion->wideLora) ? 406.25 : 125; + break; + case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW: + bw = (myRegion->wideLora) ? 406.25 : 125; + break; + } + } else { + bw = loraConfig.bandwidth; + if (bw == 31) // This parameter is not an integer + bw = 31.25; + if (bw == 62) // Fix for 62.5Khz bandwidth + bw = 62.5; + if (bw == 200) + bw = 203.125; + if (bw == 400) + bw = 406.25; + if (bw == 800) + bw = 812.5; + if (bw == 1600) + bw = 1625.0; + } + + uint32_t numChannels = 0; + if (myRegion) { + numChannels = (uint32_t)floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000.0))); + } else { + LOG_WARN("Region not set, cannot calculate number of channels"); + return; + } + + if (numChannels > (uint32_t)(MAX_CHANNEL_OPTIONS - 2)) + numChannels = (uint32_t)(MAX_CHANNEL_OPTIONS - 2); + + for (uint32_t ch = 1; ch <= numChannels; ch++) { + snprintf(channelText[ch - 1], sizeof(channelText[ch - 1]), "Slot %lu", (unsigned long)ch); + optionsArray[options] = channelText[ch - 1]; + optionsEnumArray[options++] = (int)ch; + } + + BannerOverlayOptions bannerOptions; + bannerOptions.message = "Frequency Slot"; + bannerOptions.optionsArrayPtr = optionsArray; + bannerOptions.optionsEnumPtr = optionsEnumArray; + bannerOptions.optionsCount = options; + + // Start highlight on current channel if possible, otherwise on "1" + int initial = (int)config.lora.channel_num + 1; + if (initial < 2 || initial > (int)numChannels + 1) + initial = 1; + bannerOptions.InitialSelected = initial; + + bannerOptions.bannerCallback = [](int selected) -> void { + if (selected == Back) { + menuHandler::menuQueue = menuHandler::lora_Menu; + screen->runNow(); + return; + } + + config.lora.channel_num = selected; + service->reloadConfig(SEGMENT_CONFIG); + rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); + }; + + screen->showOverlayBanner(bannerOptions); +} + void menuHandler::RadioPresetPicker() { static const RadioPresetOption presetOptions[] = { @@ -278,6 +387,8 @@ void menuHandler::RadioPresetPicker() } config.lora.modem_preset = option.value; + config.lora.channel_num = 0; // Reset to default channel for the preset + config.lora.override_frequency = 0; // Clear any custom frequency service->reloadConfig(SEGMENT_CONFIG); rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000); }); @@ -2551,6 +2662,9 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display) case radio_preset_picker: RadioPresetPicker(); break; + case frequency_slot: + FrequencySlotPicker(); + break; case no_timeout_lora_picker: LoraRegionPicker(0); break; diff --git a/src/graphics/draw/MenuHandler.h b/src/graphics/draw/MenuHandler.h index 121b6dfc9..45fd0bf5f 100644 --- a/src/graphics/draw/MenuHandler.h +++ b/src/graphics/draw/MenuHandler.h @@ -13,6 +13,7 @@ class menuHandler lora_picker, device_role_picker, radio_preset_picker, + frequency_slot, no_timeout_lora_picker, TZ_picker, twelve_hour_picker, @@ -63,6 +64,7 @@ class menuHandler static void loraMenu(); static void DeviceRolePicker(); static void RadioPresetPicker(); + static void FrequencySlotPicker(); static void handleMenuSwitch(OLEDDisplay *display); static void showConfirmationBanner(const char *message, std::function onConfirm); static void clockMenu(); diff --git a/src/mesh/generated/meshtastic/mesh.pb.cpp b/src/mesh/generated/meshtastic/mesh.pb.cpp index d8eee1203..7f1a738c6 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.cpp +++ b/src/mesh/generated/meshtastic/mesh.pb.cpp @@ -30,6 +30,9 @@ PB_BIND(meshtastic_StoreForwardPlusPlus, meshtastic_StoreForwardPlusPlus, 2) PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO) +PB_BIND(meshtastic_StatusMessage, meshtastic_StatusMessage, AUTO) + + PB_BIND(meshtastic_MqttClientProxyMessage, meshtastic_MqttClientProxyMessage, 2) diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 68552ede5..aeae4bd84 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -858,6 +858,11 @@ typedef struct _meshtastic_Waypoint { uint32_t icon; } meshtastic_Waypoint; +/* Message for node status */ +typedef struct _meshtastic_StatusMessage { + char status[80]; +} meshtastic_StatusMessage; + typedef PB_BYTES_ARRAY_T(435) meshtastic_MqttClientProxyMessage_data_t; /* This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server */ typedef struct _meshtastic_MqttClientProxyMessage { @@ -1402,6 +1407,7 @@ extern "C" { + #define meshtastic_MeshPacket_priority_ENUMTYPE meshtastic_MeshPacket_Priority #define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed #define meshtastic_MeshPacket_transport_mechanism_ENUMTYPE meshtastic_MeshPacket_TransportMechanism @@ -1444,6 +1450,7 @@ extern "C" { #define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}} #define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0} +#define meshtastic_StatusMessage_init_default {""} #define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} #define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN} #define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} @@ -1476,6 +1483,7 @@ extern "C" { #define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}} #define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0} +#define meshtastic_StatusMessage_init_zero {""} #define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} #define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN} #define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} @@ -1571,6 +1579,7 @@ extern "C" { #define meshtastic_Waypoint_name_tag 6 #define meshtastic_Waypoint_description_tag 7 #define meshtastic_Waypoint_icon_tag 8 +#define meshtastic_StatusMessage_status_tag 1 #define meshtastic_MqttClientProxyMessage_topic_tag 1 #define meshtastic_MqttClientProxyMessage_data_tag 2 #define meshtastic_MqttClientProxyMessage_text_tag 3 @@ -1806,6 +1815,11 @@ X(a, STATIC, SINGULAR, FIXED32, icon, 8) #define meshtastic_Waypoint_CALLBACK NULL #define meshtastic_Waypoint_DEFAULT NULL +#define meshtastic_StatusMessage_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, status, 1) +#define meshtastic_StatusMessage_CALLBACK NULL +#define meshtastic_StatusMessage_DEFAULT NULL + #define meshtastic_MqttClientProxyMessage_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, STRING, topic, 1) \ X(a, STATIC, ONEOF, BYTES, (payload_variant,data,payload_variant.data), 2) \ @@ -2072,6 +2086,7 @@ extern const pb_msgdesc_t meshtastic_Data_msg; extern const pb_msgdesc_t meshtastic_KeyVerification_msg; extern const pb_msgdesc_t meshtastic_StoreForwardPlusPlus_msg; extern const pb_msgdesc_t meshtastic_Waypoint_msg; +extern const pb_msgdesc_t meshtastic_StatusMessage_msg; extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg; extern const pb_msgdesc_t meshtastic_MeshPacket_msg; extern const pb_msgdesc_t meshtastic_NodeInfo_msg; @@ -2106,6 +2121,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_KeyVerification_fields &meshtastic_KeyVerification_msg #define meshtastic_StoreForwardPlusPlus_fields &meshtastic_StoreForwardPlusPlus_msg #define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg +#define meshtastic_StatusMessage_fields &meshtastic_StatusMessage_msg #define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg #define meshtastic_MeshPacket_fields &meshtastic_MeshPacket_msg #define meshtastic_NodeInfo_fields &meshtastic_NodeInfo_msg @@ -2161,6 +2177,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_QueueStatus_size 23 #define meshtastic_RouteDiscovery_size 256 #define meshtastic_Routing_size 259 +#define meshtastic_StatusMessage_size 81 #define meshtastic_StoreForwardPlusPlus_size 377 #define meshtastic_ToRadio_size 504 #define meshtastic_User_size 115 diff --git a/src/mesh/generated/meshtastic/module_config.pb.cpp b/src/mesh/generated/meshtastic/module_config.pb.cpp index f262df6a3..bb57c3f2d 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.cpp +++ b/src/mesh/generated/meshtastic/module_config.pb.cpp @@ -51,6 +51,9 @@ PB_BIND(meshtastic_ModuleConfig_CannedMessageConfig, meshtastic_ModuleConfig_Can PB_BIND(meshtastic_ModuleConfig_AmbientLightingConfig, meshtastic_ModuleConfig_AmbientLightingConfig, AUTO) +PB_BIND(meshtastic_ModuleConfig_StatusMessageConfig, meshtastic_ModuleConfig_StatusMessageConfig, AUTO) + + PB_BIND(meshtastic_RemoteHardwarePin, meshtastic_RemoteHardwarePin, AUTO) diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index dd0151e3f..46a7164d2 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -409,6 +409,12 @@ typedef struct _meshtastic_ModuleConfig_AmbientLightingConfig { uint8_t blue; } meshtastic_ModuleConfig_AmbientLightingConfig; +/* StatusMessage config - Allows setting a status message for a node to periodically rebroadcast */ +typedef struct _meshtastic_ModuleConfig_StatusMessageConfig { + /* The actual status string */ + char node_status[80]; +} meshtastic_ModuleConfig_StatusMessageConfig; + /* A GPIO pin definition for remote hardware module */ typedef struct _meshtastic_RemoteHardwarePin { /* GPIO Pin number (must match Arduino) */ @@ -460,6 +466,8 @@ typedef struct _meshtastic_ModuleConfig { meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor; /* TODO: REPLACE */ meshtastic_ModuleConfig_PaxcounterConfig paxcounter; + /* TODO: REPLACE */ + meshtastic_ModuleConfig_StatusMessageConfig statusmessage; } payload_variant; } meshtastic_ModuleConfig; @@ -515,6 +523,7 @@ extern "C" { #define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_event_press_ENUMTYPE meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar + #define meshtastic_RemoteHardwarePin_type_ENUMTYPE meshtastic_RemoteHardwarePinType @@ -534,6 +543,7 @@ extern "C" { #define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_StatusMessageConfig_init_default {""} #define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN} #define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}} #define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0, 0, false, meshtastic_ModuleConfig_MapReportSettings_init_zero} @@ -550,6 +560,7 @@ extern "C" { #define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_StatusMessageConfig_init_zero {""} #define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN} /* Field tags (for use in manual encoding/decoding) */ @@ -653,6 +664,7 @@ extern "C" { #define meshtastic_ModuleConfig_AmbientLightingConfig_red_tag 3 #define meshtastic_ModuleConfig_AmbientLightingConfig_green_tag 4 #define meshtastic_ModuleConfig_AmbientLightingConfig_blue_tag 5 +#define meshtastic_ModuleConfig_StatusMessageConfig_node_status_tag 1 #define meshtastic_RemoteHardwarePin_gpio_pin_tag 1 #define meshtastic_RemoteHardwarePin_name_tag 2 #define meshtastic_RemoteHardwarePin_type_tag 3 @@ -672,6 +684,7 @@ extern "C" { #define meshtastic_ModuleConfig_ambient_lighting_tag 11 #define meshtastic_ModuleConfig_detection_sensor_tag 12 #define meshtastic_ModuleConfig_paxcounter_tag 13 +#define meshtastic_ModuleConfig_statusmessage_tag 14 /* Struct field encoding specification for nanopb */ #define meshtastic_ModuleConfig_FIELDLIST(X, a) \ @@ -687,7 +700,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_vari X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,detection_sensor,payload_variant.detection_sensor), 12) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,paxcounter,payload_variant.paxcounter), 13) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,paxcounter,payload_variant.paxcounter), 13) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,statusmessage,payload_variant.statusmessage), 14) #define meshtastic_ModuleConfig_CALLBACK NULL #define meshtastic_ModuleConfig_DEFAULT NULL #define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig @@ -703,6 +717,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,paxcounter,payload_variant.p #define meshtastic_ModuleConfig_payload_variant_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig #define meshtastic_ModuleConfig_payload_variant_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig #define meshtastic_ModuleConfig_payload_variant_paxcounter_MSGTYPE meshtastic_ModuleConfig_PaxcounterConfig +#define meshtastic_ModuleConfig_payload_variant_statusmessage_MSGTYPE meshtastic_ModuleConfig_StatusMessageConfig #define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ @@ -865,6 +880,11 @@ X(a, STATIC, SINGULAR, UINT32, blue, 5) #define meshtastic_ModuleConfig_AmbientLightingConfig_CALLBACK NULL #define meshtastic_ModuleConfig_AmbientLightingConfig_DEFAULT NULL +#define meshtastic_ModuleConfig_StatusMessageConfig_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, node_status, 1) +#define meshtastic_ModuleConfig_StatusMessageConfig_CALLBACK NULL +#define meshtastic_ModuleConfig_StatusMessageConfig_DEFAULT NULL + #define meshtastic_RemoteHardwarePin_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, gpio_pin, 1) \ X(a, STATIC, SINGULAR, STRING, name, 2) \ @@ -887,6 +907,7 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_RangeTestConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_TelemetryConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_CannedMessageConfig_msg; extern const pb_msgdesc_t meshtastic_ModuleConfig_AmbientLightingConfig_msg; +extern const pb_msgdesc_t meshtastic_ModuleConfig_StatusMessageConfig_msg; extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ @@ -905,6 +926,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_TelemetryConfig_fields &meshtastic_ModuleConfig_TelemetryConfig_msg #define meshtastic_ModuleConfig_CannedMessageConfig_fields &meshtastic_ModuleConfig_CannedMessageConfig_msg #define meshtastic_ModuleConfig_AmbientLightingConfig_fields &meshtastic_ModuleConfig_AmbientLightingConfig_msg +#define meshtastic_ModuleConfig_StatusMessageConfig_fields &meshtastic_ModuleConfig_StatusMessageConfig_msg #define meshtastic_RemoteHardwarePin_fields &meshtastic_RemoteHardwarePin_msg /* Maximum encoded size of messages (where known) */ @@ -921,6 +943,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_RangeTestConfig_size 12 #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 +#define meshtastic_ModuleConfig_StatusMessageConfig_size 81 #define meshtastic_ModuleConfig_StoreForwardConfig_size 24 #define meshtastic_ModuleConfig_TelemetryConfig_size 50 #define meshtastic_ModuleConfig_size 227 diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 6b89c6a37..d31daa4b2 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -91,6 +91,11 @@ typedef enum _meshtastic_PortNum { This module is specifically for Native Linux nodes, and provides a Git-style chain of messages. */ meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP = 35, + /* Node Status module + ENCODING: protobuf + This module allows setting an extra string of status for a node. + Broadcasts on change and on a timer, possibly once a day. */ + meshtastic_PortNum_NODE_STATUS_APP = 36, /* Provides a hardware serial interface to send and receive from the Meshtastic network. Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network. diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 7b7ebb595..ea8d6af8e 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -173,7 +173,7 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) if (req->getMethod() == "OPTIONS") { res->setStatusCode(204); // Success with no content - // res->print(""); @todo remove + res->print(""); return; } @@ -223,7 +223,7 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res) if (req->getMethod() == "OPTIONS") { res->setStatusCode(204); // Success with no content - // res->print(""); @todo remove + res->print(""); return; } diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 04fcd8e73..8b7ce700a 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -460,12 +460,15 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from); - bool mutedNode = false; - if (sender) { - mutedNode = (sender->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK); - } meshtastic_Channel ch = channels.getByIndex(mp.channel ? mp.channel : channels.getPrimaryIndex()); + // If we receive a broadcast message, apply channel mute setting + // If we receive a direct message and the receipent is us, apply DM mute setting + // Else we just handle it as not muted. + const bool directToUs = !isBroadcast(mp.to) && isToUs(&mp); + bool is_muted = directToUs ? (sender && ((sender->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0)) + : (ch.settings.has_module_settings && ch.settings.module_settings.is_muted); + if (moduleConfig.external_notification.alert_bell) { if (containsBell) { LOG_INFO("externalNotificationModule - Notification Bell"); @@ -516,8 +519,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message && !mutedNode && - (!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) { + if (moduleConfig.external_notification.alert_message && !is_muted) { LOG_INFO("externalNotificationModule - Notification Module"); isNagging = true; setExternalState(0, true); @@ -528,8 +530,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_vibra && !mutedNode && - (!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) { + if (moduleConfig.external_notification.alert_message_vibra && !is_muted) { LOG_INFO("externalNotificationModule - Notification Module (Vibra)"); isNagging = true; setExternalState(1, true); @@ -540,8 +541,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP } } - if (moduleConfig.external_notification.alert_message_buzzer && !mutedNode && - (!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) { + if (moduleConfig.external_notification.alert_message_buzzer && !is_muted) { LOG_INFO("externalNotificationModule - Notification Module (Buzzer)"); if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY || (!isBroadcast(mp.to) && isToUs(&mp))) { diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index ec6fe4799..86a8606c2 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -53,7 +53,7 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c #include "Sensor/LTR390UVSensor.h" #endif -#if __has_include(MESHTASTIC_BME680_HEADER) +#if __has_include() || __has_include() #include "Sensor/BME680Sensor.h" #endif @@ -187,7 +187,7 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) #if __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::LTR390UV); #endif -#if __has_include(MESHTASTIC_BME680_HEADER) +#if __has_include() || __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::BME_680); #endif #if __has_include() diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.cpp b/src/modules/Telemetry/Sensor/BME680Sensor.cpp index 22330ca75..3a1eb9532 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BME680Sensor.cpp @@ -1,6 +1,6 @@ #include "configuration.h" -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER) +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && (__has_include() || __has_include()) #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "BME680Sensor.h" @@ -10,7 +10,7 @@ BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {} -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() int32_t BME680Sensor::runOnce() { if (!bme680.run()) { @@ -18,13 +18,13 @@ int32_t BME680Sensor::runOnce() } return 35; } -#endif // defined(MESHTASTIC_BME680_BSEC2_SUPPORTED) +#endif bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) { status = 0; -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() if (!bme680.begin(dev->address.address, *bus)) checkStatus("begin"); @@ -56,7 +56,7 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) status = 1; -#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED +#endif initI2CSensor(); return status; @@ -64,7 +64,7 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement) { -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0) return false; @@ -98,11 +98,11 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement) measurement->variant.environment_metrics.barometric_pressure = bme680->readPressure() / 100.0F; measurement->variant.environment_metrics.gas_resistance = bme680->readGas() / 1000.0; -#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED +#endif return true; } -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() void BME680Sensor::loadState() { #ifdef FSCom @@ -179,6 +179,6 @@ void BME680Sensor::checkStatus(const char *functionName) else if (bme680.sensor.status > BME68X_OK) LOG_WARN("%s BME68X code: %d", functionName, bme680.sensor.status); } -#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED +#endif #endif diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.h b/src/modules/Telemetry/Sensor/BME680Sensor.h index 9bef56e1e..eaeceb848 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.h +++ b/src/modules/Telemetry/Sensor/BME680Sensor.h @@ -1,29 +1,29 @@ #include "configuration.h" -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER) +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && (__has_include() || __has_include()) #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() #include #include #else #include #include -#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED +#endif #define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis() -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() const uint8_t bsec_config[] = { #include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt" }; -#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED +#endif class BME680Sensor : public TelemetrySensor { private: -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() Bsec2 bme680; #else using BME680Ptr = std::unique_ptr; @@ -31,10 +31,10 @@ class BME680Sensor : public TelemetrySensor static BME680Ptr makeBME680(TwoWire *bus) { return std::make_unique(bus); } BME680Ptr bme680; -#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED +#endif protected: -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() const char *bsecConfigFileName = "/prefs/bsec.dat"; uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0}; uint8_t accuracy = 0; @@ -51,13 +51,13 @@ class BME680Sensor : public TelemetrySensor void loadState(); void updateState(); void checkStatus(const char *functionName); -#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED +#endif public: BME680Sensor(); -#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1 +#if __has_include() virtual int32_t runOnce() override; -#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED +#endif virtual bool getMetrics(meshtastic_Telemetry *measurement) override; virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; }; diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 7430c2eae..ec9bbedca 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -55,6 +55,7 @@ void cpuDeepSleep(uint32_t msecs) void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel"); int TCPPort = SERVER_API_DEFAULT_PORT; +bool checkConfigPort = true; static error_t parse_opt(int key, char *arg, struct argp_state *state) { @@ -63,6 +64,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) if (sscanf(arg, "%d", &TCPPort) < 1) return ARGP_ERR_UNKNOWN; else + checkConfigPort = false; printf("Using config file %d\n", TCPPort); break; case 'c': @@ -870,6 +872,14 @@ bool loadConfig(const char *configPath) std::cout << "Cannot set both MACAddress and MACAddressSource!" << std::endl; exit(EXIT_FAILURE); } + if (checkConfigPort) { + portduino_config.api_port = (yamlConfig["General"]["APIPort"]).as(-1); + if (portduino_config.api_port != -1 && + portduino_config.api_port > 1023 && + portduino_config.api_port < 65536) { + TCPPort = (portduino_config.api_port); + } + } portduino_config.mac_address = (yamlConfig["General"]["MACAddress"]).as(""); if (portduino_config.mac_address != "") { portduino_config.mac_address_explicit = true; diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 8992f5f1a..3a6887421 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -175,6 +175,7 @@ extern struct portduino_config_struct { std::string mac_address = ""; bool mac_address_explicit = false; std::string mac_address_source = ""; + int api_port = -1; std::string config_directory = ""; std::string available_directory = "/etc/meshtasticd/available.d/"; int maxtophone = 100; @@ -508,6 +509,8 @@ extern struct portduino_config_struct { out << YAML::Key << "General" << YAML::Value << YAML::BeginMap; if (config_directory != "") out << YAML::Key << "ConfigDirectory" << YAML::Value << config_directory; + if (api_port != -1) + out << YAML::Key << "TCPPort" << YAML::Value << api_port; if (mac_address_explicit) out << YAML::Key << "MACAddress" << YAML::Value << mac_address; if (mac_address_source != "") @@ -519,4 +522,4 @@ extern struct portduino_config_struct { out << YAML::EndMap; // General return out.c_str(); } -} portduino_config; \ No newline at end of file +} portduino_config;