kopia lustrzana https://github.com/projecthorus/chasemapper
187 wiersze
5.9 KiB
Python
187 wiersze
5.9 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# Project Horus - Browser-Based Chase Mapper
|
|
# Sondehub Communication (Chase car position upload)
|
|
#
|
|
# Copyright (C) 2021 Mark Jessop <vk5qi@rfhead.net>
|
|
# Released under GNU GPL v3 or later
|
|
#
|
|
import chasemapper
|
|
import datetime
|
|
import logging
|
|
import requests
|
|
import time
|
|
import traceback
|
|
import json
|
|
from base64 import b64encode
|
|
from hashlib import sha256
|
|
from threading import Thread, Lock
|
|
|
|
try:
|
|
# Python 2
|
|
from Queue import Queue
|
|
except ImportError:
|
|
# Python 3
|
|
from queue import Queue
|
|
|
|
|
|
class SondehubChaseUploader(object):
|
|
""" Upload supplied chase car positions to Sondehub on a regular basis """
|
|
|
|
SONDEHUB_STATION_POSITION_URL = "https://api.v2.sondehub.org/listeners"
|
|
|
|
def __init__(
|
|
self,
|
|
update_rate=30,
|
|
callsign="N0CALL",
|
|
upload_enabled=True,
|
|
upload_timeout=10,
|
|
upload_retries=2,
|
|
):
|
|
""" Initialise the Sondehub Chase uploader, and start the update thread """
|
|
|
|
self.update_rate = update_rate
|
|
self.callsign = callsign
|
|
self.callsign_init = False
|
|
self.upload_enabled = upload_enabled
|
|
self.upload_timeout = upload_timeout
|
|
self.upload_retries = upload_retries
|
|
|
|
self.car_position = None
|
|
self.car_position_lock = Lock()
|
|
|
|
self.uploader_thread_running = True
|
|
self.uploader_thread = Thread(target=self.upload_thread)
|
|
self.uploader_thread.start()
|
|
|
|
logging.info("Sondehub - Chase-Car Position Uploader Started")
|
|
|
|
def update_position(self, position):
|
|
""" Update the chase car position state
|
|
This function accepts and stores a copy of the same dictionary structure produced by both
|
|
Horus UDP broadcasts, and the serial GPS and GPSD modules
|
|
"""
|
|
|
|
with self.car_position_lock:
|
|
self.car_position = position.copy()
|
|
|
|
def upload_thread(self):
|
|
""" Uploader thread """
|
|
while self.uploader_thread_running:
|
|
|
|
# Grab a copy of the most recent car position.
|
|
with self.car_position_lock:
|
|
if self.car_position != None:
|
|
_position = self.car_position.copy()
|
|
else:
|
|
_position = None
|
|
|
|
if self.upload_enabled and _position != None:
|
|
try:
|
|
|
|
# Upload the listener position.
|
|
self.upload_position(
|
|
self.callsign,
|
|
_position["latitude"],
|
|
_position["longitude"],
|
|
_position["altitude"],
|
|
)
|
|
except Exception as e:
|
|
logging.error(
|
|
"Sondehub - Error uploading chase-car position - %s" % str(e)
|
|
)
|
|
|
|
# Wait for next update.
|
|
_i = 0
|
|
while (_i < self.update_rate) and self.uploader_thread_running:
|
|
time.sleep(1)
|
|
_i += 1
|
|
|
|
def set_update_rate(self, rate):
|
|
""" Set the update rate """
|
|
self.update_rate = int(rate)
|
|
|
|
def set_callsign(self, call):
|
|
""" Set the callsign """
|
|
self.callsign = call
|
|
|
|
def upload_position(
|
|
self, callsign, latitude, longitude, altitude, antenna="Chase Car", mobile=True
|
|
):
|
|
""" Upload a chase car position to Sondehub
|
|
This uses the PUT /listeners API described here:
|
|
https://github.com/projecthorus/sondehub-infra/wiki/API-(Beta)
|
|
"""
|
|
|
|
_position = {
|
|
"software_name": "ChaseMapper",
|
|
"software_version": chasemapper.__version__,
|
|
"uploader_callsign": callsign,
|
|
"uploader_position": [latitude, longitude, altitude],
|
|
"uploader_antenna": antenna,
|
|
"uploader_contact_email": "none@none.com",
|
|
"mobile": mobile,
|
|
}
|
|
|
|
_retries = 0
|
|
_upload_success = False
|
|
|
|
_start_time = time.time()
|
|
|
|
while _retries < self.upload_retries:
|
|
# Run the request.
|
|
try:
|
|
headers = {
|
|
"User-Agent": "chasemapper-" + chasemapper.__version__,
|
|
"Content-Type": "application/json",
|
|
}
|
|
_req = requests.put(
|
|
self.SONDEHUB_STATION_POSITION_URL,
|
|
json=_position,
|
|
# TODO: Revisit this second timeout value.
|
|
timeout=(self.upload_timeout, 6.1),
|
|
headers=headers,
|
|
)
|
|
except Exception as e:
|
|
logging.error("Sondehub - Upload Failed: %s" % str(e))
|
|
return
|
|
|
|
if _req.status_code == 200:
|
|
# 200 is the only status code that we accept.
|
|
_upload_time = time.time() - _start_time
|
|
logging.debug("Sondehub - Uploaded chase-car position to Sondehub.")
|
|
_upload_success = True
|
|
break
|
|
|
|
elif _req.status_code == 500:
|
|
# Server Error, Retry.
|
|
_retries += 1
|
|
continue
|
|
|
|
else:
|
|
logging.error(
|
|
"Sondehub - Error uploading chase-car position to Sondehub. Status Code: %d %s."
|
|
% (_req.status_code, _req.text)
|
|
)
|
|
break
|
|
|
|
if not _upload_success:
|
|
logging.error(
|
|
"Sondehub - Chase-car position upload failed after %d retries"
|
|
% (_retries)
|
|
)
|
|
logging.debug(f"Attempted to upload {json.dumps(_position)}")
|
|
|
|
def mark_payload_recovered(self, callsign, latitude, longitude, altitude, message):
|
|
""" Upload an indication that a payload (radiosonde or otherwise) has been recovered """
|
|
# TODO
|
|
pass
|
|
|
|
def close(self):
|
|
self.uploader_thread_running = False
|
|
try:
|
|
self.uploader_thread.join()
|
|
except:
|
|
pass
|
|
logging.info("Sondehub - Chase-Car Position Uploader Closed")
|