kopia lustrzana https://github.com/projecthorus/chasemapper
Initial sondehub v2 integration
rodzic
6c3765896d
commit
c888eef454
|
@ -14,8 +14,9 @@ It will quite happily run alongside other Project Horus applications such as [ra
|
||||||
|
|
||||||
You can often find me in the #highaltitude IRC Channel on [Freenode](https://webchat.freenode.net/).
|
You can often find me in the #highaltitude IRC Channel on [Freenode](https://webchat.freenode.net/).
|
||||||
|
|
||||||
### Help Wanted!
|
## Update Notes
|
||||||
Currently Chasemapper is a bit mandrolic to set up, and this could be improved considerably, perhaps through the use of a docker container or similar. This isn't my area of expertise, so any assistance with this would be much appreciated!
|
* If you have previously had chasemapper or auto_rx installed, you may need to update flask-socketio to the most recent version. You can do this by running `sudo pip3 install -U flask-socketio`
|
||||||
|
* As of mid-April, there have been additions to the chasemapper configuration file format to enable interfacing with the new [v2 Sondehub Tracker](https://v2.sondehub.org/), including a selection for the online tracker in use. You will need to update your configuration files for chasemapper to continue working. Integration with Sondehub v2 is still in progress.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
|
@ -32,8 +33,6 @@ You also need flask-socketio (>=5.0.0) and pytz, which can be installed using pi
|
||||||
$ sudo pip3 install flask-socketio pytz
|
$ sudo pip3 install flask-socketio pytz
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note: If you have previously had chasemapper or auto_rx installed, you may need to update flask-socketio to the most recent version. You can do this by running `sudo pip3 install -U flask-socketio`**
|
|
||||||
|
|
||||||
You can then clone this repository with:
|
You can then clone this repository with:
|
||||||
```
|
```
|
||||||
$ git clone https://github.com/projecthorus/chasemapper.git
|
$ git clone https://github.com/projecthorus/chasemapper.git
|
||||||
|
|
|
@ -8,4 +8,4 @@
|
||||||
|
|
||||||
# Now using Semantic Versioning (https://semver.org/) MAJOR.MINOR.PATCH
|
# Now using Semantic Versioning (https://semver.org/) MAJOR.MINOR.PATCH
|
||||||
|
|
||||||
__version__ = "1.1.0"
|
__version__ = "1.2.0"
|
||||||
|
|
|
@ -199,12 +199,15 @@ def parse_config_file(filename):
|
||||||
_profile_section, "car_source_port"
|
_profile_section, "car_source_port"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_profile_online_tracker = config.get(_profile_section, "online_tracker")
|
||||||
|
|
||||||
chase_config["profiles"][_profile_name] = {
|
chase_config["profiles"][_profile_name] = {
|
||||||
"name": _profile_name,
|
"name": _profile_name,
|
||||||
"telemetry_source_type": _profile_telem_source_type,
|
"telemetry_source_type": _profile_telem_source_type,
|
||||||
"telemetry_source_port": _profile_telem_source_port,
|
"telemetry_source_port": _profile_telem_source_port,
|
||||||
"car_source_type": _profile_car_source_type,
|
"car_source_type": _profile_car_source_type,
|
||||||
"car_source_port": _profile_car_source_port,
|
"car_source_port": _profile_car_source_port,
|
||||||
|
"online_tracker": _profile_online_tracker,
|
||||||
}
|
}
|
||||||
if _default_profile == i:
|
if _default_profile == i:
|
||||||
chase_config["selected_profile"] = _profile_name
|
chase_config["selected_profile"] = _profile_name
|
||||||
|
|
|
@ -205,6 +205,20 @@ class HabitatChaseUploader(object):
|
||||||
""" Set the callsign """
|
""" Set the callsign """
|
||||||
self.callsign = call
|
self.callsign = call
|
||||||
|
|
||||||
|
def mark_payload_recovered(self, callsign, latitude, longitude, altitude, message):
|
||||||
|
""" Upload an indication that a payload (radiosonde or otherwise) has been recovered """
|
||||||
|
|
||||||
|
try:
|
||||||
|
initListenerCallsign(callsign, radio="", antenna=message)
|
||||||
|
uploadListenerPosition(callsign, latitude, longitude, altitude, chase=False)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
"Habitat - Unable to mark payload as recovered - %s" % (str(e))
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.info("Habitat - Payload marked as recovered.")
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.uploader_thread_running = False
|
self.uploader_thread_running = False
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -52,7 +52,7 @@ def read_last_balloon_telemetry():
|
||||||
if _entry["log_type"] == "BALLOON TELEMETRY":
|
if _entry["log_type"] == "BALLOON TELEMETRY":
|
||||||
telemetry_found = True
|
telemetry_found = True
|
||||||
_last_telemetry = _entry
|
_last_telemetry = _entry
|
||||||
|
|
||||||
if telemetry_found == True:
|
if telemetry_found == True:
|
||||||
_last_telemetry["time_dt"] = parse(_last_telemetry.pop("time"))
|
_last_telemetry["time_dt"] = parse(_last_telemetry.pop("time"))
|
||||||
return _last_telemetry
|
return _last_telemetry
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
#!/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")
|
|
@ -37,11 +37,11 @@ car_source_type = gpsd
|
||||||
# Car position source port (UDP) - only used if horus_udp is selected, but still needs to be provided.
|
# Car position source port (UDP) - only used if horus_udp is selected, but still needs to be provided.
|
||||||
car_source_port = 12345
|
car_source_port = 12345
|
||||||
|
|
||||||
# Car Position Upload System
|
# Online Tracker System
|
||||||
# Where to upload chase-car positions to
|
# Where to upload chase-car positions and balloon recovery notifications to.
|
||||||
# sondehub = Sondehub v2 Database, for viewing on the SondeHub tracker (https://tracker.sondehub.org)
|
# sondehub = Sondehub v2 Database, for viewing on the SondeHub tracker (https://tracker.sondehub.org)
|
||||||
# habitat = Habitat Database, for viewing on the HabHub tracker (https://tracker.habhub.org)
|
# habitat = Habitat Database, for viewing on the HabHub tracker (https://tracker.habhub.org)
|
||||||
car_upload = sondehub
|
online_tracker = sondehub
|
||||||
|
|
||||||
# Other profiles can be defined in sections like the following:
|
# Other profiles can be defined in sections like the following:
|
||||||
[profile_2]
|
[profile_2]
|
||||||
|
@ -58,11 +58,11 @@ car_source_type = serial
|
||||||
# Make sure to update the gps_serial settings further down in the configuration file!
|
# Make sure to update the gps_serial settings further down in the configuration file!
|
||||||
car_source_port = 55672
|
car_source_port = 55672
|
||||||
|
|
||||||
# Car Upload System
|
# Online Tracker System
|
||||||
# Where to upload chase-car positions to
|
# Where to upload chase-car positions and balloon recovery notifications to.
|
||||||
# sondehub = Sondehub v2 Database, for viewing on the SondeHub tracker (https://tracker.sondehub.org)
|
# sondehub = Sondehub v2 Database, for viewing on the SondeHub tracker (https://tracker.sondehub.org)
|
||||||
# habitat = Habitat Database, for viewing on the HabHub tracker (https://tracker.habhub.org)
|
# habitat = Habitat Database, for viewing on the HabHub tracker (https://tracker.habhub.org)
|
||||||
car_upload = habitat
|
online_tracker = habitat
|
||||||
|
|
||||||
# If you want add more profiles, you can do so here, e.g.
|
# If you want add more profiles, you can do so here, e.g.
|
||||||
# [profile_3]
|
# [profile_3]
|
||||||
|
@ -165,8 +165,8 @@ tile_server_path = /home/pi/Maps/
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Habitat Chase-Car Position Upload
|
# Habitat / SondeHub Chase-Car Position Upload
|
||||||
# If you want, this application can upload your chase-car position to the Habhub tracker,
|
# If you want, this application can upload your chase-car position to the Habhub / Sondehub trackers,
|
||||||
# for those follwing along at home.
|
# for those follwing along at home.
|
||||||
# The settings below can be modified from the web interface, but they will default to what is set below on startup.
|
# The settings below can be modified from the web interface, but they will default to what is set below on startup.
|
||||||
#
|
#
|
||||||
|
|
116
horusmapper.py
116
horusmapper.py
|
@ -6,6 +6,7 @@
|
||||||
# Released under GNU GPL v3 or later
|
# Released under GNU GPL v3 or later
|
||||||
#
|
#
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# Version check.
|
# Version check.
|
||||||
if sys.version_info < (3, 6):
|
if sys.version_info < (3, 6):
|
||||||
print("CRITICAL - chasemapper requires Python 3.6 or newer!")
|
print("CRITICAL - chasemapper requires Python 3.6 or newer!")
|
||||||
|
@ -37,6 +38,7 @@ from chasemapper.habitat import (
|
||||||
initListenerCallsign,
|
initListenerCallsign,
|
||||||
uploadListenerPosition,
|
uploadListenerPosition,
|
||||||
)
|
)
|
||||||
|
from chasemapper.sondehub import SondehubChaseUploader
|
||||||
from chasemapper.logger import ChaseLogger
|
from chasemapper.logger import ChaseLogger
|
||||||
from chasemapper.logread import read_last_balloon_telemetry
|
from chasemapper.logread import read_last_balloon_telemetry
|
||||||
from chasemapper.bearings import Bearings
|
from chasemapper.bearings import Bearings
|
||||||
|
@ -84,8 +86,8 @@ car_track = GenericTrack()
|
||||||
# Bearing store
|
# Bearing store
|
||||||
bearing_store = None
|
bearing_store = None
|
||||||
|
|
||||||
# Habitat Chase-Car uploader object
|
# Habitat/Sondehub Chase-Car uploader object
|
||||||
habitat_uploader = None
|
online_uploader = None
|
||||||
|
|
||||||
# Copy out any extra fields from incoming telemetry that we want to pass on to the GUI.
|
# Copy out any extra fields from incoming telemetry that we want to pass on to the GUI.
|
||||||
# At the moment we're really only using the burst timer field.
|
# At the moment we're really only using the burst timer field.
|
||||||
|
@ -146,7 +148,7 @@ def flask_emit_event(event_name="none", data={}):
|
||||||
|
|
||||||
@socketio.on("client_settings_update", namespace="/chasemapper")
|
@socketio.on("client_settings_update", namespace="/chasemapper")
|
||||||
def client_settings_update(data):
|
def client_settings_update(data):
|
||||||
global chasemapper_config, habitat_uploader
|
global chasemapper_config, online_uploader
|
||||||
|
|
||||||
_predictor_change = "none"
|
_predictor_change = "none"
|
||||||
if (chasemapper_config["pred_enabled"] == False) and (data["pred_enabled"] == True):
|
if (chasemapper_config["pred_enabled"] == False) and (data["pred_enabled"] == True):
|
||||||
|
@ -184,20 +186,33 @@ def client_settings_update(data):
|
||||||
|
|
||||||
# Start or Stop the Habitat Chase-Car Uploader.
|
# Start or Stop the Habitat Chase-Car Uploader.
|
||||||
if _habitat_change == "start":
|
if _habitat_change == "start":
|
||||||
if habitat_uploader == None:
|
if online_uploader == None:
|
||||||
habitat_uploader = HabitatChaseUploader(
|
_tracker = chasemapper_config["profiles"][
|
||||||
update_rate=chasemapper_config["habitat_update_rate"],
|
chasemapper_config["selected_profile"]
|
||||||
callsign=chasemapper_config["habitat_call"],
|
]["online_tracker"]
|
||||||
)
|
if _tracker == "habitat":
|
||||||
|
online_uploader = HabitatChaseUploader(
|
||||||
|
update_rate=chasemapper_config["habitat_update_rate"],
|
||||||
|
callsign=chasemapper_config["habitat_call"],
|
||||||
|
)
|
||||||
|
elif _tracker == "sondehub":
|
||||||
|
online_uploader = SondehubChaseUploader(
|
||||||
|
update_rate=chasemapper_config["habitat_update_rate"],
|
||||||
|
callsign=chasemapper_config["habitat_call"],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logging.error(
|
||||||
|
"Unknown Online Tracker %s, not starting uploader." % _tracker
|
||||||
|
)
|
||||||
|
|
||||||
elif _habitat_change == "stop":
|
elif _habitat_change == "stop":
|
||||||
habitat_uploader.close()
|
online_uploader.close()
|
||||||
habitat_uploader = None
|
online_uploader = None
|
||||||
|
|
||||||
# Update the habitat uploader with a new update rate, if one has changed.
|
# Update the habitat uploader with a new update rate, if one has changed.
|
||||||
if habitat_uploader != None:
|
if online_uploader != None:
|
||||||
habitat_uploader.set_update_rate(chasemapper_config["habitat_update_rate"])
|
online_uploader.set_update_rate(chasemapper_config["habitat_update_rate"])
|
||||||
habitat_uploader.set_callsign(chasemapper_config["habitat_call"])
|
online_uploader.set_callsign(chasemapper_config["habitat_call"])
|
||||||
|
|
||||||
# Push settings back out to all clients.
|
# Push settings back out to all clients.
|
||||||
flask_emit_event("server_settings_update", chasemapper_config)
|
flask_emit_event("server_settings_update", chasemapper_config)
|
||||||
|
@ -690,24 +705,22 @@ def clear_bearing_data(data):
|
||||||
@socketio.on("mark_recovered", namespace="/chasemapper")
|
@socketio.on("mark_recovered", namespace="/chasemapper")
|
||||||
def mark_payload_recovered(data):
|
def mark_payload_recovered(data):
|
||||||
""" Mark a payload as recovered, by uploading a station position """
|
""" Mark a payload as recovered, by uploading a station position """
|
||||||
|
global online_uploader
|
||||||
|
|
||||||
_callsign = data["recovery_title"]
|
_callsign = data["recovery_title"]
|
||||||
_lat = data["last_pos"][0]
|
_lat = data["last_pos"][0]
|
||||||
_lon = data["last_pos"][1]
|
_lon = data["last_pos"][1]
|
||||||
_alt = data["last_pos"][2]
|
_alt = data["last_pos"][2]
|
||||||
_msg = data["message"]
|
_msg = (
|
||||||
_timestamp = "Recovered at " + datetime.utcnow().strftime("%Y-%m-%d %H:%MZ")
|
data["message"]
|
||||||
|
+ " Recovered at "
|
||||||
|
+ datetime.utcnow().strftime("%Y-%m-%d %H:%MZ")
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
if online_uploader != None:
|
||||||
initListenerCallsign(_callsign, radio=_msg, antenna=_timestamp)
|
online_uploader.mark_payload_recovered(_callsign, _lat, _lon, _alt, _msg)
|
||||||
uploadListenerPosition(_callsign, _lat, _lon, _alt, chase=False)
|
else:
|
||||||
except Exception as e:
|
logging.error("No Online Tracker enabled, could not mark payload as recovered.")
|
||||||
logging.error(
|
|
||||||
"Unable to mark %s as recovered - %s" % (data["payload_call"], str(e))
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
logging.info("Payload %s marked as recovered." % data["payload_call"])
|
|
||||||
|
|
||||||
|
|
||||||
# Incoming telemetry handlers
|
# Incoming telemetry handlers
|
||||||
|
@ -788,7 +801,7 @@ def udp_listener_car_callback(data):
|
||||||
""" Handle car position data """
|
""" Handle car position data """
|
||||||
# TODO: Make a generic car position function, and have this function pass data into it
|
# TODO: Make a generic car position function, and have this function pass data into it
|
||||||
# so we can add support for other chase car position inputs.
|
# so we can add support for other chase car position inputs.
|
||||||
global car_track, habitat_uploader, bearing_store
|
global car_track, online_uploader, bearing_store
|
||||||
_lat = float(data["latitude"])
|
_lat = float(data["latitude"])
|
||||||
_lon = float(data["longitude"])
|
_lon = float(data["longitude"])
|
||||||
|
|
||||||
|
@ -833,9 +846,9 @@ def udp_listener_car_callback(data):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update the Habitat Uploader, if one exists.
|
# Update the Online Position Uploader, if one exists.
|
||||||
if habitat_uploader != None:
|
if online_uploader != None:
|
||||||
habitat_uploader.update_position(data)
|
online_uploader.update_position(data)
|
||||||
|
|
||||||
# Update the bearing store with the current car state (position & bearing)
|
# Update the bearing store with the current car state (position & bearing)
|
||||||
if bearing_store != None:
|
if bearing_store != None:
|
||||||
|
@ -904,8 +917,12 @@ def start_listeners(profile):
|
||||||
'telemetry_source_port' (int): Data source port
|
'telemetry_source_port' (int): Data source port
|
||||||
'car_source_type' (str): Car Position source type (none, horus_udp, gpsd, or station)
|
'car_source_type' (str): Car Position source type (none, horus_udp, gpsd, or station)
|
||||||
'car_source_port' (int): Car Position source port
|
'car_source_port' (int): Car Position source port
|
||||||
|
'online_tracker' (str): Which online tracker to upload chase-car info to ('habitat' or 'sondehub')
|
||||||
"""
|
"""
|
||||||
global data_listeners
|
global data_listeners, current_profile, online_uploader, chasemapper_config
|
||||||
|
|
||||||
|
current_profile = profile
|
||||||
|
|
||||||
# Stop any existing listeners.
|
# Stop any existing listeners.
|
||||||
for _thread in data_listeners:
|
for _thread in data_listeners:
|
||||||
try:
|
try:
|
||||||
|
@ -913,9 +930,32 @@ def start_listeners(profile):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Error closing thread - %s" % str(e))
|
logging.error("Error closing thread - %s" % str(e))
|
||||||
|
|
||||||
|
# Shut-down any online uploaders
|
||||||
|
if online_uploader != None:
|
||||||
|
online_uploader.close()
|
||||||
|
online_uploader = None
|
||||||
|
|
||||||
# Reset the listeners array.
|
# Reset the listeners array.
|
||||||
data_listeners = []
|
data_listeners = []
|
||||||
|
|
||||||
|
# Start up a new online uploader immediately if uploading is already enabled.
|
||||||
|
if chasemapper_config["habitat_upload_enabled"] == True:
|
||||||
|
if profile["online_tracker"] == "habitat":
|
||||||
|
online_uploader = HabitatChaseUploader(
|
||||||
|
update_rate=chasemapper_config["habitat_update_rate"],
|
||||||
|
callsign=chasemapper_config["habitat_call"],
|
||||||
|
)
|
||||||
|
elif profile["online_tracker"] == "sondehub":
|
||||||
|
online_uploader = SondehubChaseUploader(
|
||||||
|
update_rate=chasemapper_config["habitat_update_rate"],
|
||||||
|
callsign=chasemapper_config["habitat_call"],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logging.error(
|
||||||
|
"Unknown Online Tracker %s, not starting uploader"
|
||||||
|
% (profile["online_tracker"])
|
||||||
|
)
|
||||||
|
|
||||||
# Start up a OziMux listener, if we are using one.
|
# Start up a OziMux listener, if we are using one.
|
||||||
if profile["telemetry_source_type"] == "ozimux":
|
if profile["telemetry_source_type"] == "ozimux":
|
||||||
logging.info(
|
logging.info(
|
||||||
|
@ -1023,6 +1063,7 @@ def profile_change(data):
|
||||||
# Update all clients with the new profile selection
|
# Update all clients with the new profile selection
|
||||||
flask_emit_event("server_settings_update", chasemapper_config)
|
flask_emit_event("server_settings_update", chasemapper_config)
|
||||||
|
|
||||||
|
|
||||||
@socketio.on("device_position", namespace="/chasemapper")
|
@socketio.on("device_position", namespace="/chasemapper")
|
||||||
def device_position_update(data):
|
def device_position_update(data):
|
||||||
""" Accept a device position update from a client and process it as if it was a chase car position """
|
""" Accept a device position update from a client and process it as if it was a chase car position """
|
||||||
|
@ -1030,8 +1071,6 @@ def device_position_update(data):
|
||||||
udp_listener_car_callback(data)
|
udp_listener_car_callback(data)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebHandler(logging.Handler):
|
class WebHandler(logging.Handler):
|
||||||
|
@ -1113,7 +1152,7 @@ if __name__ == "__main__":
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Add in Chasemapper version information.
|
# Add in Chasemapper version information.
|
||||||
chasemapper_config['version'] = CHASEMAPPER_VERSION
|
chasemapper_config["version"] = CHASEMAPPER_VERSION
|
||||||
|
|
||||||
# Copy out the predictor settings to another dictionary.
|
# Copy out the predictor settings to another dictionary.
|
||||||
pred_settings = {
|
pred_settings = {
|
||||||
|
@ -1147,13 +1186,6 @@ if __name__ == "__main__":
|
||||||
if chasemapper_config["pred_enabled"]:
|
if chasemapper_config["pred_enabled"]:
|
||||||
initPredictor()
|
initPredictor()
|
||||||
|
|
||||||
# Start up the Habitat Chase-Car Uploader, if enabled
|
|
||||||
if chasemapper_config["habitat_upload_enabled"]:
|
|
||||||
habitat_uploader = HabitatChaseUploader(
|
|
||||||
update_rate=chasemapper_config["habitat_update_rate"],
|
|
||||||
callsign=chasemapper_config["habitat_call"],
|
|
||||||
)
|
|
||||||
|
|
||||||
# Read in last known position, if enabled
|
# Read in last known position, if enabled
|
||||||
|
|
||||||
if chasemapper_config["reload_last_position"]:
|
if chasemapper_config["reload_last_position"]:
|
||||||
|
@ -1188,8 +1220,8 @@ if __name__ == "__main__":
|
||||||
if chase_logger:
|
if chase_logger:
|
||||||
chase_logger.close()
|
chase_logger.close()
|
||||||
|
|
||||||
if habitat_uploader != None:
|
if online_uploader != None:
|
||||||
habitat_uploader.close()
|
online_uploader.close()
|
||||||
|
|
||||||
# Attempt to close the running listeners.
|
# Attempt to close the running listeners.
|
||||||
for _thread in data_listeners:
|
for _thread in data_listeners:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// Project Horus - Browser-Based Chase Mapper - Habitat Data Scraping
|
// Project Horus - Browser-Based Chase Mapper - Habitat Data Scraping
|
||||||
//
|
//
|
||||||
// Copyright (C) 2019 Mark Jessop <vk5qi@rfhead.net>
|
// Copyright (C) 2021 Mark Jessop <vk5qi@rfhead.net>
|
||||||
// Released under GNU GPL v3 or later
|
// Released under GNU GPL v3 or later
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -15,11 +15,6 @@ var spacenearus_last_position_id = 0;
|
||||||
// Not really sure if this is necessary.
|
// Not really sure if this is necessary.
|
||||||
var snear_request_running = false;
|
var snear_request_running = false;
|
||||||
|
|
||||||
// Store for vehicle data.
|
|
||||||
var habitat_vehicles = {};
|
|
||||||
// Only add chase cars which are (initially) within this range limit (km).
|
|
||||||
var habitat_vehicle_max_range = 200.0;
|
|
||||||
|
|
||||||
|
|
||||||
function process_habitat_vehicles(data){
|
function process_habitat_vehicles(data){
|
||||||
// Check we have a 'valid' response to process.
|
// Check we have a 'valid' response to process.
|
||||||
|
@ -55,37 +50,37 @@ function process_habitat_vehicles(data){
|
||||||
|
|
||||||
// If the vehicle is already known to us, then update it position.
|
// If the vehicle is already known to us, then update it position.
|
||||||
// Update any existing entries (even if the range is above the threshold)
|
// Update any existing entries (even if the range is above the threshold)
|
||||||
if (habitat_vehicles.hasOwnProperty(vcallsign)){
|
if (chase_vehicles.hasOwnProperty(vcallsign)){
|
||||||
|
|
||||||
// Only update if the position ID of this position is newer than that last seen.
|
// Only update if the position ID of this position is newer than that last seen.
|
||||||
if (habitat_vehicles[vcallsign].position_id < position.position_id){
|
if (chase_vehicles[vcallsign].position_id < position.position_id){
|
||||||
//console.log("Updating: " + vcallsign);
|
//console.log("Updating: " + vcallsign);
|
||||||
// Update the position ID.
|
// Update the position ID.
|
||||||
habitat_vehicles[vcallsign].position_id = position.position_id;
|
chase_vehicles[vcallsign].position_id = position.position_id;
|
||||||
|
|
||||||
// Since we don't always get a heading with the vehicle position, calculate it.
|
// Since we don't always get a heading with the vehicle position, calculate it.
|
||||||
var old_v_pos = {lat:habitat_vehicles[vcallsign].latest_data[0],
|
var old_v_pos = {lat:chase_vehicles[vcallsign].latest_data[0],
|
||||||
lon: habitat_vehicles[vcallsign].latest_data[1],
|
lon: chase_vehicles[vcallsign].latest_data[1],
|
||||||
alt:habitat_vehicles[vcallsign].latest_data[2]};
|
alt:chase_vehicles[vcallsign].latest_data[2]};
|
||||||
var new_v_pos = {lat: v_lat, lon:v_lon, alt:v_alt};
|
var new_v_pos = {lat: v_lat, lon:v_lon, alt:v_alt};
|
||||||
habitat_vehicles[vcallsign].heading = calculate_lookangles(old_v_pos, new_v_pos).azimuth;
|
chase_vehicles[vcallsign].heading = calculate_lookangles(old_v_pos, new_v_pos).azimuth;
|
||||||
|
|
||||||
// Update the position data.
|
// Update the position data.
|
||||||
habitat_vehicles[vcallsign].latest_data = [v_lat, v_lon, v_alt];
|
chase_vehicles[vcallsign].latest_data = [v_lat, v_lon, v_alt];
|
||||||
|
|
||||||
// Update the marker position.
|
// Update the marker position.
|
||||||
habitat_vehicles[vcallsign].marker.setLatLng(habitat_vehicles[vcallsign].latest_data).update();
|
chase_vehicles[vcallsign].marker.setLatLng(chase_vehicles[vcallsign].latest_data).update();
|
||||||
|
|
||||||
// Rotate/replace the icon to match the bearing.
|
// Rotate/replace the icon to match the bearing.
|
||||||
var _car_heading = habitat_vehicles[vcallsign].heading - 90.0;
|
var _car_heading = chase_vehicles[vcallsign].heading - 90.0;
|
||||||
if (_car_heading<=90.0){
|
if (_car_heading<=90.0){
|
||||||
habitat_vehicles[vcallsign].marker.setIcon(habitat_car_icons[habitat_vehicles[vcallsign].colour]);
|
chase_vehicles[vcallsign].marker.setIcon(habitat_car_icons[chase_vehicles[vcallsign].colour]);
|
||||||
habitat_vehicles[vcallsign].marker.setRotationAngle(_car_heading);
|
chase_vehicles[vcallsign].marker.setRotationAngle(_car_heading);
|
||||||
}else{
|
}else{
|
||||||
// We are travelling West - we need to use the flipped car icon.
|
// We are travelling West - we need to use the flipped car icon.
|
||||||
_car_heading = _car_heading - 180.0;
|
_car_heading = _car_heading - 180.0;
|
||||||
habitat_vehicles[vcallsign].marker.setIcon(habitat_car_icons_flipped[habitat_vehicles[vcallsign].colour]);
|
chase_vehicles[vcallsign].marker.setIcon(habitat_car_icons_flipped[chase_vehicles[vcallsign].colour]);
|
||||||
habitat_vehicles[vcallsign].marker.setRotationAngle(_car_heading);
|
chase_vehicles[vcallsign].marker.setRotationAngle(_car_heading);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -107,31 +102,31 @@ function process_habitat_vehicles(data){
|
||||||
var v_range = calculate_lookangles(my_pos, v_pos).range/1000.0;
|
var v_range = calculate_lookangles(my_pos, v_pos).range/1000.0;
|
||||||
|
|
||||||
// If the range is less than the threshold, add it to our list of chase vehicles.
|
// If the range is less than the threshold, add it to our list of chase vehicles.
|
||||||
if(v_range < habitat_vehicle_max_range){
|
if(v_range < vehicle_max_range){
|
||||||
//console.log("Adding: " + vcallsign);
|
//console.log("Adding: " + vcallsign);
|
||||||
habitat_vehicles[vcallsign] = {};
|
chase_vehicles[vcallsign] = {};
|
||||||
// Initialise a few default values
|
// Initialise a few default values
|
||||||
habitat_vehicles[vcallsign].heading = 90;
|
chase_vehicles[vcallsign].heading = 90;
|
||||||
habitat_vehicles[vcallsign].latest_data = [v_lat, v_lon, v_alt];
|
chase_vehicles[vcallsign].latest_data = [v_lat, v_lon, v_alt];
|
||||||
habitat_vehicles[vcallsign].position_id = position.position_id;
|
chase_vehicles[vcallsign].position_id = position.position_id;
|
||||||
|
|
||||||
// Get an index for the car icon. This is incremented for each vehicle,
|
// Get an index for the car icon. This is incremented for each vehicle,
|
||||||
// giving each a different colour.
|
// giving each a different colour.
|
||||||
habitat_vehicles[vcallsign].colour = car_colour_values[car_colour_idx];
|
chase_vehicles[vcallsign].colour = car_colour_values[car_colour_idx];
|
||||||
car_colour_idx = (car_colour_idx+1)%car_colour_values.length;
|
car_colour_idx = (car_colour_idx+1)%car_colour_values.length;
|
||||||
|
|
||||||
// Create marker
|
// Create marker
|
||||||
habitat_vehicles[vcallsign].marker = L.marker(habitat_vehicles[vcallsign].latest_data,
|
chase_vehicles[vcallsign].marker = L.marker(chase_vehicles[vcallsign].latest_data,
|
||||||
{title:vcallsign,
|
{title:vcallsign,
|
||||||
icon: habitat_car_icons[habitat_vehicles[vcallsign].colour],
|
icon: habitat_car_icons[chase_vehicles[vcallsign].colour],
|
||||||
rotationOrigin: "center center"})
|
rotationOrigin: "center center"})
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
// Keep our own record of if this marker has been added to a map,
|
// Keep our own record of if this marker has been added to a map,
|
||||||
// as we shouldn't be using the private _map property of the marker object.
|
// as we shouldn't be using the private _map property of the marker object.
|
||||||
habitat_vehicles[vcallsign].onmap = true;
|
chase_vehicles[vcallsign].onmap = true;
|
||||||
|
|
||||||
// Add tooltip, with custom CSS which removes all tooltip borders, and adds a text shadow.
|
// Add tooltip, with custom CSS which removes all tooltip borders, and adds a text shadow.
|
||||||
habitat_vehicles[vcallsign].marker.bindTooltip(vcallsign,
|
chase_vehicles[vcallsign].marker.bindTooltip(vcallsign,
|
||||||
{permanent: true,
|
{permanent: true,
|
||||||
direction: 'center',
|
direction: 'center',
|
||||||
offset:[0,25],
|
offset:[0,25],
|
||||||
|
@ -150,6 +145,7 @@ function get_habitat_vehicles(){
|
||||||
|
|
||||||
if(!snear_request_running){
|
if(!snear_request_running){
|
||||||
snear_request_running = true;
|
snear_request_running = true;
|
||||||
|
console.log("Requesting vehicles from Habitat...")
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: snear_request_url,
|
url: snear_request_url,
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
|
@ -166,19 +162,19 @@ function get_habitat_vehicles(){
|
||||||
// Show/Hide all vehicles.
|
// Show/Hide all vehicles.
|
||||||
function show_habitat_vehicles(){
|
function show_habitat_vehicles(){
|
||||||
var state = document.getElementById("showOtherCars").checked;
|
var state = document.getElementById("showOtherCars").checked;
|
||||||
for (_car in habitat_vehicles){
|
for (_car in chase_vehicles){
|
||||||
// Add to map, if its not already on there.
|
// Add to map, if its not already on there.
|
||||||
if(state){
|
if(state){
|
||||||
if(!habitat_vehicles[_car].onmap){
|
if(!chase_vehicles[_car].onmap){
|
||||||
habitat_vehicles[_car].marker.addTo(map);
|
chase_vehicles[_car].marker.addTo(map);
|
||||||
habitat_vehicles[_car].onmap = true;
|
chase_vehicles[_car].onmap = true;
|
||||||
}
|
}
|
||||||
} else{
|
} else{
|
||||||
if(habitat_vehicles[_car].onmap){
|
if(chase_vehicles[_car].onmap){
|
||||||
habitat_vehicles[_car].marker.remove();
|
chase_vehicles[_car].marker.remove();
|
||||||
habitat_vehicles[_car].onmap = false;
|
chase_vehicles[_car].onmap = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
//
|
||||||
|
// Project Horus - Browser-Based Chase Mapper - SondeHub Data Scraping
|
||||||
|
//
|
||||||
|
// Copyright (C) 2021 Mark Jessop <vk5qi@rfhead.net>
|
||||||
|
// Released under GNU GPL v3 or later
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// URL to scrape recent vehicle position data from.
|
||||||
|
// TODO: Allow adjustment of the number of positions to request.
|
||||||
|
var sondehub_vehicle_url = "https://v2.api";
|
||||||
|
|
||||||
|
function process_sondehub_vehicles(data){
|
||||||
|
// Check we have a 'valid' response to process.
|
||||||
|
if (data === null ||
|
||||||
|
!data.positions ||
|
||||||
|
!data.positions.position ||
|
||||||
|
!data.positions.position.length) {
|
||||||
|
snear_request_running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.positions.position.forEach(function(position){
|
||||||
|
// Update the highest position ID, so we don't request old data.
|
||||||
|
if (position.position_id > spacenearus_last_position_id){
|
||||||
|
spacenearus_last_position_id = position.position_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vcallsign = position.vehicle;
|
||||||
|
|
||||||
|
// Check this isn't our callsign.
|
||||||
|
// If it is, don't process it.
|
||||||
|
if (vcallsign.startsWith(chase_config.habitat_call)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if the vehicle is a chase car.
|
||||||
|
// This is denoted by _chase at the end of the callsign.
|
||||||
|
if(vcallsign.search(/(chase)/i) != -1) {
|
||||||
|
|
||||||
|
var v_lat = parseFloat(position.gps_lat);
|
||||||
|
var v_lon = parseFloat(position.gps_lon);
|
||||||
|
var v_alt = parseFloat(position.gps_alt);
|
||||||
|
|
||||||
|
// If the vehicle is already known to us, then update it position.
|
||||||
|
// Update any existing entries (even if the range is above the threshold)
|
||||||
|
if (chase_vehicles.hasOwnProperty(vcallsign)){
|
||||||
|
|
||||||
|
// Only update if the position ID of this position is newer than that last seen.
|
||||||
|
if (chase_vehicles[vcallsign].position_id < position.position_id){
|
||||||
|
//console.log("Updating: " + vcallsign);
|
||||||
|
// Update the position ID.
|
||||||
|
chase_vehicles[vcallsign].position_id = position.position_id;
|
||||||
|
|
||||||
|
// Since we don't always get a heading with the vehicle position, calculate it.
|
||||||
|
var old_v_pos = {lat:chase_vehicles[vcallsign].latest_data[0],
|
||||||
|
lon: chase_vehicles[vcallsign].latest_data[1],
|
||||||
|
alt:chase_vehicles[vcallsign].latest_data[2]};
|
||||||
|
var new_v_pos = {lat: v_lat, lon:v_lon, alt:v_alt};
|
||||||
|
chase_vehicles[vcallsign].heading = calculate_lookangles(old_v_pos, new_v_pos).azimuth;
|
||||||
|
|
||||||
|
// Update the position data.
|
||||||
|
chase_vehicles[vcallsign].latest_data = [v_lat, v_lon, v_alt];
|
||||||
|
|
||||||
|
// Update the marker position.
|
||||||
|
chase_vehicles[vcallsign].marker.setLatLng(chase_vehicles[vcallsign].latest_data).update();
|
||||||
|
|
||||||
|
// Rotate/replace the icon to match the bearing.
|
||||||
|
var _car_heading = chase_vehicles[vcallsign].heading - 90.0;
|
||||||
|
if (_car_heading<=90.0){
|
||||||
|
chase_vehicles[vcallsign].marker.setIcon(habitat_car_icons[chase_vehicles[vcallsign].colour]);
|
||||||
|
chase_vehicles[vcallsign].marker.setRotationAngle(_car_heading);
|
||||||
|
}else{
|
||||||
|
// We are travelling West - we need to use the flipped car icon.
|
||||||
|
_car_heading = _car_heading - 180.0;
|
||||||
|
chase_vehicles[vcallsign].marker.setIcon(habitat_car_icons_flipped[chase_vehicles[vcallsign].colour]);
|
||||||
|
chase_vehicles[vcallsign].marker.setRotationAngle(_car_heading);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// No need to go any further.
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we need to decide if we're going to add it or not.
|
||||||
|
// Determine the vehicle distance from our current position.
|
||||||
|
var v_pos = {lat: v_lat, lon:v_lon, alt:v_alt};
|
||||||
|
if (chase_car_position.marker === "NONE"){
|
||||||
|
var my_pos = {lat:chase_config.default_lat, lon:chase_config.default_lon, alt:0};
|
||||||
|
}else{
|
||||||
|
var my_pos = {lat:chase_car_position.latest_data[0], lon:chase_car_position.latest_data[1], alt:chase_car_position.latest_data[2]};
|
||||||
|
}
|
||||||
|
var v_range = calculate_lookangles(my_pos, v_pos).range/1000.0;
|
||||||
|
|
||||||
|
// If the range is less than the threshold, add it to our list of chase vehicles.
|
||||||
|
if(v_range < vehicle_max_range){
|
||||||
|
//console.log("Adding: " + vcallsign);
|
||||||
|
chase_vehicles[vcallsign] = {};
|
||||||
|
// Initialise a few default values
|
||||||
|
chase_vehicles[vcallsign].heading = 90;
|
||||||
|
chase_vehicles[vcallsign].latest_data = [v_lat, v_lon, v_alt];
|
||||||
|
chase_vehicles[vcallsign].position_id = position.position_id;
|
||||||
|
|
||||||
|
// Get an index for the car icon. This is incremented for each vehicle,
|
||||||
|
// giving each a different colour.
|
||||||
|
chase_vehicles[vcallsign].colour = car_colour_values[car_colour_idx];
|
||||||
|
car_colour_idx = (car_colour_idx+1)%car_colour_values.length;
|
||||||
|
|
||||||
|
// Create marker
|
||||||
|
chase_vehicles[vcallsign].marker = L.marker(chase_vehicles[vcallsign].latest_data,
|
||||||
|
{title:vcallsign,
|
||||||
|
icon: habitat_car_icons[chase_vehicles[vcallsign].colour],
|
||||||
|
rotationOrigin: "center center"})
|
||||||
|
.addTo(map);
|
||||||
|
// Keep our own record of if this marker has been added to a map,
|
||||||
|
// as we shouldn't be using the private _map property of the marker object.
|
||||||
|
chase_vehicles[vcallsign].onmap = true;
|
||||||
|
|
||||||
|
// Add tooltip, with custom CSS which removes all tooltip borders, and adds a text shadow.
|
||||||
|
chase_vehicles[vcallsign].marker.bindTooltip(vcallsign,
|
||||||
|
{permanent: true,
|
||||||
|
direction: 'center',
|
||||||
|
offset:[0,25],
|
||||||
|
className:'custom_label'}).openTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
snear_request_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function get_sondehub_vehicles(){
|
||||||
|
// nothing here yet.
|
||||||
|
console.log("Requesting vehicles from Sondehub...")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ function markPayloadRecovered(callsign){
|
||||||
"Submit": function() {
|
"Submit": function() {
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
_recovery_data.message = $('#customRecoveryMessage').val();
|
_recovery_data.message = $('#customRecoveryMessage').val();
|
||||||
_recovery_data.title = $('#customRecoveryTitle').val();
|
_recovery_data.recovery_title = $('#customRecoveryTitle').val();
|
||||||
|
|
||||||
// If the user has requested to use the chase car position, override the last position with it.
|
// If the user has requested to use the chase car position, override the last position with it.
|
||||||
if(document.getElementById("recoveryCarPosition").checked == true){
|
if(document.getElementById("recoveryCarPosition").checked == true){
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
<!-- Custom scripts -->
|
<!-- Custom scripts -->
|
||||||
<script src="{{ url_for('static', filename='js/habitat.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/habitat.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/sondehub.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/tables.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/tables.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
||||||
|
@ -65,6 +66,11 @@
|
||||||
// The sonde we are currently following on the map
|
// The sonde we are currently following on the map
|
||||||
var balloon_currently_following = "none";
|
var balloon_currently_following = "none";
|
||||||
|
|
||||||
|
// Other chase vehicles
|
||||||
|
var chase_vehicles = {};
|
||||||
|
// Only add chase cars which are (initially) within this range limit (km).
|
||||||
|
var vehicle_max_range = 200.0;
|
||||||
|
|
||||||
// Chase car position.
|
// Chase car position.
|
||||||
// properties will contain:
|
// properties will contain:
|
||||||
// latest_data: [lat,lon, alt] (latest car position)
|
// latest_data: [lat,lon, alt] (latest car position)
|
||||||
|
@ -614,11 +620,19 @@
|
||||||
}, age_update_rate);
|
}, age_update_rate);
|
||||||
|
|
||||||
|
|
||||||
// Habitat Chase Car Position Grabber
|
// Habitat/Sondehub Chase Car Position Grabber
|
||||||
var habitat_update_rate = 20000;
|
var habitat_update_rate = 20000;
|
||||||
window.setInterval(function(){
|
window.setInterval(function(){
|
||||||
if(document.getElementById("showOtherCars").checked){
|
if(document.getElementById("showOtherCars").checked){
|
||||||
get_habitat_vehicles();
|
if (chase_config.profiles[chase_config.selected_profile].online_tracker === "habitat"){
|
||||||
|
get_habitat_vehicles();
|
||||||
|
}
|
||||||
|
else if (chase_config.profiles[chase_config.selected_profile].online_tracker === "sondehub"){
|
||||||
|
get_sondehub_vehicles();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Do nothing...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, habitat_update_rate);
|
}, habitat_update_rate);
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue