1
0
forked from iarv/contact

Compare commits

..

3 Commits

Author SHA1 Message Date
pdxlocations
30402f4906 show connection errors in console 2025-07-17 00:10:17 -07:00
pdxlocations
324e0b03e7 Merge pull request #206 from pdxlocations/notifications
maybe fix aplay
2025-07-16 19:43:37 -07:00
pdxlocations
056db12911 maybe fix aplay 2025-07-16 18:46:51 -07:00
2 changed files with 69 additions and 62 deletions

View File

@@ -68,10 +68,6 @@ def prompt_region_if_unset(args: object) -> None:
def initialize_globals(args: object) -> None: def initialize_globals(args: object) -> None:
"""Initializes interface and shared globals.""" """Initializes interface and shared globals."""
interface_state.interface = initialize_interface(args)
if interface_state.interface.localNode.localConfig.lora.region == 0:
prompt_region_if_unset(args)
interface_state.myNodeNum = get_nodeNum() interface_state.myNodeNum = get_nodeNum()
ui_state.channel_list = get_channels() ui_state.channel_list = get_channels()
@@ -84,55 +80,63 @@ def initialize_globals(args: object) -> None:
def main(stdscr: curses.window) -> None: def main(stdscr: curses.window) -> None:
"""Main entry point for the curses UI.""" """Main entry point for the curses UI."""
output_capture = io.StringIO() output_capture = io.StringIO()
try: try:
with contextlib.redirect_stdout(output_capture), contextlib.redirect_stderr(output_capture): setup_colors()
setup_colors() draw_splash(stdscr)
draw_splash(stdscr)
args = setup_parser().parse_args() args = setup_parser().parse_args()
if getattr(args, "settings", False): if getattr(args, "settings", False):
subprocess.run([sys.executable, "-m", "contact.settings"], check=True) subprocess.run([sys.executable, "-m", "contact.settings"], check=True)
return return
logging.info("Initializing interface...") logging.info("Initializing interface...")
with app_state.lock: with app_state.lock:
initialize_globals(args) interface_state.interface = initialize_interface(args)
logging.info("Starting main UI")
main_ui(stdscr) if interface_state.interface.localNode.localConfig.lora.region == 0:
prompt_region_if_unset(args)
except Exception as e: initialize_globals(args)
console_output = output_capture.getvalue() logging.info("Starting main UI")
logging.error("Uncaught exception: %s", e)
logging.error("Traceback: %s", traceback.format_exc()) try:
logging.error("Console output:\n%s", console_output) with contextlib.redirect_stdout(output_capture), contextlib.redirect_stderr(output_capture):
main_ui(stdscr)
except Exception:
console_output = output_capture.getvalue()
logging.error("Uncaught exception inside main_ui")
logging.error("Traceback:\n%s", traceback.format_exc())
logging.error("Console output:\n%s", console_output)
return
except Exception:
raise raise
def start() -> None: def start() -> None:
"""Launch curses wrapper and redirect logs to file.""" """Entry point for the application."""
if "--help" in sys.argv or "-h" in sys.argv: if "--help" in sys.argv or "-h" in sys.argv:
setup_parser().print_help() setup_parser().print_help()
sys.exit(0) sys.exit(0)
with open(config.log_file_path, "a", buffering=1) as log_f: try:
sys.stdout = log_f curses.wrapper(main)
sys.stderr = log_f except KeyboardInterrupt:
logging.info("User exited with Ctrl+C")
with contextlib.redirect_stdout(log_f), contextlib.redirect_stderr(log_f): sys.exit(0)
try: except Exception as e:
curses.wrapper(main) logging.critical("Fatal error", exc_info=True)
except KeyboardInterrupt: try:
logging.info("User exited with Ctrl+C") curses.endwin()
sys.exit(0) except Exception:
except Exception as e: pass
logging.error("Fatal error: %s", e) print("Fatal error:", e)
logging.error("Traceback: %s", traceback.format_exc()) traceback.print_exc()
sys.exit(1) sys.exit(1)
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -6,8 +6,8 @@ import subprocess
from typing import Any, Dict from typing import Any, Dict
from contact.utilities.utils import ( from contact.utilities.utils import (
refresh_node_list, refresh_node_list,
add_new_message, add_new_message,
) )
from contact.ui.contact_ui import ( from contact.ui.contact_ui import (
draw_packetlog_win, draw_packetlog_win,
@@ -30,40 +30,43 @@ from contact.utilities.singleton import ui_state, interface_state, app_state
def play_sound(): def play_sound():
try: try:
system = platform.system() system = platform.system()
sound_path = "" sound_path = None
executable = "" executable = None
if system == "Darwin": #macOS if system == "Darwin": # macOS
sound_path = "/System/Library/Sounds/Ping.aiff" sound_path = "/System/Library/Sounds/Ping.aiff"
executable = "afplay" executable = "afplay"
elif system == "Linux":
sound_path = "/usr/share/sounds/freedesktop/stereo/complete.oga"
if(shutil.which("paplay")):
executable = "paplay"
else:
executable = "aplay"
if executable != "" and sound_path != "": elif system == "Linux":
if os.path.exists(sound_path): ogg_path = "/usr/share/sounds/freedesktop/stereo/complete.oga"
if shutil.which(executable): wav_path = "/usr/share/sounds/alsa/Front_Center.wav" # common fallback
subprocess.run([executable, sound_path], check=True,
stdout=subprocess.DEVNULL, stderr = subprocess.DEVNULL) if shutil.which("paplay") and os.path.exists(ogg_path):
return executable = "paplay"
else: sound_path = ogg_path
logging.warning("No sound player found (afplay/paplay/aplay)") 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: else:
logging.warning(f"Sound file not found: {sound_path}") logging.warning("No suitable sound player or sound file found on Linux")
if executable and sound_path:
cmd = [executable, sound_path]
if executable == "ffplay":
cmd = [executable, "-nodisp", "-autoexit", sound_path]
subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
logging.error(f"Sound playback failed: {e}") logging.error(f"Sound playback failed: {e}")
except Exception as e: except Exception as e:
logging.error(f"Unexpected error: {e}") logging.error(f"Unexpected error: {e}")
# Final fallback: terminal beep
print("\a")
def on_receive(packet: Dict[str, Any], interface: Any) -> None: def on_receive(packet: Dict[str, Any], interface: Any) -> None:
""" """
Handles an incoming packet from a Meshtastic interface. Handles an incoming packet from a Meshtastic interface.