diff --git a/CHANGELOG.md b/CHANGELOG.md index b078a33..b40587f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ -## ADSBCOT beta +## ADSBCOT 7.0.0 +- New for 2024! - Fixed formatting of CHANGELOG.md +- Fixes #28: COT_STALE in documentation - Fixes #37: Move RTFD docs over to Markdown. - Fixes #38: Don't discard ImportError exception. - - +- Fixes #39: Move CoT generation to PyTAK's `gen_cot_xml()` function. +- Fixes #40: Add CoT `access` attribute. ## ADSBCOT 6.1.0 diff --git a/adsbcot/__init__.py b/adsbcot/__init__.py index 5f9e75d..3289220 100644 --- a/adsbcot/__init__.py +++ b/adsbcot/__init__.py @@ -21,7 +21,7 @@ :source: """ -__version__ = "6.2.0-beta7" +__version__ = "7.0.0-beta1" __author__ = "Greg Albrecht " __copyright__ = "Copyright Sensors & Signals LLC https://www.snstac.com" __license__ = "Apache License, Version 2.0" diff --git a/adsbcot/functions.py b/adsbcot/functions.py index 76977d6..e191b09 100644 --- a/adsbcot/functions.py +++ b/adsbcot/functions.py @@ -21,7 +21,7 @@ import asyncio import importlib.util import warnings -import xml.etree.ElementTree as etree +import xml.etree.ElementTree as ET from configparser import SectionProxy from typing import Optional, Set, Union @@ -41,8 +41,9 @@ # We won't use pyModeS if it isn't installed: try: import pyModeS # NOQA pylint: disable=unused-import -except ImportError: - pass +except ImportError as exc: + warnings.warn(str(exc)) + warnings.warn("ADSBCOT ignoring ImportError for: pyModeS") def create_tasks(config: SectionProxy, clitool: pytak.CLITool) -> Set[pytak.Worker,]: @@ -108,8 +109,9 @@ def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,t craft: dict, config: Union[SectionProxy, dict, None] = None, known_craft: Optional[dict] = None, -) -> Optional[etree.Element]: - """Serialize a Dump1090 ADS-B aircraft object as Cursor on Target XML. +) -> Optional[ET.Element]: + """ + Serialize ADS-B data as Cursor on Target. Parameters ---------- @@ -118,6 +120,8 @@ def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,t config : `configparser.SectionProxy` Configuration options and values. Uses config options: UID_KEY, COT_STALE, COT_HOST_ID + kown_craft : `dict` + Optional list of know craft to transform CoT data. Returns ------- @@ -139,7 +143,7 @@ def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,t cot_stale: int = int(config.get("COT_STALE", pytak.DEFAULT_COT_STALE)) cot_host_id: str = config.get("COT_HOST_ID", pytak.DEFAULT_HOST_ID) - aircotx = etree.Element("_aircot_") + aircotx = ET.Element("_aircot_") aircotx.set("cot_host_id", cot_host_id) icao_hex: str = str(craft.get("hex", craft.get("icao", ""))).strip().upper() @@ -213,54 +217,50 @@ def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,t cat = aircot.set_category(cat, known_craft) cot_type = aircot.set_cot_type(icao_hex, cat, flight, known_craft) - point: etree.Element = etree.Element("point") - point.set("lat", str(lat)) - point.set("lon", str(lon)) - point.set("ce", str(craft.get("nac_p", "9999999.0"))) - point.set("le", str(craft.get("nac_v", "9999999.0"))) - # Multiply alt_geom by "Clarke 1880 (international foot)" - point.set("hae", aircot.functions.get_hae(alt_geom)) - - contact: etree.Element = etree.Element("contact") + contact: ET.Element = ET.Element("contact") contact.set("callsign", callsign) - track: etree.Element = etree.Element("track") + track: ET.Element = ET.Element("track") track.set("course", str(craft.get("trk", craft.get("track", "9999999.0")))) track.set("speed", aircot.functions.get_speed(craft.get("gs"))) - detail = etree.Element("detail") + detail = ET.Element("detail") detail.append(contact) detail.append(track) + detail.append(aircotx) icon = known_craft.get("ICON") if icon: - usericon = etree.Element("usericon") + usericon = ET.Element("usericon") usericon.set("iconsetpath", icon) detail.append(usericon) - remarks = etree.Element("remarks") - + remarks = ET.Element("remarks") remarks_fields.append(f"{cot_host_id}") - _remarks = " ".join(list(filter(None, remarks_fields))) - remarks.text = _remarks detail.append(remarks) - detail.append(aircotx) - root = etree.Element("event") - root.set("version", "2.0") - root.set("type", cot_type) - root.set("uid", cot_uid) - root.set("how", "m-g") - root.set("time", pytak.cot_time()) - root.set("start", pytak.cot_time()) - root.set("stale", pytak.cot_time(cot_stale)) + cot_d = { + "lat": str(lat), + "lon": str(lon), + "ce": str(craft.get("nac_p", "9999999.0")), + "le": str(craft.get("nac_v", "9999999.0")), + "hae": aircot.functions.get_hae(craft.get("alt_geom")), # Multiply alt_geom by "Clarke 1880 (international foot)" + "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)) - root.append(point) - root.append(detail) + _detail = cot.findall("detail")[0] + flowtags = _detail.findall("_flow-tags_") + detail.extend(flowtags) + cot.remove(_detail) + cot.append(detail) - return root + return cot def adsb_to_cot( @@ -269,9 +269,9 @@ def adsb_to_cot( known_craft: Optional[dict] = None, ) -> Optional[bytes]: """Return CoT XML object as an XML string.""" - cot: Optional[etree.Element] = adsb_to_cot_xml(craft, config, known_craft) + cot: Optional[ET.Element] = adsb_to_cot_xml(craft, config, known_craft) return ( - b"\n".join([pytak.DEFAULT_XML_DECLARATION, etree.tostring(cot)]) + b"\n".join([pytak.DEFAULT_XML_DECLARATION, ET.tostring(cot)]) if cot else None ) diff --git a/docs/aircraft_data.md b/docs/aircraft_data.md index 44cfe44..20fb160 100644 --- a/docs/aircraft_data.md +++ b/docs/aircraft_data.md @@ -1,6 +1,5 @@ -[ TK screenshot of ATAK w/ aircraft details panel open. ] - +![ADS-B flight data displayed in ATAK](screenshots/screenshot_1705531116_13879.png) Tracks within TAK retain the aircraft's position, course & speed, and remarks contain the received Flight, Tail & Category ADS-B data. -ADSBCOT includes a set of filters and transforms TK TK TK. +ADSBCOT includes a set of filters and transforms in known_craft format. TK diff --git a/docs/requirements.md b/docs/requirements.md index 8a0bd7e..9723dc2 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -1,8 +1,15 @@ -ADSBCOT runs in any Python 3.6+ environment, including Windows & Linux. +ADSBCOT runs in any Python 3.6+ environment, including Windows, Linux & Raspberry Pi. -ADS-B data can be recevied from dump1090 using the following network formats: +Aircraft ADS-B data can be received & decoded from a variety of sources, and can run along-side dump1090 on a single computer, or on seperate computers connected over an IP network. -1. Local file. -2. Aircraft JSON HTTP feed. See `dump1090 README-json.md `_. -3. Raw TCP (via `pyModeS `_) -4. Beast TCP (via `pyModeS `_) \ No newline at end of file +To receive ADS-B data from aircraft, you'll need: + +1. [Recommended software defined radio (SDR)](https://www.amazon.com/Dual-Band-Foreflight-FlightAware-Applications-Adapters/dp/B01K5KAN60/ref=sr_1_15?crid=2HESSUCJX53PB&dib=eyJ2IjoiMSJ9.-BcrVEkozejNi01aZntC01cMv0KcaesQ8bVarAjJXfvBOcpNBZTuE52sF7Ncae2NWJJlsUpahxo7_Lv-B2lsr8gxDgmcuBgDG2IGSR3lJT9D4c0QlAdPm-L47-PiQe70GhQVuaaKSqjb4TiWmIKds_alrhkugTEy44F5k9jA7p93fIm6l6kgwppDBWQ8j3DDJB4rrtTi4diAVoa7Oupa4qqxd8w8wkCcomm16FTuCOs._OoQ15ZrlyppX6-3TFgZUavBlkf1890BnLKywhCAkNo&dib_tag=se&keywords=stratux&qid=1705529274&sprefix=stratux%252Caps%252C168&sr=8-15&ufe=app_do%253Aamzn1.fos.006c50ae-5d4c-4777-9bc0-4513d670b6bc&_encoding=UTF8&tag=ampledata-20&linkCode=ur2&linkId=5567b944046518dfafee00ec1885502f&camp=1789&creative=9325) +2. [Recommended computer (Raspberry Pi 4)](https://www.amazon.com/RasTech-Raspberry-Starter-Heatsink-Screwdriver/dp/B0C8LV6VNZ/ref=sr_1_11?crid=1E77D6JPU1EYV&dib=eyJ2IjoiMSJ9.GmziFBXjr5waSxQc8tV4UirP2DPEP4YHR9azinNNab80_feQ4H_nwyzD8MttAneBqvOa5ko8TQ5pSxQ9PDx0HMStTqpFiigDPJdpxEEtXUBbMjto4kJZPQjauJgYHP396nz_oVnBd9qupwyea05vFTvRAij1VWCtPOxTfPP3UDrbVpMoLWp6GoDYW0FewjKympsFDFDpg_51OmOy3LFsaQNcApAhyVvx3YN1P3oKrE4.AMS1HrucumtXmJp3lLz_72GORdtCB8TeUAJRc8lbxuo&dib_tag=se&keywords=raspberry+pi&qid=1705529616&sprefix=raspberry+pi%252Caps%252C151&sr=8-11&ufe=app_do%253Aamzn1.fos.006c50ae-5d4c-4777-9bc0-4513d670b6bc&_encoding=UTF8&tag=ampledata-20&linkCode=ur2&linkId=216dea4837fb50857da9ade1f09bf15a&camp=1789&creative=9325) +3. [Flightaware's dump1090-fa](https://www.flightaware.com/adsb/piaware/install) + +There'a also a variety of pre-assembled ADS-B receivers available: + +* [Flightaware's PiAware](https://www.flightaware.com/adsb/piaware/) +* [Flightradar24 Pi24](https://www.flightradar24.com/build-your-own) +* [ADS-B Exchange](https://www.adsbexchange.com/ways-to-join-the-exchange/build-your-own/) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 80f9c49..6e93bde 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,7 +1,26 @@ -To report bugs, please set the DEBUG=1 environment variable to collect logs:: +To report bugs, please set the DEBUG=1 environment variable to collect logs: - $ DEBUG=1 adsbcot - $ # -OR- - $ export DEBUG=1 - $ adsbcot +```sh +DEBUG=1 adsbcot +``` + +Or: + +```sh linenums="1" +export DEBUG=1 +adsbcot +``` + +Or: + +```sh linenums="1" +echo 'DEBUG=1' >> adsbcot.ini +adsbcot -c adsbcot.ini +``` + +You can view systemd/systemctl/service logs via: + +```journalctl -fu adsbcot``` + +Please use GitHub issues for support requests. Please note that ADSBCOT 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 index 84d053e..6460948 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,9 +1,9 @@ ## Command-line -Command-line usage is available by running ``adsbxcot -h``. +Command-line usage is available by running ``adsbcot -h``. ``` -usage: adsbxcot [-h] [-c CONFIG_FILE] [-p PREF_PACKAGE] +usage: adsbcot [-h] [-c CONFIG_FILE] [-p PREF_PACKAGE] options: -h, --help show this help message and exit @@ -13,6 +13,36 @@ options: Optional connection preferences package zip file (aka data package). ``` -## Run as a service / Run forever. +## Run as a service / Run forever -TK +1. Add the text contents below a file named `/etc/systemd/system/adsbcot.service` + You can use `nano` or `vi` editors: `sudo nano /etc/systemd/system/adsbcot.service` +2. Reload systemctl: `sudo systemctl daemon-reload` +3. Enable ADSBCOT: `sudo systemctl enable adsbcot` +4. Start ADSBCOT: `sudo systemctl start adsbcot` + +### `adsbcot.service` Content +```ini +[Unit] +Description=ADSBCOT - Display Aircraft in TAK +Documentation=https://adsbcot.rtfd.io +Wants=network.target +After=network.target +# Uncomment this line if you're running dump1090 & adsbcot on the same computer: +# After=dump1090-fa.service + +[Service] +RuntimeDirectoryMode=0755 +ExecStart=/usr/local/bin/adsbcot -c /etc/adsbcot.ini +SyslogIdentifier=adsbcot +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 adsbcot executable & adsbcot configuration files. \ No newline at end of file