From 6d204581ce520a2b0d6815db0dda326f9a94a63f Mon Sep 17 00:00:00 2001 From: vidplace7 Date: Tue, 25 Mar 2025 08:58:11 -0400 Subject: [PATCH 01/13] Package with poetry --- .gitignore | 3 +- globals.py => mtcontact/globals.py | 0 .../localisations}/en.ini | 0 main.py => mtcontact/main.py | 31 ++++++++++--------- .../message_handlers}/rx_handler.py | 10 +++--- .../message_handlers}/tx_handler.py | 6 ++-- settings.py => mtcontact/settings.py | 14 ++++----- {ui => mtcontact/ui}/colors.py | 2 +- {ui => mtcontact/ui}/control_ui.py | 23 ++++++++------ {ui => mtcontact/ui}/curses_ui.py | 18 +++++------ {ui => mtcontact/ui}/default_config.py | 0 {ui => mtcontact/ui}/dialog.py | 2 +- {ui => mtcontact/ui}/menus.py | 0 {ui => mtcontact/ui}/splash.py | 2 +- {ui => mtcontact/ui}/user_config.py | 6 ++-- .../utilities}/arg_parser.py | 0 .../utilities}/config_io.py | 0 .../utilities}/control_utils.py | 0 .../utilities}/db_handler.py | 6 ++-- .../utilities}/input_handlers.py | 2 +- .../utilities}/interfaces.py | 2 +- .../utilities}/save_to_radio.py | 0 {utilities => mtcontact/utilities}/utils.py | 4 +-- pyproject.toml | 21 +++++++++++++ 24 files changed, 90 insertions(+), 62 deletions(-) rename globals.py => mtcontact/globals.py (100%) rename {localisations => mtcontact/localisations}/en.ini (100%) rename main.py => mtcontact/main.py (81%) rename {message_handlers => mtcontact/message_handlers}/rx_handler.py (91%) rename {message_handlers => mtcontact/message_handlers}/tx_handler.py (97%) rename settings.py => mtcontact/settings.py (83%) rename {ui => mtcontact/ui}/colors.py (95%) rename {ui => mtcontact/ui}/control_ui.py (97%) rename {ui => mtcontact/ui}/curses_ui.py (97%) rename {ui => mtcontact/ui}/default_config.py (100%) rename {ui => mtcontact/ui}/dialog.py (96%) rename {ui => mtcontact/ui}/menus.py (100%) rename {ui => mtcontact/ui}/splash.py (92%) rename {ui => mtcontact/ui}/user_config.py (98%) rename {utilities => mtcontact/utilities}/arg_parser.py (100%) rename {utilities => mtcontact/utilities}/config_io.py (100%) rename {utilities => mtcontact/utilities}/control_utils.py (100%) rename {utilities => mtcontact/utilities}/db_handler.py (99%) rename {utilities => mtcontact/utilities}/input_handlers.py (99%) rename {utilities => mtcontact/utilities}/interfaces.py (96%) rename {utilities => mtcontact/utilities}/save_to_radio.py (100%) rename {utilities => mtcontact/utilities}/utils.py (97%) create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore index 5bceb25..1d30efb 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ client.db client.log settings.log config.json -default_config.log \ No newline at end of file +default_config.log +dist/ \ No newline at end of file diff --git a/globals.py b/mtcontact/globals.py similarity index 100% rename from globals.py rename to mtcontact/globals.py diff --git a/localisations/en.ini b/mtcontact/localisations/en.ini similarity index 100% rename from localisations/en.ini rename to mtcontact/localisations/en.ini diff --git a/main.py b/mtcontact/main.py similarity index 81% rename from main.py rename to mtcontact/main.py index c0028c3..51f6fd2 100644 --- a/main.py +++ b/mtcontact/main.py @@ -18,18 +18,18 @@ import logging import traceback import threading -from utilities.db_handler import init_nodedb, load_messages_from_db -from message_handlers.rx_handler import on_receive -from settings import set_region -from ui.curses_ui import main_ui -from ui.colors import setup_colors -from ui.splash import draw_splash -import ui.default_config as config -from utilities.arg_parser import setup_parser -from utilities.interfaces import initialize_interface -from utilities.input_handlers import get_list_input -from utilities.utils import get_channels, get_node_list, get_nodeNum -import globals +from mtcontact.utilities.db_handler import init_nodedb, load_messages_from_db +from mtcontact.message_handlers.rx_handler import on_receive +from mtcontact.settings import set_region +from mtcontact.ui.curses_ui import main_ui +from mtcontact.ui.colors import setup_colors +from mtcontact.ui.splash import draw_splash +import mtcontact.ui.default_config as config +from mtcontact.utilities.arg_parser import setup_parser +from mtcontact.utilities.interfaces import initialize_interface +from mtcontact.utilities.input_handlers import get_list_input +from mtcontact.utilities.utils import get_channels, get_node_list, get_nodeNum +import mtcontact.globals as globals # Set ncurses compatibility settings os.environ["NCURSES_NO_UTF8_ACS"] = "1" @@ -87,7 +87,7 @@ def main(stdscr): logging.error("Console output before crash:\n%s", console_output) raise # Re-raise only unexpected errors -if __name__ == "__main__": +def start(): log_file = config.log_file_path log_f = open(log_file, "a", buffering=1) # Enable line-buffering for immediate log writes @@ -103,4 +103,7 @@ if __name__ == "__main__": except Exception as e: logging.error("Fatal error in curses wrapper: %s", e) logging.error("Traceback: %s", traceback.format_exc()) - sys.exit(1) # Exit with an error code \ No newline at end of file + sys.exit(1) # Exit with an error code + +if __name__ == "__main__": + start() diff --git a/message_handlers/rx_handler.py b/mtcontact/message_handlers/rx_handler.py similarity index 91% rename from message_handlers/rx_handler.py rename to mtcontact/message_handlers/rx_handler.py index c95f0c5..b260587 100644 --- a/message_handlers/rx_handler.py +++ b/mtcontact/message_handlers/rx_handler.py @@ -1,11 +1,11 @@ import logging import time -from utilities.utils import refresh_node_list +from mtcontact.utilities.utils import refresh_node_list from datetime import datetime -from ui.curses_ui import draw_packetlog_win, draw_node_list, draw_messages_window, draw_channel_list, add_notification -from utilities.db_handler import save_message_to_db, maybe_store_nodeinfo_in_db, get_name_from_database, update_node_info_in_db -import ui.default_config as config -import globals +from mtcontact.ui.curses_ui import draw_packetlog_win, draw_node_list, draw_messages_window, draw_channel_list, add_notification +from mtcontact.utilities.db_handler import save_message_to_db, maybe_store_nodeinfo_in_db, get_name_from_database, update_node_info_in_db +import mtcontact.ui.default_config as config +import mtcontact.globals as globals from datetime import datetime diff --git a/message_handlers/tx_handler.py b/mtcontact/message_handlers/tx_handler.py similarity index 97% rename from message_handlers/tx_handler.py rename to mtcontact/message_handlers/tx_handler.py index 0b72fc9..e0772c5 100644 --- a/message_handlers/tx_handler.py +++ b/mtcontact/message_handlers/tx_handler.py @@ -3,9 +3,9 @@ import google.protobuf.json_format from meshtastic import BROADCAST_NUM from meshtastic.protobuf import mesh_pb2, portnums_pb2 -from utilities.db_handler import save_message_to_db, update_ack_nak, get_name_from_database, is_chat_archived, update_node_info_in_db -import ui.default_config as config -import globals +from mtcontact.utilities.db_handler import save_message_to_db, update_ack_nak, get_name_from_database, is_chat_archived, update_node_info_in_db +import mtcontact.ui.default_config as config +import mtcontact.globals as globals ack_naks = {} diff --git a/settings.py b/mtcontact/settings.py similarity index 83% rename from settings.py rename to mtcontact/settings.py index 5be03b4..cf6593c 100644 --- a/settings.py +++ b/mtcontact/settings.py @@ -5,13 +5,13 @@ import logging import sys import traceback -import ui.default_config as config -from utilities.input_handlers import get_list_input -from ui.colors import setup_colors -from ui.splash import draw_splash -from ui.control_ui import set_region, settings_menu -from utilities.arg_parser import setup_parser -from utilities.interfaces import initialize_interface +import mtcontact.ui.default_config as config +from mtcontact.utilities.input_handlers import get_list_input +from mtcontact.ui.colors import setup_colors +from mtcontact.ui.splash import draw_splash +from mtcontact.ui.control_ui import set_region, settings_menu +from mtcontact.utilities.arg_parser import setup_parser +from mtcontact.utilities.interfaces import initialize_interface def main(stdscr): diff --git a/ui/colors.py b/mtcontact/ui/colors.py similarity index 95% rename from ui/colors.py rename to mtcontact/ui/colors.py index 8016542..3891073 100644 --- a/ui/colors.py +++ b/mtcontact/ui/colors.py @@ -1,5 +1,5 @@ import curses -import ui.default_config as config +import mtcontact.ui.default_config as config COLOR_MAP = { "black": curses.COLOR_BLACK, diff --git a/ui/control_ui.py b/mtcontact/ui/control_ui.py similarity index 97% rename from ui/control_ui.py rename to mtcontact/ui/control_ui.py index c89a1a6..00630cf 100644 --- a/ui/control_ui.py +++ b/mtcontact/ui/control_ui.py @@ -5,14 +5,16 @@ import os import re import sys -from utilities.save_to_radio import save_changes -from utilities.config_io import config_export, config_import -from utilities.input_handlers import get_repeated_input, get_text_input, get_fixed32_input, get_list_input, get_admin_key_input -from ui.menus import generate_menu_from_protobuf -from ui.colors import get_color -from ui.dialog import dialog -from utilities.control_utils import parse_ini_file, transform_menu_path -from ui.user_config import json_editor +from mtcontact.utilities.save_to_radio import save_changes +from mtcontact.utilities.config_io import config_export, config_import +from mtcontact.utilities.input_handlers import get_repeated_input, get_text_input, get_fixed32_input, get_list_input, get_admin_key_input +from mtcontact.ui.menus import generate_menu_from_protobuf +from mtcontact.ui.colors import get_color +from mtcontact.ui.dialog import dialog +from mtcontact.utilities.control_utils import parse_ini_file, transform_menu_path +from mtcontact.ui.user_config import json_editor + +import mtcontact.localisations # Constants width = 80 @@ -27,8 +29,9 @@ parent_dir = os.path.abspath(os.path.join(script_dir, os.pardir)) # Paths locals_dir = os.path.dirname(os.path.abspath(sys.argv[0])) # Current script directory -translation_file = os.path.join(locals_dir, "localisations", "en.ini") -config_folder = os.path.join(parent_dir, "node-configs") +translation_file = os.path.join(parent_dir, "localisations", "en.ini") + +config_folder = os.path.join(locals_dir, "node-configs") # Load translations field_mapping, help_text = parse_ini_file(translation_file) diff --git a/ui/curses_ui.py b/mtcontact/ui/curses_ui.py similarity index 97% rename from ui/curses_ui.py rename to mtcontact/ui/curses_ui.py index 7547cfd..ca2f559 100644 --- a/ui/curses_ui.py +++ b/mtcontact/ui/curses_ui.py @@ -2,14 +2,14 @@ import curses import textwrap import logging import traceback -from utilities.utils import get_channels, get_readable_duration, get_time_ago, refresh_node_list -from settings import settings_menu -from message_handlers.tx_handler import send_message, send_traceroute -from ui.colors import setup_colors, get_color -from utilities.db_handler import get_name_from_database, update_node_info_in_db, is_chat_archived -import ui.default_config as config -import ui.dialog -import globals +from mtcontact.utilities.utils import get_channels, get_readable_duration, get_time_ago, refresh_node_list +from mtcontact.settings import settings_menu +from mtcontact.message_handlers.tx_handler import send_message, send_traceroute +from mtcontact.ui.colors import setup_colors, get_color +from mtcontact.utilities.db_handler import get_name_from_database, update_node_info_in_db, is_chat_archived +import mtcontact.ui.default_config as config +import mtcontact.ui.dialog +import mtcontact.globals as globals def handle_resize(stdscr, firstrun): global messages_pad, messages_win, nodes_pad, nodes_win, channel_pad, channel_win, function_win, packetlog_win, entry_win @@ -212,7 +212,7 @@ def main_ui(stdscr): elif char == chr(20): send_traceroute() curses.curs_set(0) # Hide cursor - ui.dialog.dialog(stdscr, "Traceroute Sent", "Results will appear in messages window.\nNote: Traceroute is limited to once every 30 seconds.") + mtcontact.ui.dialog.dialog(stdscr, "Traceroute Sent", "Results will appear in messages window.\nNote: Traceroute is limited to once every 30 seconds.") curses.curs_set(1) # Show cursor again handle_resize(stdscr, False) diff --git a/ui/default_config.py b/mtcontact/ui/default_config.py similarity index 100% rename from ui/default_config.py rename to mtcontact/ui/default_config.py diff --git a/ui/dialog.py b/mtcontact/ui/dialog.py similarity index 96% rename from ui/dialog.py rename to mtcontact/ui/dialog.py index 2d9ed67..c5a4c7a 100644 --- a/ui/dialog.py +++ b/mtcontact/ui/dialog.py @@ -1,5 +1,5 @@ import curses -from ui.colors import get_color +from mtcontact.ui.colors import get_color def dialog(stdscr, title, message): height, width = stdscr.getmaxyx() diff --git a/ui/menus.py b/mtcontact/ui/menus.py similarity index 100% rename from ui/menus.py rename to mtcontact/ui/menus.py diff --git a/ui/splash.py b/mtcontact/ui/splash.py similarity index 92% rename from ui/splash.py rename to mtcontact/ui/splash.py index 08fe2e5..785b5da 100644 --- a/ui/splash.py +++ b/mtcontact/ui/splash.py @@ -1,5 +1,5 @@ import curses -from ui.colors import get_color +from mtcontact.ui.colors import get_color def draw_splash(stdscr): curses.curs_set(0) diff --git a/ui/user_config.py b/mtcontact/ui/user_config.py similarity index 98% rename from ui/user_config.py rename to mtcontact/ui/user_config.py index 32aae7f..dc10db8 100644 --- a/ui/user_config.py +++ b/mtcontact/ui/user_config.py @@ -1,9 +1,9 @@ import os import json import curses -from ui.colors import get_color, setup_colors, COLOR_MAP -from ui.default_config import format_json_single_line_arrays, loaded_config -from utilities.input_handlers import get_list_input +from mtcontact.ui.colors import get_color, setup_colors, COLOR_MAP +from mtcontact.ui.default_config import format_json_single_line_arrays, loaded_config +from mtcontact.utilities.input_handlers import get_list_input width = 60 save_option_text = "Save Changes" diff --git a/utilities/arg_parser.py b/mtcontact/utilities/arg_parser.py similarity index 100% rename from utilities/arg_parser.py rename to mtcontact/utilities/arg_parser.py diff --git a/utilities/config_io.py b/mtcontact/utilities/config_io.py similarity index 100% rename from utilities/config_io.py rename to mtcontact/utilities/config_io.py diff --git a/utilities/control_utils.py b/mtcontact/utilities/control_utils.py similarity index 100% rename from utilities/control_utils.py rename to mtcontact/utilities/control_utils.py diff --git a/utilities/db_handler.py b/mtcontact/utilities/db_handler.py similarity index 99% rename from utilities/db_handler.py rename to mtcontact/utilities/db_handler.py index c471fb7..5a483aa 100644 --- a/utilities/db_handler.py +++ b/mtcontact/utilities/db_handler.py @@ -3,9 +3,9 @@ import time import logging from datetime import datetime -from utilities.utils import decimal_to_hex -import ui.default_config as config -import globals +from mtcontact.utilities.utils import decimal_to_hex +import mtcontact.ui.default_config as config +import mtcontact.globals as globals def get_table_name(channel): # Construct the table name diff --git a/utilities/input_handlers.py b/mtcontact/utilities/input_handlers.py similarity index 99% rename from utilities/input_handlers.py rename to mtcontact/utilities/input_handlers.py index 34b41ae..2c0ed34 100644 --- a/utilities/input_handlers.py +++ b/mtcontact/utilities/input_handlers.py @@ -3,7 +3,7 @@ import binascii import curses import ipaddress import re -from ui.colors import get_color +from mtcontact.ui.colors import get_color def wrap_text(text, wrap_width): """Wraps text while preserving spaces and breaking long words.""" diff --git a/utilities/interfaces.py b/mtcontact/utilities/interfaces.py similarity index 96% rename from utilities/interfaces.py rename to mtcontact/utilities/interfaces.py index 66c6e7b..03aeace 100644 --- a/utilities/interfaces.py +++ b/mtcontact/utilities/interfaces.py @@ -1,6 +1,6 @@ import logging import meshtastic.serial_interface, meshtastic.tcp_interface, meshtastic.ble_interface -import globals +import mtcontact.globals as globals def initialize_interface(args): try: diff --git a/utilities/save_to_radio.py b/mtcontact/utilities/save_to_radio.py similarity index 100% rename from utilities/save_to_radio.py rename to mtcontact/utilities/save_to_radio.py diff --git a/utilities/utils.py b/mtcontact/utilities/utils.py similarity index 97% rename from utilities/utils.py rename to mtcontact/utilities/utils.py index ce8d567..1997c36 100644 --- a/utilities/utils.py +++ b/mtcontact/utilities/utils.py @@ -1,7 +1,7 @@ -import globals +import mtcontact.globals as globals import datetime from meshtastic.protobuf import config_pb2 -import ui.default_config as config +import mtcontact.ui.default_config as config def get_channels(): """Retrieve channels from the node and update globals.channel_list and globals.all_messages.""" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0a20233 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,21 @@ +[project] +name = "mtcontact" +version = "1.2.3" +description = "This Python curses client for Meshtastic is a terminal-based client designed to manage device settings, enable mesh chat communication, and handle configuration backups and restores." +authors = [ + {name = "pdxlocations",email = "you@example.com"} +] +license = "GPL-3.0-only" +readme = "README.md" +requires-python = ">=3.9" +dependencies = [ + "meshtastic (>=2.6.0,<3.0.0)" +] + + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +mtcontact = "mtcontact.main:start" From 3df012dd69c84dd4eadc02f00cecac25d13961a7 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Wed, 26 Mar 2025 21:59:33 -0700 Subject: [PATCH 02/13] add launch.json --- .vscode/launch.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..b70e770 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.1.0", + "configurations": [ + { + "name": "Python Debugger: Current File", + "type": "debugpy", + "request": "launch", + "cwd": "${workspaceFolder}", + "module": "mtcontact.main", + "args": [] + } + ] +} \ No newline at end of file From 66a9954149e7bb9de863b6e9e75e24a2cdd4b061 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Wed, 26 Mar 2025 22:27:03 -0700 Subject: [PATCH 03/13] mtcontact to mcontact --- .vscode/launch.json | 2 +- mtcontact/main.py | 24 ++++++++++++------------ mtcontact/message_handlers/rx_handler.py | 10 +++++----- mtcontact/message_handlers/tx_handler.py | 6 +++--- mtcontact/settings.py | 14 +++++++------- mtcontact/ui/colors.py | 2 +- mtcontact/ui/control_ui.py | 18 +++++++++--------- mtcontact/ui/curses_ui.py | 18 +++++++++--------- mtcontact/ui/dialog.py | 2 +- mtcontact/ui/splash.py | 2 +- mtcontact/ui/user_config.py | 6 +++--- mtcontact/utilities/db_handler.py | 6 +++--- mtcontact/utilities/input_handlers.py | 2 +- mtcontact/utilities/interfaces.py | 2 +- mtcontact/utilities/utils.py | 4 ++-- pyproject.toml | 4 ++-- 16 files changed, 61 insertions(+), 61 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index b70e770..f10e079 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "type": "debugpy", "request": "launch", "cwd": "${workspaceFolder}", - "module": "mtcontact.main", + "module": "mcontact.main", "args": [] } ] diff --git a/mtcontact/main.py b/mtcontact/main.py index 51f6fd2..4851967 100644 --- a/mtcontact/main.py +++ b/mtcontact/main.py @@ -18,18 +18,18 @@ import logging import traceback import threading -from mtcontact.utilities.db_handler import init_nodedb, load_messages_from_db -from mtcontact.message_handlers.rx_handler import on_receive -from mtcontact.settings import set_region -from mtcontact.ui.curses_ui import main_ui -from mtcontact.ui.colors import setup_colors -from mtcontact.ui.splash import draw_splash -import mtcontact.ui.default_config as config -from mtcontact.utilities.arg_parser import setup_parser -from mtcontact.utilities.interfaces import initialize_interface -from mtcontact.utilities.input_handlers import get_list_input -from mtcontact.utilities.utils import get_channels, get_node_list, get_nodeNum -import mtcontact.globals as globals +from mcontact.utilities.db_handler import init_nodedb, load_messages_from_db +from mcontact.message_handlers.rx_handler import on_receive +from mcontact.settings import set_region +from mcontact.ui.curses_ui import main_ui +from mcontact.ui.colors import setup_colors +from mcontact.ui.splash import draw_splash +import mcontact.ui.default_config as config +from mcontact.utilities.arg_parser import setup_parser +from mcontact.utilities.interfaces import initialize_interface +from mcontact.utilities.input_handlers import get_list_input +from mcontact.utilities.utils import get_channels, get_node_list, get_nodeNum +import mcontact.globals as globals # Set ncurses compatibility settings os.environ["NCURSES_NO_UTF8_ACS"] = "1" diff --git a/mtcontact/message_handlers/rx_handler.py b/mtcontact/message_handlers/rx_handler.py index b260587..f461f62 100644 --- a/mtcontact/message_handlers/rx_handler.py +++ b/mtcontact/message_handlers/rx_handler.py @@ -1,11 +1,11 @@ import logging import time -from mtcontact.utilities.utils import refresh_node_list +from mcontact.utilities.utils import refresh_node_list from datetime import datetime -from mtcontact.ui.curses_ui import draw_packetlog_win, draw_node_list, draw_messages_window, draw_channel_list, add_notification -from mtcontact.utilities.db_handler import save_message_to_db, maybe_store_nodeinfo_in_db, get_name_from_database, update_node_info_in_db -import mtcontact.ui.default_config as config -import mtcontact.globals as globals +from mcontact.ui.curses_ui import draw_packetlog_win, draw_node_list, draw_messages_window, draw_channel_list, add_notification +from mcontact.utilities.db_handler import save_message_to_db, maybe_store_nodeinfo_in_db, get_name_from_database, update_node_info_in_db +import mcontact.ui.default_config as config +import mcontact.globals as globals from datetime import datetime diff --git a/mtcontact/message_handlers/tx_handler.py b/mtcontact/message_handlers/tx_handler.py index e0772c5..0c0cb2b 100644 --- a/mtcontact/message_handlers/tx_handler.py +++ b/mtcontact/message_handlers/tx_handler.py @@ -3,9 +3,9 @@ import google.protobuf.json_format from meshtastic import BROADCAST_NUM from meshtastic.protobuf import mesh_pb2, portnums_pb2 -from mtcontact.utilities.db_handler import save_message_to_db, update_ack_nak, get_name_from_database, is_chat_archived, update_node_info_in_db -import mtcontact.ui.default_config as config -import mtcontact.globals as globals +from mcontact.utilities.db_handler import save_message_to_db, update_ack_nak, get_name_from_database, is_chat_archived, update_node_info_in_db +import mcontact.ui.default_config as config +import mcontact.globals as globals ack_naks = {} diff --git a/mtcontact/settings.py b/mtcontact/settings.py index cf6593c..2ba7f94 100644 --- a/mtcontact/settings.py +++ b/mtcontact/settings.py @@ -5,13 +5,13 @@ import logging import sys import traceback -import mtcontact.ui.default_config as config -from mtcontact.utilities.input_handlers import get_list_input -from mtcontact.ui.colors import setup_colors -from mtcontact.ui.splash import draw_splash -from mtcontact.ui.control_ui import set_region, settings_menu -from mtcontact.utilities.arg_parser import setup_parser -from mtcontact.utilities.interfaces import initialize_interface +import mcontact.ui.default_config as config +from mcontact.utilities.input_handlers import get_list_input +from mcontact.ui.colors import setup_colors +from mcontact.ui.splash import draw_splash +from mcontact.ui.control_ui import set_region, settings_menu +from mcontact.utilities.arg_parser import setup_parser +from mcontact.utilities.interfaces import initialize_interface def main(stdscr): diff --git a/mtcontact/ui/colors.py b/mtcontact/ui/colors.py index 3891073..3c579d6 100644 --- a/mtcontact/ui/colors.py +++ b/mtcontact/ui/colors.py @@ -1,5 +1,5 @@ import curses -import mtcontact.ui.default_config as config +import mcontact.ui.default_config as config COLOR_MAP = { "black": curses.COLOR_BLACK, diff --git a/mtcontact/ui/control_ui.py b/mtcontact/ui/control_ui.py index 00630cf..1672771 100644 --- a/mtcontact/ui/control_ui.py +++ b/mtcontact/ui/control_ui.py @@ -5,16 +5,16 @@ import os import re import sys -from mtcontact.utilities.save_to_radio import save_changes -from mtcontact.utilities.config_io import config_export, config_import -from mtcontact.utilities.input_handlers import get_repeated_input, get_text_input, get_fixed32_input, get_list_input, get_admin_key_input -from mtcontact.ui.menus import generate_menu_from_protobuf -from mtcontact.ui.colors import get_color -from mtcontact.ui.dialog import dialog -from mtcontact.utilities.control_utils import parse_ini_file, transform_menu_path -from mtcontact.ui.user_config import json_editor +from mcontact.utilities.save_to_radio import save_changes +from mcontact.utilities.config_io import config_export, config_import +from mcontact.utilities.input_handlers import get_repeated_input, get_text_input, get_fixed32_input, get_list_input, get_admin_key_input +from mcontact.ui.menus import generate_menu_from_protobuf +from mcontact.ui.colors import get_color +from mcontact.ui.dialog import dialog +from mcontact.utilities.control_utils import parse_ini_file, transform_menu_path +from mcontact.ui.user_config import json_editor -import mtcontact.localisations +import mcontact.localisations # Constants width = 80 diff --git a/mtcontact/ui/curses_ui.py b/mtcontact/ui/curses_ui.py index ca2f559..b27808f 100644 --- a/mtcontact/ui/curses_ui.py +++ b/mtcontact/ui/curses_ui.py @@ -2,14 +2,14 @@ import curses import textwrap import logging import traceback -from mtcontact.utilities.utils import get_channels, get_readable_duration, get_time_ago, refresh_node_list -from mtcontact.settings import settings_menu -from mtcontact.message_handlers.tx_handler import send_message, send_traceroute -from mtcontact.ui.colors import setup_colors, get_color -from mtcontact.utilities.db_handler import get_name_from_database, update_node_info_in_db, is_chat_archived -import mtcontact.ui.default_config as config -import mtcontact.ui.dialog -import mtcontact.globals as globals +from mcontact.utilities.utils import get_channels, get_readable_duration, get_time_ago, refresh_node_list +from mcontact.settings import settings_menu +from mcontact.message_handlers.tx_handler import send_message, send_traceroute +from mcontact.ui.colors import setup_colors, get_color +from mcontact.utilities.db_handler import get_name_from_database, update_node_info_in_db, is_chat_archived +import mcontact.ui.default_config as config +import mcontact.ui.dialog +import mcontact.globals as globals def handle_resize(stdscr, firstrun): global messages_pad, messages_win, nodes_pad, nodes_win, channel_pad, channel_win, function_win, packetlog_win, entry_win @@ -212,7 +212,7 @@ def main_ui(stdscr): elif char == chr(20): send_traceroute() curses.curs_set(0) # Hide cursor - mtcontact.ui.dialog.dialog(stdscr, "Traceroute Sent", "Results will appear in messages window.\nNote: Traceroute is limited to once every 30 seconds.") + mcontact.ui.dialog.dialog(stdscr, "Traceroute Sent", "Results will appear in messages window.\nNote: Traceroute is limited to once every 30 seconds.") curses.curs_set(1) # Show cursor again handle_resize(stdscr, False) diff --git a/mtcontact/ui/dialog.py b/mtcontact/ui/dialog.py index c5a4c7a..0edd950 100644 --- a/mtcontact/ui/dialog.py +++ b/mtcontact/ui/dialog.py @@ -1,5 +1,5 @@ import curses -from mtcontact.ui.colors import get_color +from mcontact.ui.colors import get_color def dialog(stdscr, title, message): height, width = stdscr.getmaxyx() diff --git a/mtcontact/ui/splash.py b/mtcontact/ui/splash.py index 785b5da..fab6739 100644 --- a/mtcontact/ui/splash.py +++ b/mtcontact/ui/splash.py @@ -1,5 +1,5 @@ import curses -from mtcontact.ui.colors import get_color +from mcontact.ui.colors import get_color def draw_splash(stdscr): curses.curs_set(0) diff --git a/mtcontact/ui/user_config.py b/mtcontact/ui/user_config.py index dc10db8..5e0f938 100644 --- a/mtcontact/ui/user_config.py +++ b/mtcontact/ui/user_config.py @@ -1,9 +1,9 @@ import os import json import curses -from mtcontact.ui.colors import get_color, setup_colors, COLOR_MAP -from mtcontact.ui.default_config import format_json_single_line_arrays, loaded_config -from mtcontact.utilities.input_handlers import get_list_input +from mcontact.ui.colors import get_color, setup_colors, COLOR_MAP +from mcontact.ui.default_config import format_json_single_line_arrays, loaded_config +from mcontact.utilities.input_handlers import get_list_input width = 60 save_option_text = "Save Changes" diff --git a/mtcontact/utilities/db_handler.py b/mtcontact/utilities/db_handler.py index 5a483aa..3ca7418 100644 --- a/mtcontact/utilities/db_handler.py +++ b/mtcontact/utilities/db_handler.py @@ -3,9 +3,9 @@ import time import logging from datetime import datetime -from mtcontact.utilities.utils import decimal_to_hex -import mtcontact.ui.default_config as config -import mtcontact.globals as globals +from mcontact.utilities.utils import decimal_to_hex +import mcontact.ui.default_config as config +import mcontact.globals as globals def get_table_name(channel): # Construct the table name diff --git a/mtcontact/utilities/input_handlers.py b/mtcontact/utilities/input_handlers.py index 2c0ed34..e6a12c1 100644 --- a/mtcontact/utilities/input_handlers.py +++ b/mtcontact/utilities/input_handlers.py @@ -3,7 +3,7 @@ import binascii import curses import ipaddress import re -from mtcontact.ui.colors import get_color +from mcontact.ui.colors import get_color def wrap_text(text, wrap_width): """Wraps text while preserving spaces and breaking long words.""" diff --git a/mtcontact/utilities/interfaces.py b/mtcontact/utilities/interfaces.py index 03aeace..5b51eff 100644 --- a/mtcontact/utilities/interfaces.py +++ b/mtcontact/utilities/interfaces.py @@ -1,6 +1,6 @@ import logging import meshtastic.serial_interface, meshtastic.tcp_interface, meshtastic.ble_interface -import mtcontact.globals as globals +import mcontact.globals as globals def initialize_interface(args): try: diff --git a/mtcontact/utilities/utils.py b/mtcontact/utilities/utils.py index 1997c36..c51ab27 100644 --- a/mtcontact/utilities/utils.py +++ b/mtcontact/utilities/utils.py @@ -1,7 +1,7 @@ -import mtcontact.globals as globals +import mcontact.globals as globals import datetime from meshtastic.protobuf import config_pb2 -import mtcontact.ui.default_config as config +import mcontact.ui.default_config as config def get_channels(): """Retrieve channels from the node and update globals.channel_list and globals.all_messages.""" diff --git a/pyproject.toml b/pyproject.toml index 0a20233..9e49405 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "mtcontact" +name = "mcontact" version = "1.2.3" description = "This Python curses client for Meshtastic is a terminal-based client designed to manage device settings, enable mesh chat communication, and handle configuration backups and restores." authors = [ @@ -18,4 +18,4 @@ requires = ["poetry-core>=2.0.0,<3.0.0"] build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] -mtcontact = "mtcontact.main:start" +mcontact = "mcontact.main:start" From c236a386a5633465ee998ced908834017fd81cf4 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Wed, 26 Mar 2025 22:30:35 -0700 Subject: [PATCH 04/13] mcontact --- {mtcontact => mcontact}/globals.py | 0 {mtcontact => mcontact}/localisations/en.ini | 0 {mtcontact => mcontact}/main.py | 0 {mtcontact => mcontact}/message_handlers/rx_handler.py | 0 {mtcontact => mcontact}/message_handlers/tx_handler.py | 0 {mtcontact => mcontact}/settings.py | 0 {mtcontact => mcontact}/ui/colors.py | 0 {mtcontact => mcontact}/ui/control_ui.py | 0 {mtcontact => mcontact}/ui/curses_ui.py | 0 {mtcontact => mcontact}/ui/default_config.py | 0 {mtcontact => mcontact}/ui/dialog.py | 0 {mtcontact => mcontact}/ui/menus.py | 0 {mtcontact => mcontact}/ui/splash.py | 0 {mtcontact => mcontact}/ui/user_config.py | 0 {mtcontact => mcontact}/utilities/arg_parser.py | 0 {mtcontact => mcontact}/utilities/config_io.py | 0 {mtcontact => mcontact}/utilities/control_utils.py | 0 {mtcontact => mcontact}/utilities/db_handler.py | 0 {mtcontact => mcontact}/utilities/input_handlers.py | 0 {mtcontact => mcontact}/utilities/interfaces.py | 0 {mtcontact => mcontact}/utilities/save_to_radio.py | 0 {mtcontact => mcontact}/utilities/utils.py | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename {mtcontact => mcontact}/globals.py (100%) rename {mtcontact => mcontact}/localisations/en.ini (100%) rename {mtcontact => mcontact}/main.py (100%) rename {mtcontact => mcontact}/message_handlers/rx_handler.py (100%) rename {mtcontact => mcontact}/message_handlers/tx_handler.py (100%) rename {mtcontact => mcontact}/settings.py (100%) rename {mtcontact => mcontact}/ui/colors.py (100%) rename {mtcontact => mcontact}/ui/control_ui.py (100%) rename {mtcontact => mcontact}/ui/curses_ui.py (100%) rename {mtcontact => mcontact}/ui/default_config.py (100%) rename {mtcontact => mcontact}/ui/dialog.py (100%) rename {mtcontact => mcontact}/ui/menus.py (100%) rename {mtcontact => mcontact}/ui/splash.py (100%) rename {mtcontact => mcontact}/ui/user_config.py (100%) rename {mtcontact => mcontact}/utilities/arg_parser.py (100%) rename {mtcontact => mcontact}/utilities/config_io.py (100%) rename {mtcontact => mcontact}/utilities/control_utils.py (100%) rename {mtcontact => mcontact}/utilities/db_handler.py (100%) rename {mtcontact => mcontact}/utilities/input_handlers.py (100%) rename {mtcontact => mcontact}/utilities/interfaces.py (100%) rename {mtcontact => mcontact}/utilities/save_to_radio.py (100%) rename {mtcontact => mcontact}/utilities/utils.py (100%) diff --git a/mtcontact/globals.py b/mcontact/globals.py similarity index 100% rename from mtcontact/globals.py rename to mcontact/globals.py diff --git a/mtcontact/localisations/en.ini b/mcontact/localisations/en.ini similarity index 100% rename from mtcontact/localisations/en.ini rename to mcontact/localisations/en.ini diff --git a/mtcontact/main.py b/mcontact/main.py similarity index 100% rename from mtcontact/main.py rename to mcontact/main.py diff --git a/mtcontact/message_handlers/rx_handler.py b/mcontact/message_handlers/rx_handler.py similarity index 100% rename from mtcontact/message_handlers/rx_handler.py rename to mcontact/message_handlers/rx_handler.py diff --git a/mtcontact/message_handlers/tx_handler.py b/mcontact/message_handlers/tx_handler.py similarity index 100% rename from mtcontact/message_handlers/tx_handler.py rename to mcontact/message_handlers/tx_handler.py diff --git a/mtcontact/settings.py b/mcontact/settings.py similarity index 100% rename from mtcontact/settings.py rename to mcontact/settings.py diff --git a/mtcontact/ui/colors.py b/mcontact/ui/colors.py similarity index 100% rename from mtcontact/ui/colors.py rename to mcontact/ui/colors.py diff --git a/mtcontact/ui/control_ui.py b/mcontact/ui/control_ui.py similarity index 100% rename from mtcontact/ui/control_ui.py rename to mcontact/ui/control_ui.py diff --git a/mtcontact/ui/curses_ui.py b/mcontact/ui/curses_ui.py similarity index 100% rename from mtcontact/ui/curses_ui.py rename to mcontact/ui/curses_ui.py diff --git a/mtcontact/ui/default_config.py b/mcontact/ui/default_config.py similarity index 100% rename from mtcontact/ui/default_config.py rename to mcontact/ui/default_config.py diff --git a/mtcontact/ui/dialog.py b/mcontact/ui/dialog.py similarity index 100% rename from mtcontact/ui/dialog.py rename to mcontact/ui/dialog.py diff --git a/mtcontact/ui/menus.py b/mcontact/ui/menus.py similarity index 100% rename from mtcontact/ui/menus.py rename to mcontact/ui/menus.py diff --git a/mtcontact/ui/splash.py b/mcontact/ui/splash.py similarity index 100% rename from mtcontact/ui/splash.py rename to mcontact/ui/splash.py diff --git a/mtcontact/ui/user_config.py b/mcontact/ui/user_config.py similarity index 100% rename from mtcontact/ui/user_config.py rename to mcontact/ui/user_config.py diff --git a/mtcontact/utilities/arg_parser.py b/mcontact/utilities/arg_parser.py similarity index 100% rename from mtcontact/utilities/arg_parser.py rename to mcontact/utilities/arg_parser.py diff --git a/mtcontact/utilities/config_io.py b/mcontact/utilities/config_io.py similarity index 100% rename from mtcontact/utilities/config_io.py rename to mcontact/utilities/config_io.py diff --git a/mtcontact/utilities/control_utils.py b/mcontact/utilities/control_utils.py similarity index 100% rename from mtcontact/utilities/control_utils.py rename to mcontact/utilities/control_utils.py diff --git a/mtcontact/utilities/db_handler.py b/mcontact/utilities/db_handler.py similarity index 100% rename from mtcontact/utilities/db_handler.py rename to mcontact/utilities/db_handler.py diff --git a/mtcontact/utilities/input_handlers.py b/mcontact/utilities/input_handlers.py similarity index 100% rename from mtcontact/utilities/input_handlers.py rename to mcontact/utilities/input_handlers.py diff --git a/mtcontact/utilities/interfaces.py b/mcontact/utilities/interfaces.py similarity index 100% rename from mtcontact/utilities/interfaces.py rename to mcontact/utilities/interfaces.py diff --git a/mtcontact/utilities/save_to_radio.py b/mcontact/utilities/save_to_radio.py similarity index 100% rename from mtcontact/utilities/save_to_radio.py rename to mcontact/utilities/save_to_radio.py diff --git a/mtcontact/utilities/utils.py b/mcontact/utilities/utils.py similarity index 100% rename from mtcontact/utilities/utils.py rename to mcontact/utilities/utils.py From 25240f211b15e4e6ee9bef911bf63e7093594c68 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Thu, 27 Mar 2025 20:55:50 -0700 Subject: [PATCH 05/13] add release.yaml --- .github/workflows/release.yaml | 143 ++++++++++++++++++ mtcontact/message_handlers/tx_handler.py | 181 +++++++++++++++++++++++ 2 files changed, 324 insertions(+) create mode 100644 .github/workflows/release.yaml create mode 100644 mtcontact/message_handlers/tx_handler.py diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..4a82287 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,143 @@ +name: release + +on: + push: + tags: + - "[0-9]+.[0-9]+.[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+a[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+b[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+rc[0-9]+" + +env: + PACKAGE_NAME: "mcontact" + OWNER: "pdxlocations" + +jobs: + details: + runs-on: ubuntu-latest + outputs: + new_version: ${{ steps.release.outputs.new_version }} + suffix: ${{ steps.release.outputs.suffix }} + tag_name: ${{ steps.release.outputs.tag_name }} + steps: + - uses: actions/checkout@v2 + + - name: Extract tag and Details + id: release + run: | + if [ "${{ github.ref_type }}" = "tag" ]; then + TAG_NAME=${GITHUB_REF#refs/tags/} + NEW_VERSION=$(echo $TAG_NAME | awk -F'-' '{print $1}') + SUFFIX=$(echo $TAG_NAME | grep -oP '[a-z]+[0-9]+' || echo "") + echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT" + echo "suffix=$SUFFIX" >> "$GITHUB_OUTPUT" + echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT" + echo "Version is $NEW_VERSION" + echo "Suffix is $SUFFIX" + echo "Tag name is $TAG_NAME" + else + echo "No tag found" + exit 1 + fi + + check_pypi: + needs: details + runs-on: ubuntu-latest + steps: + - name: Fetch information from PyPI + run: | + response=$(curl -s https://pypi.org/pypi/${{ env.PACKAGE_NAME }}/json || echo "{}") + latest_previous_version=$(echo $response | jq --raw-output "select(.releases != null) | .releases | keys_unsorted | last") + if [ -z "$latest_previous_version" ]; then + echo "Package not found on PyPI." + latest_previous_version="0.0.0" + fi + echo "Latest version on PyPI: $latest_previous_version" + echo "latest_previous_version=$latest_previous_version" >> $GITHUB_ENV + + - name: Compare versions and exit if not newer + run: | + NEW_VERSION=${{ needs.details.outputs.new_version }} + LATEST_VERSION=$latest_previous_version + if [ "$(printf '%s\n' "$LATEST_VERSION" "$NEW_VERSION" | sort -rV | head -n 1)" != "$NEW_VERSION" ] || [ "$NEW_VERSION" == "$LATEST_VERSION" ]; then + echo "The new version $NEW_VERSION is not greater than the latest version $LATEST_VERSION on PyPI." + exit 1 + else + echo "The new version $NEW_VERSION is greater than the latest version $LATEST_VERSION on PyPI." + fi + + setup_and_build: + needs: [details, check_pypi] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.12" + + - name: Install Poetry + run: | + curl -sSL https://install.python-poetry.org | python3 - + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Set project version with Poetry + run: | + poetry version ${{ needs.details.outputs.new_version }} + + - name: Install dependencies + run: poetry install --sync --no-interaction + + - name: Build source and wheel distribution + run: | + poetry build + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: dist + path: dist/ + + pypi_publish: + name: Upload release to PyPI + needs: [setup_and_build, details] + runs-on: ubuntu-latest + environment: + name: release + permissions: + id-token: write + steps: + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: dist + path: dist/ + + - name: Publish distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + github_release: + name: Create GitHub Release + needs: [setup_and_build, details] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout Code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: dist + path: dist/ + + - name: Create GitHub Release + id: create_release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create ${{ needs.details.outputs.tag_name }} dist/* --title ${{ needs.details.outputs.tag_name }} --generate-notes diff --git a/mtcontact/message_handlers/tx_handler.py b/mtcontact/message_handlers/tx_handler.py new file mode 100644 index 0000000..7fe9ed1 --- /dev/null +++ b/mtcontact/message_handlers/tx_handler.py @@ -0,0 +1,181 @@ +from datetime import datetime +import google.protobuf.json_format +from meshtastic import BROADCAST_NUM +from meshtastic.protobuf import mesh_pb2, portnums_pb2 + +from mcontact.utilities.db_handler import save_message_to_db, update_ack_nak, get_name_from_database, is_chat_archived, update_node_info_in_db +import mcontact.ui.default_config as config +import mcontact.globals as globals + +ack_naks = {} + +# Note "onAckNak" has special meaning to the API, thus the nonstandard naming convention +# See https://github.com/meshtastic/python/blob/master/meshtastic/mesh_interface.py#L462 +def onAckNak(packet): + from mcontact.ui.curses_ui import draw_messages_window + request = packet['decoded']['requestId'] + if(request not in ack_naks): + return + + acknak = ack_naks.pop(request) + message = globals.all_messages[acknak['channel']][acknak['messageIndex']][1] + + confirm_string = " " + ack_type = None + if(packet['decoded']['routing']['errorReason'] == "NONE"): + if(packet['from'] == globals.myNodeNum): # Ack "from" ourself means implicit ACK + confirm_string = config.ack_implicit_str + ack_type = "Implicit" + else: + confirm_string = config.ack_str + ack_type = "Ack" + else: + confirm_string = config.nak_str + ack_type = "Nak" + + globals.all_messages[acknak['channel']][acknak['messageIndex']] = (config.sent_message_prefix + confirm_string + ": ", message) + + update_ack_nak(acknak['channel'], acknak['timestamp'], message, ack_type) + + channel_number = globals.channel_list.index(acknak['channel']) + if globals.channel_list[channel_number] == globals.channel_list[globals.selected_channel]: + draw_messages_window() + +def on_response_traceroute(packet): + """on response for trace route""" + from mcontact.ui.curses_ui import draw_channel_list, draw_messages_window, add_notification + + refresh_channels = False + refresh_messages = False + + UNK_SNR = -128 # Value representing unknown SNR + + route_discovery = mesh_pb2.RouteDiscovery() + route_discovery.ParseFromString(packet["decoded"]["payload"]) + msg_dict = google.protobuf.json_format.MessageToDict(route_discovery) + + msg_str = "Traceroute to:\n" + + route_str = get_name_from_database(packet["to"], 'short') or f"{packet['to']:08x}" # Start with destination of response + + # SNR list should have one more entry than the route, as the final destination adds its SNR also + lenTowards = 0 if "route" not in msg_dict else len(msg_dict["route"]) + snrTowardsValid = "snrTowards" in msg_dict and len(msg_dict["snrTowards"]) == lenTowards + 1 + if lenTowards > 0: # Loop through hops in route and add SNR if available + for idx, node_num in enumerate(msg_dict["route"]): + route_str += " --> " + (get_name_from_database(node_num, 'short') or f"{node_num:08x}") \ + + " (" + (str(msg_dict["snrTowards"][idx] / 4) if snrTowardsValid and msg_dict["snrTowards"][idx] != UNK_SNR else "?") + "dB)" + + # End with origin of response + route_str += " --> " + (get_name_from_database(packet["from"], 'short') or f"{packet['from']:08x}") \ + + " (" + (str(msg_dict["snrTowards"][-1] / 4) if snrTowardsValid and msg_dict["snrTowards"][-1] != UNK_SNR else "?") + "dB)" + + msg_str += route_str + "\n" # Print the route towards destination + + # Only if hopStart is set and there is an SNR entry (for the origin) it's valid, even though route might be empty (direct connection) + lenBack = 0 if "routeBack" not in msg_dict else len(msg_dict["routeBack"]) + backValid = "hopStart" in packet and "snrBack" in msg_dict and len(msg_dict["snrBack"]) == lenBack + 1 + if backValid: + msg_str += "Back:\n" + route_str = get_name_from_database(packet["from"], 'short') or f"{packet['from']:08x}" # Start with origin of response + + if lenBack > 0: # Loop through hops in routeBack and add SNR if available + for idx, node_num in enumerate(msg_dict["routeBack"]): + route_str += " --> " + (get_name_from_database(node_num, 'short') or f"{node_num:08x}") \ + + " (" + (str(msg_dict["snrBack"][idx] / 4) if msg_dict["snrBack"][idx] != UNK_SNR else "?") + "dB)" + + # End with destination of response (us) + route_str += " --> " + (get_name_from_database(packet["to"], 'short') or f"{packet['to']:08x}") \ + + " (" + (str(msg_dict["snrBack"][-1] / 4) if msg_dict["snrBack"][-1] != UNK_SNR else "?") + "dB)" + + msg_str += route_str + "\n" # Print the route back to us + + if(packet['from'] not in globals.channel_list): + globals.channel_list.append(packet['from']) + refresh_channels = True + + if(is_chat_archived(packet['from'])): + update_node_info_in_db(packet['from'], chat_archived=False) + + channel_number = globals.channel_list.index(packet['from']) + + if globals.channel_list[channel_number] == globals.channel_list[globals.selected_channel]: + refresh_messages = True + else: + add_notification(channel_number) + refresh_channels = True + + message_from_string = get_name_from_database(packet['from'], type='short') + ":\n" + + if globals.channel_list[channel_number] not in globals.all_messages: + globals.all_messages[globals.channel_list[channel_number]] = [] + globals.all_messages[globals.channel_list[channel_number]].append((f"{config.message_prefix} {message_from_string}", msg_str)) + + if refresh_channels: + draw_channel_list() + if refresh_messages: + draw_messages_window(True) + save_message_to_db(globals.channel_list[channel_number], packet['from'], msg_str) + + +def send_message(message, destination=BROADCAST_NUM, channel=0): + myid = globals.myNodeNum + send_on_channel = 0 + channel_id = globals.channel_list[channel] + if isinstance(channel_id, int): + send_on_channel = 0 + destination = channel_id + elif isinstance(channel_id, str): + send_on_channel = channel + + sent_message_data = globals.interface.sendText( + text=message, + destinationId=destination, + wantAck=True, + wantResponse=False, + onResponse=onAckNak, + channelIndex=send_on_channel, + ) + + # Add sent message to the messages dictionary + if channel_id not in globals.all_messages: + globals.all_messages[channel_id] = [] + + # Handle timestamp logic + current_timestamp = int(datetime.now().timestamp()) # Get current timestamp + current_hour = datetime.fromtimestamp(current_timestamp).strftime('%Y-%m-%d %H:00') + + # Retrieve the last timestamp if available + channel_messages = globals.all_messages[channel_id] + if channel_messages: + # Check the last entry for a timestamp + for entry in reversed(channel_messages): + if entry[0].startswith("--"): + last_hour = entry[0].strip("- ").strip() + break + else: + last_hour = None + else: + last_hour = None + + # Add a new timestamp if it's a new hour + if last_hour != current_hour: + globals.all_messages[channel_id].append((f"-- {current_hour} --", "")) + + globals.all_messages[channel_id].append((config.sent_message_prefix + config.ack_unknown_str + ": ", message)) + + timestamp = save_message_to_db(channel_id, myid, message) + + ack_naks[sent_message_data.id] = {'channel': channel_id, 'messageIndex': len(globals.all_messages[channel_id]) - 1, 'timestamp': timestamp} + +def send_traceroute(): + r = mesh_pb2.RouteDiscovery() + globals.interface.sendData( + r, + destinationId=globals.node_list[globals.selected_node], + portNum=portnums_pb2.PortNum.TRACEROUTE_APP, + wantResponse=True, + onResponse=on_response_traceroute, + channelIndex=0, + hopLimit=3, + ) From 37c5a7dbc392a4ed8e251329653fa4767803f84e Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Thu, 27 Mar 2025 21:07:15 -0700 Subject: [PATCH 06/13] fix some imports --- mcontact/message_handlers/tx_handler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mcontact/message_handlers/tx_handler.py b/mcontact/message_handlers/tx_handler.py index 0c0cb2b..7fe9ed1 100644 --- a/mcontact/message_handlers/tx_handler.py +++ b/mcontact/message_handlers/tx_handler.py @@ -12,7 +12,7 @@ ack_naks = {} # Note "onAckNak" has special meaning to the API, thus the nonstandard naming convention # See https://github.com/meshtastic/python/blob/master/meshtastic/mesh_interface.py#L462 def onAckNak(packet): - from ui.curses_ui import draw_messages_window + from mcontact.ui.curses_ui import draw_messages_window request = packet['decoded']['requestId'] if(request not in ack_naks): return @@ -43,7 +43,7 @@ def onAckNak(packet): def on_response_traceroute(packet): """on response for trace route""" - from ui.curses_ui import draw_channel_list, draw_messages_window, add_notification + from mcontact.ui.curses_ui import draw_channel_list, draw_messages_window, add_notification refresh_channels = False refresh_messages = False From 2960553fef64694a562169dde9603b5f07725b5b Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Thu, 27 Mar 2025 21:08:26 -0700 Subject: [PATCH 07/13] rm extra file --- mtcontact/message_handlers/tx_handler.py | 181 ----------------------- 1 file changed, 181 deletions(-) delete mode 100644 mtcontact/message_handlers/tx_handler.py diff --git a/mtcontact/message_handlers/tx_handler.py b/mtcontact/message_handlers/tx_handler.py deleted file mode 100644 index 7fe9ed1..0000000 --- a/mtcontact/message_handlers/tx_handler.py +++ /dev/null @@ -1,181 +0,0 @@ -from datetime import datetime -import google.protobuf.json_format -from meshtastic import BROADCAST_NUM -from meshtastic.protobuf import mesh_pb2, portnums_pb2 - -from mcontact.utilities.db_handler import save_message_to_db, update_ack_nak, get_name_from_database, is_chat_archived, update_node_info_in_db -import mcontact.ui.default_config as config -import mcontact.globals as globals - -ack_naks = {} - -# Note "onAckNak" has special meaning to the API, thus the nonstandard naming convention -# See https://github.com/meshtastic/python/blob/master/meshtastic/mesh_interface.py#L462 -def onAckNak(packet): - from mcontact.ui.curses_ui import draw_messages_window - request = packet['decoded']['requestId'] - if(request not in ack_naks): - return - - acknak = ack_naks.pop(request) - message = globals.all_messages[acknak['channel']][acknak['messageIndex']][1] - - confirm_string = " " - ack_type = None - if(packet['decoded']['routing']['errorReason'] == "NONE"): - if(packet['from'] == globals.myNodeNum): # Ack "from" ourself means implicit ACK - confirm_string = config.ack_implicit_str - ack_type = "Implicit" - else: - confirm_string = config.ack_str - ack_type = "Ack" - else: - confirm_string = config.nak_str - ack_type = "Nak" - - globals.all_messages[acknak['channel']][acknak['messageIndex']] = (config.sent_message_prefix + confirm_string + ": ", message) - - update_ack_nak(acknak['channel'], acknak['timestamp'], message, ack_type) - - channel_number = globals.channel_list.index(acknak['channel']) - if globals.channel_list[channel_number] == globals.channel_list[globals.selected_channel]: - draw_messages_window() - -def on_response_traceroute(packet): - """on response for trace route""" - from mcontact.ui.curses_ui import draw_channel_list, draw_messages_window, add_notification - - refresh_channels = False - refresh_messages = False - - UNK_SNR = -128 # Value representing unknown SNR - - route_discovery = mesh_pb2.RouteDiscovery() - route_discovery.ParseFromString(packet["decoded"]["payload"]) - msg_dict = google.protobuf.json_format.MessageToDict(route_discovery) - - msg_str = "Traceroute to:\n" - - route_str = get_name_from_database(packet["to"], 'short') or f"{packet['to']:08x}" # Start with destination of response - - # SNR list should have one more entry than the route, as the final destination adds its SNR also - lenTowards = 0 if "route" not in msg_dict else len(msg_dict["route"]) - snrTowardsValid = "snrTowards" in msg_dict and len(msg_dict["snrTowards"]) == lenTowards + 1 - if lenTowards > 0: # Loop through hops in route and add SNR if available - for idx, node_num in enumerate(msg_dict["route"]): - route_str += " --> " + (get_name_from_database(node_num, 'short') or f"{node_num:08x}") \ - + " (" + (str(msg_dict["snrTowards"][idx] / 4) if snrTowardsValid and msg_dict["snrTowards"][idx] != UNK_SNR else "?") + "dB)" - - # End with origin of response - route_str += " --> " + (get_name_from_database(packet["from"], 'short') or f"{packet['from']:08x}") \ - + " (" + (str(msg_dict["snrTowards"][-1] / 4) if snrTowardsValid and msg_dict["snrTowards"][-1] != UNK_SNR else "?") + "dB)" - - msg_str += route_str + "\n" # Print the route towards destination - - # Only if hopStart is set and there is an SNR entry (for the origin) it's valid, even though route might be empty (direct connection) - lenBack = 0 if "routeBack" not in msg_dict else len(msg_dict["routeBack"]) - backValid = "hopStart" in packet and "snrBack" in msg_dict and len(msg_dict["snrBack"]) == lenBack + 1 - if backValid: - msg_str += "Back:\n" - route_str = get_name_from_database(packet["from"], 'short') or f"{packet['from']:08x}" # Start with origin of response - - if lenBack > 0: # Loop through hops in routeBack and add SNR if available - for idx, node_num in enumerate(msg_dict["routeBack"]): - route_str += " --> " + (get_name_from_database(node_num, 'short') or f"{node_num:08x}") \ - + " (" + (str(msg_dict["snrBack"][idx] / 4) if msg_dict["snrBack"][idx] != UNK_SNR else "?") + "dB)" - - # End with destination of response (us) - route_str += " --> " + (get_name_from_database(packet["to"], 'short') or f"{packet['to']:08x}") \ - + " (" + (str(msg_dict["snrBack"][-1] / 4) if msg_dict["snrBack"][-1] != UNK_SNR else "?") + "dB)" - - msg_str += route_str + "\n" # Print the route back to us - - if(packet['from'] not in globals.channel_list): - globals.channel_list.append(packet['from']) - refresh_channels = True - - if(is_chat_archived(packet['from'])): - update_node_info_in_db(packet['from'], chat_archived=False) - - channel_number = globals.channel_list.index(packet['from']) - - if globals.channel_list[channel_number] == globals.channel_list[globals.selected_channel]: - refresh_messages = True - else: - add_notification(channel_number) - refresh_channels = True - - message_from_string = get_name_from_database(packet['from'], type='short') + ":\n" - - if globals.channel_list[channel_number] not in globals.all_messages: - globals.all_messages[globals.channel_list[channel_number]] = [] - globals.all_messages[globals.channel_list[channel_number]].append((f"{config.message_prefix} {message_from_string}", msg_str)) - - if refresh_channels: - draw_channel_list() - if refresh_messages: - draw_messages_window(True) - save_message_to_db(globals.channel_list[channel_number], packet['from'], msg_str) - - -def send_message(message, destination=BROADCAST_NUM, channel=0): - myid = globals.myNodeNum - send_on_channel = 0 - channel_id = globals.channel_list[channel] - if isinstance(channel_id, int): - send_on_channel = 0 - destination = channel_id - elif isinstance(channel_id, str): - send_on_channel = channel - - sent_message_data = globals.interface.sendText( - text=message, - destinationId=destination, - wantAck=True, - wantResponse=False, - onResponse=onAckNak, - channelIndex=send_on_channel, - ) - - # Add sent message to the messages dictionary - if channel_id not in globals.all_messages: - globals.all_messages[channel_id] = [] - - # Handle timestamp logic - current_timestamp = int(datetime.now().timestamp()) # Get current timestamp - current_hour = datetime.fromtimestamp(current_timestamp).strftime('%Y-%m-%d %H:00') - - # Retrieve the last timestamp if available - channel_messages = globals.all_messages[channel_id] - if channel_messages: - # Check the last entry for a timestamp - for entry in reversed(channel_messages): - if entry[0].startswith("--"): - last_hour = entry[0].strip("- ").strip() - break - else: - last_hour = None - else: - last_hour = None - - # Add a new timestamp if it's a new hour - if last_hour != current_hour: - globals.all_messages[channel_id].append((f"-- {current_hour} --", "")) - - globals.all_messages[channel_id].append((config.sent_message_prefix + config.ack_unknown_str + ": ", message)) - - timestamp = save_message_to_db(channel_id, myid, message) - - ack_naks[sent_message_data.id] = {'channel': channel_id, 'messageIndex': len(globals.all_messages[channel_id]) - 1, 'timestamp': timestamp} - -def send_traceroute(): - r = mesh_pb2.RouteDiscovery() - globals.interface.sendData( - r, - destinationId=globals.node_list[globals.selected_node], - portNum=portnums_pb2.PortNum.TRACEROUTE_APP, - wantResponse=True, - onResponse=on_response_traceroute, - channelIndex=0, - hopLimit=3, - ) From 92a30ad8b0d7c74ea845b19ef1b61a3f9f77e237 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Thu, 27 Mar 2025 21:14:51 -0700 Subject: [PATCH 08/13] flix user config location --- mcontact/ui/user_config.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mcontact/ui/user_config.py b/mcontact/ui/user_config.py index 5e0f938..9a8f586 100644 --- a/mcontact/ui/user_config.py +++ b/mcontact/ui/user_config.py @@ -196,7 +196,10 @@ def json_editor(stdscr): menu_path = ["App Settings"] selected_index = 0 # Track the selected option - file_path = "config.json" + script_dir = os.path.dirname(os.path.abspath(__file__)) + parent_dir = os.path.abspath(os.path.join(script_dir, os.pardir)) + file_path = os.path.join(parent_dir, "config.json") + # file_path = "config.json" show_save_option = True # Always show the Save button # Ensure the file exists From 4cd7c4e24d479f1f0e1d791373ef5e5a006804a7 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Sun, 30 Mar 2025 16:28:26 -0700 Subject: [PATCH 09/13] change email --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9e49405..3f9fcfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,9 +1,9 @@ [project] name = "mcontact" -version = "1.2.3" +version = "1.3.0" description = "This Python curses client for Meshtastic is a terminal-based client designed to manage device settings, enable mesh chat communication, and handle configuration backups and restores." authors = [ - {name = "pdxlocations",email = "you@example.com"} + {name = "Ben Lipsey",email = "ben@pdxlocations.com"} ] license = "GPL-3.0-only" readme = "README.md" From 2b0f6515af62071bc8b8182c33bff60ac4c058ba Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Sun, 30 Mar 2025 19:15:59 -0700 Subject: [PATCH 10/13] update workflow --- .github/workflows/release.yaml | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4a82287..8c2c5f7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -70,7 +70,7 @@ jobs: needs: [details, check_pypi] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 @@ -94,7 +94,7 @@ jobs: poetry build - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: dist path: dist/ @@ -109,7 +109,7 @@ jobs: id-token: write steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: dist path: dist/ @@ -125,12 +125,12 @@ jobs: contents: write steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: dist path: dist/ diff --git a/pyproject.toml b/pyproject.toml index 3f9fcfd..96e1754 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ authors = [ ] license = "GPL-3.0-only" readme = "README.md" -requires-python = ">=3.9" +requires-python = ">=3.9,<3.14" dependencies = [ "meshtastic (>=2.6.0,<3.0.0)" ] From 372204a684b4d3fc32025c2ed3173ff4c9746e7e Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Tue, 1 Apr 2025 14:57:51 -0700 Subject: [PATCH 11/13] mcontact -> contact --- .github/workflows/release.yaml | 2 +- .vscode/launch.json | 2 +- mcontact/main.py | 24 ++++++++++++------------ mcontact/message_handlers/rx_handler.py | 10 +++++----- mcontact/message_handlers/tx_handler.py | 10 +++++----- mcontact/settings.py | 14 +++++++------- mcontact/ui/colors.py | 2 +- mcontact/ui/control_ui.py | 18 +++++++++--------- mcontact/ui/curses_ui.py | 18 +++++++++--------- mcontact/ui/dialog.py | 2 +- mcontact/ui/splash.py | 2 +- mcontact/ui/user_config.py | 6 +++--- mcontact/utilities/db_handler.py | 6 +++--- mcontact/utilities/input_handlers.py | 2 +- mcontact/utilities/interfaces.py | 2 +- mcontact/utilities/utils.py | 4 ++-- pyproject.toml | 4 ++-- 17 files changed, 64 insertions(+), 64 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 8c2c5f7..700c750 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -9,7 +9,7 @@ on: - "[0-9]+.[0-9]+.[0-9]+rc[0-9]+" env: - PACKAGE_NAME: "mcontact" + PACKAGE_NAME: "contact" OWNER: "pdxlocations" jobs: diff --git a/.vscode/launch.json b/.vscode/launch.json index f10e079..6d8c679 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "type": "debugpy", "request": "launch", "cwd": "${workspaceFolder}", - "module": "mcontact.main", + "module": "contact.main", "args": [] } ] diff --git a/mcontact/main.py b/mcontact/main.py index 4851967..9b861bd 100644 --- a/mcontact/main.py +++ b/mcontact/main.py @@ -18,18 +18,18 @@ import logging import traceback import threading -from mcontact.utilities.db_handler import init_nodedb, load_messages_from_db -from mcontact.message_handlers.rx_handler import on_receive -from mcontact.settings import set_region -from mcontact.ui.curses_ui import main_ui -from mcontact.ui.colors import setup_colors -from mcontact.ui.splash import draw_splash -import mcontact.ui.default_config as config -from mcontact.utilities.arg_parser import setup_parser -from mcontact.utilities.interfaces import initialize_interface -from mcontact.utilities.input_handlers import get_list_input -from mcontact.utilities.utils import get_channels, get_node_list, get_nodeNum -import mcontact.globals as globals +from contact.utilities.db_handler import init_nodedb, load_messages_from_db +from contact.message_handlers.rx_handler import on_receive +from contact.settings import set_region +from contact.ui.curses_ui import main_ui +from contact.ui.colors import setup_colors +from contact.ui.splash import draw_splash +import contact.ui.default_config as config +from contact.utilities.arg_parser import setup_parser +from contact.utilities.interfaces import initialize_interface +from contact.utilities.input_handlers import get_list_input +from contact.utilities.utils import get_channels, get_node_list, get_nodeNum +import contact.globals as globals # Set ncurses compatibility settings os.environ["NCURSES_NO_UTF8_ACS"] = "1" diff --git a/mcontact/message_handlers/rx_handler.py b/mcontact/message_handlers/rx_handler.py index f461f62..74cc5f9 100644 --- a/mcontact/message_handlers/rx_handler.py +++ b/mcontact/message_handlers/rx_handler.py @@ -1,11 +1,11 @@ import logging import time -from mcontact.utilities.utils import refresh_node_list +from contact.utilities.utils import refresh_node_list from datetime import datetime -from mcontact.ui.curses_ui import draw_packetlog_win, draw_node_list, draw_messages_window, draw_channel_list, add_notification -from mcontact.utilities.db_handler import save_message_to_db, maybe_store_nodeinfo_in_db, get_name_from_database, update_node_info_in_db -import mcontact.ui.default_config as config -import mcontact.globals as globals +from contact.ui.curses_ui import draw_packetlog_win, draw_node_list, draw_messages_window, draw_channel_list, add_notification +from contact.utilities.db_handler import save_message_to_db, maybe_store_nodeinfo_in_db, get_name_from_database, update_node_info_in_db +import contact.ui.default_config as config +import contact.globals as globals from datetime import datetime diff --git a/mcontact/message_handlers/tx_handler.py b/mcontact/message_handlers/tx_handler.py index 7fe9ed1..45cfc13 100644 --- a/mcontact/message_handlers/tx_handler.py +++ b/mcontact/message_handlers/tx_handler.py @@ -3,16 +3,16 @@ import google.protobuf.json_format from meshtastic import BROADCAST_NUM from meshtastic.protobuf import mesh_pb2, portnums_pb2 -from mcontact.utilities.db_handler import save_message_to_db, update_ack_nak, get_name_from_database, is_chat_archived, update_node_info_in_db -import mcontact.ui.default_config as config -import mcontact.globals as globals +from contact.utilities.db_handler import save_message_to_db, update_ack_nak, get_name_from_database, is_chat_archived, update_node_info_in_db +import contact.ui.default_config as config +import contact.globals as globals ack_naks = {} # Note "onAckNak" has special meaning to the API, thus the nonstandard naming convention # See https://github.com/meshtastic/python/blob/master/meshtastic/mesh_interface.py#L462 def onAckNak(packet): - from mcontact.ui.curses_ui import draw_messages_window + from contact.ui.curses_ui import draw_messages_window request = packet['decoded']['requestId'] if(request not in ack_naks): return @@ -43,7 +43,7 @@ def onAckNak(packet): def on_response_traceroute(packet): """on response for trace route""" - from mcontact.ui.curses_ui import draw_channel_list, draw_messages_window, add_notification + from contact.ui.curses_ui import draw_channel_list, draw_messages_window, add_notification refresh_channels = False refresh_messages = False diff --git a/mcontact/settings.py b/mcontact/settings.py index 2ba7f94..c0ee3ae 100644 --- a/mcontact/settings.py +++ b/mcontact/settings.py @@ -5,13 +5,13 @@ import logging import sys import traceback -import mcontact.ui.default_config as config -from mcontact.utilities.input_handlers import get_list_input -from mcontact.ui.colors import setup_colors -from mcontact.ui.splash import draw_splash -from mcontact.ui.control_ui import set_region, settings_menu -from mcontact.utilities.arg_parser import setup_parser -from mcontact.utilities.interfaces import initialize_interface +import contact.ui.default_config as config +from contact.utilities.input_handlers import get_list_input +from contact.ui.colors import setup_colors +from contact.ui.splash import draw_splash +from contact.ui.control_ui import set_region, settings_menu +from contact.utilities.arg_parser import setup_parser +from contact.utilities.interfaces import initialize_interface def main(stdscr): diff --git a/mcontact/ui/colors.py b/mcontact/ui/colors.py index 3c579d6..cb8c064 100644 --- a/mcontact/ui/colors.py +++ b/mcontact/ui/colors.py @@ -1,5 +1,5 @@ import curses -import mcontact.ui.default_config as config +import contact.ui.default_config as config COLOR_MAP = { "black": curses.COLOR_BLACK, diff --git a/mcontact/ui/control_ui.py b/mcontact/ui/control_ui.py index 1672771..b3c5b9e 100644 --- a/mcontact/ui/control_ui.py +++ b/mcontact/ui/control_ui.py @@ -5,16 +5,16 @@ import os import re import sys -from mcontact.utilities.save_to_radio import save_changes -from mcontact.utilities.config_io import config_export, config_import -from mcontact.utilities.input_handlers import get_repeated_input, get_text_input, get_fixed32_input, get_list_input, get_admin_key_input -from mcontact.ui.menus import generate_menu_from_protobuf -from mcontact.ui.colors import get_color -from mcontact.ui.dialog import dialog -from mcontact.utilities.control_utils import parse_ini_file, transform_menu_path -from mcontact.ui.user_config import json_editor +from contact.utilities.save_to_radio import save_changes +from contact.utilities.config_io import config_export, config_import +from contact.utilities.input_handlers import get_repeated_input, get_text_input, get_fixed32_input, get_list_input, get_admin_key_input +from contact.ui.menus import generate_menu_from_protobuf +from contact.ui.colors import get_color +from contact.ui.dialog import dialog +from contact.utilities.control_utils import parse_ini_file, transform_menu_path +from contact.ui.user_config import json_editor -import mcontact.localisations +import contact.localisations # Constants width = 80 diff --git a/mcontact/ui/curses_ui.py b/mcontact/ui/curses_ui.py index b27808f..c71a172 100644 --- a/mcontact/ui/curses_ui.py +++ b/mcontact/ui/curses_ui.py @@ -2,14 +2,14 @@ import curses import textwrap import logging import traceback -from mcontact.utilities.utils import get_channels, get_readable_duration, get_time_ago, refresh_node_list -from mcontact.settings import settings_menu -from mcontact.message_handlers.tx_handler import send_message, send_traceroute -from mcontact.ui.colors import setup_colors, get_color -from mcontact.utilities.db_handler import get_name_from_database, update_node_info_in_db, is_chat_archived -import mcontact.ui.default_config as config -import mcontact.ui.dialog -import mcontact.globals as globals +from contact.utilities.utils import get_channels, get_readable_duration, get_time_ago, refresh_node_list +from contact.settings import settings_menu +from contact.message_handlers.tx_handler import send_message, send_traceroute +from contact.ui.colors import setup_colors, get_color +from contact.utilities.db_handler import get_name_from_database, update_node_info_in_db, is_chat_archived +import contact.ui.default_config as config +import contact.ui.dialog +import contact.globals as globals def handle_resize(stdscr, firstrun): global messages_pad, messages_win, nodes_pad, nodes_win, channel_pad, channel_win, function_win, packetlog_win, entry_win @@ -212,7 +212,7 @@ def main_ui(stdscr): elif char == chr(20): send_traceroute() curses.curs_set(0) # Hide cursor - mcontact.ui.dialog.dialog(stdscr, "Traceroute Sent", "Results will appear in messages window.\nNote: Traceroute is limited to once every 30 seconds.") + contact.ui.dialog.dialog(stdscr, "Traceroute Sent", "Results will appear in messages window.\nNote: Traceroute is limited to once every 30 seconds.") curses.curs_set(1) # Show cursor again handle_resize(stdscr, False) diff --git a/mcontact/ui/dialog.py b/mcontact/ui/dialog.py index 0edd950..ea39b43 100644 --- a/mcontact/ui/dialog.py +++ b/mcontact/ui/dialog.py @@ -1,5 +1,5 @@ import curses -from mcontact.ui.colors import get_color +from contact.ui.colors import get_color def dialog(stdscr, title, message): height, width = stdscr.getmaxyx() diff --git a/mcontact/ui/splash.py b/mcontact/ui/splash.py index fab6739..403bc34 100644 --- a/mcontact/ui/splash.py +++ b/mcontact/ui/splash.py @@ -1,5 +1,5 @@ import curses -from mcontact.ui.colors import get_color +from contact.ui.colors import get_color def draw_splash(stdscr): curses.curs_set(0) diff --git a/mcontact/ui/user_config.py b/mcontact/ui/user_config.py index 9a8f586..eb4e9b6 100644 --- a/mcontact/ui/user_config.py +++ b/mcontact/ui/user_config.py @@ -1,9 +1,9 @@ import os import json import curses -from mcontact.ui.colors import get_color, setup_colors, COLOR_MAP -from mcontact.ui.default_config import format_json_single_line_arrays, loaded_config -from mcontact.utilities.input_handlers import get_list_input +from contact.ui.colors import get_color, setup_colors, COLOR_MAP +from contact.ui.default_config import format_json_single_line_arrays, loaded_config +from contact.utilities.input_handlers import get_list_input width = 60 save_option_text = "Save Changes" diff --git a/mcontact/utilities/db_handler.py b/mcontact/utilities/db_handler.py index 3ca7418..ebd588b 100644 --- a/mcontact/utilities/db_handler.py +++ b/mcontact/utilities/db_handler.py @@ -3,9 +3,9 @@ import time import logging from datetime import datetime -from mcontact.utilities.utils import decimal_to_hex -import mcontact.ui.default_config as config -import mcontact.globals as globals +from contact.utilities.utils import decimal_to_hex +import contact.ui.default_config as config +import contact.globals as globals def get_table_name(channel): # Construct the table name diff --git a/mcontact/utilities/input_handlers.py b/mcontact/utilities/input_handlers.py index e6a12c1..847b9f0 100644 --- a/mcontact/utilities/input_handlers.py +++ b/mcontact/utilities/input_handlers.py @@ -3,7 +3,7 @@ import binascii import curses import ipaddress import re -from mcontact.ui.colors import get_color +from contact.ui.colors import get_color def wrap_text(text, wrap_width): """Wraps text while preserving spaces and breaking long words.""" diff --git a/mcontact/utilities/interfaces.py b/mcontact/utilities/interfaces.py index 5b51eff..6cb0918 100644 --- a/mcontact/utilities/interfaces.py +++ b/mcontact/utilities/interfaces.py @@ -1,6 +1,6 @@ import logging import meshtastic.serial_interface, meshtastic.tcp_interface, meshtastic.ble_interface -import mcontact.globals as globals +import contact.globals as globals def initialize_interface(args): try: diff --git a/mcontact/utilities/utils.py b/mcontact/utilities/utils.py index c51ab27..6392899 100644 --- a/mcontact/utilities/utils.py +++ b/mcontact/utilities/utils.py @@ -1,7 +1,7 @@ -import mcontact.globals as globals +import contact.globals as globals import datetime from meshtastic.protobuf import config_pb2 -import mcontact.ui.default_config as config +import contact.ui.default_config as config def get_channels(): """Retrieve channels from the node and update globals.channel_list and globals.all_messages.""" diff --git a/pyproject.toml b/pyproject.toml index 96e1754..3798286 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "mcontact" +name = "contact" version = "1.3.0" description = "This Python curses client for Meshtastic is a terminal-based client designed to manage device settings, enable mesh chat communication, and handle configuration backups and restores." authors = [ @@ -18,4 +18,4 @@ requires = ["poetry-core>=2.0.0,<3.0.0"] build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] -mcontact = "mcontact.main:start" +contact = "contact.main:start" From ec0554df14671812f30dbf14482fbffe7342cbb0 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Tue, 1 Apr 2025 14:58:35 -0700 Subject: [PATCH 12/13] working changes --- {mcontact => contact}/globals.py | 0 {mcontact => contact}/localisations/en.ini | 0 {mcontact => contact}/main.py | 0 {mcontact => contact}/message_handlers/rx_handler.py | 0 {mcontact => contact}/message_handlers/tx_handler.py | 0 {mcontact => contact}/settings.py | 0 {mcontact => contact}/ui/colors.py | 0 {mcontact => contact}/ui/control_ui.py | 0 {mcontact => contact}/ui/curses_ui.py | 0 {mcontact => contact}/ui/default_config.py | 0 {mcontact => contact}/ui/dialog.py | 0 {mcontact => contact}/ui/menus.py | 0 {mcontact => contact}/ui/splash.py | 0 {mcontact => contact}/ui/user_config.py | 0 {mcontact => contact}/utilities/arg_parser.py | 0 {mcontact => contact}/utilities/config_io.py | 0 {mcontact => contact}/utilities/control_utils.py | 0 {mcontact => contact}/utilities/db_handler.py | 0 {mcontact => contact}/utilities/input_handlers.py | 0 {mcontact => contact}/utilities/interfaces.py | 0 {mcontact => contact}/utilities/save_to_radio.py | 0 {mcontact => contact}/utilities/utils.py | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename {mcontact => contact}/globals.py (100%) rename {mcontact => contact}/localisations/en.ini (100%) rename {mcontact => contact}/main.py (100%) rename {mcontact => contact}/message_handlers/rx_handler.py (100%) rename {mcontact => contact}/message_handlers/tx_handler.py (100%) rename {mcontact => contact}/settings.py (100%) rename {mcontact => contact}/ui/colors.py (100%) rename {mcontact => contact}/ui/control_ui.py (100%) rename {mcontact => contact}/ui/curses_ui.py (100%) rename {mcontact => contact}/ui/default_config.py (100%) rename {mcontact => contact}/ui/dialog.py (100%) rename {mcontact => contact}/ui/menus.py (100%) rename {mcontact => contact}/ui/splash.py (100%) rename {mcontact => contact}/ui/user_config.py (100%) rename {mcontact => contact}/utilities/arg_parser.py (100%) rename {mcontact => contact}/utilities/config_io.py (100%) rename {mcontact => contact}/utilities/control_utils.py (100%) rename {mcontact => contact}/utilities/db_handler.py (100%) rename {mcontact => contact}/utilities/input_handlers.py (100%) rename {mcontact => contact}/utilities/interfaces.py (100%) rename {mcontact => contact}/utilities/save_to_radio.py (100%) rename {mcontact => contact}/utilities/utils.py (100%) diff --git a/mcontact/globals.py b/contact/globals.py similarity index 100% rename from mcontact/globals.py rename to contact/globals.py diff --git a/mcontact/localisations/en.ini b/contact/localisations/en.ini similarity index 100% rename from mcontact/localisations/en.ini rename to contact/localisations/en.ini diff --git a/mcontact/main.py b/contact/main.py similarity index 100% rename from mcontact/main.py rename to contact/main.py diff --git a/mcontact/message_handlers/rx_handler.py b/contact/message_handlers/rx_handler.py similarity index 100% rename from mcontact/message_handlers/rx_handler.py rename to contact/message_handlers/rx_handler.py diff --git a/mcontact/message_handlers/tx_handler.py b/contact/message_handlers/tx_handler.py similarity index 100% rename from mcontact/message_handlers/tx_handler.py rename to contact/message_handlers/tx_handler.py diff --git a/mcontact/settings.py b/contact/settings.py similarity index 100% rename from mcontact/settings.py rename to contact/settings.py diff --git a/mcontact/ui/colors.py b/contact/ui/colors.py similarity index 100% rename from mcontact/ui/colors.py rename to contact/ui/colors.py diff --git a/mcontact/ui/control_ui.py b/contact/ui/control_ui.py similarity index 100% rename from mcontact/ui/control_ui.py rename to contact/ui/control_ui.py diff --git a/mcontact/ui/curses_ui.py b/contact/ui/curses_ui.py similarity index 100% rename from mcontact/ui/curses_ui.py rename to contact/ui/curses_ui.py diff --git a/mcontact/ui/default_config.py b/contact/ui/default_config.py similarity index 100% rename from mcontact/ui/default_config.py rename to contact/ui/default_config.py diff --git a/mcontact/ui/dialog.py b/contact/ui/dialog.py similarity index 100% rename from mcontact/ui/dialog.py rename to contact/ui/dialog.py diff --git a/mcontact/ui/menus.py b/contact/ui/menus.py similarity index 100% rename from mcontact/ui/menus.py rename to contact/ui/menus.py diff --git a/mcontact/ui/splash.py b/contact/ui/splash.py similarity index 100% rename from mcontact/ui/splash.py rename to contact/ui/splash.py diff --git a/mcontact/ui/user_config.py b/contact/ui/user_config.py similarity index 100% rename from mcontact/ui/user_config.py rename to contact/ui/user_config.py diff --git a/mcontact/utilities/arg_parser.py b/contact/utilities/arg_parser.py similarity index 100% rename from mcontact/utilities/arg_parser.py rename to contact/utilities/arg_parser.py diff --git a/mcontact/utilities/config_io.py b/contact/utilities/config_io.py similarity index 100% rename from mcontact/utilities/config_io.py rename to contact/utilities/config_io.py diff --git a/mcontact/utilities/control_utils.py b/contact/utilities/control_utils.py similarity index 100% rename from mcontact/utilities/control_utils.py rename to contact/utilities/control_utils.py diff --git a/mcontact/utilities/db_handler.py b/contact/utilities/db_handler.py similarity index 100% rename from mcontact/utilities/db_handler.py rename to contact/utilities/db_handler.py diff --git a/mcontact/utilities/input_handlers.py b/contact/utilities/input_handlers.py similarity index 100% rename from mcontact/utilities/input_handlers.py rename to contact/utilities/input_handlers.py diff --git a/mcontact/utilities/interfaces.py b/contact/utilities/interfaces.py similarity index 100% rename from mcontact/utilities/interfaces.py rename to contact/utilities/interfaces.py diff --git a/mcontact/utilities/save_to_radio.py b/contact/utilities/save_to_radio.py similarity index 100% rename from mcontact/utilities/save_to_radio.py rename to contact/utilities/save_to_radio.py diff --git a/mcontact/utilities/utils.py b/contact/utilities/utils.py similarity index 100% rename from mcontact/utilities/utils.py rename to contact/utilities/utils.py From 857d8d0c0472e7557f5fadb7901aa2876adab152 Mon Sep 17 00:00:00 2001 From: pdxlocations Date: Tue, 1 Apr 2025 15:52:57 -0700 Subject: [PATCH 13/13] update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0badf56..f4e2ce9 100644 --- a/README.md +++ b/README.md @@ -54,11 +54,11 @@ If no connection arguments are specified, the client will attempt a serial conne ### Example Usage ```sh -python main.py --port /dev/ttyUSB0 -python main.py --host 192.168.1.1 -python main.py --ble BlAddressOfDevice +contact --port /dev/ttyUSB0 +contact --host 192.168.1.1 +contact --ble BlAddressOfDevice ``` To quickly connect to localhost, use: ```sh -python main.py -t +contact -t ```