From 10f509f731d6e7b766c4184f5c3ef6db0829916b Mon Sep 17 00:00:00 2001 From: Jeremiah K <17190268+jeremiah-k@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:50:56 -0500 Subject: [PATCH] It's working --- meshtastic_utils.py | 193 ++++++++++++++++++++++++++++---------------- 1 file changed, 123 insertions(+), 70 deletions(-) diff --git a/meshtastic_utils.py b/meshtastic_utils.py index 9b88975..6c49d88 100644 --- a/meshtastic_utils.py +++ b/meshtastic_utils.py @@ -2,12 +2,12 @@ import asyncio import time import meshtastic.tcp_interface import meshtastic.serial_interface +import meshtastic.ble_interface from typing import List from config import relay_config from log_utils import get_logger from db_utils import get_longname, get_shortname from plugin_loader import load_plugins -from ble_interface import BLEInterface matrix_rooms: List[dict] = relay_config["matrix_rooms"] @@ -32,80 +32,133 @@ def connect_meshtastic(force_connect=False): attempts = 1 successful = False - if connection_type == "serial": - serial_port = relay_config["meshtastic"]["serial_port"] - logger.info(f"Connecting to serial port {serial_port} ...") - while not successful and attempts <= retry_limit: - try: - meshtastic_client = meshtastic.serial_interface.SerialInterface( - serial_port - ) - successful = True - except Exception as e: - attempts += 1 - if attempts <= retry_limit: - logger.warn( - f"Attempt #{attempts-1} failed. Retrying in {attempts} secs {e}" - ) - time.sleep(attempts) - else: - logger.error(f"Could not connect: {e}") - return None + while not successful and attempts <= retry_limit: + try: + if connection_type == "serial": + serial_port = relay_config["meshtastic"]["serial_port"] + logger.info(f"Connecting to serial port {serial_port} ...") + meshtastic_client = meshtastic.serial_interface.SerialInterface(serial_port) + + elif connection_type == "ble": + ble_address = relay_config["meshtastic"].get("ble_address") + ble_name = relay_config["meshtastic"].get("ble_name") - elif connection_type == "ble": - ble_address = relay_config["meshtastic"].get("ble_address") - ble_name = relay_config["meshtastic"].get("ble_name") - - if ble_address and ble_name: - logger.info(f"Connecting to BLE address {ble_address} ...") - elif ble_address: - logger.info(f"Connecting to BLE address {ble_address} ...") - elif ble_name: - logger.info(f"Connecting to BLE name {ble_name} ...") - else: - logger.error("No BLE address or name provided.") - return None - - while not successful and attempts <= retry_limit: - try: if ble_address: - meshtastic_client = BLEInterface(address=ble_address) + logger.info(f"Connecting to BLE address {ble_address} ...") + meshtastic_client = meshtastic.ble_interface.BLEInterface(address=ble_address) elif ble_name: - meshtastic_client = BLEInterface(address=ble_name) - successful = True - except Exception as e: - attempts += 1 - if attempts <= retry_limit: - logger.warn( - f"Attempt #{attempts-1} failed. Retrying in {attempts} secs {e}" - ) - time.sleep(attempts) + logger.info(f"Connecting to BLE name {ble_name} ...") + meshtastic_client = meshtastic.ble_interface.BLEInterface(address=ble_name) else: - logger.error(f"Could not connect: {e}") + logger.error("No BLE address or name provided.") return None + + else: + target_host = relay_config["meshtastic"]["host"] + logger.info(f"Connecting to host {target_host} ...") + meshtastic_client = meshtastic.tcp_interface.TCPInterface(hostname=target_host) - else: - target_host = relay_config["meshtastic"]["host"] - logger.info(f"Connecting to host {target_host} ...") - while not successful and attempts <= retry_limit: - try: - meshtastic_client = meshtastic.tcp_interface.TCPInterface( - hostname=target_host - ) - successful = True - except Exception as e: - attempts += 1 - if attempts <= retry_limit: - logger.warn( - f"Attempt #{attempts-1} failed. Retrying in {attempts} secs... {e}" - ) - time.sleep(attempts) - else: - logger.error(f"Could not connect: {e}") - return None + successful = True + nodeInfo = meshtastic_client.getMyNodeInfo() + logger.info(f"Connected to {nodeInfo['user']['shortName']} / {nodeInfo['user']['hwModel']}") + + except Exception as e: + attempts += 1 + if attempts <= retry_limit: + logger.warn(f"Attempt #{attempts-1} failed. Retrying in {attempts} secs {e}") + time.sleep(attempts) + else: + logger.error(f"Could not connect: {e}") + return None - nodeInfo = meshtastic_client.getMyNodeInfo() - logger.info( - f"Connected to {nodeInfo['user']['shortName']} / {nodeInfo['user']['hwModel']}" - ) return meshtastic_client + +def on_lost_meshtastic_connection(interface): + logger.error("Lost connection. Reconnecting...") + connect_meshtastic(force_connect=True) + +def on_meshtastic_message(packet, loop=None): + from matrix_utils import matrix_relay + + sender = packet["fromId"] + + if "text" in packet["decoded"] and packet["decoded"]["text"]: + text = packet["decoded"]["text"] + + if "channel" in packet: + channel = packet["channel"] + else: + if packet["decoded"]["portnum"] == "TEXT_MESSAGE_APP": + channel = 0 + else: + logger.debug(f"Unknown packet") + return + + # Check if the channel is mapped to a Matrix room in the configuration + channel_mapped = False + for room in matrix_rooms: + if room["meshtastic_channel"] == channel: + channel_mapped = True + break + + if not channel_mapped: + logger.debug(f"Skipping message from unmapped channel {channel}") + return + + logger.info(f"Processing inbound radio message from {sender} on channel {channel}") + + longname = get_longname(sender) or sender + shortname = get_shortname(sender) or sender + meshnet_name = relay_config["meshtastic"]["meshnet_name"] + + formatted_message = f"[{longname}/{meshnet_name}]: {text}" + + # Plugin functionality + plugins = load_plugins() + + found_matching_plugin = False + for plugin in plugins: + if not found_matching_plugin: + result = asyncio.run_coroutine_threadsafe( + plugin.handle_meshtastic_message( + packet, formatted_message, longname, meshnet_name + ), + loop=loop, + ) + found_matching_plugin = result.result() + if found_matching_plugin: + logger.debug(f"Processed by plugin {plugin.plugin_name}") + + if found_matching_plugin: + return + + logger.info(f"Relaying Meshtastic message from {longname} to Matrix: {formatted_message}") + + for room in matrix_rooms: + if room["meshtastic_channel"] == channel: + asyncio.run_coroutine_threadsafe( + matrix_relay( + room["id"], + formatted_message, + longname, + shortname, + meshnet_name, + ), + loop=loop, + ) + else: + portnum = packet["decoded"]["portnum"] + + plugins = load_plugins() + found_matching_plugin = False + for plugin in plugins: + if not found_matching_plugin: + result = asyncio.run_coroutine_threadsafe( + plugin.handle_meshtastic_message( + packet, formatted_message=None, longname=None, meshnet_name=None + ), + loop=loop, + ) + found_matching_plugin = result.result() + if found_matching_plugin: + logger.debug(f"Processed {portnum} with plugin {plugin.plugin_name}")