Skip to content

Commit

Permalink
add ground station lookup by iata code
Browse files Browse the repository at this point in the history
  • Loading branch information
rpatel3001 committed Mar 27, 2024
1 parent 4f6774e commit 72ae849
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 17 deletions.
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,11 @@ RUN set -x && \
apt-get autoremove -y && \
rm -rf /src/* /tmp/* /var/lib/apt/lists/*

RUN set -x && \
mkdir -p /opt && \
pushd /opt && \
curl --location --output /opt/citycodes.csv https://raw.githubusercontent.com/rpatel3001/Airports/main/citycodes.csv && \
curl --location --output /opt/airports.csv https://raw.githubusercontent.com/rpatel3001/Airports/main/airports.csv && \
popd

COPY rootfs /
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ docker logs -f satdump | grep -v "(D)" | grep -v "Table Broadcast" | grep -v "Re
| `LOG_IN_JSON_FILT` | Set to any value to log the JSON output of satdump to stdout, after filtering out non-ACARS messages. | Unset |
| `LOG_OUT_JSON` | Set to any value to log the reformatted JSON output to stdout. | Unset |
| `LOG_OUT_JSON_FILT` | Set to any value to log the reformatted JSON output to stdout, after filtering out non-ACARS messages. | Unset |
| `OUTPUT_ACARS_ONLY` | Set to any value to prevent outputting JSON for non-ACARS messages to ease the load on your Acarshub instance a little. | Unset |

## Docker Compose

Expand Down Expand Up @@ -68,7 +69,7 @@ services:

The above setup is intended to decode Inmarsat 4F3 98W from an rtl_tcp stream at 10.0.0.114:7373. To directly use an RTL-SDR instead, uncomment the `cgroup` and `/dev` lines and switch which `RUN_CMD` line is commented. You may need to change the `--source_id` if you have more than one RTL-SDR.

`vfo.json` contains the frequencies and decoder pipelines being used. You'll note that they are not exact due to an approximately 3.8 kHz frequency error in my RTL-SDR. You will likely need to look at a waterfall and adjust these values based on your specific device. They may even need tuning as ambient temperature or the tuned center frequency changes. I have since bought a Nooelec SMArt XTR which does not require any offset.
`vfo.json` contains the frequencies and decoder pipelines being used. You'll note that they are not exact due to an approximately 3.8 kHz frequency error in my RTL-SDR. You will likely need to look at a waterfall and adjust these values based on your specific device. They may even need tuning as ambient temperature or the tuned center frequency changes. If all channels require the same offset, you can apply the offset in the satdump --frequency argument instead of adjusting the VFO frequencies. I have since bought a Nooelec SMArt XTR which does not require any offset.

```
{
Expand Down Expand Up @@ -167,7 +168,7 @@ The above setup is intended to decode Inmarsat 4F3 98W from an rtl_tcp stream at
}
```

`Inmarsat.json` overrides the default settings for each decoder pipeline, including station_id, udp_sink, and save_file. The below file does not save files, sends every decoder pipeline's output to 10.0.0.14:5557, and sets a `station_id` based on the pipeline.
`Inmarsat.json` overrides the default settings for each decoder pipeline, including station_id, udp_sink, and save_file. The below file does not save files, sends every decoder pipeline's output to the reformatter script at localhost:5557, and sets a `station_id` based on the pipeline.

```
{
Expand Down
61 changes: 46 additions & 15 deletions rootfs/etc/scripts/reformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from queue import SimpleQueue
from threading import Thread, current_thread
from time import sleep
from csv import DictReader

from util import geslookup

Expand Down Expand Up @@ -62,6 +63,24 @@ def thread_wrapper(func, *args):
print(f"[{current_thread().name}] thread function returned; restarting thread in {slp} seconds")
sleep(slp)

with open('/opt/airports.csv', encoding='utf-8') as csvfile:
airports_raw = DictReader(csvfile)
airports = {}
for row in airports_raw:
loc = row["city"]
if not loc:
loc = row["state"]
if loc:
loc += ", "
loc += row["country_id"]
airports[row["code"]] = loc

with open('/opt/citycodes.csv', encoding='utf-8') as csvfile:
citycodes_raw = DictReader(csvfile)
citycodes = {}
for row in citycodes_raw:
citycodes[row["code"]] = " ".join(row["name"].split()[:-2]) + f", {row['country_id']}"

json_in = getenv("UDP_IN", "5557")
json_in = json_in.split(";")
json_in = [int(x) for x in json_in]
Expand All @@ -83,16 +102,19 @@ def thread_wrapper(func, *args):
fn1 = compile(r"\/FN(?P<fn>\w+)\/")
fn2 = compile(r"\/FMH(?P<fn>\w+),")

gs1 = compile(r"[\s\/](?P<gs>\w{7})\.")
gs1 = compile(r"^(\/|- #\w{2}\/\w{2} )(?P<gs>\w{7})\.")

while True:
try:
raw = rxq.get()
# print(f"{raw}\n")

data = loads(raw)
# if not data or "ACARS" != data.get("msg_name"):
# continue
if data and (getenv("LOG_IN_JSON") or (getenv("LOG_IN_JSON_FILT") and "ACARS" == data.get("msg_name"))):
pprint(data)
print()
if not data or "ACARS" != data.get("msg_name"):
continue

out = data

Expand All @@ -117,24 +139,33 @@ def thread_wrapper(func, *args):
if flight and len(flight) <= 9:
out["flight"] = flight

# try to decode ground station
# try to parse ground station
gsa = data.get("libacars", {}).get("arinc622", {}).get("gs_addr", "")
if not gsa:
ges1 = gs1.search(data.get("message", ""))
if ges1:
gsa = ges1.groupdict().get("gs")
if decoded := geslookup(gsa):
out["fromaddr_decoded"] = f"{gsa}/{geslookup(gsa)}"

if (getenv("LOG_IN_JSON")) or (getenv("LOG_IN_JSON_FILT") and "ACARS" == data.get("msg_name")):
pprint(data)
print()
if (getenv("LOG_OUT_JSON")) or (getenv("LOG_OUT_JSON_FILT") and "ACARS" == out.get("msg_name")):
pprint(out)
print()

for q in txqs:
q.put(f"{dumps(out)}\r\n")
# try to decode ground station
if gsa:
fromaddr = gsa
decoded = geslookup(gsa)
if not decoded:
decoded = citycodes.get(gsa[:3])
if not decoded:
decoded = airports.get(gsa[:3])
if decoded:
fromaddr += f"/{decoded}"
else:
print(f"ground station {gsa} not found")
out["fromaddr_decoded"] = fromaddr

if not getenv("OUTPUT_ACARS_ONLY") or data["msg_name"] == "ACARS":
if (getenv("LOG_OUT_JSON")) or (getenv("LOG_OUT_JSON_FILT") and "ACARS" == out.get("msg_name")):
pprint(out)
print()
for q in txqs:
q.put(f"{dumps(out)}\r\n")
except KeyboardInterrupt:
exit()
except BaseException:
Expand Down

0 comments on commit 72ae849

Please sign in to comment.