Merge pull request #63 from projecthorus/gambier2025

Mt Gambier Hunt Additions
master v1.5.7
Mark Jessop 2025-08-16 16:23:07 +09:30 zatwierdzone przez GitHub
commit b13ec7d6f6
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
12 zmienionych plików z 652 dodań i 18 usunięć

Wyświetl plik

@ -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.

Wyświetl plik

@ -8,4 +8,4 @@
# Now using Semantic Versioning (https://semver.org/) MAJOR.MINOR.PATCH
__version__ = "1.5.4"
__version__ = "1.5.7"

Wyświetl plik

@ -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")

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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')){

Wyświetl plik

@ -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();
}

Wyświetl plik

@ -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);
};

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>