Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ampledata committed Jun 22, 2022
1 parent 644b343 commit b629ad2
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 68 deletions.
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Install adsbcot from the Python Package Index (PyPI)::

**To install with TCP Beast & TCP Raw support:**

You must install `adsbcot` with the extra `pymodes` package:
You must install `adsbcot` with the extra `pymodes` package::

$ python3 -m pip install adsbcot[with_pymodes]

Expand Down Expand Up @@ -95,7 +95,7 @@ Parameters:

There are other configuration parameters available via `PyTAK <https://github.com/ampledata/pytak#configuration-parameters>`_.

Configuration parameters are imported in the following priority order::
Configuration parameters are imported in the following priority order:

1. config.ini (if exists) or -c <filename> (if specified).
2. Environment Variables (if set).
Expand Down
2 changes: 0 additions & 2 deletions adsbcot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
"""

from .constants import ( # NOQA
LOG_FORMAT,
LOG_LEVEL,
DEFAULT_POLL_INTERVAL,
DEFAULT_DUMP1090_TCP_RAW_PORT,
DEFAULT_DUMP1090_TCP_BEAST_PORT,
Expand Down
119 changes: 81 additions & 38 deletions adsbcot/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@

import asyncio

from typing import Union
from urllib.parse import ParseResult, urlparse

import aiohttp
import pytak
import aircot
import adsbcot

# We won't use pyModeS if it isn't installed:
Expand All @@ -42,78 +44,120 @@

class ADSBWorker(pytak.QueueWorker):

"""Reads ADS-B Data from inputs, renders to CoT, and puts on queue."""
"""Reads ADS-B Data from inputs, serializes to COT, and puts on TX queue."""

def __init__(self, queue, config):
super().__init__(queue, config)
_ = [x.setFormatter(adsbcot.LOG_FORMAT) for x in self._logger.handlers]
self.known_craft_db = None
self.session = None
self.uid_key: str = self.config.get("UID_KEY", "ICAO")

known_craft = self.config.get("KNOWN_CRAFT")
if known_craft:
self._logger.info("Using KNOWN_CRAFT: %s", known_craft)
self.known_craft_db = aircot.read_known_craft(known_craft)

async def handle_data(self, data: list) -> None:
"""
Transforms Aircraft ADS-B data to CoT and puts it onto tx queue.
Handle Data from ADS-B receiver: Render to COT, put on TX queue.
Parameters
----------
data : `list[dict, ]`
List of craft data as key/value arrays.
"""
if not isinstance(data, list):
self._logger.warning("Invalid aircraft data, should be a Python list.")
return False
self._logger.warning("Invalid aircraft data, should be a Python `list`.")
return

if not data:
self._logger.warning("Empty aircraft list")
return False
return

lod = len(data)
i = 1
for craft in data:
self._logger.debug("craft='%s'", craft)
i += 1
if not isinstance(craft, dict):
self._logger.warning("Aircraft list item was not a Python `dict`.")
continue

icao: str = craft.get("hex", "")
if icao:
icao = icao.strip().upper()
else:
continue

if "~" in icao and not self.config.getboolean("INCLUDE_TISB"):
continue

known_craft: dict = aircot.get_known_craft(self.known_craft_db, icao, "HEX")

# Skip if we're using known_craft CSV and this Craft isn't found:
if (
self.known_craft_db
and not known_craft
and not self.config.getboolean("INCLUDE_ALL_CRAFT")
):
continue

event: Union[str, None] = adsbcot.adsb_to_cot(
craft, self.config, known_craft
)

event = adsbcot.adsb_to_cot(craft, self.config)
if not event:
self._logger.debug("Empty COT Event for craft=%s", craft)
i += 1
continue

self._logger.debug(
"Handling %s/%s ICAO: %s Flight: %s Category: %s Registration: %s",
i,
len(data),
craft.get("hex"),
craft.get("flight"),
craft.get("category"),
craft.get("reg"),
)
self._logger.debug("Handling %s/%s ICAO: %s", i, lod, icao)
await self.put_queue(event)
i += 1

async def get_dump1090_feed(self, url: str):
"""
Polls the dump1090 JSON API and passes data to message handler.
Polls the dump1090 JSON API and passes data to data handler.
"""
async with aiohttp.ClientSession() as session:
resp = await session.request(method="GET", url=url)
resp.raise_for_status()
async with self.session.get(url) as resp:
if resp.status != 200:
response_content = await resp.text()
self._logger.error("Received HTTP Status %s for %s", resp.status, url)
self._logger.error(response_content)
return

json_resp = await resp.json()
if json_resp == None:
return

data = json_resp.get("aircraft")
if data == None:
return

self._logger.info("Retrieved %s aircraft messages.", len(data))
self._logger.info("Retrieved %s aircraft messages.", str(len(data) or "No"))
await self.handle_data(data)

async def run(self, number_of_iterations=-1):
"""Runs this Thread, Reads from Pollers."""
url: str = self.config.get("DUMP1090_URL")
poll_interval: int = int(
self.config.get("POLL_INTERVAL", adsbcot.DEFAULT_POLL_INTERVAL)
)
url: str = self.config.get("DUMP1090_URL", "")
if not url:
raise Exception("Please specify a DUMP1090_URL.")

self._logger.info(
"Using UID_KEY=%s & COT_STALE=%ss",
self.uid_key,
self.config.get("COT_STALE"),
self._logger.info("Running %s", self.__class__)

known_craft: str = self.config.get("KNOWN_CRAFT", "")
poll_interval: str = self.config.get(
"POLL_INTERVAL", adsbcot.DEFAULT_POLL_INTERVAL
)

while 1:
self._logger.info("Polling every %ss: %s", url, poll_interval)
await self.get_dump1090_feed(url)
await asyncio.sleep(poll_interval)
if known_craft:
self._logger.info("Using KNOWN_CRAFT: %s", known_craft)
self.known_craft_db = aircot.read_known_craft(known_craft)

async with aiohttp.ClientSession() as self.session:
while 1:
self._logger.info(
"%s polling every %ss: %s", self.__class__, poll_interval, url
)
await self.get_dump1090_feed(url)
await asyncio.sleep(int(poll_interval))


class ADSBNetWorker(ADSBWorker):
Expand Down Expand Up @@ -240,8 +284,7 @@ class ADSBNetReceiver(pytak.QueueWorker): # pylint: disable=too-few-public-meth

def __init__(self, queue, config, data_type):
super().__init__(queue, config)
self.data_type = data_type
_ = [x.setFormatter(adsbcot.LOG_FORMAT) for x in self._logger.handlers]
self.data_type: str = data_type

async def run(self, number_of_iterations=-1):
"""Runs the main process loop."""
Expand Down
5 changes: 3 additions & 2 deletions adsbcot/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@


def main() -> None:
"""Main func."""
# PyTAK CLI tool boilerplate:
pytak.cli(__name__.split(".")[0])


if __name__ == '__main__':
main()
if __name__ == "__main__":
main()
21 changes: 5 additions & 16 deletions adsbcot/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,12 @@
__license__ = "Apache License, Version 2.0"


if os.getenv("DEBUG"):
LOG_LEVEL = logging.DEBUG
LOG_FORMAT = logging.Formatter(
(
"%(asctime)s adsbcot %(levelname)s %(name)s.%(funcName)s:%(lineno)d "
" - %(message)s"
)
)
logging.debug("adsbcot Debugging Enabled via DEBUG Environment Variable.")
else:
LOG_LEVEL = logging.INFO
LOG_FORMAT = logging.Formatter(("%(asctime)s adsbcot %(levelname)s - %(message)s"))
# Dump1090 URL to use out of the box, in this case the HTTP JSON feed URL.
DEFAULT_DUMP1090_URL: str = "http://piaware.local:8080/data/aircraft.json"

DEFAULT_POLL_INTERVAL: int = 30
# Default dump1090 HTTP JSON feed polling interval, in seconds.
DEFAULT_POLL_INTERVAL: str = "3"

# Default non-HTTP TCP ports for dump1090, raw & beast.
DEFAULT_DUMP1090_TCP_RAW_PORT: int = 30002
DEFAULT_DUMP1090_TCP_BEAST_PORT: int = 30005
DEFAULT_DUMP1090_URL: str = (
f"tcp+beast://piaware.local:{DEFAULT_DUMP1090_TCP_BEAST_PORT}"
)
19 changes: 12 additions & 7 deletions adsbcot/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ def create_tasks(


def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,too-many-statements
craft: dict, config: Union[dict, None] = None, known_craft: Union[dict, None] = None
craft: dict,
config: Union[SectionProxy, None] = None,
known_craft: Union[dict, None] = None,
) -> Union[ET.Element, None]:
"""
Serializes a Dump1090 ADS-B aircraft object as Cursor-on-Target XML.
Expand All @@ -114,7 +116,7 @@ def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,t
----------
craft : `dict`
Key/Value data struct of decoded ADS-B aircraft data.
config : `configparser.ConfigParser`
config : `configparser.SectionProxy`
Configuration options and values.
Uses config options: UID_KEY, COT_STALE, COT_HOST_ID
Expand All @@ -123,15 +125,14 @@ def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,t
`xml.etree.ElementTree.Element`
Cursor-On-Target XML ElementTree object.
"""
known_craft: dict = known_craft or {}
config: dict = config or {}

lat = craft.get("lat")
lon = craft.get("lon")

if lat is None or lon is None:
return None

known_craft: dict = known_craft or {}
config: dict = config or {}
remarks_fields = []

uid_key = config.get("UID_KEY", "ICAO")
Expand Down Expand Up @@ -192,7 +193,9 @@ def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,t
else:
callsign = icao_hex

cot_type = aircot.adsb_to_cot_type(craft.get("hex"), cat, flight)
_, callsign = aircot.set_name_callsign(icao_hex, reg, None, flight, known_craft)
cat = aircot.set_category(cat, known_craft)
cot_type = aircot.set_cot_type(icao_hex, cat, flight, known_craft)

point: ET.Element = ET.Element("point")
point.set("lat", str(lat))
Expand Down Expand Up @@ -256,7 +259,9 @@ def adsb_to_cot_xml( # NOQA pylint: disable=too-many-locals,too-many-branches,t


def adsb_to_cot(
craft: dict, config: Union[dict, None] = None, known_craft: Union[dict, None] = None
craft: dict,
config: Union[SectionProxy, None] = None,
known_craft: Union[dict, None] = None,
) -> Union[bytes, None]:
"""Wrapper that returns COT as an XML string."""
cot: Union[ET.Element, None] = adsb_to_cot_xml(craft, config, known_craft)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import setuptools

__title__ = "adsbcot"
__version__ = "5.0.2"
__version__ = "5.0.3"
__author__ = "Greg Albrecht W2GMD <oss@undef.net>"
__copyright__ = "Copyright 2022 Greg Albrecht"
__license__ = "Apache License, Version 2.0"
Expand Down

0 comments on commit b629ad2

Please sign in to comment.