diff --git a/protobufs b/protobufs index f16a13e4339..dfcbebecd51 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit f16a13e43393f3c6a88a1da36e75dfc29f448d3e +Subproject commit dfcbebecd51fc9f668e89be77086a27b35cceb65 diff --git a/src/buzz/FindNodeBuzzer.cpp b/src/buzz/FindNodeBuzzer.cpp new file mode 100644 index 00000000000..66ec365c80c --- /dev/null +++ b/src/buzz/FindNodeBuzzer.cpp @@ -0,0 +1,71 @@ +#include "FindNodeBuzzer.h" +#include "NodeDB.h" +#include "buzz.h" +#include "configuration.h" +#include "mesh/Throttle.h" +#include +#include + +namespace +{ +constexpr uint32_t FIND_NODE_REPEAT_INTERVAL_MS = 2000; +} + +FindNodeBuzzer *findNodeBuzzer; + +FindNodeBuzzer::FindNodeBuzzer() : concurrency::OSThread("FindNodeBuzzer", INT32_MAX) {} + +FindNodeBuzzer::Result FindNodeBuzzer::start() +{ + if (!hasFindNodeBuzzer()) { + return Result::NoBuzzer; + } + + if (config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_DISABLED) { + return Result::BuzzerDisabled; + } + + startMsec = millis(); + durationMsec = DEFAULT_DURATION_SECONDS * 1000U; + + if (!playFindNodeBuzzer()) { + stop(); + return Result::NoBuzzer; + } + + setIntervalFromNow(FIND_NODE_REPEAT_INTERVAL_MS); + return Result::Started; +} + +FindNodeBuzzer::Result FindNodeBuzzer::stop() +{ + startMsec = 0; + durationMsec = 0; + setIntervalFromNow(INT32_MAX); + return Result::Stopped; +} + +bool FindNodeBuzzer::isActive() const +{ + return durationMsec != 0 && Throttle::isWithinTimespanMs(startMsec, durationMsec); +} + +int32_t FindNodeBuzzer::runOnce() +{ + if (!isActive()) { + stop(); + return INT32_MAX; + } + + if (config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_DISABLED || !playFindNodeBuzzer()) { + stop(); + return INT32_MAX; + } + + if (!isActive()) { + stop(); + return INT32_MAX; + } + + return FIND_NODE_REPEAT_INTERVAL_MS; +} diff --git a/src/buzz/FindNodeBuzzer.h b/src/buzz/FindNodeBuzzer.h new file mode 100644 index 00000000000..5d5ee0f288f --- /dev/null +++ b/src/buzz/FindNodeBuzzer.h @@ -0,0 +1,26 @@ +#pragma once + +#include "concurrency/OSThread.h" +#include + +class FindNodeBuzzer : private concurrency::OSThread +{ + public: + enum class Result : uint8_t { Started, Stopped, NoBuzzer, BuzzerDisabled }; + + static constexpr uint32_t DEFAULT_DURATION_SECONDS = 5 * 60; + + FindNodeBuzzer(); + + Result start(); + Result stop(); + bool isActive() const; + + private: + uint32_t startMsec = 0; + uint32_t durationMsec = 0; + + int32_t runOnce() override; +}; + +extern FindNodeBuzzer *findNodeBuzzer; diff --git a/src/buzz/buzz.cpp b/src/buzz/buzz.cpp index 6692d996dfa..257a05ca617 100644 --- a/src/buzz/buzz.cpp +++ b/src/buzz/buzz.cpp @@ -15,6 +15,29 @@ extern "C" void delay(uint32_t dwMs); #endif +namespace +{ +uint32_t getPwmBuzzerGpio() +{ + if (config.device.buzzer_gpio) { + return config.device.buzzer_gpio; + } +#if defined(PIN_BUZZER) + return PIN_BUZZER; +#else + return 0; +#endif +} + +void enableBuzzerPower() +{ +#ifdef BUZZER_EN_PIN + pinMode(BUZZER_EN_PIN, OUTPUT); + digitalWrite(BUZZER_EN_PIN, HIGH); +#endif +} +} // namespace + struct ToneDuration { int frequency_khz; int duration_ms; @@ -117,6 +140,7 @@ void playTones(const ToneDuration *tone_durations, int size) config.device.buzzer_gpio = PIN_BUZZER; #endif if (config.device.buzzer_gpio) { + enableBuzzerPower(); for (int i = 0; i < size; i++) { const auto &tone_duration = tone_durations[i]; tone(config.device.buzzer_gpio, tone_duration.frequency_khz, tone_duration.duration_ms); @@ -126,6 +150,63 @@ void playTones(const ToneDuration *tone_durations, int size) } } +bool hasFindNodeBuzzer() +{ +#ifdef HAS_I2S + if (moduleConfig.external_notification.use_i2s_as_buzzer && audioThread) { + return true; + } +#endif +#if defined(PIN_BUZZER) + return true; +#endif + return getPwmBuzzerGpio() || + (moduleConfig.external_notification.output_buzzer && !moduleConfig.external_notification.use_pwm); +} + +bool playFindNodeBuzzer() +{ + if (config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_DISABLED) { + return false; + } + +#ifdef HAS_I2S + if (moduleConfig.external_notification.use_i2s_as_buzzer && audioThread) { + static constexpr const char *findNodeRtttl = "find:d=16,o=5,b=220:c6,p,c6,p,g6"; + if (!audioThread->isPlaying()) { + audioThread->beginRttl(findNodeRtttl, strlen(findNodeRtttl)); + } + return true; + } +#endif + + const uint32_t buzzerGpio = getPwmBuzzerGpio(); + if (buzzerGpio) { + enableBuzzerPower(); + const ToneDuration melody[] = {{NOTE_C5, DURATION_1_8}, {NOTE_C5, DURATION_1_8}, {NOTE_G5, DURATION_1_8}}; + for (const auto &tone_duration : melody) { + tone(buzzerGpio, tone_duration.frequency_khz, tone_duration.duration_ms); + delay(1.3 * tone_duration.duration_ms); + } + return true; + } + + if (moduleConfig.external_notification.output_buzzer && !moduleConfig.external_notification.use_pwm) { + const uint32_t buzzerPin = moduleConfig.external_notification.output_buzzer; + enableBuzzerPower(); + pinMode(buzzerPin, OUTPUT); + for (int i = 0; i < 3; i++) { + digitalWrite(buzzerPin, HIGH); + delay(DURATION_1_8); + digitalWrite(buzzerPin, LOW); + delay(DURATION_1_8); + } + return true; + } + + return false; +} + void playBeep() { ToneDuration melody[] = {{NOTE_B3, DURATION_1_16}}; @@ -265,4 +346,4 @@ void play4ClickUp() // Quick high-pitched notes with trills ToneDuration melody[] = {{NOTE_F5, 50}, {NOTE_G6, 45}, {NOTE_E7, 60}}; playTones(melody, sizeof(melody) / sizeof(ToneDuration)); -} \ No newline at end of file +} diff --git a/src/buzz/buzz.h b/src/buzz/buzz.h index 1b97e24deff..4b0a2021295 100644 --- a/src/buzz/buzz.h +++ b/src/buzz/buzz.h @@ -14,4 +14,6 @@ void playChirp(); void playClick(); void playLongPressLeadUp(); bool playNextLeadUpNote(); // Play the next note in the lead-up sequence -void resetLeadUpSequence(); // Reset the lead-up sequence to start from beginning \ No newline at end of file +void resetLeadUpSequence(); // Reset the lead-up sequence to start from beginning +bool hasFindNodeBuzzer(); +bool playFindNodeBuzzer(); diff --git a/src/input/InputBroker.cpp b/src/input/InputBroker.cpp index 3d18f69cf51..05113faedf5 100644 --- a/src/input/InputBroker.cpp +++ b/src/input/InputBroker.cpp @@ -1,8 +1,10 @@ #include "InputBroker.h" #include "PowerFSM.h" // needed for event trigger +#include "buzz/FindNodeBuzzer.h" #include "configuration.h" #include "graphics/Screen.h" #include "modules/ExternalNotificationModule.h" +#include #ifdef MESHTASTIC_LOCKDOWN #include "security/LockdownDisplay.h" #endif @@ -111,6 +113,13 @@ int InputBroker::handleInputEvent(const InputEvent *event) #endif powerFSM.trigger(EVENT_INPUT); + const bool isLocalInput = + event && event->inputEvent != INPUT_BROKER_NONE && (!event->source || strcmp(event->source, "admin") != 0); + if (isLocalInput && findNodeBuzzer && findNodeBuzzer->isActive()) { + findNodeBuzzer->stop(); + LOG_INFO("Find-node buzzer stopped by local input"); + } + if (event && event->inputEvent != INPUT_BROKER_NONE && externalNotificationModule && moduleConfig.external_notification.enabled && externalNotificationModule->nagging()) { externalNotificationModule->stopNow(); @@ -391,8 +400,10 @@ void InputBroker::Init() rotaryEncoderInterruptImpl1 = nullptr; } #endif +#if !MESHTASTIC_EXCLUDE_I2C cardKbI2cImpl = new CardKbI2cImpl(); cardKbI2cImpl->init(); +#endif #if defined(M5STACK_UNITC6L) i2cButton = new i2cButtonThread("i2cButtonThread"); #endif diff --git a/src/main.cpp b/src/main.cpp index 1ca52c05922..ae8fdeb3856 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1158,6 +1158,7 @@ extern meshtastic_DeviceMetadata getDeviceMetadata() deviceMetadata.position_flags = config.position.position_flags; deviceMetadata.hw_model = HW_VENDOR; deviceMetadata.hasRemoteHardware = moduleConfig.remote_hardware.enabled; + deviceMetadata.hasBuzzer = hasFindNodeBuzzer(); deviceMetadata.excluded_modules = meshtastic_ExcludedModules_EXCLUDED_NONE; #if MESHTASTIC_EXCLUDE_REMOTEHARDWARE deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_REMOTEHARDWARE_CONFIG; diff --git a/src/mesh/generated/meshtastic/admin.pb.cpp b/src/mesh/generated/meshtastic/admin.pb.cpp index 945840c0f4d..118a0cf2e6b 100644 --- a/src/mesh/generated/meshtastic/admin.pb.cpp +++ b/src/mesh/generated/meshtastic/admin.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9.1 */ +/* Generated by nanopb-0.4.9 */ #include "meshtastic/admin.pb.h" #if PB_PROTO_HEADER_VERSION != 40 @@ -15,6 +15,12 @@ PB_BIND(meshtastic_AdminMessage_InputEvent, meshtastic_AdminMessage_InputEvent, PB_BIND(meshtastic_AdminMessage_OTAEvent, meshtastic_AdminMessage_OTAEvent, AUTO) +PB_BIND(meshtastic_AdminMessage_FindNodeRequest, meshtastic_AdminMessage_FindNodeRequest, AUTO) + + +PB_BIND(meshtastic_AdminMessage_FindNodeResponse, meshtastic_AdminMessage_FindNodeResponse, AUTO) + + PB_BIND(meshtastic_LockdownAuth, meshtastic_LockdownAuth, AUTO) @@ -56,3 +62,5 @@ PB_BIND(meshtastic_SHTXX_config, meshtastic_SHTXX_config, AUTO) + + diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index a099d7d5e5b..5b3d9c63492 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9.1 */ +/* Generated by nanopb-0.4.9 */ #ifndef PB_MESHTASTIC_MESHTASTIC_ADMIN_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_ADMIN_PB_H_INCLUDED @@ -93,6 +93,13 @@ typedef enum _meshtastic_AdminMessage_BackupLocation { meshtastic_AdminMessage_BackupLocation_SD = 1 } meshtastic_AdminMessage_BackupLocation; +typedef enum _meshtastic_AdminMessage_FindNodeResponse_Result { + meshtastic_AdminMessage_FindNodeResponse_Result_STARTED = 0, + meshtastic_AdminMessage_FindNodeResponse_Result_STOPPED = 1, + meshtastic_AdminMessage_FindNodeResponse_Result_NO_BUZZER = 2, + meshtastic_AdminMessage_FindNodeResponse_Result_BUZZER_DISABLED = 3 +} meshtastic_AdminMessage_FindNodeResponse_Result; + /* Three stages of this request. */ typedef enum _meshtastic_KeyVerificationAdmin_MessageType { /* This is the first stage, where a client initiates */ @@ -130,6 +137,18 @@ typedef struct _meshtastic_AdminMessage_OTAEvent { meshtastic_AdminMessage_OTAEvent_ota_hash_t ota_hash; } meshtastic_AdminMessage_OTAEvent; +/* Request that the node emit an audible find-node pattern. */ +typedef struct _meshtastic_AdminMessage_FindNodeRequest { + /* Stop any active find-node pattern instead of starting a new one. */ + bool stop; +} meshtastic_AdminMessage_FindNodeRequest; + +/* Response to a find-node request. */ +typedef struct _meshtastic_AdminMessage_FindNodeResponse { + /* Result of the request. */ + meshtastic_AdminMessage_FindNodeResponse_Result result; +} meshtastic_AdminMessage_FindNodeResponse; + typedef PB_BYTES_ARRAY_T(32) meshtastic_LockdownAuth_passphrase_t; /* Lockdown passphrase delivery payload. @@ -457,6 +476,10 @@ typedef struct _meshtastic_AdminMessage { meshtastic_SharedContact add_contact; /* Initiate or respond to a key verification request */ meshtastic_KeyVerificationAdmin key_verification; + /* Start or stop the audible find-node pattern. */ + meshtastic_AdminMessage_FindNodeRequest find_node_request; + /* Result of a find-node request. */ + meshtastic_AdminMessage_FindNodeResponse find_node_response; /* Tell the node to factory reset config everything; all device state and configuration will be returned to factory defaults and BLE bonds will be cleared. */ int32_t factory_reset_device; /* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) @@ -517,6 +540,10 @@ extern "C" { #define _meshtastic_AdminMessage_BackupLocation_MAX meshtastic_AdminMessage_BackupLocation_SD #define _meshtastic_AdminMessage_BackupLocation_ARRAYSIZE ((meshtastic_AdminMessage_BackupLocation)(meshtastic_AdminMessage_BackupLocation_SD+1)) +#define _meshtastic_AdminMessage_FindNodeResponse_Result_MIN meshtastic_AdminMessage_FindNodeResponse_Result_STARTED +#define _meshtastic_AdminMessage_FindNodeResponse_Result_MAX meshtastic_AdminMessage_FindNodeResponse_Result_BUZZER_DISABLED +#define _meshtastic_AdminMessage_FindNodeResponse_Result_ARRAYSIZE ((meshtastic_AdminMessage_FindNodeResponse_Result)(meshtastic_AdminMessage_FindNodeResponse_Result_BUZZER_DISABLED+1)) + #define _meshtastic_KeyVerificationAdmin_MessageType_MIN meshtastic_KeyVerificationAdmin_MessageType_INITIATE_VERIFICATION #define _meshtastic_KeyVerificationAdmin_MessageType_MAX meshtastic_KeyVerificationAdmin_MessageType_DO_NOT_VERIFY #define _meshtastic_KeyVerificationAdmin_MessageType_ARRAYSIZE ((meshtastic_KeyVerificationAdmin_MessageType)(meshtastic_KeyVerificationAdmin_MessageType_DO_NOT_VERIFY+1)) @@ -531,6 +558,9 @@ extern "C" { #define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode +#define meshtastic_AdminMessage_FindNodeResponse_result_ENUMTYPE meshtastic_AdminMessage_FindNodeResponse_Result + + @@ -546,6 +576,8 @@ extern "C" { #define meshtastic_AdminMessage_init_default {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0} #define meshtastic_AdminMessage_OTAEvent_init_default {_meshtastic_OTAMode_MIN, {0, {0}}} +#define meshtastic_AdminMessage_FindNodeRequest_init_default {0} +#define meshtastic_AdminMessage_FindNodeResponse_init_default {_meshtastic_AdminMessage_FindNodeResponse_Result_MIN} #define meshtastic_LockdownAuth_init_default {{0, {0}}, 0, 0, 0, 0, 0} #define meshtastic_HamParameters_init_default {"", 0, 0, "", ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} @@ -559,6 +591,8 @@ extern "C" { #define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0} #define meshtastic_AdminMessage_OTAEvent_init_zero {_meshtastic_OTAMode_MIN, {0, {0}}} +#define meshtastic_AdminMessage_FindNodeRequest_init_zero {0} +#define meshtastic_AdminMessage_FindNodeResponse_init_zero {_meshtastic_AdminMessage_FindNodeResponse_Result_MIN} #define meshtastic_LockdownAuth_init_zero {{0, {0}}, 0, 0, 0, 0, 0} #define meshtastic_HamParameters_init_zero {"", 0, 0, "", ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} @@ -577,6 +611,8 @@ extern "C" { #define meshtastic_AdminMessage_InputEvent_touch_y_tag 4 #define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_tag 1 #define meshtastic_AdminMessage_OTAEvent_ota_hash_tag 2 +#define meshtastic_AdminMessage_FindNodeRequest_stop_tag 1 +#define meshtastic_AdminMessage_FindNodeResponse_result_tag 1 #define meshtastic_LockdownAuth_passphrase_tag 1 #define meshtastic_LockdownAuth_boots_remaining_tag 2 #define meshtastic_LockdownAuth_valid_until_epoch_tag 3 @@ -665,6 +701,8 @@ extern "C" { #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 #define meshtastic_AdminMessage_key_verification_tag 67 +#define meshtastic_AdminMessage_find_node_request_tag 68 +#define meshtastic_AdminMessage_find_node_response_tag 69 #define meshtastic_AdminMessage_factory_reset_device_tag 94 #define meshtastic_AdminMessage_reboot_ota_seconds_tag 95 #define meshtastic_AdminMessage_exit_simulator_tag 96 @@ -727,6 +765,8 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_ed X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,key_verification,key_verification), 67) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,find_node_request,find_node_request), 68) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,find_node_response,find_node_response), 69) \ X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_device,factory_reset_device), 94) \ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,exit_simulator,exit_simulator), 96) \ @@ -758,6 +798,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,lockdown_auth,lockdown_auth) #define meshtastic_AdminMessage_payload_variant_store_ui_config_MSGTYPE meshtastic_DeviceUIConfig #define meshtastic_AdminMessage_payload_variant_add_contact_MSGTYPE meshtastic_SharedContact #define meshtastic_AdminMessage_payload_variant_key_verification_MSGTYPE meshtastic_KeyVerificationAdmin +#define meshtastic_AdminMessage_payload_variant_find_node_request_MSGTYPE meshtastic_AdminMessage_FindNodeRequest +#define meshtastic_AdminMessage_payload_variant_find_node_response_MSGTYPE meshtastic_AdminMessage_FindNodeResponse #define meshtastic_AdminMessage_payload_variant_ota_request_MSGTYPE meshtastic_AdminMessage_OTAEvent #define meshtastic_AdminMessage_payload_variant_sensor_config_MSGTYPE meshtastic_SensorConfig #define meshtastic_AdminMessage_payload_variant_lockdown_auth_MSGTYPE meshtastic_LockdownAuth @@ -776,6 +818,16 @@ X(a, STATIC, SINGULAR, BYTES, ota_hash, 2) #define meshtastic_AdminMessage_OTAEvent_CALLBACK NULL #define meshtastic_AdminMessage_OTAEvent_DEFAULT NULL +#define meshtastic_AdminMessage_FindNodeRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BOOL, stop, 1) +#define meshtastic_AdminMessage_FindNodeRequest_CALLBACK NULL +#define meshtastic_AdminMessage_FindNodeRequest_DEFAULT NULL + +#define meshtastic_AdminMessage_FindNodeResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, result, 1) +#define meshtastic_AdminMessage_FindNodeResponse_CALLBACK NULL +#define meshtastic_AdminMessage_FindNodeResponse_DEFAULT NULL + #define meshtastic_LockdownAuth_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BYTES, passphrase, 1) \ X(a, STATIC, SINGULAR, UINT32, boots_remaining, 2) \ @@ -865,6 +917,8 @@ X(a, STATIC, OPTIONAL, UINT32, set_accuracy, 1) extern const pb_msgdesc_t meshtastic_AdminMessage_msg; extern const pb_msgdesc_t meshtastic_AdminMessage_InputEvent_msg; extern const pb_msgdesc_t meshtastic_AdminMessage_OTAEvent_msg; +extern const pb_msgdesc_t meshtastic_AdminMessage_FindNodeRequest_msg; +extern const pb_msgdesc_t meshtastic_AdminMessage_FindNodeResponse_msg; extern const pb_msgdesc_t meshtastic_LockdownAuth_msg; extern const pb_msgdesc_t meshtastic_HamParameters_msg; extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg; @@ -880,6 +934,8 @@ extern const pb_msgdesc_t meshtastic_SHTXX_config_msg; #define meshtastic_AdminMessage_fields &meshtastic_AdminMessage_msg #define meshtastic_AdminMessage_InputEvent_fields &meshtastic_AdminMessage_InputEvent_msg #define meshtastic_AdminMessage_OTAEvent_fields &meshtastic_AdminMessage_OTAEvent_msg +#define meshtastic_AdminMessage_FindNodeRequest_fields &meshtastic_AdminMessage_FindNodeRequest_msg +#define meshtastic_AdminMessage_FindNodeResponse_fields &meshtastic_AdminMessage_FindNodeResponse_msg #define meshtastic_LockdownAuth_fields &meshtastic_LockdownAuth_msg #define meshtastic_HamParameters_fields &meshtastic_HamParameters_msg #define meshtastic_NodeRemoteHardwarePinsResponse_fields &meshtastic_NodeRemoteHardwarePinsResponse_msg @@ -893,6 +949,8 @@ extern const pb_msgdesc_t meshtastic_SHTXX_config_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_ADMIN_PB_H_MAX_SIZE meshtastic_AdminMessage_size +#define meshtastic_AdminMessage_FindNodeRequest_size 2 +#define meshtastic_AdminMessage_FindNodeResponse_size 2 #define meshtastic_AdminMessage_InputEvent_size 14 #define meshtastic_AdminMessage_OTAEvent_size 36 #define meshtastic_AdminMessage_size 511 diff --git a/src/mesh/generated/meshtastic/mesh.pb.cpp b/src/mesh/generated/meshtastic/mesh.pb.cpp index ac991c58057..ecef87388a8 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.cpp +++ b/src/mesh/generated/meshtastic/mesh.pb.cpp @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9.1 */ +/* Generated by nanopb-0.4.9 */ #include "meshtastic/mesh.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index ce92d81f1a3..6ef4c7ee0e3 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9.1 */ +/* Generated by nanopb-0.4.9 */ #ifndef PB_MESHTASTIC_MESHTASTIC_MESH_PB_H_INCLUDED #define PB_MESHTASTIC_MESHTASTIC_MESH_PB_H_INCLUDED @@ -1353,6 +1353,8 @@ typedef struct _meshtastic_DeviceMetadata { /* Bit field of boolean for excluded modules (bitwise OR of ExcludedModules) */ uint32_t excluded_modules; + /* Indicates that the device has a buzzer or audio output usable by the find-node command */ + bool hasBuzzer; } meshtastic_DeviceMetadata; /* A distinct set of legal modem presets shared by one or more LoRa regions. @@ -1699,7 +1701,7 @@ extern "C" { #define meshtastic_Compressed_init_default {_meshtastic_PortNum_MIN, {0, {0}}} #define meshtastic_NeighborInfo_init_default {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}} #define meshtastic_Neighbor_init_default {0, 0, 0, 0} -#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0, 0, 0} +#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0, 0, 0, 0} #define meshtastic_LoRaPresetGroup_init_default {0, {_meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN}, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0} #define meshtastic_LoRaRegionPresets_init_default {_meshtastic_Config_LoRaConfig_RegionCode_MIN, 0} #define meshtastic_LoRaRegionPresetMap_init_default {0, {meshtastic_LoRaPresetGroup_init_default, meshtastic_LoRaPresetGroup_init_default, meshtastic_LoRaPresetGroup_init_default, meshtastic_LoRaPresetGroup_init_default, meshtastic_LoRaPresetGroup_init_default, meshtastic_LoRaPresetGroup_init_default, meshtastic_LoRaPresetGroup_init_default, meshtastic_LoRaPresetGroup_init_default}, 0, {meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default, meshtastic_LoRaRegionPresets_init_default}} @@ -1737,7 +1739,7 @@ extern "C" { #define meshtastic_Compressed_init_zero {_meshtastic_PortNum_MIN, {0, {0}}} #define meshtastic_NeighborInfo_init_zero {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}} #define meshtastic_Neighbor_init_zero {0, 0, 0, 0} -#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0, 0, 0} +#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0, 0, 0, 0} #define meshtastic_LoRaPresetGroup_init_zero {0, {_meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, _meshtastic_Config_LoRaConfig_ModemPreset_MIN}, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0} #define meshtastic_LoRaRegionPresets_init_zero {_meshtastic_Config_LoRaConfig_RegionCode_MIN, 0} #define meshtastic_LoRaRegionPresetMap_init_zero {0, {meshtastic_LoRaPresetGroup_init_zero, meshtastic_LoRaPresetGroup_init_zero, meshtastic_LoRaPresetGroup_init_zero, meshtastic_LoRaPresetGroup_init_zero, meshtastic_LoRaPresetGroup_init_zero, meshtastic_LoRaPresetGroup_init_zero, meshtastic_LoRaPresetGroup_init_zero, meshtastic_LoRaPresetGroup_init_zero}, 0, {meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero, meshtastic_LoRaRegionPresets_init_zero}} @@ -1931,6 +1933,7 @@ extern "C" { #define meshtastic_DeviceMetadata_hasRemoteHardware_tag 10 #define meshtastic_DeviceMetadata_hasPKC_tag 11 #define meshtastic_DeviceMetadata_excluded_modules_tag 12 +#define meshtastic_DeviceMetadata_hasBuzzer_tag 13 #define meshtastic_LoRaPresetGroup_presets_tag 1 #define meshtastic_LoRaPresetGroup_default_preset_tag 2 #define meshtastic_LoRaPresetGroup_licensed_only_tag 3 @@ -2335,7 +2338,8 @@ X(a, STATIC, SINGULAR, UINT32, position_flags, 8) \ X(a, STATIC, SINGULAR, UENUM, hw_model, 9) \ X(a, STATIC, SINGULAR, BOOL, hasRemoteHardware, 10) \ X(a, STATIC, SINGULAR, BOOL, hasPKC, 11) \ -X(a, STATIC, SINGULAR, UINT32, excluded_modules, 12) +X(a, STATIC, SINGULAR, UINT32, excluded_modules, 12) \ +X(a, STATIC, SINGULAR, BOOL, hasBuzzer, 13) #define meshtastic_DeviceMetadata_CALLBACK NULL #define meshtastic_DeviceMetadata_DEFAULT NULL @@ -2481,7 +2485,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_ClientNotification_size 482 #define meshtastic_Compressed_size 239 #define meshtastic_Data_size 335 -#define meshtastic_DeviceMetadata_size 54 +#define meshtastic_DeviceMetadata_size 56 #define meshtastic_DuplicatedPublicKey_size 0 #define meshtastic_FileInfo_size 236 #define meshtastic_FromRadio_size 510 diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index af4e3f96989..03eff265a1b 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -6,6 +6,7 @@ #include "PowerFSM.h" #include "RTC.h" #include "SPILock.h" +#include "buzz/FindNodeBuzzer.h" #include "input/InputBroker.h" #include "meshUtils.h" #include @@ -72,6 +73,37 @@ static void writeSecret(char *buf, size_t bufsz, const char *currentVal) } } +static uint32_t effectiveButtonGpio(uint32_t gpio) +{ +#if defined(BUTTON_PIN) + return gpio ? gpio : BUTTON_PIN; +#else + return gpio; +#endif +} + +static uint32_t effectiveBuzzerGpio(uint32_t gpio) +{ +#if defined(PIN_BUZZER) + return gpio ? gpio : PIN_BUZZER; +#else + return gpio; +#endif +} + +static bool sameDeviceConfig(const meshtastic_Config_DeviceConfig ¤t, const meshtastic_Config_DeviceConfig &requested) +{ + return current.role == requested.role && + effectiveButtonGpio(current.button_gpio) == effectiveButtonGpio(requested.button_gpio) && + effectiveBuzzerGpio(current.buzzer_gpio) == effectiveBuzzerGpio(requested.buzzer_gpio) && + current.rebroadcast_mode == requested.rebroadcast_mode && + current.node_info_broadcast_secs == requested.node_info_broadcast_secs && + current.double_tap_as_button_press == requested.double_tap_as_button_press && + current.disable_triple_click == requested.disable_triple_click && + strncmp(current.tzdef, requested.tzdef, sizeof(current.tzdef)) == 0 && + current.led_heartbeat_disabled == requested.led_heartbeat_disabled && current.buzzer_mode == requested.buzzer_mode; +} + /** * @brief Handle received protobuf message * @@ -630,6 +662,11 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta handleSendInputEvent(r->send_input_event); break; } + case meshtastic_AdminMessage_find_node_request_tag: { + LOG_INFO("Client requesting find-node buzzer"); + handleFindNodeRequest(mp, r->find_node_request); + break; + } #ifdef ARCH_PORTDUINO case meshtastic_AdminMessage_exit_simulator_tag: LOG_INFO("Exiting simulator"); @@ -762,23 +799,31 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c, bool fromOthers) switch (c.which_payload_variant) { case meshtastic_Config_device_tag: { LOG_INFO("Set config: Device"); + auto requestedDevice = c.payload_variant.device; + if (config.has_device) { + requestedDevice.serial_enabled = config.device.serial_enabled; + requestedDevice.is_managed = config.device.is_managed; + } + if (config.has_device && sameDeviceConfig(config.device, requestedDevice)) { + LOG_DEBUG("Device config unchanged, skipping save"); + return; + } config.has_device = true; -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && \ +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && \ !MESHTASTIC_EXCLUDE_ACCELEROMETER - if (config.device.double_tap_as_button_press == false && c.payload_variant.device.double_tap_as_button_press == true && + if (config.device.double_tap_as_button_press == false && requestedDevice.double_tap_as_button_press == true && accelerometerThread->enabled == false) { - config.device.double_tap_as_button_press = c.payload_variant.device.double_tap_as_button_press; + config.device.double_tap_as_button_press = requestedDevice.double_tap_as_button_press; accelerometerThread->enabled = true; accelerometerThread->start(); } #endif - if (config.device.button_gpio == c.payload_variant.device.button_gpio && - config.device.buzzer_gpio == c.payload_variant.device.buzzer_gpio && - config.device.role == c.payload_variant.device.role && - config.device.rebroadcast_mode == c.payload_variant.device.rebroadcast_mode) { + if (effectiveButtonGpio(config.device.button_gpio) == effectiveButtonGpio(requestedDevice.button_gpio) && + effectiveBuzzerGpio(config.device.buzzer_gpio) == effectiveBuzzerGpio(requestedDevice.buzzer_gpio) && + config.device.role == requestedDevice.role && config.device.rebroadcast_mode == requestedDevice.rebroadcast_mode) { requiresReboot = false; } - config.device = c.payload_variant.device; + config.device = requestedDevice; if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_NONE && (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)) { @@ -788,8 +833,8 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c, bool fromOthers) sendWarning(warning); } // If we're setting router role for the first time, install its intervals - if (existingRole != c.payload_variant.device.role) { - nodeDB->installRoleDefaults(c.payload_variant.device.role); + if (existingRole != requestedDevice.role) { + nodeDB->installRoleDefaults(requestedDevice.role); changes |= SEGMENT_NODEDATABASE | SEGMENT_DEVICESTATE; // Some role defaults affect owner } if (config.device.node_info_broadcast_secs < min_node_info_broadcast_secs) { @@ -797,7 +842,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c, bool fromOthers) config.device.node_info_broadcast_secs = min_node_info_broadcast_secs; } // Router Client and Repeater deprecated; Set it to client - if (IS_ONE_OF(c.payload_variant.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT, + if (IS_ONE_OF(requestedDevice.role, meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT, meshtastic_Config_DeviceConfig_Role_REPEATER)) { config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; if (moduleConfig.store_forward.enabled && !moduleConfig.store_forward.is_server) { @@ -867,7 +912,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c, bool fromOthers) c.payload_variant.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { config.bluetooth.enabled = false; } -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && \ +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && \ !MESHTASTIC_EXCLUDE_ACCELEROMETER if (config.display.wake_on_tap_or_motion == false && c.payload_variant.display.wake_on_tap_or_motion == true && accelerometerThread->enabled == false) { @@ -1432,6 +1477,43 @@ void AdminModule::handleGetDeviceMetadata(const meshtastic_MeshPacket &req) } } +void AdminModule::handleFindNodeRequest(const meshtastic_MeshPacket &req, const meshtastic_AdminMessage_FindNodeRequest &request) +{ + meshtastic_AdminMessage r = meshtastic_AdminMessage_init_default; + r.which_payload_variant = meshtastic_AdminMessage_find_node_response_tag; + + FindNodeBuzzer::Result result = FindNodeBuzzer::Result::NoBuzzer; + if (findNodeBuzzer) { + result = request.stop ? findNodeBuzzer->stop() : findNodeBuzzer->start(); + } + + switch (result) { + case FindNodeBuzzer::Result::Started: + r.find_node_response.result = meshtastic_AdminMessage_FindNodeResponse_Result_STARTED; + LOG_INFO("Find-node buzzer started for %u seconds", FindNodeBuzzer::DEFAULT_DURATION_SECONDS); + break; + case FindNodeBuzzer::Result::Stopped: + r.find_node_response.result = meshtastic_AdminMessage_FindNodeResponse_Result_STOPPED; + LOG_INFO("Find-node buzzer stopped"); + break; + case FindNodeBuzzer::Result::BuzzerDisabled: + r.find_node_response.result = meshtastic_AdminMessage_FindNodeResponse_Result_BUZZER_DISABLED; + LOG_WARN("Find-node buzzer request rejected: buzzer disabled"); + break; + case FindNodeBuzzer::Result::NoBuzzer: + default: + r.find_node_response.result = meshtastic_AdminMessage_FindNodeResponse_Result_NO_BUZZER; + LOG_WARN("Find-node buzzer request rejected: no buzzer available"); + break; + } + + setPassKey(&r); + myReply = allocDataProtobuf(r); + if (req.pki_encrypted) { + myReply->pki_encrypted = true; + } +} + void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &req) { meshtastic_AdminMessage r = meshtastic_AdminMessage_init_default; @@ -1647,6 +1729,7 @@ bool AdminModule::messageIsResponse(const meshtastic_AdminMessage *r) r->which_payload_variant == meshtastic_AdminMessage_get_canned_message_module_messages_response_tag || r->which_payload_variant == meshtastic_AdminMessage_get_device_metadata_response_tag || r->which_payload_variant == meshtastic_AdminMessage_get_ringtone_response_tag || + r->which_payload_variant == meshtastic_AdminMessage_find_node_response_tag || r->which_payload_variant == meshtastic_AdminMessage_get_device_connection_status_response_tag || r->which_payload_variant == meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag || r->which_payload_variant == meshtastic_AdminMessage_get_ui_config_response_tag) diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index 1d5c64423bc..e7f7971afd4 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -55,6 +55,7 @@ class AdminModule : public ProtobufModule, public Obser void handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &req); void handleGetNodeRemoteHardwarePins(const meshtastic_MeshPacket &req); void handleGetDeviceUIConfig(const meshtastic_MeshPacket &req); + void handleFindNodeRequest(const meshtastic_MeshPacket &req, const meshtastic_AdminMessage_FindNodeRequest &request); /** * Setters */ @@ -93,4 +94,4 @@ static constexpr const char *publicChannelPrecisionMessage = extern AdminModule *adminModule; -void disableBluetooth(); \ No newline at end of file +void disableBluetooth(); diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 5cc94a68fca..47a5171e7c0 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -1,3 +1,4 @@ +#include "buzz/FindNodeBuzzer.h" #include "configuration.h" #if !MESHTASTIC_EXCLUDE_INPUTBROKER #include "buzz/BuzzerFeedbackThread.h" @@ -115,6 +116,7 @@ */ void setupModules() { + findNodeBuzzer = new FindNodeBuzzer(); #if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { inputBroker = new InputBroker();