diff --git a/README.md b/README.md index 8425153..9fa55cf 100644 --- a/README.md +++ b/README.md @@ -30,38 +30,36 @@ There is a bug in the takproto library which causes an exception in TAK Meshtast There is a [PR](https://github.com/snstac/takproto/pull/16) that will fix the issue once it is merged. Until it is merged, TAK Meshtastic Gateway will install takproto from the GitHub PR instead of PyPI. +On Windows, the `unishox2-py3` library fails to build from the source distribution with the command `pip install unishox2-py3`. +TAK Meshtastic Gateway will instead install [this wheel](https://github.com/brian7704/OpenTAKServer-Installer/blob/master/unishox2_py3-1.0.0-cp312-cp312-win_amd64.whl). +As a result, Python 3.12 is required when running TAK Meshtastic Gateway on Windows. ## Installation -### Linux +For installation you only need to create a Python virtual environment, activate the virtual environment, and install using pip. -Steps may differ slightly on some distros +### Linux/macOS -```bash -git clone https://github.com/brian7704/TAK_Meshtastic_Gateway.git -cd TAK_Meshtastic_Gateway -python3 -m venv venv -. ./venv/bin/activate -pip install bs4 meshtastic pubsub takproto colorlog unishox2-py3 netifaces2 +The unishox2-py3 Python library requires C build tools. In Debian based distros (i.e. Ubuntu) they can be installed with +`apt install build-essential`. + +```shell +python3 -m venv tak_meshtastic_gateway_venv +. ./tak_meshtastic_gateway_venv/bin/activate +pip install tak-meshtastic-gateway ``` ### Windows -These instructions assume you already have git and Python installed. In a future release there will be a binary made -with PyInstaller which won't require git or Python to be installed. - -```bash -git clone https://github.com/brian7704/TAK_Meshtastic_Gateway.git -cd TAK_Meshtastic_Gateway -python -m venv venv -.\venv\Scripts\activate.bat -pip install bs4 meshtastic pubsub takproto colorlog unishox2-py3 netifaces2 +```powershell +python -m venv tak_meshtastic_gateway_venv +.\tak_meshtastic_gateway_venv\Scripts\activate +pip install tak-meshtastic-gateway ``` -### MacOS +## Usage -TAK Meshtastic Gateway is untested on MacOS but should work fine. Try the Linux installation instructions and open -an issue to let us know if there are any problems. +When your virtual environment active, run the `tak-meshtastic-gateway` command ## Architecture @@ -73,9 +71,21 @@ node over the LAN allows it to be mounted in a spot outside with good mesh recep The Meshtastic node should be set to the TAK role. TAK Meshtastic Gateway will automatically change the node's long name to the TAK client's callsign and the short name to the last four characters of the TAK client's UID. This ensures that -the callsign shows up correctly for mesh users who are only using the Meshtastic app and not a TAK client. +the callsign shows up correctly for mesh users who are only using the Meshtastic app as well as ATAK plugin users. TAK Meshtastic Gateway will also update the Meshtastic node's location with the location of the EUD. +## ATAK Plugin Settings + +For best results, use the following settings on devices using the [Meshtastic ATAK Plugin.](https://meshtastic.org/docs/software/integrations/integrations-atak-plugin/). +You can find the settings in ATAK by clicking the Settings tool -> Tool Preferences -> Specific Tool Preferences -> +Meshtastic Preferences. + +- Show all Meshtastic devices: On +- Don't sshow Meshtastic devices without GPS: On +- Do not show your local Meshtastic device: On + +The rest of the settings can be changed as needed. + ## Usage All arguments are optional. If an argument is not specified its default value will be used. @@ -104,14 +114,14 @@ not require elevated permissions. - WinTAK on a PC - Meshtastic node connected to the PC via USB - TAK Meshtastic Gateway running on the same PC -- Command: `python3 tak_meshtastic_gateway.py` +- Command: `tak_meshtastic_gateway` ### Scenario 2 - WinTAK on a PC - Meshtastic node on the same LAN as the PC - TAK Meshtastic Gateway running on the same PC as WinTAK -- Command: `python3 tak_meshtastic_gateway.py --mesh-ip MESHTASTIC_NODE_IP` Note: Substitute `MESHTASTIC_NODE_IP` with +- Command: `tak_meshtastic_gateway --mesh-ip MESHTASTIC_NODE_IP` Note: Substitute `MESHTASTIC_NODE_IP` with the node's actual IP (i.e. `192.168.1.10`) ### Scenario 3 @@ -119,5 +129,5 @@ the node's actual IP (i.e. `192.168.1.10`) - ATAK or iTAK on a mobile device connected to a Wi-Fi network - Meshtastic node connected to the same network - TAK Meshtastic Gateway running on a computer or VM on the same network -- Command: `python3 tak_meshtastic_gateway.py --mesh-ip MESHTASTIC_NODE_IP --tak-client-ip TAK_CLIENT_IP` Note: Substitute +- Command: `tak_meshtastic_gateway --mesh-ip MESHTASTIC_NODE_IP --tak-client-ip TAK_CLIENT_IP` Note: Substitute `MESHTASTIC_NODE_IP` and `TAK_CLIENT_IP` with their actual IPs (i.e. `192.168.1.10` and `192.168.1.11`) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index bacc12a..ef3ce0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ python = [ {platform = "macos", version = "^3.8"} ] beautifulsoup4 = "4.12.3" +lxml = "5.2.2" meshtastic = "2.3.11" pypubsub = "4.0.3" colorlog = "6.8.2" diff --git a/tak_meshtastic_gateway/__init__.py b/tak_meshtastic_gateway/__init__.py index 4a01667..55405b9 100644 --- a/tak_meshtastic_gateway/__init__.py +++ b/tak_meshtastic_gateway/__init__.py @@ -1,3 +1,3 @@ # These version placeholders will be replaced later during substitution. -__version__ = "0.0.0-post.13+f653ee9" -__version_tuple__ = (0, 0, 0, "post", 13, "f653ee9") +__version__ = "0.0.0-post.14+c0c6411" +__version_tuple__ = (0, 0, 0, "post", 14, "c0c6411") diff --git a/tak_meshtastic_gateway/tak_meshtastic_gateway.py b/tak_meshtastic_gateway/tak_meshtastic_gateway.py index 3818d93..3a04481 100644 --- a/tak_meshtastic_gateway/tak_meshtastic_gateway.py +++ b/tak_meshtastic_gateway/tak_meshtastic_gateway.py @@ -49,6 +49,7 @@ def __init__(self, ip=None, serial_device=None, mesh_ip=None, tak_client_ip="loc self.dm_port = dm_port self.serial_device = serial_device self.mesh_ip = mesh_ip + self.tak_client_ip = tak_client_ip self.tx_interval = tx_interval self.log_file = log_file self.log_level = logging.DEBUG if debug else logging.INFO @@ -411,11 +412,11 @@ def main(self): if platform.system() == 'Windows': self.chat_sock.bind((self.ip, chat_in[1])) self.chat_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(self.ip)) - self.chat_sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(chat_in[0]) + socket.inet_aton(self.ip) + socket.inet_aton(self.ip)) + self.chat_sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(chat_in[0]) + socket.inet_aton(self.ip)) else: self.chat_sock.bind(chat_in) self.chat_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(self.ip)) - self.chat_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(chat_in[0]) + socket.inet_aton(self.ip) + socket.inet_aton(self.ip)) + self.chat_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(chat_in[0]) + socket.inet_aton(self.ip)) self.sa_multicast_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) self.sa_multicast_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) @@ -423,11 +424,11 @@ def main(self): if platform.system() == 'Windows': self.sa_multicast_sock.bind((self.ip, sa_multicast_in[1])) self.sa_multicast_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(self.ip)) - self.sa_multicast_sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(sa_multicast_in[0]) + socket.inet_aton(self.ip) + socket.inet_aton(self.ip)) + self.sa_multicast_sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(sa_multicast_in[0]) + socket.inet_aton(self.ip)) else: self.sa_multicast_sock.bind(sa_multicast_in) self.sa_multicast_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(self.ip)) - self.sa_multicast_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(sa_multicast_in[0]) + socket.inet_aton(self.ip) + socket.inet_aton(self.ip)) + self.sa_multicast_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(sa_multicast_in[0]) + socket.inet_aton(self.ip)) self.dm_sock.start() @@ -439,7 +440,7 @@ def main(self): data, sender = s.recvfrom(4096) # Only accept multicast data from one TAK client - if sender[0] != self.ip: + if sender[0] != self.ip and sender[0] != self.tak_client_ip: self.logger.warning(f"Got data from {sender[0]}, ignoring") continue except KeyboardInterrupt: