kopia lustrzana https://github.com/projecthorus/chasemapper
commit
b13ec7d6f6
|
@ -106,6 +106,7 @@ Another option to obtain map tiles is [FoxtrotGPS](https://www.foxtrotgps.org/).
|
|||
To grab map tiles using FoxtrotGPS, we're going to use FoxtrotGPS's [Cached Maps](https://www.foxtrotgps.org/doc/foxtrotgps.html#Cached-Maps) feature.
|
||||
|
||||
* Install FoxtrotGPS (Linux only unfortunately, works OK on a Pi!) either [from source](https://www.foxtrotgps.org/releases/), or via your system package manager (`sudo apt-get install foxtrotgps`).
|
||||
* Warning - Installing foxtrotgps will also install gpsd, which may 'take over' your GPS receiver! If you aren't using GPSD, I'd recommend uninstalling it with: `sudo apt-get purge gpsd`
|
||||
* Load up FoxtrotGPS, and pan around the area you are intersted in caching. Pick the map layer you want, right-click on the map, and choose 'Map download'. You can then select how many zoom levels you want to cache, and start it downloading (this may take a while!)
|
||||
* Once you have a set of folders within your `~/Maps` cache directory, you can startup Chasemapper and start using them! Tiles will be served up as they become available.
|
||||
|
||||
|
|
|
@ -8,4 +8,4 @@
|
|||
|
||||
# Now using Semantic Versioning (https://semver.org/) MAJOR.MINOR.PATCH
|
||||
|
||||
__version__ = "1.5.4"
|
||||
__version__ = "1.5.7"
|
||||
|
|
|
@ -50,6 +50,13 @@ default_config = {
|
|||
"bearing_weight": 1.0,
|
||||
"bearing_color": "black",
|
||||
"bearing_custom_color": "#FF0000",
|
||||
"bearings_only_mode": False,
|
||||
# TimeSync Hunting Settings (not in config file, but needs to be shared between clients)
|
||||
"time_seq_enabled": False,
|
||||
"time_seq_times": [0,0,0,0],
|
||||
"time_seq_active": 25,
|
||||
"time_seq_cycle": 120,
|
||||
|
||||
# History
|
||||
"reload_last_position": False,
|
||||
}
|
||||
|
@ -182,6 +189,18 @@ def parse_config_file(filename):
|
|||
logging.info("Missing ascent_rate_averaging setting, using default (10)")
|
||||
chase_config["ascent_rate_averaging"] = 10
|
||||
|
||||
try:
|
||||
chase_config["bearings_only_mode"] = config.getboolean("bearings", "bearings_only_mode")
|
||||
except:
|
||||
logging.info("Missing bearing_only_mode setting, using default (False)")
|
||||
chase_config["bearings_only_mode"] = False
|
||||
|
||||
try:
|
||||
chase_config["doa_confidence_threshold"] = config.getfloat("bearings", "doa_confidence_threshold")
|
||||
except:
|
||||
logging.info("Missing DoA Confidence Threshold Setting, using default (4.0)")
|
||||
chase_config["doa_confidence_threshold"] = 4.0
|
||||
|
||||
# Telemetry Source Profiles
|
||||
|
||||
_profile_count = config.getint("profile_selection", "profile_count")
|
||||
|
|
|
@ -288,6 +288,7 @@ class DataStream(object):
|
|||
|
||||
except (ValueError, KeyError) as error:
|
||||
logging.error("GPSD Parser - Other Error - %s" % str(error))
|
||||
print(gpsd_socket_response)
|
||||
return
|
||||
|
||||
|
||||
|
@ -418,6 +419,11 @@ class GPSDAdaptor(object):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Little test script to print out received data from GPSD for debugging.
|
||||
# Run with: python3 -m chasemapper.gpsd 127.0.0.1
|
||||
# or whatever IP your gpsd server is running on.
|
||||
|
||||
import sys
|
||||
|
||||
def print_dict(data):
|
||||
print(data)
|
||||
|
@ -426,16 +432,7 @@ if __name__ == "__main__":
|
|||
format="%(asctime)s %(levelname)s:%(message)s", level=logging.DEBUG
|
||||
)
|
||||
|
||||
_gpsd = GPSDAdaptor(callback=print_dict)
|
||||
time.sleep(30)
|
||||
_gpsd = GPSDAdaptor(callback=print_dict, hostname=sys.argv[1])
|
||||
time.sleep(3000)
|
||||
_gpsd.close()
|
||||
|
||||
# gpsd_socket = GPSDSocket()
|
||||
# data_stream = DataStream()
|
||||
# gpsd_socket.connect()
|
||||
# gpsd_socket.watch()
|
||||
# for new_data in gpsd_socket:
|
||||
# if new_data:
|
||||
# data_stream.unpack(new_data)
|
||||
# print(data_stream.TPV)
|
||||
# #print(data_stream.SKY)
|
||||
|
|
|
@ -243,6 +243,9 @@ chase_car_speed = True
|
|||
#
|
||||
[bearings]
|
||||
|
||||
# If true, will hide balloon-related display elements from the map
|
||||
bearings_only_mode = False
|
||||
|
||||
# Number of bearings to store
|
||||
max_bearings = 300
|
||||
|
||||
|
@ -260,6 +263,10 @@ car_speed_gate = 10
|
|||
# 4 degrees/second seems to work fairly well.
|
||||
turn_rate_threshold = 4.0
|
||||
|
||||
# DoA Confidence Threshold
|
||||
# Used to gate bearings provided by a KrakenSDR system
|
||||
doa_confidence_threshold = 4.0
|
||||
|
||||
# Visual Settings - these can be adjust in the Web GUI during runtime
|
||||
|
||||
# Bearing length in km
|
||||
|
|
|
@ -110,6 +110,11 @@ def flask_bearing_entry():
|
|||
""" Render bearing entry page """
|
||||
return flask.render_template("bearing_entry.html")
|
||||
|
||||
@app.route("/oclock")
|
||||
def flask_oclock():
|
||||
""" Render bearing o'clock page """
|
||||
return flask.render_template("oclock.html")
|
||||
|
||||
@app.route("/get_telemetry_archive")
|
||||
def flask_get_telemetry_archive():
|
||||
return json.dumps(current_payloads)
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
.circle {
|
||||
position: relative;
|
||||
left: 0;
|
||||
border: 1px solid black;
|
||||
padding: 0;
|
||||
width: 20em;
|
||||
height: 20em;
|
||||
border-radius: 50%;
|
||||
list-style: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
li {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0; right: 0;
|
||||
width: 50%; height: 50%;
|
||||
transform-origin: 0% 100%;
|
||||
}
|
||||
.text {
|
||||
position: absolute;
|
||||
left: -100%;
|
||||
width: 200%; height: 200%;
|
||||
text-align: center;
|
||||
-webkit-transform: skewY(60deg) rotate(15deg);
|
||||
-ms-transform: skewY(60deg) rotate(15deg);
|
||||
transform: skewY(60deg) rotate(15deg);
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
li:first-child {
|
||||
-webkit-transform: rotate(15deg) skewY(-60deg);
|
||||
-ms-transform: rotate(15deg) skewY(-60deg);
|
||||
transform: rotate(15deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(2) {
|
||||
-webkit-transform: rotate(45deg) skewY(-60deg);
|
||||
-ms-transform: rotate(45deg) skewY(-60deg);
|
||||
transform: rotate(45deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(3) {
|
||||
-webkit-transform: rotate(75deg) skewY(-60deg);
|
||||
-ms-transform: rotate(75deg) skewY(-60deg);
|
||||
transform: rotate(75deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(4) {
|
||||
-webkit-transform: rotate(105deg) skewY(-60deg);
|
||||
-ms-transform: rotate(105deg) skewY(-60deg);
|
||||
transform: rotate(105deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(5) {
|
||||
-webkit-transform: rotate(135deg) skewY(-60deg);
|
||||
-ms-transform: rotate(135deg) skewY(-60deg);
|
||||
transform: rotate(135deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(6) {
|
||||
-webkit-transform: rotate(165deg) skewY(-60deg);
|
||||
-ms-transform: rotate(165deg) skewY(-60deg);
|
||||
transform: rotate(165deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(7) {
|
||||
-webkit-transform: rotate(195deg) skewY(-60deg);
|
||||
-ms-transform: rotate(195deg) skewY(-60deg);
|
||||
transform: rotate(195deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(8) {
|
||||
-webkit-transform: rotate(225deg) skewY(-60deg);
|
||||
-ms-transform: rotate(225deg) skewY(-60deg);
|
||||
transform: rotate(225deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(9) {
|
||||
-webkit-transform: rotate(255deg) skewY(-60deg);
|
||||
-ms-transform: rotate(255deg) skewY(-60deg);
|
||||
transform: rotate(255deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(10) {
|
||||
-webkit-transform: rotate(285deg) skewY(-60deg);
|
||||
-ms-transform: rotate(285deg) skewY(-60deg);
|
||||
transform: rotate(285deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(11) {
|
||||
-webkit-transform: rotate(315deg) skewY(-60deg);
|
||||
-ms-transform: rotate(315deg) skewY(-60deg);
|
||||
transform: rotate(315deg) skewY(-60deg);
|
||||
}
|
||||
li:nth-child(12) {
|
||||
-webkit-transform: rotate(345deg) skewY(-60deg);
|
||||
-ms-transform: rotate(345deg) skewY(-60deg);
|
||||
transform: rotate(345deg) skewY(-60deg);
|
||||
}
|
||||
li:first-child .text {
|
||||
background: green;
|
||||
}
|
||||
li:nth-child(2) .text {
|
||||
background: tomato;
|
||||
}
|
||||
li:nth-child(3) .text {
|
||||
background: aqua;
|
||||
}
|
||||
li:nth-child(4) .text {
|
||||
background: yellow;
|
||||
}
|
||||
li:nth-child(5) .text {
|
||||
background: orange;
|
||||
}
|
||||
li:nth-child(6) .text {
|
||||
background: purple;
|
||||
}
|
||||
li:nth-child(7) .text {
|
||||
background: cyan;
|
||||
}
|
||||
li:nth-child(8) .text {
|
||||
background: brown;
|
||||
}
|
||||
li:nth-child(9) .text {
|
||||
background: gray;
|
||||
}
|
||||
li:nth-child(10) .text {
|
||||
background: pink;
|
||||
}
|
||||
li:nth-child(11) .text {
|
||||
background: maroon;
|
||||
}
|
||||
li:nth-child(12) .text {
|
||||
background: gold;
|
||||
}
|
|
@ -247,7 +247,17 @@ function handleTelemetry(data){
|
|||
|
||||
// Update Detailed GPS / Heading Info
|
||||
if(data.hasOwnProperty('heading_status')){
|
||||
$("#headingStatus").text(data.heading_status);
|
||||
if(data.heading_status != null){
|
||||
$("#headingStatus").text(data.heading_status);
|
||||
|
||||
if(data.heading_status.includes("Ongoing")){
|
||||
$('#car_warning').text("IMU Not Aligned")
|
||||
$('#car_warning').removeClass();
|
||||
$('#car_warning').addClass('dataAgeBad');
|
||||
} else {
|
||||
$('#car_warning').text("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(data.hasOwnProperty('numSV')){
|
||||
|
|
|
@ -36,6 +36,16 @@ var bearing_large_plot = false;
|
|||
// Start out with just our own local timestamp.
|
||||
var latest_server_timestamp = Date.now()/1000.0;
|
||||
|
||||
// Time-Sequenced Transmitter Code
|
||||
// ... which is entirely specific to one event at the Mt Gambier Convention,
|
||||
// yet took me ages to write.
|
||||
|
||||
// These values are set to a instantaneous time when a button is clicked.
|
||||
var timeSeqEnabled = false;
|
||||
var timeSeqActive = 25;
|
||||
var timeSeqCycle = 120;
|
||||
var timeSeqTimes = [0,0,0,0];
|
||||
|
||||
|
||||
function updateBearingSettings(){
|
||||
// Update bearing settings, but do *not* redraw.
|
||||
|
@ -69,7 +79,7 @@ function destroyAllBearings(){
|
|||
});
|
||||
|
||||
bearing_store = {};
|
||||
bearing_sources = [];
|
||||
//bearing_sources = [];
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,6 +124,15 @@ function addBearing(timestamp, bearing, live){
|
|||
|
||||
bearing_store[timestamp] = bearing;
|
||||
|
||||
if (timeSeqEnabled){
|
||||
// Check if this bearing is from the current time-sequenced transmitter.
|
||||
var _current_seq = getCurrentSeqNumber();
|
||||
if (_current_seq >= 0){
|
||||
bearing.source = bearing.source + "_Fox" + _current_seq;
|
||||
}
|
||||
updateTimeSeqStatus();
|
||||
}
|
||||
|
||||
if ( !bearing_sources.includes(bearing.source)){
|
||||
bearing_sources.push(bearing.source);
|
||||
_new_bearing_div_name = "bearing_source_" + bearing.source;
|
||||
|
@ -297,7 +316,7 @@ function toggleBearingsOnlyMode(){
|
|||
var _bearings_only_enabled = document.getElementById("bearingsOnlyMode").checked;
|
||||
|
||||
|
||||
if ((_bearings_only_enabled == true) && (bearings_only_mode == false)){
|
||||
if ((_bearings_only_enabled == true) ){//} && (bearings_only_mode == false)){
|
||||
// The user had just enabled the bearings_only_mode, so hide things that are not relevant.
|
||||
|
||||
$("#summary_table").hide();
|
||||
|
@ -309,7 +328,7 @@ function toggleBearingsOnlyMode(){
|
|||
bearings_only_mode = true;
|
||||
|
||||
|
||||
} else if ((_bearings_only_enabled == false) && (bearings_only_mode == true)){
|
||||
} else if ((_bearings_only_enabled == false)){//} && (bearings_only_mode == true)){
|
||||
// Un-hide balloon stuff
|
||||
|
||||
$("#summary_table").show();
|
||||
|
@ -473,3 +492,125 @@ function manualBearing(){
|
|||
|
||||
socket.emit('add_manual_bearing', _bearing_info);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function updateTimeSeqStatus(){
|
||||
// Update text indicating which sequence number is active.
|
||||
var _current_seq = getCurrentSeqNumber();
|
||||
if(_current_seq >= 0 ){
|
||||
var _timeseqtext = "Current Active: " + _current_seq + "<br>";
|
||||
} else {
|
||||
var _timeseqtext = "Current Active: None<br>";
|
||||
}
|
||||
for (var n=0; n<4; n++){
|
||||
if(timeSeqTimes[n] > 0){
|
||||
timeseq_hms = new Date(timeSeqTimes[n]);
|
||||
_timeseqtext += "Fox "+n+": " + timeseq_hms.toLocaleTimeString() + "<br>";
|
||||
$("#timeSeqSet" + n).css("background-color", "#00FF00");
|
||||
}else if (timeSeqTimes[n] < 0){
|
||||
_timeseqtext += "Fox "+n+": Not Set<br>";
|
||||
$("#timeSeqSet" + num).css("background-color", "#FF0000");
|
||||
} else {
|
||||
_timeseqtext += "Fox "+n+": Not Set<br>";
|
||||
$("#timeSeqSet" + n).css("background-color", "buttonface");
|
||||
}
|
||||
}
|
||||
|
||||
$("#timeSeqStatus").html(_timeseqtext);
|
||||
}
|
||||
|
||||
function updateTimeSeqClock(){
|
||||
if(timeSeqEnabled == true){
|
||||
var _current_seq = getCurrentSeqNumber();
|
||||
if( _current_seq >= 0 ){
|
||||
|
||||
var _current_time = Date.now();
|
||||
var _seqtime = timeSeqActive - ((_current_time - timeSeqTimes[_current_seq]) % (timeSeqCycle*1000))/1000.0;
|
||||
|
||||
$('#timeseq_notice').text("Fox " + _current_seq + ": " + _seqtime.toFixed(1));
|
||||
|
||||
} else {
|
||||
$('#timeseq_notice').text("");
|
||||
}
|
||||
|
||||
} else {
|
||||
$('#timeseq_notice').text("");
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentSeqNumber(offset_seconds){
|
||||
// Determine the current transmitter number, based on current time and the timeSeqTimes.
|
||||
// Optional offset_seconds argument, to enable testing times slightly into the future.
|
||||
|
||||
if (typeof offset_seconds === 'undefined') {
|
||||
offset_seconds = 0;
|
||||
}
|
||||
|
||||
var _current_time = Date.now() + offset_seconds*1000;
|
||||
|
||||
if(timeSeqTimes[0] > 0){
|
||||
if ((_current_time - timeSeqTimes[0]) % (timeSeqCycle*1000) < timeSeqActive*1000){
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if(timeSeqTimes[1] > 0){
|
||||
if ((_current_time - timeSeqTimes[1]) % (timeSeqCycle*1000) < timeSeqActive*1000){
|
||||
return 1
|
||||
}
|
||||
}
|
||||
if(timeSeqTimes[2] > 0){
|
||||
if ((_current_time - timeSeqTimes[2]) % (timeSeqCycle*1000) < timeSeqActive*1000){
|
||||
return 2
|
||||
}
|
||||
}
|
||||
if(timeSeqTimes[3] > 0){
|
||||
if ((_current_time - timeSeqTimes[3]) % (timeSeqCycle*1000) < timeSeqActive*1000){
|
||||
return 3
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function setTimeSeq(num){
|
||||
|
||||
if (num>= 0){
|
||||
timeSeqEnabled = true;
|
||||
$("#timeSeqEnabled").prop('checked', true);
|
||||
// Check we arent currently in the middle of a transmit period
|
||||
if (getCurrentSeqNumber() < 0 && getCurrentSeqNumber(timeSeqActive)){
|
||||
// Update
|
||||
timeSeqTimes[num] = Date.now();
|
||||
// Set button color to green.
|
||||
$("#timeSeqSet" + num).css("background-color", "#00FF00");
|
||||
} else {
|
||||
timeSeqTimes[num] = -1;
|
||||
// Set button color to red.
|
||||
$("#timeSeqSet" + num).css("background-color", "#FF0000");
|
||||
}
|
||||
} else {
|
||||
timeSeqEnabled = false;
|
||||
$("#timeSeqEnabled").prop('checked', false);
|
||||
timeSeqTimes = [0,0,0,0];
|
||||
$("#timeSeqSet0").css("background-color", "buttonface");
|
||||
$("#timeSeqSet1").css("background-color", "buttonface");
|
||||
$("#timeSeqSet2").css("background-color", "buttonface");
|
||||
$("#timeSeqSet3").css("background-color", "buttonface");
|
||||
}
|
||||
updateTimeSeqStatus();
|
||||
clientSettingsUpdate();
|
||||
}
|
||||
|
||||
function toggleTimeSeqEnabled(){
|
||||
// Enable-disable time sequenced transmitters.
|
||||
var _time_seq_enabled = document.getElementById("timeSeqEnabled").checked;
|
||||
|
||||
if (_time_seq_enabled == true){
|
||||
// Enable time-sequenced transmitters.
|
||||
timeSeqEnabled = true;
|
||||
} else {
|
||||
// Disable time-sequenced transmitters.
|
||||
timeSeqEnabled = false;
|
||||
}
|
||||
clientSettingsUpdate();
|
||||
}
|
|
@ -65,6 +65,19 @@ function serverSettingsUpdate(data){
|
|||
$('#bearingColorSelect').val(chase_config.bearing_color);
|
||||
$('#bearingCustomColor').val(chase_config.bearing_custom_color);
|
||||
$('#bearingMaximumAge').val((chase_config.max_bearing_age/60.0).toFixed(0));
|
||||
$('#bearingConfidenceThreshold').val(chase_config.doa_confidence_threshold.toFixed(1));
|
||||
|
||||
$('#bearingsOnlyMode').prop('checked', chase_config.bearings_only_mode);
|
||||
toggleBearingsOnlyMode()
|
||||
// Add new time sync bearing settings here
|
||||
|
||||
timeSeqEnabled = chase_config.time_seq_enabled;
|
||||
$("#timeSeqEnabled").prop('checked', timeSeqEnabled);
|
||||
timeSeqActive = chase_config.time_seq_active;
|
||||
timeSeqCycle = chase_config.time_seq_cycle;
|
||||
timeSeqTimes = chase_config.time_seq_times;
|
||||
updateTimeSeqStatus();
|
||||
|
||||
|
||||
// Clear and populate the profile selection.
|
||||
$('#profileSelect').children('option:not(:first)').remove();
|
||||
|
@ -108,6 +121,12 @@ function clientSettingsUpdate(){
|
|||
chase_config.habitat_update_rate = _habitat_update_rate
|
||||
}
|
||||
|
||||
// Add in a selection of the bearing settings here.
|
||||
// These don't change anything on the backend, but need to be propagated to other clients.
|
||||
chase_config.time_seq_times = timeSeqTimes;
|
||||
chase_config.time_seq_enabled = timeSeqEnabled;
|
||||
chase_config.time_seq_active = timeSeqActive;
|
||||
chase_config.time_seq_cycle = timeSeqCycle;
|
||||
|
||||
socket.emit('client_settings_update', chase_config);
|
||||
};
|
|
@ -358,7 +358,7 @@
|
|||
// Data age display - shows how old the various datasets are.
|
||||
L.control.custom({
|
||||
position: 'topleft',
|
||||
content : "<div class='dataAgeHeader'>Data Age</div><div id='payload_age' class='dataAgeOK'></div><div id='car_age' class='dataAgeOK'></div><div id='pred_age' class='dataAgeOK'></div>",
|
||||
content : "<div class='dataAgeHeader'>Data Age</div><div id='payload_age' class='dataAgeOK'></div><div id='car_age' class='dataAgeOK'></div><div id='car_warning' class='dataAgeOK'></div><div id='pred_age' class='dataAgeOK'></div>",
|
||||
classes : 'btn-group-vertical btn-group-sm',
|
||||
id: 'age_display',
|
||||
style :
|
||||
|
@ -414,6 +414,20 @@
|
|||
})
|
||||
.addTo(map);
|
||||
|
||||
// Time-to-landing display - shows the time until landing for the currently tracked payload.
|
||||
L.control.custom({
|
||||
position: 'bottomcenter',
|
||||
content : "<div id='timeseq_notice' class='timeToLanding'></div>",
|
||||
classes : 'btn-group-vertical btn-group-sm',
|
||||
id: 'ttl_display',
|
||||
style :
|
||||
{
|
||||
margin: '5px',
|
||||
padding: '0px 0 0 0',
|
||||
cursor: 'pointer',
|
||||
}
|
||||
})
|
||||
.addTo(map);
|
||||
|
||||
L.control.custom({
|
||||
position: 'bottomright',
|
||||
|
@ -675,6 +689,8 @@
|
|||
}else{
|
||||
$("#pred_age").text("Predictions: " + pred_data_age.toFixed(1)+"s");
|
||||
}
|
||||
|
||||
updateTimeSeqClock();
|
||||
}, age_update_rate);
|
||||
|
||||
// Start connection to Sondehub Websockets.
|
||||
|
@ -705,6 +721,9 @@
|
|||
});
|
||||
}
|
||||
},10000);
|
||||
|
||||
// Enable bearings only mode if it's set.
|
||||
toggleBearingsOnlyMode();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
@ -1014,7 +1033,28 @@
|
|||
<div class="paramRow">
|
||||
<input type="text" id="bearingManualEntry" value="0"><br/><button type="button" class="paramSelector" id="manualBearingBtn" onclick='manualBearing();'>Plot</button></br>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="/bearing" target="_blank" rel="noopener noreferrer">EasyBearing</a></br><a href="/oclock" target="_blank" rel="noopener noreferrer">O'Clock Entry</a>
|
||||
</div>
|
||||
<h3>Mt Gambier</h3>
|
||||
<div class="form-switch form-check-reverse">
|
||||
<input class="form-check-input" type="checkbox" role="switch" value="" id="timeSeqEnabled" onclick='toggleTimeSeqEnabled();'>
|
||||
<label class="form-check-label" for="bearingsEnabled">
|
||||
<b>Enable Time-Seq Mode </b>
|
||||
</label>
|
||||
</div>
|
||||
<div class="paramRow">
|
||||
<b>Active Time (s)</b><input type="text" class="paramEntry" id="timeSeqActiveTime" value="25"><br/>
|
||||
</div>
|
||||
<div class="paramRow">
|
||||
<b>Cycle Time (s)</b><input type="text" class="paramEntry" id="timeSeqActiveTime" value="120"><br/>
|
||||
</div>
|
||||
<div class="paramRow">
|
||||
<button type="button" class="paramSelector" id="timeSeqSet0" onclick='setTimeSeq(0);'>Set 0</button><button type="button" class="paramSelector" id="timeSeqSet1" onclick='setTimeSeq(1);'>Set 1</button><button type="button" class="paramSelector" id="timeSeqSet2" onclick='setTimeSeq(2);'>Set 2</button><button type="button" class="paramSelector" id="timeSeqSet3" onclick='setTimeSeq(3);'>Set 3</button><button type="button" class="paramSelector" id="timeSeqSetClr" onclick='setTimeSeq(-1);'>Clr</button></br>
|
||||
</div>
|
||||
<div class="paramRow">
|
||||
<div class="form-check-label" id='timeSeqStatus'></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,270 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>O'Clock Bearing Entry</title>
|
||||
|
||||
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/leaflet.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/leaflet-sidebar.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/leaflet-control-topcenter.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/Leaflet.PolylineMeasure.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/leaflet-routing-machine.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/easy-button.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/tabulator_simple.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/jquery-ui.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/chasemapper.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='css/oclock.css') }}" rel="stylesheet">
|
||||
|
||||
|
||||
<!-- I should probably feel bad for using so many libraries, but apparently this is the way thing are done :-/ -->
|
||||
<script src="{{ url_for('static', filename='js/jquery-3.3.1.min.js')}}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery-ui.min.js')}}"></script>
|
||||
<script src="{{ url_for('static', filename='js/socket.io.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/leaflet.js') }}"></script>
|
||||
<!-- Leaflet plugins... -->
|
||||
<script src="{{ url_for('static', filename='js/leaflet.rotatedMarker.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/leaflet-control-topcenter.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/leaflet-sidebar.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/Leaflet.Control.Custom.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/Leaflet.PolylineMeasure.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/easy-button.js') }}"></script>
|
||||
|
||||
|
||||
|
||||
<!-- Custom scripts -->
|
||||
|
||||
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
||||
|
||||
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
|
||||
// Chase car position.
|
||||
// properties will contain:
|
||||
// latest_data: [lat,lon, alt] (latest car position)
|
||||
// heading: Car heading (to point icon appropriately.)
|
||||
// marker: Leaflet marker
|
||||
var chase_car_position = {latest_data: [0.0,0.0,0.0], heading:0, marker: 'NONE', path: 'NONE'};
|
||||
|
||||
var current_bearing = 0;
|
||||
|
||||
var bearing_length = 20000;
|
||||
|
||||
|
||||
// These values are set to a instantaneous time when a button is clicked.
|
||||
var timeSeqEnabled = false;
|
||||
var timeSeqActive = 25;
|
||||
var timeSeqCycle = 120;
|
||||
var timeSeqTimes = [0,0,0,0];
|
||||
|
||||
var chase_config = {};
|
||||
|
||||
function handleSettings(data){
|
||||
chase_config = data;
|
||||
|
||||
timeSeqEnabled = chase_config.time_seq_enabled;
|
||||
timeSeqActive = chase_config.time_seq_active;
|
||||
timeSeqCycle = chase_config.time_seq_cycle;
|
||||
timeSeqTimes = chase_config.time_seq_times;
|
||||
}
|
||||
|
||||
function getCurrentSeqNumber(offset_seconds){
|
||||
// Determine the current transmitter number, based on current time and the timeSeqTimes.
|
||||
// Optional offset_seconds argument, to enable testing times slightly into the future.
|
||||
|
||||
if (typeof offset_seconds === 'undefined') {
|
||||
offset_seconds = 0;
|
||||
}
|
||||
|
||||
var _current_time = Date.now() + offset_seconds*1000;
|
||||
|
||||
if(timeSeqTimes[0] > 0){
|
||||
if ((_current_time - timeSeqTimes[0]) % (timeSeqCycle*1000) < timeSeqActive*1000){
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if(timeSeqTimes[1] > 0){
|
||||
if ((_current_time - timeSeqTimes[1]) % (timeSeqCycle*1000) < timeSeqActive*1000){
|
||||
return 1
|
||||
}
|
||||
}
|
||||
if(timeSeqTimes[2] > 0){
|
||||
if ((_current_time - timeSeqTimes[2]) % (timeSeqCycle*1000) < timeSeqActive*1000){
|
||||
return 2
|
||||
}
|
||||
}
|
||||
if(timeSeqTimes[3] > 0){
|
||||
if ((_current_time - timeSeqTimes[3]) % (timeSeqCycle*1000) < timeSeqActive*1000){
|
||||
return 3
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function updateTimeSeqClock(){
|
||||
if(timeSeqEnabled == true){
|
||||
var _current_seq = getCurrentSeqNumber();
|
||||
if( _current_seq >= 0 ){
|
||||
|
||||
var _current_time = Date.now();
|
||||
var _seqtime = timeSeqActive - ((_current_time - timeSeqTimes[_current_seq]) % (timeSeqCycle*1000))/1000.0;
|
||||
|
||||
$('#timeseq_notice').html("<h2>Fox " + _current_seq + ": " + _seqtime.toFixed(1) + "</h2>");
|
||||
|
||||
} else {
|
||||
$('#timeseq_notice').html("");
|
||||
}
|
||||
|
||||
} else {
|
||||
$('#timeseq_notice').html("");
|
||||
}
|
||||
}
|
||||
|
||||
// Leaflet map instance.
|
||||
var map;
|
||||
|
||||
|
||||
|
||||
// Socket.IO Settings
|
||||
var namespace = '/chasemapper';
|
||||
// Socket.IO instance.
|
||||
var socket;
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
// Connect to the Socket.IO server.
|
||||
// The connection URL has the following format:
|
||||
// http[s]://<domain>:<port>[/<namespace>]
|
||||
socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);
|
||||
|
||||
// Grab the System config on startup.
|
||||
// Refer to config.py for the contents of the configuration blob.
|
||||
$.ajax({
|
||||
url: "/get_config",
|
||||
dataType: 'json',
|
||||
async: false, // Yes, this is deprecated...
|
||||
success: function(data) {
|
||||
handleSettings(data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Tell the server we are connected and ready for data.
|
||||
socket.on('connect', function() {
|
||||
socket.emit('client_connected', {data: 'I\'m connected!'});
|
||||
// This will cause the server to emit a few messages telling us to fetch data.
|
||||
});
|
||||
|
||||
socket.on('server_settings_update', function(data){
|
||||
handleSettings(data);
|
||||
});
|
||||
|
||||
|
||||
function handleOclockClick(value){
|
||||
console.log(value);
|
||||
_bearing_info = {
|
||||
'type': 'BEARING',
|
||||
'bearing_type': 'relative',
|
||||
'source': 'EasyBearing',
|
||||
'bearing': value
|
||||
};
|
||||
console.log(_bearing_info);
|
||||
socket.emit('add_manual_bearing', _bearing_info);
|
||||
|
||||
// Update the bearing info.
|
||||
$("#bearing_info").html("Last Bearing: " + value + "</br>Last Time: " + new Date().toLocaleTimeString());
|
||||
}
|
||||
|
||||
$("#clock1").click(function(){handleOclockClick(30);});
|
||||
$("#clock2").click(function(){handleOclockClick(60);});
|
||||
$("#clock3").click(function(){handleOclockClick(90);});
|
||||
$("#clock4").click(function(){handleOclockClick(120);});
|
||||
$("#clock5").click(function(){handleOclockClick(150);});
|
||||
$("#clock6").click(function(){handleOclockClick(180);});
|
||||
$("#clock7").click(function(){handleOclockClick(210);});
|
||||
$("#clock8").click(function(){handleOclockClick(240);});
|
||||
$("#clock9").click(function(){handleOclockClick(270);});
|
||||
$("#clock10").click(function(){handleOclockClick(300);});
|
||||
$("#clock11").click(function(){handleOclockClick(330);});
|
||||
$("#clock12").click(function(){handleOclockClick(0);});
|
||||
|
||||
|
||||
function handleTelemetry(data){
|
||||
// Telemetry Event messages contain a dictionary of position data.
|
||||
// It should have the fields:
|
||||
// callsign: string
|
||||
// position: [lat, lon, alt]
|
||||
// vel_v: float
|
||||
// time_to_landing: String
|
||||
// If callsign = 'CAR', the lat/lon/alt will be considered to be a car telemetry position.
|
||||
|
||||
// Handle chase car position updates.
|
||||
if (data.callsign == 'CAR'){
|
||||
// Update car position.
|
||||
chase_car_position.latest_data = data.position;
|
||||
chase_car_position.heading = data.heading; // degrees true
|
||||
chase_car_position.speed = data.speed; // m/s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Telemetry event handler.
|
||||
// We will get one of these mesages with every new balloon position
|
||||
socket.on('telemetry_event', function(data) {
|
||||
handleTelemetry(data);
|
||||
});
|
||||
|
||||
|
||||
window.setInterval(function () {
|
||||
|
||||
|
||||
updateTimeSeqClock();
|
||||
}, 500);
|
||||
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class='col-12'>
|
||||
<div id="title_div"><h1>O'Clock Entry</h1></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class='col-12'>
|
||||
<ul class="circle">
|
||||
<li><div class="text" id="clock1">1</div></li>
|
||||
<li><div class="text" id="clock2">2</div></li>
|
||||
<li><div class="text" id="clock3"> 3</div></li>
|
||||
<li><div class="text" id="clock4">4</div></li>
|
||||
<li><div class="text" id="clock5">5</div></li>
|
||||
<li><div class="text" id="clock6">6</div></li>
|
||||
<li><div class="text" id="clock7">7</div></li>
|
||||
<li><div class="text" id="clock8">8</div></li>
|
||||
<li><div class="text" id="clock9">9</div></li>
|
||||
<li><div class="text" id="clock10">10</div></li>
|
||||
<li><div class="text" id="clock11">11</div></li>
|
||||
<li><div class="text" id="clock12">12</div></li>
|
||||
<ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class='col-12'>
|
||||
<div id="bearing_info">Last Bearing:</br>Last Time:</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class='col-12'>
|
||||
<div id="timeseq_notice"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
Ładowanie…
Reference in New Issue