From b1b9f22203820c36e3c483f2249c7a3edd06f5f9 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Fri, 24 Jul 2026 23:12:21 -0700 Subject: [PATCH] Add notification sound feature and update configuration --- README.md | 8 ++++++ contact/localisations/en.ini | 2 +- contact/message_handlers/rx_handler.py | 33 ++++++++----------------- contact/sounds/alert.mp3 | Bin 0 -> 50155 bytes contact/ui/default_config.py | 11 ++++++++- contact/ui/user_config.py | 16 +++++++++++- 6 files changed, 44 insertions(+), 26 deletions(-) create mode 100644 contact/sounds/alert.mp3 diff --git a/README.md b/README.md index 9c1543f..448be15 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,14 @@ All messages will saved in a SQLite DB and restored upon relaunch of the app. Y By navigating to Settings -> App Settings, you may customize your UI's icons, colors, and more! +### Notification sounds + +Add audio files to Contact's `contact/sounds/` folder, then choose one in Settings → App Settings → Notification sound. `alert.mp3` is the default selection; choose `None` to disable notification audio. Supported file types are MP3, WAV, OGG, AIFF, and FLAC. + +### Remote administration + +With the Nodes pane selected, press `` ` `` or `F12` and choose **Remote admin** for the highlighted node. Contact requests the node's settings through Meshtastic Remote Admin and displays an error if the node does not authorize your public key. Remote App Settings are intentionally unavailable because they apply only to the local Contact client. + For smaller displays you may wish to enable `single_pane_mode`: Screenshot 2025-08-22 at 11 15 54 PM diff --git a/contact/localisations/en.ini b/contact/localisations/en.ini index 38ceadc..b7f47d4 100644 --- a/contact/localisations/en.ini +++ b/contact/localisations/en.ini @@ -112,7 +112,7 @@ language, "Language", "UI language for labels and help text." message_prefix, "Message prefix", "" sent_message_prefix, "Sent message prefix", "" notification_symbol, "Notification symbol", "" -notification_sound, "Notification sound", "" +notification_sound, "Notification sound", "Select a sound file from Contact's sounds folder, or None to disable notification audio." ack_implicit_str, "ACK (implicit)", "" ack_str, "ACK", "" nak_str, "NAK", "" diff --git a/contact/message_handlers/rx_handler.py b/contact/message_handlers/rx_handler.py index 44c8b27..6ffb1e5 100644 --- a/contact/message_handlers/rx_handler.py +++ b/contact/message_handlers/rx_handler.py @@ -66,29 +66,15 @@ from contact.message_handlers.bot_handler import bot_respond def play_sound(): try: - system = platform.system() - sound_path = None - executable = None + selected_sound = str(getattr(config, "notification_sound", "None")) + if selected_sound.casefold() in {"none", "false", ""}: + return + sound_path = os.path.join(config.parent_dir, "sounds", selected_sound) + if not os.path.isfile(sound_path): + logging.warning("Configured notification sound is unavailable: %s", sound_path) + return - if system == "Darwin": # macOS - sound_path = "/System/Library/Sounds/Ping.aiff" - executable = "afplay" - - elif system == "Linux": - ogg_path = "/usr/share/sounds/freedesktop/stereo/complete.oga" - wav_path = "/usr/share/sounds/alsa/Front_Center.wav" # common fallback - - if shutil.which("paplay") and os.path.exists(ogg_path): - executable = "paplay" - sound_path = ogg_path - elif shutil.which("ffplay") and os.path.exists(ogg_path): - executable = "ffplay" - sound_path = ogg_path - elif shutil.which("aplay") and os.path.exists(wav_path): - executable = "aplay" - sound_path = wav_path - else: - logging.warning("No suitable sound player or sound file found on Linux") + executable = "afplay" if platform.system() == "Darwin" else shutil.which("ffplay") or shutil.which("mpg123") if executable and sound_path: cmd = [executable, sound_path] @@ -97,6 +83,7 @@ def play_sound(): subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return + logging.warning("No suitable sound player found for notification sound") except subprocess.CalledProcessError as e: logging.error(f"Sound playback failed: {e}") @@ -144,7 +131,7 @@ def on_receive(packet: Dict[str, Any], interface: Any) -> None: hops = hop_start - hop_limit - if config.notification_sound == "True": + if str(config.notification_sound).casefold() not in {"none", "false", ""}: schedule_notification_sound() message_bytes = packet["decoded"]["payload"] diff --git a/contact/sounds/alert.mp3 b/contact/sounds/alert.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..fc30cfd7b4a6806e65ac5bd11a224026df0e32a8 GIT binary patch literal 50155 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 Dict[str, object]: "message_prefix": ">>", "sent_message_prefix": ">> Sent", "notification_symbol": "*", - "notification_sound": "True", + "notification_sound": "alert.mp3", "ack_implicit_str": "[◌]", "ack_str": "[✓]", "nak_str": "[x]", @@ -264,6 +264,15 @@ def initialize_config() -> Dict[str, object]: # Check and add missing variables updated = update_dict(default_config_variables, loaded_config) + # Migrate the legacy boolean notification preference to the file-based + # sound selection introduced in 1.5.12. + if loaded_config.get("notification_sound") == "True": + loaded_config["notification_sound"] = "alert.mp3" + updated = True + elif loaded_config.get("notification_sound") == "False": + loaded_config["notification_sound"] = "None" + updated = True + # Update the JSON file if any variables were missing if updated: formatted_json = format_json_single_line_arrays(loaded_config) diff --git a/contact/ui/user_config.py b/contact/ui/user_config.py index ad04a2e..b0336c7 100644 --- a/contact/ui/user_config.py +++ b/contact/ui/user_config.py @@ -115,9 +115,23 @@ def edit_color_pair(key: str, display_label: str, current_value: List[str]) -> L def edit_value(key: str, display_label: str, current_value: str) -> str: - if key in ("notification_sound", "single_pane_mode", "enabled"): + if key in ("single_pane_mode", "enabled"): return get_list_input(display_label, current_value, ["True", "False"]) + if key == "notification_sound": + sounds_dir = os.path.join(config.parent_dir, "sounds") + try: + sound_options = sorted( + filename for filename in os.listdir(sounds_dir) + if filename.lower().endswith((".mp3", ".wav", ".ogg", ".aiff", ".flac")) + ) + except OSError: + sound_options = [] + sound_options = ["None"] + sound_options + if current_value not in sound_options: + sound_options.append(current_value) + return get_list_input(display_label, current_value, sound_options) + w = get_effective_width() height = 10 input_width = w - 16 # Allow space for "New Value: "