From d6e6a35de13940f86602cdab32c0c077d705305f Mon Sep 17 00:00:00 2001 From: Greg Albrecht Date: Tue, 13 Aug 2024 15:35:16 -0700 Subject: [PATCH] Rewrite for 2024 --- .github/workflows/debian.yml | 40 ++-- .github/workflows/python-publish_to_pypi.yml | 2 +- .github/workflows/python-test_and_lint.yml | 5 +- .readthedocs.yml | 17 ++ CHANGELOG.md | 4 + LICENSE | 195 +++++++++++++++++- Makefile | 59 ++++-- README.md | 25 +++ README.rst | 158 -------------- aprscot/__init__.py | 50 ++--- aprscot/classes.py | 37 ++-- aprscot/commands.py | 16 +- aprscot/constants.py | 29 +-- aprscot/functions.py | 104 +++++----- docs/changelog.md | 1 + docs/configuration.md | 67 ++++++ docs/conop.md | 4 + docs/index.md | 1 + docs/installation.md | 35 ++++ docs/{ => media}/aprscot-concept.png | Bin docs/{ => media}/screenshot.png | Bin docs/{ => media}/screenshot2-25.png | Bin docs/{ => media}/screenshot2-50.png | Bin docs/{ => media}/screenshot2.png | Bin docs/{ => media}/screenshot3.png | Bin docs/{ => media}/screenshot4.png | Bin docs/{ => media}/screenshot5.png | Bin docs/{ => media}/screenshot6.png | Bin .../screenshot_1637083156_28841.png | Bin .../screenshot_1637083168_26966.png | Bin .../screenshot_1637083172_3709.png | Bin .../screenshot_1637083240_16797-25p.png | Bin .../screenshot_1637083240_16797-50p.png | Bin .../screenshot_1637083240_16797.png | Bin .../screenshot_1637083260_7170.png | Bin docs/requirements.txt | 23 +++ docs/troubleshooting.md | 26 +++ docs/usage.md | 46 +++++ setup.cfg | 105 +++++++++- setup.py | 63 +----- tests/test_functions.py | 12 +- 41 files changed, 708 insertions(+), 416 deletions(-) create mode 100644 .readthedocs.yml create mode 100644 CHANGELOG.md create mode 100644 README.md delete mode 100644 README.rst create mode 100644 docs/changelog.md create mode 100644 docs/configuration.md create mode 100644 docs/conop.md create mode 100644 docs/index.md create mode 100644 docs/installation.md rename docs/{ => media}/aprscot-concept.png (100%) rename docs/{ => media}/screenshot.png (100%) rename docs/{ => media}/screenshot2-25.png (100%) rename docs/{ => media}/screenshot2-50.png (100%) rename docs/{ => media}/screenshot2.png (100%) rename docs/{ => media}/screenshot3.png (100%) rename docs/{ => media}/screenshot4.png (100%) rename docs/{ => media}/screenshot5.png (100%) rename docs/{ => media}/screenshot6.png (100%) rename docs/{ => media}/screenshot_1637083156_28841.png (100%) rename docs/{ => media}/screenshot_1637083168_26966.png (100%) rename docs/{ => media}/screenshot_1637083172_3709.png (100%) rename docs/{ => media}/screenshot_1637083240_16797-25p.png (100%) rename docs/{ => media}/screenshot_1637083240_16797-50p.png (100%) rename docs/{ => media}/screenshot_1637083240_16797.png (100%) rename docs/{ => media}/screenshot_1637083260_7170.png (100%) create mode 100644 docs/requirements.txt create mode 100644 docs/troubleshooting.md create mode 100644 docs/usage.md diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 035a5ba..64eb243 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -1,4 +1,4 @@ -name: Build Debian package +name: Build Debian Package on: push: @@ -10,38 +10,24 @@ env: jobs: build-artifact: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@master - - name: Install packaging dependencies - run: | - sudo apt-get update -qq - sudo apt-get install -y \ - python3 python3-dev python3-pip python3-venv python3-all \ - dh-python debhelper devscripts dput software-properties-common \ - python3-distutils python3-setuptools python3-wheel python3-stdeb - - - name: Build Debian/Apt sdist_dsc - run: | - rm -Rf deb_dist/* - python3 setup.py --command-packages=stdeb.command sdist_dsc - - - name: Build Debian/Apt bdist_deb - run: | - export REPO_NAME=$(echo ${{ github.repository }} | awk -F"/" '{print $2}') - python3 setup.py --command-packages=stdeb.command bdist_deb - ls -al deb_dist/ - cp deb_dist/python3-${REPO_NAME}_*_all.deb deb_dist/python3-${REPO_NAME}_latest_all.deb - - - uses: actions/upload-artifact@master + - name: Install Debian Package Building Dependencies + run: sudo bash debian/install_pkg_build_deps.sh + + - name: Create Debian Package + run: make clean package + + - name: Upload Artifacts to GitHub + uses: actions/upload-artifact@master with: name: artifact-deb - path: | - deb_dist/*.deb + path: deb_dist/*.deb - - name: Create Release + - name: Create GitHub Release id: create_release uses: actions/create-release@master env: @@ -52,7 +38,7 @@ jobs: draft: false prerelease: false - - name: Upload Release Asset + - name: Upload Release Asset to GitHub id: upload-release-asset uses: svenstaro/upload-release-action@v2 with: diff --git a/.github/workflows/python-publish_to_pypi.yml b/.github/workflows/python-publish_to_pypi.yml index 2c719cf..a068d8a 100644 --- a/.github/workflows/python-publish_to_pypi.yml +++ b/.github/workflows/python-publish_to_pypi.yml @@ -9,7 +9,7 @@ on: jobs: deploy: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/python-test_and_lint.yml b/.github/workflows/python-test_and_lint.yml index 455c927..14b51c4 100644 --- a/.github/workflows/python-test_and_lint.yml +++ b/.github/workflows/python-test_and_lint.yml @@ -9,11 +9,12 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + # python-version: [3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12"] + python-version: [3.7, 3.8, 3.9, "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v2 diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..e941dac --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,17 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +mkdocs: + configuration: mkdocs.yml + +python: + install: + - requirements: docs/requirements.txt diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..54e1ab1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +## APRSCOT 8.0.0 + +* Rewrite for 2024. +* Fixed #12 & #15: Add support for APRS-IS Passcodes ("passwords"). diff --git a/LICENSE b/LICENSE index 24b9c09..52df472 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,199 @@ -Copyright 2022 Greg Albrecht + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/Makefile b/Makefile index e68fbb9..982a4d8 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ +# Makefile from https://github.com/snstac/pytak +# PyTAK Makefile # -# Copyright 2022 Greg Albrecht +# Copyright Sensors & Signals LLC https://www.snstac.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -13,15 +13,15 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Author:: Greg Albrecht W2GMD -# Copyright:: Copyright 2022 Greg Albrecht -# License:: Apache License, Version 2.0 -# -this_app = aprscot -.DEFAULT_GOAL := all +REPO_NAME ?= $(shell echo $(wildcard */__init__.py) | awk -F'/' '{print $$1}') +SHELL := /bin/bash +.DEFAULT_GOAL := editable +# postinst = $(wildcard debian/*.postinst.sh) +# service = $(wildcard debian/*.service) -all: editable +prepare: + mkdir -p build/ develop: python3 setup.py develop @@ -30,13 +30,13 @@ editable: python3 -m pip install -e . install_test_requirements: - python3 -m pip install -r requirements_test.txt + python3 -m pip install -r requirements_test.txt install: python3 setup.py install uninstall: - python3 -m pip uninstall -y $(this_app) + python3 -m pip uninstall -y $(REPO_NAME) reinstall: uninstall install @@ -47,16 +47,16 @@ clean: @rm -rf *.egg* build dist *.py[oc] */*.py[co] cover doctest_pypi.cfg \ nosetests.xml pylint.log output.xml flake8.log tests.log \ test-result.xml htmlcov fab.log .coverage __pycache__ \ - */__pycache__ + */__pycache__ deb_dist .mypy_cache pep8: - flake8 --max-line-length=88 --extend-ignore=E203 --exit-zero $(this_app)/*.py + flake8 --max-line-length=88 --extend-ignore=E203 --exit-zero $(REPO_NAME)/*.py flake8: pep8 lint: pylint --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" \ - --max-line-length=88 -r n $(this_app)/*.py || exit 0 + --max-line-length=88 -r n $(REPO_NAME)/*.py || exit 0 pylint: lint @@ -72,7 +72,32 @@ pytest: test: editable install_test_requirements pytest test_cov: - pytest --cov=$(this_app) + pytest --cov=$(REPO_NAME) --cov-report term-missing black: black . + +mkdocs: + pip install -r docs/requirements.txt + mkdocs serve + +deb_dist: + python3 setup.py --command-packages=stdeb.command sdist_dsc + +deb_custom: + cp debian/$(REPO_NAME).conf $(wildcard deb_dist/*/debian)/$(REPO_NAME).default + cp debian/$(REPO_NAME).postinst $(wildcard deb_dist/*/debian)/$(REPO_NAME).postinst + cp debian/$(REPO_NAME).service $(wildcard deb_dist/*/debian)/$(REPO_NAME).service + +bdist_deb: deb_dist deb_custom + cd deb_dist/$(REPO_NAME)-*/ && dpkg-buildpackage -rfakeroot -uc -us + +faux_latest: + cp deb_dist/$(REPO_NAME)_*-1_all.deb deb_dist/$(REPO_NAME)_latest_all.deb + cp deb_dist/$(REPO_NAME)_*-1_all.deb deb_dist/python3-$(REPO_NAME)_latest_all.deb + +package: bdist_deb faux_latest + +extract: + dpkg-deb -e $(wildcard deb_dist/*latest_all.deb) deb_dist/extract + dpkg-deb -x $(wildcard deb_dist/*latest_all.deb) deb_dist/extract diff --git a/README.md b/README.md new file mode 100644 index 0000000..fde4f3c --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +![ATAK screenshot](https://raw.githubusercontent.com/ampledata/aprscot/main/docs/media/screenshot_1637083240_16797.png) + +# Display APRS in TAK + +APRSCOT is software for monitoring and analyzing APRS via the [Team Awareness Kit (TAK)](https://www.tak.gov) ecosystem of products. + +APRSCOT captures & reports real-time APRS data received from over-the-air RF or Internet gateways, including APRS-IS. + +[Documentation is available here.](https://aprscot.rtfd.io) + +# License & Copyright + +Copyright Sensors & Signals LLC https://www.snstac.com/ + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +[Automatic Packet Reporting System (APRS)](http://www.aprs.org/) is Copyright Bob Bruninga WB4APR (SK) wb4apr@amsat.org diff --git a/README.rst b/README.rst deleted file mode 100644 index 9cbb8fc..0000000 --- a/README.rst +++ /dev/null @@ -1,158 +0,0 @@ -aprscot - APRS Cursor-on-Target Gateway. -**************************************** - -.. image:: https://raw.githubusercontent.com/ampledata/aprscot/main/docs/screenshot_1637083240_16797-50p.png - :alt: Screenshot of APRS PLI in ATAK. - :target: https://raw.githubusercontent.com/ampledata/aprscot/main/docs/screenshot_1637083240_16797.png - -The APRS to Cursor On Target Gateway (APRSCOT) provides beyond line-of-sight -blue force tracking capabilities using commercial off the shelf components. -This gateway uses the Automatic Packet Reporting System (APRS) and APRS-IS -network to forward APRS position reports to Cursor On Target (COT) clients -such as the Android Team Awareness Kit (ATAK), WinTAK, et al. Other -situational awareness & common operating picture platforms are supported -through use of COT, such as TAKX & COPERS. - -APRS Frames can also be transformed or callsigns normalized before forwarding -as COT. Almost any network destination is available, including TCP & UDP -Mulitcast. - -Features of ``aprscot``: - -* Handles APRS-IS transported APRS Frames from over-the-air or Internet-based stations. -* Can transform APRS station callsign, COT Type and COT Icon for display in TAK systems. -* Can run as a service ('daemon') on any Linux system. -* Can send COT Events to any destination supported by `PyTAK `_: TLS/SSL, TCP, UDP, UDP Multicast. - -See also: - -* Hayt's `APRS-TAK ATAK Plugin `_ -* Alan Barrow's aprstak: https://github.com/pinztrek/aprstak - -Concept: - -.. image:: https://raw.githubusercontent.com/ampledata/aprscot/main/docs/aprscot-concept.png - :alt: APRSCOT concept diagram. - :target: https://raw.githubusercontent.com/ampledata/aprscot/main/docs/aprscot-concept.png - - -Support Development -=================== - -**Tech Support**: Email support@undef.net or Signal/WhatsApp: +1-310-621-9598 - -This tool has been developed for the Disaster Response, Public Safety and -Frontline Healthcare community. This software is currently provided at no-cost -to users. Any contribution you can make to further this project's development -efforts is greatly appreciated. - -.. image:: https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png - :target: https://www.buymeacoffee.com/ampledata - :alt: Support Development: Buy me a coffee! - - -Installation -============ - -The APRS to COT gateway is service started with a command-line tool -called ``aprscot``. There are three options for installing ``aprscot``, in order -preferred option they are: - -**Option I: Install as a Debian / Ubuntu Package**:: - - $ wget https://github.com/ampledata/pytak/releases/latest/download/python3-pytak_latest_all.deb - $ sudo apt install -f ./python3-pytak_latest_all.deb - $ wget https://github.com/ampledata/aprs-python/releases/latest/download/python3-aprslib_latest_all.deb - $ sudo apt install -f ./python3-aprslib_latest_all.deb - $ wget https://github.com/ampledata/aprscot/releases/latest/download/python3-aprscot_latest_all.deb - $ sudo apt install -f ./python3-aprscot_latest_all.deb - - -Option II: Install from the Python Package Index (PyPI):: - - $ python3 -m pip install aprscot - - -Option III: Install from this source tree:: - - $ git clone https://github.com/ampledata/aprscot.git - $ cd aprscot/ - $ python3 setup.py install - - -Usage -===== - -The ``aprscot`` program has one command-line argument:: - - $ aprscot -h - usage: aprscot [-h] [-c CONFIG_FILE] - - optional arguments: - -h, --help show this help message and exit - -c CONFIG_FILE, --CONFIG_FILE CONFIG_FILE - -You must create a configuration file, see ``example-config.ini`` in the source -repository. - -An example config, ``COT_URL`` is our COT destination server or client:: - - [aprscot] - COT_URL = tcp://takserver.example.com:8088 - - -`APRS-IS Server-side Filter Commands `_ -can be used to filter incoming APRS Frames:: - - [aprscot] - COT_URL = tcp:takserver.example.com:8088 - APRSIS_FILTER = f/W6PW-10/50 - -PLI Transforms can be created using per-station sections. In this example, -we're overriding ``W2GMD-9``'s COT Type & Callsign, and ``NB6F-2``'s Callsign:: - - [aprscot] - COT_URL = tcp:takserver.example.com:8088 - - [W2GMD-9] - COT_TYPE = a-f-G-U-C - COT_STALE = 600 - COT_NAME = Medic 52 - - [NB6F-2] - COT_NAME = Transport 2 - - -Source -====== -Github: https://github.com/ampledata/aprscot - - -Author -====== -Greg Albrecht W2GMD oss@undef.net - -https://ampledata.org/ - - -Copyright -========= - -* APRSCOT is Copyright 2022 Greg Albrecht -* `Automatic Packet Reporting System (APRS) `_ is Copyright Bob Bruninga WB4APR (SK) wb4apr@amsat.org - - -License -======= - -Copyright 2022 Greg Albrecht - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/aprscot/__init__.py b/aprscot/__init__.py index 2c2d653..6f0c136 100644 --- a/aprscot/__init__.py +++ b/aprscot/__init__.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright 2022 Greg Albrecht +# Copyright Sensors & Signals LLC https://www.snstac.com # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -13,35 +15,27 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Author:: Greg Albrecht W2GMD -# -""" -APRS Cursor-on-Target Gateway. -~~~~ +"""APRS to TAK Gateway.""" -:author: Greg Albrecht W2GMD -:copyright: Copyright 2022 Greg Albrecht -:license: Apache License, Version 2.0 -:source: -""" +__version__ = "8.0.0-beta1" -from .constants import ( # NOQA - LOG_FORMAT, - LOG_LEVEL, - DEFAULT_APRSIS_PORT, - DEFAULT_COT_TYPE, - DEFAULT_COT_STALE, - DEFAULT_APRSIS_HOST, - DEFAULT_APRSIS_CALLSIGN, - DEFAULT_APRSIS_FILTER, -) +# COMPAT: CI compat (was py 3.6) +try: + from .constants import ( # NOQA + DEFAULT_APRSIS_PORT, + DEFAULT_COT_TYPE, + DEFAULT_COT_STALE, + DEFAULT_APRSIS_HOST, + DEFAULT_APRSIS_CALLSIGN, + DEFAULT_APRSIS_PASSCODE, + DEFAULT_APRSIS_FILTER, + ) -from .functions import aprs_to_cot, create_tasks # NOQA + from .functions import aprs_to_cot, create_tasks # NOQA -from .classes import APRSWorker # NOQA + from .classes import APRSWorker # NOQA +except ImportError as exc: + import warnings -__author__ = "Greg Albrecht W2GMD " -__copyright__ = "Copyright 2022 Greg Albrecht" -__license__ = "Apache License, Version 2.0" -__source__ = "https://github.com/ampledata/aprscot" + warnings.warn(f"COMPAT: CI. Ignoring Exception {str(exc)}") diff --git a/aprscot/classes.py b/aprscot/classes.py index d1c706b..19788c6 100644 --- a/aprscot/classes.py +++ b/aprscot/classes.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright 2022 Greg Albrecht +# Copyright Sensors & Signals LLC https://www.snstac.com # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -13,35 +15,24 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Author:: Greg Albrecht W2GMD -# """APRSCOT Class Definitions.""" import asyncio -from configparser import ConfigParser +from typing import Optional import aprslib.parsing import pytak import aprscot -__author__ = "Greg Albrecht W2GMD " -__copyright__ = "Copyright 2022 Greg Albrecht" -__license__ = "Apache License, Version 2.0" - class APRSWorker(pytak.QueueWorker): - - """APRS Cursor-on-Target Worker Class.""" - - def __init__(self, queue: asyncio.Queue, config: ConfigParser): - super().__init__(queue, config) - _ = [x.setFormatter(aprscot.LOG_FORMAT) for x in self._logger.handlers] + """APRS Cursor on Target Worker Class.""" async def handle_data(self, data: bytes) -> None: - """Handles messages from APRS Worker.""" + """Handle messages from APRS Worker.""" self._logger.debug("APRS data='%s'", data) frame = None @@ -57,21 +48,21 @@ async def handle_data(self, data: bytes) -> None: self._logger.warning("Unhandled APRS Frame: '%s'", data) return except aprslib.exceptions.ParseError: - self._logger.warning("Invalid Format: '%s'", data) + self._logger.warning("Invalid APRS Format: '%s'", data) return if not frame: return - event: bytes = aprscot.aprs_to_cot(frame, self.config) + event: Optional[bytes] = aprscot.aprs_to_cot(frame, self.config) if not event: - self._logger.warning("Empty COT for frame: '%s'", frame.get("raw")) + self._logger.warning("Empty CoT for APRS frame: '%s'", frame.get("raw")) return await self.put_queue(event) async def run(self, number_of_iterations=-1): - """Runs this Thread, Reads from Pollers.""" + """Run this Thread, Reads from Pollers.""" self._logger.info("Running %s", self.__class__) aprs_host: str = self.config.get("APRS_HOST", aprscot.DEFAULT_APRSIS_HOST) @@ -83,13 +74,15 @@ async def run(self, number_of_iterations=-1): reader, writer = await asyncio.open_connection(aprs_host, int(aprs_port)) # APRS Parameters: - passcode = "-1" + passcode: str = self.config.get( + "APRSIS_PASSCODE", aprscot.DEFAULT_APRSIS_PASSCODE + ) callsign: str = self.config.get("CALLSIGN", aprscot.DEFAULT_APRSIS_CALLSIGN) aprs_filter: str = self.config.get( "APRSIS_FILTER", aprscot.DEFAULT_APRSIS_FILTER ) - _login = f"user {callsign} pass {passcode} vers aprscot v6.0.0" + _login = f"user {callsign} pass {passcode} vers aprscot v8" if aprs_filter: self._logger.info("Using APRS Filter: '%s'", aprs_filter) diff --git a/aprscot/commands.py b/aprscot/commands.py index 2f1c06c..742ff70 100644 --- a/aprscot/commands.py +++ b/aprscot/commands.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright 2022 Greg Albrecht +# Copyright Sensors & Signals LLC https://www.snstac.com # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -13,22 +15,16 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Author:: Greg Albrecht W2GMD -# """PyTAK Command Line.""" import pytak -__author__ = "Greg Albrecht W2GMD " -__copyright__ = "Copyright 2022 Greg Albrecht" -__license__ = "Apache License, Version 2.0" - def main() -> None: - """Main func.""" + """Boilerplate main func.""" # PyTAK CLI tool boilerplate: - pytak.cli(__name__.split(".")[0]) + pytak.cli(__name__.split(".", maxsplit=1)[0]) if __name__ == "__main__": diff --git a/aprscot/constants.py b/aprscot/constants.py index 46a9584..6e09943 100644 --- a/aprscot/constants.py +++ b/aprscot/constants.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright 2022 Greg Albrecht +# Copyright Sensors & Signals LLC https://www.snstac.com # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -13,33 +15,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Author:: Greg Albrecht W2GMD -# """APRSCOT Constants.""" -import logging -import os import re -__author__ = "Greg Albrecht W2GMD " -__copyright__ = "Copyright 2022 Greg Albrecht" -__license__ = "Apache License, Version 2.0" - - -if bool(os.environ.get("DEBUG")): - LOG_LEVEL = logging.DEBUG - LOG_FORMAT = logging.Formatter( - ( - "%(asctime)s aprscot %(levelname)s %(name)s.%(funcName)s:%(lineno)d " - " - %(message)s" - ) - ) - logging.debug("aprscot Debugging Enabled via DEBUG Environment Variable.") -else: - LOG_LEVEL = logging.INFO - LOG_FORMAT = logging.Formatter(("%(asctime)s aprscot - %(message)s")) - # 3833.55N/12248.93W LL_REX = re.compile( r"(?P\d{4}\.\d{2})[NS][^\n]{1}(?P\d{5}\.\d{2})[EW]" @@ -48,6 +28,7 @@ DEFAULT_APRSIS_PORT: int = 14580 DEFAULT_APRSIS_HOST: str = "rotate.aprs.net" DEFAULT_APRSIS_CALLSIGN: str = "SUNSET" +DEFAULT_APRSIS_PASSCODE: str = "-1" DEFAULT_APRSIS_FILTER: str = "m/50" DEFAULT_COT_TYPE: str = "a-f-G-I-U-T-r" diff --git a/aprscot/functions.py b/aprscot/functions.py index 6eb8b1f..ce3d502 100644 --- a/aprscot/functions.py +++ b/aprscot/functions.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright 2022 Greg Albrecht +# Copyright Sensors & Signals LLC https://www.snstac.com # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -13,8 +15,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Author:: Greg Albrecht W2GMD -# """APRSCOT Functions.""" @@ -27,17 +27,9 @@ import aprscot -__author__ = "Greg Albrecht W2GMD " -__copyright__ = "Copyright 2022 Greg Albrecht" -__license__ = "Apache License, Version 2.0" -__source__ = "https://github.com/ampledata/aprscot" - - -def create_tasks( - config: ConfigParser, clitool: pytak.CLITool -) -> Set[pytak.Worker,]: +def create_tasks(config: ConfigParser, clitool: pytak.CLITool) -> Set[pytak.Worker,]: """ - Creates specific coroutine task set for this application. + Create a specific coroutine task set for this application. Parameters ---------- @@ -59,21 +51,23 @@ def aprs_to_cot_xml( ) -> Union[ ET.Element, None ]: # NOQA pylint: disable=too-many-locals,too-many-statements - """Converts an APRS Frame to a Cursor-on-Target Event.""" + """Convert an APRS Frame to a Cursor on Target Event.""" lat = frame.get("latitude") lon = frame.get("longitude") + afrom = frame.get("from") - if not lat or not lon: + if not lat or not lon or not afrom: return None - config: dict = config or {} - cot_stale = int(config.get("COT_STALE", pytak.DEFAULT_COT_STALE)) + config = config or {} + cot_stale = int(config.get("COT_STALE", aprscot.DEFAULT_COT_STALE)) - callsign = frame.get("from").replace(" ", "") + callsign = afrom.replace(" ", "") name = callsign cot_uid = f"APRS.{callsign}" cot_type = config.get("COT_TYPE", aprscot.DEFAULT_COT_TYPE) + cot_icon = config.get("COT_ICON") if "sections" in config and callsign in config.sections(): cs_conf = config[callsign] @@ -82,26 +76,6 @@ def aprs_to_cot_xml( name = cs_conf.get("COT_NAME", name) cot_icon = cs_conf.get("COT_ICON") - point = ET.Element("point") - point.set("lat", str(lat)) - point.set("lon", str(lon)) - - # Circular area around the point defined by lat and lon fields in meters. - # When used to represent error, the value represents the one sigma point - # for a zero mean normal (Gaussian) distribution. - point.set("ce", "9999999.0") - - # A height range about the event point in meters associated with the HAE - # field. When used to represent error, the value represents the one sigma - # point for a zero mean normal (Gaussian) distribution. - point.set("le", "9999999.0") - - # Height above Ellipsoid based on WGS-84 ellipsoid (measured in meters) - point.set("hae", "9999999.0") - - uid = ET.Element("UID") - uid.set("Droid", f"{name} (APRS)") - contact = ET.Element("contact") contact.set("callsign", f"{callsign} (APRS)") @@ -109,11 +83,14 @@ def aprs_to_cot_xml( track.set("course", "9999999.0") detail = ET.Element("detail") - detail.set("uid", cot_uid) - detail.append(uid) detail.append(contact) detail.append(track) + if cot_icon: + usericon = ET.Element("usericon") + usericon.set("iconsetpath", cot_icon) + detail.append(usericon) + remarks = ET.Element("remarks") comment = frame.get("comment") @@ -121,19 +98,40 @@ def aprs_to_cot_xml( remarks.text = comment detail.append(remarks) - root = ET.Element("event") - root.set("version", "2.0") - root.set("type", cot_type) - root.set("uid", cot_uid) - root.set("how", "h-g-i-g-o") - root.set("time", pytak.cot_time()) - root.set("start", pytak.cot_time()) - root.set("stale", pytak.cot_time(cot_stale)) - - root.append(point) - root.append(detail) + # CE + # Circular area around the point defined by lat and lon fields in meters. + # When used to represent error, the value represents the one sigma point + # for a zero mean normal (Gaussian) distribution. + # + # LE + # A height range about the event point in meters associated with the HAE + # field. When used to represent error, the value represents the one sigma + # point for a zero mean normal (Gaussian) distribution. + # + # HAE + # Height above Ellipsoid based on WGS-84 ellipsoid (measured in meters) - return root + cot_d = { + "lat": str(lat), + "lon": str(lon), + "ce": "9999999.0", + "le": "9999999.0", + "hae": "9999999.0", + "uid": cot_uid, + "cot_type": cot_type, + "stale": cot_stale, + } + + cot = pytak.gen_cot_xml(**cot_d) + cot.set("access", config.get("COT_ACCESS", pytak.DEFAULT_COT_ACCESS)) + + _detail = cot.findall("detail")[0] + flowtags = _detail.findall("_flow-tags_") + detail.extend(flowtags) + cot.remove(_detail) + cot.append(detail) + + return cot def aprs_to_cot(frame: dict, config: Union[dict, None] = None) -> Union[bytes, None]: diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..f4d16fd --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1 @@ +{!CHANGELOG.md!} diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..d6e0f77 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,67 @@ +APRSCOT's configuration parameters can be set two ways: + +1. In an INI-style configuration file. (ex. ``aprscot -c config.ini``) +2. As environment variables. (ex. ``export DEBUG=1;aprscot``) + +APRSCOT has the following built-in configuration parameters: + +APRSIS_FILTER = f/W6PW-10/50 + +* **`APRSIS_FILTER`**: + * Default: ``m/50`` + + [APRS-IS Server-side Filter](http://www.aprs-is.net/javAPRSFilter.aspx). + +* **`COT_TYPE`**: + * Default: ``a-f-G-I-U-T-r`` seconds + + COT Event type. + +* **`COT_STALE`**: + * Default: ``3600`` + + COT Stale time. + +* **`COT_NAME`**: + * Default: unset + + COT Callsign. + +* **`APRSIS_CALLSIGN`**: + * Default: ``SUNSET`` + + APRS-IS connection callsign. + +* **`APRSIS_PASSWORD`**: + * Default: ``-1`` + + APRS-IS connection password. + +* **`APRSIS_PORT`**: + * Default: ``14580`` + + APRS-IS port + +* **`APRSIS_HOST`**: + * Default: ``rotate.aprs.net`` + + APRS-IS host. + +Additional configuration parameters, including TAK Server configuration, are included in the [PyTAK Configuration](https://pytak.readthedocs.io/en/latest/configuration/) documentation. + +## Transformations + +`COT_NAME`, `COT_STALE` & `COT_STALE` can be set on a per-APRS callsign basis, for example: + +``` +[aprscot] +COT_URL = tcp://takserver.example.com:8088 + +[W2GMD-9] +COT_TYPE = a-f-G-U-C +COT_STALE = 600 +COT_NAME = Medic 52 + +[NB6F-2] +COT_NAME = Transport 2 +``` diff --git a/docs/conop.md b/docs/conop.md new file mode 100644 index 0000000..a2bf411 --- /dev/null +++ b/docs/conop.md @@ -0,0 +1,4 @@ +# Concept of Operations (CONOP) + +[![APRSCOT Concept of Operations (CONOP)](media/aprscot-concept.png)](media/aprscot-concept.png) + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..10882f6 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +{!README.md!} \ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..2c3c744 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,35 @@ +APRSCOT's functionality provided by a command-line program called `aprscot`. + +There are several methods of installing APRSCOT. They are listed below, in order of complexity. + +## Debian, Ubuntu, Raspberry Pi + +Install APRSCOT, and prerequisite packages of [PyTAK](https://pytak.rtfd.io) + +```sh linenums="1" +sudo apt update -qq +wget https://github.com/snstac/aprs-python/releases/latest/download/aprslib_latest_all.deb +sudo apt install -f ./aprslib_latest_all.deb +wget https://github.com/snstac/pytak/releases/latest/download/pytak_latest_all.deb +sudo apt install -f ./pytak_latest_all.deb +wget https://github.com/snstac/aprscot/releases/latest/download/aprscot_latest_all.deb +sudo apt install -f ./aprscot_latest_all.deb +``` + +## Windows, Linux + +Install from the Python Package Index (PyPI) [Advanced Users]:: + +```sh +sudo python3 -m pip install aprscot +``` + +## Developers + +PRs welcome! + +```sh linenums="1" +git clone https://github.com/snstac/aprscot.git +cd aprscot/ +python3 setup.py install +``` diff --git a/docs/aprscot-concept.png b/docs/media/aprscot-concept.png similarity index 100% rename from docs/aprscot-concept.png rename to docs/media/aprscot-concept.png diff --git a/docs/screenshot.png b/docs/media/screenshot.png similarity index 100% rename from docs/screenshot.png rename to docs/media/screenshot.png diff --git a/docs/screenshot2-25.png b/docs/media/screenshot2-25.png similarity index 100% rename from docs/screenshot2-25.png rename to docs/media/screenshot2-25.png diff --git a/docs/screenshot2-50.png b/docs/media/screenshot2-50.png similarity index 100% rename from docs/screenshot2-50.png rename to docs/media/screenshot2-50.png diff --git a/docs/screenshot2.png b/docs/media/screenshot2.png similarity index 100% rename from docs/screenshot2.png rename to docs/media/screenshot2.png diff --git a/docs/screenshot3.png b/docs/media/screenshot3.png similarity index 100% rename from docs/screenshot3.png rename to docs/media/screenshot3.png diff --git a/docs/screenshot4.png b/docs/media/screenshot4.png similarity index 100% rename from docs/screenshot4.png rename to docs/media/screenshot4.png diff --git a/docs/screenshot5.png b/docs/media/screenshot5.png similarity index 100% rename from docs/screenshot5.png rename to docs/media/screenshot5.png diff --git a/docs/screenshot6.png b/docs/media/screenshot6.png similarity index 100% rename from docs/screenshot6.png rename to docs/media/screenshot6.png diff --git a/docs/screenshot_1637083156_28841.png b/docs/media/screenshot_1637083156_28841.png similarity index 100% rename from docs/screenshot_1637083156_28841.png rename to docs/media/screenshot_1637083156_28841.png diff --git a/docs/screenshot_1637083168_26966.png b/docs/media/screenshot_1637083168_26966.png similarity index 100% rename from docs/screenshot_1637083168_26966.png rename to docs/media/screenshot_1637083168_26966.png diff --git a/docs/screenshot_1637083172_3709.png b/docs/media/screenshot_1637083172_3709.png similarity index 100% rename from docs/screenshot_1637083172_3709.png rename to docs/media/screenshot_1637083172_3709.png diff --git a/docs/screenshot_1637083240_16797-25p.png b/docs/media/screenshot_1637083240_16797-25p.png similarity index 100% rename from docs/screenshot_1637083240_16797-25p.png rename to docs/media/screenshot_1637083240_16797-25p.png diff --git a/docs/screenshot_1637083240_16797-50p.png b/docs/media/screenshot_1637083240_16797-50p.png similarity index 100% rename from docs/screenshot_1637083240_16797-50p.png rename to docs/media/screenshot_1637083240_16797-50p.png diff --git a/docs/screenshot_1637083240_16797.png b/docs/media/screenshot_1637083240_16797.png similarity index 100% rename from docs/screenshot_1637083240_16797.png rename to docs/media/screenshot_1637083240_16797.png diff --git a/docs/screenshot_1637083260_7170.png b/docs/media/screenshot_1637083260_7170.png similarity index 100% rename from docs/screenshot_1637083260_7170.png rename to docs/media/screenshot_1637083260_7170.png diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..b00f781 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,23 @@ +click +ghp-import +griffe +importlib-metadata +jinja2 +markdown +markdown-include +markupsafe +mergedeep +mkdocs +mkdocs-autorefs +mkdocs-include-markdown-plugin +mkdocs-material +mkdocstrings-python +mkdocstrings[python] +packaging +pymdown-extensions +pyparsing +python-dateutil +pyyaml +pyyaml-env-tag +six +zipp diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..649c09c --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,26 @@ + +To report bugs, please set the DEBUG=1 environment variable to collect logs: + +```sh +DEBUG=1 aprscot +``` + +Or: + +```sh linenums="1" +export DEBUG=1 +aprscot +``` + +Or: + +```sh linenums="1" +echo 'DEBUG=1' >> aprscot.ini +aprscot -c aprscot.ini +``` + +You can view systemd/systemctl/service logs via: + +```journalctl -fu aprscot``` + +Please use GitHub issues for support requests. Please note that APRSCOT is free open source software and comes with no warranty. See LICENSE. \ No newline at end of file diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..749bfcc --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,46 @@ +## Command-line + +Command-line usage is available by running ``aprscot -h``. + +``` +usage: aprscot [-h] [-c CONFIG_FILE] [-p PREF_PACKAGE] + +options: + -h, --help show this help message and exit + -c CONFIG_FILE, --CONFIG_FILE CONFIG_FILE + Optional configuration file. Default: config.ini + -p PREF_PACKAGE, --PREF_PACKAGE PREF_PACKAGE + Optional connection preferences package zip file (aka data package). +``` + +## Run as a service / Run forever + +1. Add the text contents below a file named `/etc/systemd/system/aprscot.service` + You can use `nano` or `vi` editors: `sudo nano /etc/systemd/system/aprscot.service` +2. Reload systemctl: `sudo systemctl daemon-reload` +3. Enable APRSCOT: `sudo systemctl enable aprscot` +4. Start APRSCOT: `sudo systemctl start aprscot` + +### `aprscot.service` Content +```ini +[Unit] +Description=APRSCOT - Display APRS in TAK +Documentation=https://aprscot.rtfd.io +Wants=network.target +After=network.target + +[Service] +RuntimeDirectoryMode=0755 +ExecStart=/usr/local/bin/aprscot -c /etc/aprscot.ini +SyslogIdentifier=aprscot +Type=simple +Restart=always +RestartSec=30 +RestartPreventExitStatus=64 +Nice=-5 + +[Install] +WantedBy=default.target +``` + +> Pay special attention to the `ExecStart` line above. You'll need to provide the full local filesystem path to both your aprscot executable & aprscot configuration files. \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 07d8ca3..5f92ae3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,11 +1,102 @@ -# Setup configuration for APRS Cursor-on-Target Gateway. +# Setup configuration for APRSCOT: APRS to TAK Gateway # -# Source:: https://github.com/ampledata/aprscot -# Author:: Greg Albrecht W2GMD -# Copyright:: Copyright 2022 Greg Albrecht -# License:: Apache License, Version 2.0 +# Copyright Sensors & Signals LLC https://www.snstac.com # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +[metadata] +name = aprscot +version = attr: aprscot.__version__ +url = https://github.com/snstac/aprscot +project_urls = + CI: GitHub Actions = https://github.com/snstac/aprscot/actions + GitHub: issues = https://github.com/snstac/aprscot/issues + GitHub: repo = https://github.com/snstac/aprscot +description = Monitor and analyze APRS with TAK. +long_description = file: README.md +long_description_content_type = text/markdown +maintainer = Greg Albrecht +maintainer_email = oss@undef.net +license = Apache 2.0 +license_files = LICENSE +classifiers = + License :: OSI Approved :: Apache Software License + + Intended Audience :: Developers + + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3 :: Only + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 + + Development Status :: 5 - Production/Stable + + Operating System :: POSIX + Operating System :: MacOS :: MacOS X + Operating System :: Microsoft :: Windows + Operating System :: OS Independent +keywords = + Cursor on Target + CoT + ATAK + TAK + WinTAK + TAK + TAK Server + iTAK + APRS + Ham Radio + Amateur Radio + + +[options.entry_points] +console_scripts = + aprscot = aprscot.commands:main + + +[options] +packages = aprscot +package_dir = + aprscot = aprscot +python_requires = >=3.7, <4 +install_requires = + pytak >= 7.0.1 + aprslib + + +[options.extras_require] +test = + pytest-asyncio + pytest-cov + pylint + flake8 + black +[isort] +profile = black + +[flake8] +max-line-length = 88 +extend-ignore = E203, E704 +[pylint] +max-line-length = 88 -[aliases] -test=pytest +[pycodestyle] +ignore = E203 +max_line_length = 88 diff --git a/setup.py b/setup.py index e76a220..6e45913 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright 2022 Greg Albrecht +# Copyright Sensors & Signals LLC https://www.snstac.com # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -13,59 +15,10 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Author:: Greg Albrecht W2GMD -# - -""" -Setup for the APRS Cursor-on-Target Gateway. - -Source:: https://github.com/ampledata/aprscot -""" - -import os -import sys - -import setuptools - -__title__ = "aprscot" -__version__ = "6.1.0" -__author__ = "Greg Albrecht W2GMD " -__copyright__ = "Copyright 2022 Greg Albrecht" -__license__ = "Apache License, Version 2.0" - - -def publish(): - """Function for publishing package to pypi.""" - if sys.argv[-1] == "publish": - os.system("python setup.py sdist") - os.system("twine upload dist/*") - sys.exit() - -publish() +"""Setup for ADSBCOT.""" +from setuptools import setup -setuptools.setup( - name=__title__, - version=__version__, - packages=[__title__], - package_dir={__title__: __title__}, - url=f"https://github.com/ampledata/{__title__}", - entry_points={"console_scripts": [f"{__title__} = {__title__}.commands:main"]}, - description="APRS Cursor-on-Target Gateway.", - author="Greg Albrecht", - author_email="oss@undef.net", - package_data={"": ["LICENSE"]}, - license="Apache License, Version 2.0", - long_description=open("README.rst").read(), - long_description_content_type="text/x-rst", - zip_safe=False, - include_package_data=True, - install_requires=["aprslib", "pytak >= 5.4.0"], - classifiers=[ - "Topic :: Communications :: Ham Radio", - "Programming Language :: Python", - "License :: OSI Approved :: Apache Software License", - ], - keywords=["Ham Radio", "APRS", "Cursor on Target", "ATAK", "TAK", "CoT"], -) +if __name__ == "__main__": + setup() diff --git a/tests/test_functions.py b/tests/test_functions.py index ec518af..eca851e 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -3,15 +3,7 @@ # Tests for APRS Cursor-on-Target Gateway. -""" -Tests for APRS Cursor-on-Target Gateway. -~~~~ - -:author: Greg Albrecht W2GMD -:copyright: Copyright 2022 Greg Albrecht -:license: Apache License, Version 2.0 -:source: -""" +"""Tests for APRSCOT: APRS to TAK Gateway.""" import unittest @@ -29,7 +21,7 @@ class FunctionsTestCase(unittest.TestCase): def test_aprs_to_cot_xml(self): """ - Tests that aprs_to_cot decodes an APRS Frame into a Cursor-on-Target + Tests that aprs_to_cot decodes an APRS Frame into a Cursor on Target message. """ test_frame = (