kopia lustrzana https://github.com/cyoung/stratux
new 'weather' page which uses new 'WatchList' setting
rodzic
45215e258b
commit
a1502307aa
|
@ -648,6 +648,7 @@ type settings struct {
|
|||
ReplayLog bool // Startup only option. Cannot be changed during runtime.
|
||||
PPM int
|
||||
OwnshipModeS int32
|
||||
WatchList string
|
||||
}
|
||||
|
||||
type status struct {
|
||||
|
|
|
@ -151,6 +151,8 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
|
|||
globalSettings.ReplayLog = val.(bool)
|
||||
case "PPM":
|
||||
globalSettings.PPM = int(val.(float64))
|
||||
case "WatchList":
|
||||
globalSettings.WatchList = val.(string)
|
||||
case "OwnshipModeS":
|
||||
// Expecting a hex string less than 6 characters (24 bits) long.
|
||||
hexc := val.(string)
|
||||
|
|
107
web/css/main.css
107
web/css/main.css
|
@ -2,20 +2,26 @@
|
|||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.traffic-page {}
|
||||
|
||||
.weather-page {}
|
||||
|
||||
.section_invisible {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ahrs_connected {
|
||||
content:
|
||||
.text-normal {
|
||||
font-weight:100;
|
||||
}
|
||||
|
||||
.ahrs_disconnected {}
|
||||
.reset-flow {
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.separator {
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
margin-bottom: 4px;
|
||||
margin: 0 2px 4px 2px;
|
||||
}
|
||||
|
||||
.label_adj {
|
||||
|
@ -24,13 +30,13 @@
|
|||
}
|
||||
|
||||
.col-padding-shift-right {
|
||||
margin-left: -12px;
|
||||
margin-right: 12px;
|
||||
margin-left: -10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.col-padding-shift-left {
|
||||
margin-left: 12px;
|
||||
margin-right: -12px;
|
||||
margin-left: 10px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
|
@ -47,10 +53,65 @@
|
|||
}
|
||||
|
||||
.list-simple {
|
||||
padding-left: 12px;
|
||||
list-style: none;
|
||||
padding-left: 12px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.fa-ascent:before {
|
||||
content: "\f176";
|
||||
}
|
||||
|
||||
.fa-descent:before {
|
||||
content: "\f175";
|
||||
}
|
||||
|
||||
.fa-ascent,
|
||||
.fa-descent,
|
||||
.fa-airplane-solid,
|
||||
.fa-airplane-hollow {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.fa-ascent,
|
||||
.fa-descent {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.fa-airplane-solid:before {
|
||||
content: "\f1d8";
|
||||
}
|
||||
|
||||
.fa-airplane-hollow:before {
|
||||
content: "\f1d9";
|
||||
}
|
||||
|
||||
.traffic-style1 {
|
||||
color: #000000;
|
||||
background-color: cornflowerblue;
|
||||
}
|
||||
|
||||
.traffic-style2 {
|
||||
color: #000000;
|
||||
background-color: darkkhaki
|
||||
}
|
||||
|
||||
.icon-red {
|
||||
color: crimson;
|
||||
}
|
||||
|
||||
.icon-green {
|
||||
color: forestgreen;
|
||||
}
|
||||
|
||||
.icon-blue {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.icon-yellow {
|
||||
color: darkgoldenrod;
|
||||
}
|
||||
|
||||
|
||||
/* ***************************************************************************
|
||||
everything below this comment represents tweeks to the mobile-angular-uis CSS
|
||||
*************************************************************************** */
|
||||
|
@ -125,11 +186,6 @@ input[type="number_format"] {
|
|||
text-align: end;
|
||||
}
|
||||
|
||||
.sidebar .scrollable-header,
|
||||
.panel-title {
|
||||
border-bottom: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
.app-body,
|
||||
.panel-default,
|
||||
.scrollable-content,
|
||||
|
@ -146,6 +202,7 @@ input[type="number_format"] {
|
|||
line-height: 50px;
|
||||
color: #000;
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
|
@ -213,4 +270,24 @@ pre {
|
|||
background-color: inherit;
|
||||
border: 0px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
|
||||
/* change right sidebar behavior to always push */
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.sidebar-right-in .app {
|
||||
margin-right: 0;
|
||||
right: 0;
|
||||
}
|
||||
.sidebar-right-in .app {
|
||||
width: auto;
|
||||
-webkit-transform: translate3d(-300px, 0, 0)!important;
|
||||
-moz-transform: translate3d(-300px, 0, 0)!important;
|
||||
transform: translate3d(-300px, 0, 0)!important;
|
||||
position: relative;
|
||||
-webkit-transition: -webkit-transform 0 ease;
|
||||
-moz-transition: -moz-transform 0 ease;
|
||||
transition: transform 0 ease;
|
||||
}
|
||||
}
|
|
@ -12,20 +12,24 @@ function SettingsCtrl($rootScope, $scope, $state, $http) {
|
|||
settings[toggles[i]] = undefined;
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
// Simple GET request example (note: responce is asynchronous)
|
||||
$http.get(URL_SETTINGS_GET).
|
||||
then(function (response) {
|
||||
//process
|
||||
$scope.rawSettings = response.data; // angular.toJson(response.data, true);
|
||||
settings = angular.fromJson(response.data);
|
||||
$scope.UAT_Enabled = settings.UAT_Enabled;
|
||||
function loadSettings(data) {
|
||||
settings = angular.fromJson(data);
|
||||
$scope.rawSettings = angular.toJson(data, true);
|
||||
$scope.UAT_Enabled = settings.UAT_Enabled;
|
||||
$scope.ES_Enabled = settings.ES_Enabled;
|
||||
$scope.GPS_Enabled = settings.GPS_Enabled;
|
||||
$scope.AHRS_Enabled = settings.AHRS_Enabled;
|
||||
$scope.DEBUG = settings.DEBUG;
|
||||
$scope.ReplayLog = settings.ReplayLog;
|
||||
$scope.PPM = settings.PPM;
|
||||
$scope.WatchList = settings.WatchList;
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
// Simple GET request example (note: responce is asynchronous)
|
||||
$http.get(URL_SETTINGS_GET).
|
||||
then(function (response) {
|
||||
loadSettings (response.data);
|
||||
// $scope.$apply();
|
||||
}, function (response) {
|
||||
$scope.rawSettings = "error getting settings";
|
||||
|
@ -40,16 +44,7 @@ function SettingsCtrl($rootScope, $scope, $state, $http) {
|
|||
// Simple POST request example (note: responce is asynchronous)
|
||||
$http.post(URL_SETTINGS_SET, msg).
|
||||
then(function (response) {
|
||||
//process
|
||||
$scope.rawSettings = response.data; // angular.toJson(response.data, true);
|
||||
settings = angular.fromJson(response.data);
|
||||
$scope.UAT_Enabled = settings.UAT_Enabled;
|
||||
$scope.ES_Enabled = settings.ES_Enabled;
|
||||
$scope.GPS_Enabled = settings.GPS_Enabled;
|
||||
$scope.AHRS_Enabled = settings.AHRS_Enabled;
|
||||
$scope.DEBUG = settings.DEBUG;
|
||||
$scope.ReplayLog = settings.ReplayLog;
|
||||
$scope.PPM = settings.PPM;
|
||||
loadSettings (response.data);
|
||||
// $scope.$apply();
|
||||
}, function (response) {
|
||||
$scope.rawSettings = "error setting settings";
|
||||
|
@ -80,7 +75,17 @@ function SettingsCtrl($rootScope, $scope, $state, $http) {
|
|||
}
|
||||
});
|
||||
|
||||
$scope.updateppm = function() {
|
||||
$scope.updatewatchlist = function() {
|
||||
if (($scope.WatchList !== undefined) && ($scope.WatchList !== null) && $scope.WatchList !== settings["WatchList"]) {
|
||||
settings["WatchList"] = $scope.WatchList.toUpperCase();
|
||||
newsettings = {
|
||||
"WatchList": $scope.WatchList.toUpperCase()
|
||||
};
|
||||
console.log(angular.toJson(newsettings));
|
||||
setSettings(angular.toJson(newsettings));
|
||||
}
|
||||
};
|
||||
$scope.updateppm = function() {
|
||||
if (($scope.PPM !== undefined) && ($scope.PPM !== null) && $scope.PPM !== settings["PPM"]) {
|
||||
settings["PPM"] = parseInt($scope.PPM);
|
||||
newsettings = {
|
||||
|
|
|
@ -4,103 +4,105 @@ StatusCtrl.$inject = ['$rootScope', '$scope', '$state', '$http']; // Inject my d
|
|||
// create our controller function with all necessary logic
|
||||
function StatusCtrl($rootScope, $scope, $state, $http) {
|
||||
|
||||
$scope.$parent.helppage = 'plates/status-help.html';
|
||||
$scope.$parent.helppage = 'plates/status-help.html';
|
||||
|
||||
function connect($scope) {
|
||||
if (($scope === undefined) || ($scope === null))
|
||||
return; // we are getting called once after clicking away from the status page
|
||||
function connect($scope) {
|
||||
if (($scope === undefined) || ($scope === null))
|
||||
return; // we are getting called once after clicking away from the status page
|
||||
|
||||
if (($scope.socket === undefined) || ($scope.socket === null)) {
|
||||
socket = new WebSocket('ws://' + URL_HOST_BASE + '/status');
|
||||
$scope.socket = socket; // store socket in scope for enter/exit usage
|
||||
}
|
||||
if (($scope.socket === undefined) || ($scope.socket === null)) {
|
||||
socket = new WebSocket('ws://' + URL_HOST_BASE + '/status');
|
||||
$scope.socket = socket; // store socket in scope for enter/exit usage
|
||||
}
|
||||
|
||||
$scope.ConnectState = "Disconnected";
|
||||
$scope.ConnectState = "Disconnected";
|
||||
|
||||
socket.onopen = function (msg) {
|
||||
$scope.ConnectStyle = "label-success";
|
||||
$scope.ConnectState = "Connected";
|
||||
};
|
||||
socket.onopen = function (msg) {
|
||||
// $scope.ConnectStyle = "label-success";
|
||||
$scope.ConnectState = "Connected";
|
||||
};
|
||||
|
||||
socket.onclose = function (msg) {
|
||||
$scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Closed";
|
||||
setTimeout(connect, 1000);
|
||||
};
|
||||
socket.onclose = function (msg) {
|
||||
// $scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Closed";
|
||||
$scope.$apply();
|
||||
setTimeout(connect, 1000);
|
||||
};
|
||||
|
||||
socket.onerror = function (msg) {
|
||||
$scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Error";
|
||||
};
|
||||
socket.onerror = function (msg) {
|
||||
// $scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Error";
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
socket.onmessage = function (msg) {
|
||||
console.log('Received status update.')
|
||||
socket.onmessage = function (msg) {
|
||||
console.log('Received status update.')
|
||||
|
||||
var status = JSON.parse(msg.data)
|
||||
// Update Status
|
||||
$scope.Version = status.Version;
|
||||
$scope.Devices = status.Devices;
|
||||
$scope.Connected_Users = status.Connected_Users;
|
||||
$scope.UAT_messages_last_minute = status.UAT_messages_last_minute;
|
||||
// $scope.UAT_products_last_minute = JSON.stringify(status.UAT_products_last_minute);
|
||||
$scope.UAT_messages_max = status.UAT_messages_max;
|
||||
$scope.ES_messages_last_minute = status.ES_messages_last_minute;
|
||||
$scope.ES_messages_max = status.ES_messages_max;
|
||||
$scope.GPS_satellites_locked = status.GPS_satellites_locked;
|
||||
$scope.RY835AI_connected = status.RY835AI_connected;
|
||||
var status = JSON.parse(msg.data)
|
||||
// Update Status
|
||||
$scope.Version = status.Version;
|
||||
$scope.Devices = status.Devices;
|
||||
$scope.Connected_Users = status.Connected_Users;
|
||||
$scope.UAT_messages_last_minute = status.UAT_messages_last_minute;
|
||||
// $scope.UAT_products_last_minute = JSON.stringify(status.UAT_products_last_minute);
|
||||
$scope.UAT_messages_max = status.UAT_messages_max;
|
||||
$scope.ES_messages_last_minute = status.ES_messages_last_minute;
|
||||
$scope.ES_messages_max = status.ES_messages_max;
|
||||
$scope.GPS_satellites_locked = status.GPS_satellites_locked;
|
||||
$scope.RY835AI_connected = status.RY835AI_connected;
|
||||
|
||||
var uptime = status.Uptime;
|
||||
if (uptime != undefined) {
|
||||
var up_s = parseInt((uptime / 1000) % 60),
|
||||
up_m = parseInt((uptime / (1000 * 60)) % 60),
|
||||
up_h = parseInt((uptime / (1000 * 60 * 60)) % 24);
|
||||
$scope.Uptime = String(((up_h < 10) ? "0" + up_h : up_h) + "h" + ((up_m < 10) ? "0" + up_m : up_m) + "m" + ((up_s < 10) ? "0" + up_s : up_s) + "s");
|
||||
} else {
|
||||
// $('#Uptime').text('unavailable');
|
||||
}
|
||||
var boardtemp = status.CPUTemp;
|
||||
if (boardtemp != undefined) {
|
||||
/* boardtemp is celcius to tenths */
|
||||
$scope.CPUTemp = String(boardtemp.toFixed(1) + 'C / ' + ((boardtemp * 9 / 5) + 32.0).toFixed(1) + 'F');
|
||||
} else {
|
||||
// $('#CPUTemp').text('unavailable');
|
||||
}
|
||||
var uptime = status.Uptime;
|
||||
if (uptime != undefined) {
|
||||
var up_s = parseInt((uptime / 1000) % 60),
|
||||
up_m = parseInt((uptime / (1000 * 60)) % 60),
|
||||
up_h = parseInt((uptime / (1000 * 60 * 60)) % 24);
|
||||
$scope.Uptime = String(((up_h < 10) ? "0" + up_h : up_h) + "h" + ((up_m < 10) ? "0" + up_m : up_m) + "m" + ((up_s < 10) ? "0" + up_s : up_s) + "s");
|
||||
} else {
|
||||
// $('#Uptime').text('unavailable');
|
||||
}
|
||||
var boardtemp = status.CPUTemp;
|
||||
if (boardtemp != undefined) {
|
||||
/* boardtemp is celcius to tenths */
|
||||
$scope.CPUTemp = String(boardtemp.toFixed(1) + 'C / ' + ((boardtemp * 9 / 5) + 32.0).toFixed(1) + 'F');
|
||||
} else {
|
||||
// $('#CPUTemp').text('unavailable');
|
||||
}
|
||||
|
||||
$scope.$apply(); // trigger any needed refreshing of data
|
||||
};
|
||||
}
|
||||
$scope.$apply(); // trigger any needed refreshing of data
|
||||
};
|
||||
}
|
||||
|
||||
function setHardwareVisibility() {
|
||||
$scope.visible_uat = true;
|
||||
$scope.visible_es = true;
|
||||
$scope.visible_gps = true;
|
||||
$scope.visible_ahrs = true;
|
||||
function setHardwareVisibility() {
|
||||
$scope.visible_uat = true;
|
||||
$scope.visible_es = true;
|
||||
$scope.visible_gps = true;
|
||||
$scope.visible_ahrs = true;
|
||||
|
||||
// Simple GET request example (note: responce is asynchronous)
|
||||
$http.get(URL_SETTINGS_GET).
|
||||
then(function (response) {
|
||||
settings = angular.fromJson(response.data);
|
||||
$scope.visible_uat = settings.UAT_Enabled;
|
||||
$scope.visible_es = settings.ES_Enabled;
|
||||
$scope.visible_gps = settings.GPS_Enabled;
|
||||
$scope.visible_ahrs = settings.AHRS_Enabled;
|
||||
}, function (response) {
|
||||
// nop
|
||||
});
|
||||
};
|
||||
// Simple GET request example (note: responce is asynchronous)
|
||||
$http.get(URL_SETTINGS_GET).
|
||||
then(function (response) {
|
||||
settings = angular.fromJson(response.data);
|
||||
$scope.visible_uat = settings.UAT_Enabled;
|
||||
$scope.visible_es = settings.ES_Enabled;
|
||||
$scope.visible_gps = settings.GPS_Enabled;
|
||||
$scope.visible_ahrs = settings.AHRS_Enabled;
|
||||
}, function (response) {
|
||||
// nop
|
||||
});
|
||||
};
|
||||
|
||||
$state.get('home').onEnter = function () {
|
||||
// everything gets handled correctly by the controller
|
||||
};
|
||||
$state.get('home').onExit = function () {
|
||||
if (($scope.socket !== undefined) && ($scope.socket !== null)) {
|
||||
$scope.socket.close();
|
||||
$scope.socket = null;
|
||||
}
|
||||
};
|
||||
$state.get('home').onEnter = function () {
|
||||
// everything gets handled correctly by the controller
|
||||
};
|
||||
$state.get('home').onExit = function () {
|
||||
if (($scope.socket !== undefined) && ($scope.socket !== null)) {
|
||||
$scope.socket.close();
|
||||
$scope.socket = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Status Controller tasks
|
||||
setHardwareVisibility();
|
||||
connect($scope); // connect - opens a socket and listens for messages
|
||||
// Status Controller tasks
|
||||
setHardwareVisibility();
|
||||
connect($scope); // connect - opens a socket and listens for messages
|
||||
};
|
|
@ -5,7 +5,7 @@ TrafficCtrl.$inject = ['$rootScope', '$scope', '$state', '$http', '$interval'];
|
|||
function TrafficCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||
|
||||
$scope.$parent.helppage = 'plates/traffic-help.html';
|
||||
$scope.traffic = [];
|
||||
$scope.data_list = [];
|
||||
|
||||
function utcTimeString(epoc) {
|
||||
var time = "";
|
||||
|
@ -43,6 +43,7 @@ function TrafficCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
new_traffic.vspeed = Math.round(obj.Vvel / 100) * 100
|
||||
new_traffic.age = Date.parse(obj.Last_seen);
|
||||
new_traffic.time = utcTimeString(new_traffic.age);
|
||||
new_traffic.src = obj.Last_source; // 1=ES, 2=UAT
|
||||
// return new_aircraft;
|
||||
}
|
||||
|
||||
|
@ -58,40 +59,43 @@ function TrafficCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
$scope.ConnectState = "Not Receiving";
|
||||
|
||||
socket.onopen = function (msg) {
|
||||
$scope.ConnectStyle = "label-success";
|
||||
// $scope.ConnectStyle = "label-success";
|
||||
$scope.ConnectState = "Receiving";
|
||||
};
|
||||
|
||||
socket.onclose = function (msg) {
|
||||
$scope.ConnectStyle = "label-danger";
|
||||
// $scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Not Receiving";
|
||||
$scope.$apply();
|
||||
setTimeout(connect, 1000);
|
||||
};
|
||||
|
||||
socket.onerror = function (msg) {
|
||||
$scope.ConnectStyle = "label-danger";
|
||||
// $scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Problem";
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
socket.onmessage = function (msg) {
|
||||
console.log('Received traffic update.')
|
||||
|
||||
var aircraft = JSON.parse(msg.data);
|
||||
if (aircraft.Position_valid) {
|
||||
$scope.rawTraffic = msg.data;
|
||||
var message = JSON.parse(msg.data);
|
||||
$scope.raw_data = angular.toJson(msg.data, true);
|
||||
|
||||
if (message.Position_valid) {
|
||||
// we need to use an array so AngularJS can perform sorting; it also means we need to loop to find an aircraft in the traffic set
|
||||
var found = false;
|
||||
for (var i = 0, len = $scope.traffic.length; i < len; i++) {
|
||||
if ($scope.traffic[i].icao_int === aircraft.Icao_addr) {
|
||||
setAircraft(aircraft, $scope.traffic[i]);
|
||||
for (var i = 0, len = $scope.data_list.length; i < len; i++) {
|
||||
if ($scope.data_list[i].icao_int === message.Icao_addr) {
|
||||
setAircraft(message, $scope.data_list[i]);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
var new_traffic = {};
|
||||
setAircraft(aircraft, new_traffic);
|
||||
$scope.traffic.unshift(new_traffic); // add to start of array
|
||||
setAircraft(message, new_traffic);
|
||||
$scope.data_list.unshift(new_traffic); // add to start of array
|
||||
}
|
||||
$scope.$apply();
|
||||
}
|
||||
|
@ -104,13 +108,14 @@ function TrafficCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
var dirty = false;
|
||||
var cutoff = Date.now() - (180 * 1000);
|
||||
|
||||
for (var i = len = $scope.traffic.length; i > 0; i--) {
|
||||
if ($scope.traffic[i - 1].age < cutoff) {
|
||||
$scope.traffic.splice(i - 1, 1);
|
||||
for (var i = len = $scope.data_list.length; i > 0; i--) {
|
||||
if ($scope.data_list[i - 1].age < cutoff) {
|
||||
$scope.data_list.splice(i - 1, 1);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
if (dirty) {
|
||||
$scope.raw_data = "";
|
||||
$scope.$apply();
|
||||
}
|
||||
}, (1000 * 60), 0, false);
|
||||
|
|
|
@ -1,15 +1,179 @@
|
|||
angular.module('appControllers').controller('WeatherCtrl', WeatherCtrl); // get the main module contollers set
|
||||
WeatherCtrl.$inject = ['$rootScope', '$scope', '$state', '$http']; // Inject my dependencies
|
||||
WeatherCtrl.$inject = ['$rootScope', '$scope', '$state', '$http', '$interval']; // Inject my dependencies
|
||||
|
||||
// create our controller function with all necessary logic
|
||||
function WeatherCtrl($rootScope, $scope, $state, $http) {
|
||||
function WeatherCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||
|
||||
/*
|
||||
$state.get('weather').onEnter = function () {
|
||||
};
|
||||
$state.get('weather').onExit = function () {
|
||||
};
|
||||
*/
|
||||
var CONF_WATCHLIST = "KBOS KATL KORD KLAX"; // we default to 4 major airports
|
||||
var MAX_DATALIST = 10;
|
||||
|
||||
// Weather Controller tasks go here
|
||||
$scope.$parent.helppage = 'plates/weather-help.html';
|
||||
$scope.data_list = [];
|
||||
$scope.watch_list = [];
|
||||
|
||||
function updateWatchList() {
|
||||
$scope.watching = CONF_WATCHLIST;
|
||||
// Simple GET request example (note: responce is asynchronous)
|
||||
$http.get(URL_SETTINGS_GET).
|
||||
then(function (response) {
|
||||
settings = angular.fromJson(response.data);
|
||||
$scope.watching = settings.WatchList.toUpperCase();
|
||||
}, function (response) {
|
||||
// nop
|
||||
});
|
||||
};
|
||||
|
||||
function inList(word, sentence) {
|
||||
// since the watch list is just one long string, we cheat and see if the word in anywhere in the 'sentence'
|
||||
if ((sentence) && (word)) {
|
||||
return sentence.includes(word);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function utcTimeString(epoc) {
|
||||
var time = "";
|
||||
var val;
|
||||
var d = new Date(epoc);
|
||||
val = d.getUTCHours();
|
||||
time += (val < 10 ? "0" + val : "" + val);
|
||||
val = d.getUTCMinutes();
|
||||
time += ":" + (val < 10 ? "0" + val : "" + val);
|
||||
val = d.getUTCSeconds();
|
||||
time += ":" + (val < 10 ? "0" + val : "" + val);
|
||||
time += "Z";
|
||||
return time;
|
||||
}
|
||||
|
||||
function parseShortDatetime(sdt) {
|
||||
var d = new Date();
|
||||
var s = String(sdt);
|
||||
if (s.length < 7)
|
||||
return 0;
|
||||
d.setUTCDate(parseInt(s.substring(0, 2)));
|
||||
d.setUTCHours(parseInt(s.substring(2, 4)));
|
||||
d.setUTCMinutes(parseInt(s.substring(4, 6)));
|
||||
d.setUTCSeconds(0);
|
||||
d.setUTCMilliseconds(0);
|
||||
return d.getTime();
|
||||
}
|
||||
|
||||
function setDataItem(obj, data_item) {
|
||||
if (obj.Type === "TAF.AMD") {
|
||||
data_item.type = "TAF";
|
||||
data_item.update = true;
|
||||
} else {
|
||||
data_item.type = obj.Type;
|
||||
data_item.update = false;
|
||||
}
|
||||
data_item.location = obj.Location;
|
||||
data_item.age = parseShortDatetime(obj.Time);
|
||||
data_item.time = utcTimeString(data_item.age);
|
||||
data_item.received = utcTimeString(obj.LocaltimeReceived);
|
||||
data_item.data = obj.Data;
|
||||
}
|
||||
|
||||
function connect($scope) {
|
||||
if (($scope === undefined) || ($scope === null))
|
||||
return; // we are getting called once after clicking away from the status page
|
||||
|
||||
if (($scope.socket === undefined) || ($scope.socket === null)) {
|
||||
socket = new WebSocket('ws://' + URL_HOST_BASE + '/weather');
|
||||
$scope.socket = socket; // store socket in scope for enter/exit usage
|
||||
}
|
||||
|
||||
$scope.ConnectState = "Not Receiving";
|
||||
|
||||
socket.onopen = function (msg) {
|
||||
// $scope.ConnectStyle = "label-success";
|
||||
$scope.ConnectState = "Receiving";
|
||||
};
|
||||
|
||||
socket.onclose = function (msg) {
|
||||
// $scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Not Receiving";
|
||||
$scope.$apply();
|
||||
setTimeout(connect, 1000);
|
||||
};
|
||||
|
||||
socket.onerror = function (msg) {
|
||||
// $scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Problem";
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
socket.onmessage = function (msg) {
|
||||
console.log('Received data_list update.');
|
||||
|
||||
$scope.raw_data = angular.toJson(msg.data, true);
|
||||
var message = JSON.parse(msg.data);
|
||||
// we need to use an array so AngularJS can perform sorting; it also means we need to loop to find an aircraft in the data_list set
|
||||
var found = false;
|
||||
if (inList(message.Location, $scope.watching)) {
|
||||
for (var i = 0, len = $scope.watch_list.length; i < len; i++) {
|
||||
if (($scope.watch_list[i].type === message.Type) && ($scope.watch_list[i].location === message.Location)) {
|
||||
setDataItem(message, $scope.watch_list[i]);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
var new_data_item = {};
|
||||
setDataItem(message, new_data_item);
|
||||
$scope.watch_list.unshift(new_data_item); // add to start of array
|
||||
}
|
||||
}
|
||||
// add to scrolling data_list
|
||||
{
|
||||
var new_data_item = {};
|
||||
setDataItem(message, new_data_item);
|
||||
$scope.data_list.unshift(new_data_item); // add to start of array
|
||||
if ($scope.data_list.length > MAX_DATALIST)
|
||||
$scope.data_list.pop(); // remove last from array
|
||||
}
|
||||
$scope.data_count = $scope.data_list.length;
|
||||
$scope.watch_count = $scope.watch_list.length;
|
||||
$scope.$apply();
|
||||
};
|
||||
}
|
||||
|
||||
// perform cleanup every 5 minutes
|
||||
var clearStaleMessages = $interval(function () {
|
||||
// remove stail data = anything more than 30 minutes old
|
||||
var dirty = false;
|
||||
var cutoff = Date.now() - (30 * 60 * 1000);
|
||||
|
||||
for (var i = len = $scope.watch_list.length; i > 0; i--) {
|
||||
if ($scope.watch_list[i - 1].age < cutoff) {
|
||||
$scope.watch_list.splice(i - 1, 1);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
if (dirty) {
|
||||
$scope.raw_data = "";
|
||||
$scope.$apply();
|
||||
}
|
||||
}, (5 * 60 * 1000), 0, false);
|
||||
|
||||
|
||||
$state.get('weather').onEnter = function () {
|
||||
// everything gets handled correctly by the controller
|
||||
updateWatchList();
|
||||
};
|
||||
|
||||
$state.get('weather').onExit = function () {
|
||||
// disconnect from the socket
|
||||
if (($scope.socket !== undefined) && ($scope.socket !== null)) {
|
||||
$scope.socket.close();
|
||||
$scope.socket = null;
|
||||
}
|
||||
// stop stale message cleanup
|
||||
$interval.cancel(clearStaleMessages);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Weather Controller tasks
|
||||
updateWatchList();
|
||||
connect($scope); // connect - opens a socket and listens for messages
|
||||
};
|
|
@ -14,7 +14,7 @@
|
|||
<p>The <strong>Configuration</strong> section lets you adjust the default operation of your Stratux device.</p>
|
||||
<ul>
|
||||
<li>The SDR (software defined radio) receiver support error correction. From the Raspberry Pi, you may use the command <code>kal -g 48 -s GSM850</code> to scan for available channels in your area. Then use the command <code>kal -g 48 -c <em>channel#</em></code> to calculate the PPM. <div class="text-warning">NOTE: You will need to perform all commands as <code>root</code> by issuing the command: <code>sudo su -</code>. You will need to stop the Stratux software before running the calibration process. You can stop all of the Stratux processes with the command: <code>pkill screen</code>.</div></li>
|
||||
<li>The <strong>Weather</strong> page uses a user-defined <em>watch list</em> to filter the large volume of ADS-B weather messages for display. Define a list of identifiers (airport, VOR, etc) separated by a spaces. For example <code>KBOS EEN LAH LKP</code>. You may change this list at any time and the <strong>Weather</strong> page will start watching for the updated list immediately.</li>
|
||||
<li>Addiitonal settings will be added in future releases.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
|
@ -55,14 +55,20 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Configuration</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-8">PPM Correction</label>
|
||||
<div class="form-group reset-flow">
|
||||
<label class="control-label col-xs-5">PPM Correction</label>
|
||||
<form name="ppmForm" ng-submit="updateppm()" novalidate>
|
||||
<!-- type="number" not supported except on mobile -->
|
||||
<input class="col-xs-4" type="number_format" required ng-model="PPM" placeholder="integer" />
|
||||
<input class="col-xs-7" type="number_format" required ng-model="PPM" placeholder="integer" />
|
||||
</form>
|
||||
</div>
|
||||
<div class="form-group reset-flow">
|
||||
<label class="control-label col-xs-5">Watch List</label>
|
||||
<form name="ppmForm" ng-submit="updatewatchlist()" novalidate>
|
||||
<!-- type="number" not supported except on mobile -->
|
||||
<input class="col-xs-7" type="string" required ng-model="WatchList" placeholder="space delimeted identifiers" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="panel_label">Status</span> <span class="label" ng-class="ConnectStyle">{{ConnectState}}</span>
|
||||
<span class="panel_label">Status</span>
|
||||
<span ng-show="ConnectState == 'Connected'" class="label label-success">{{ConnectState}}</span>
|
||||
<span ng-hide="ConnectState == 'Connected'" class="label label-danger">{{ConnectState}}</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-horizontal">
|
||||
|
|
|
@ -2,12 +2,17 @@
|
|||
<p>The <strong>Traffic</strong> page provides a list of recent aircraft received. Each time a new aircraft is reported, it is added to the list. Each time a new report is received for an existing aircraft, the list is updated. If a report for an aircraft is not received for 3 minutes (180 seconds), the aircraft is removed from the list.</p>
|
||||
<p>For each aircraft, the list includes the following details:</p>
|
||||
<ul class="list-simple">
|
||||
<li><strong>Flight</strong> - either the aircraft tail number / ATC call sign or the ICAO number. When the ICAO number is used, it is displayed in grey.</li>
|
||||
<li><strong>Flight</strong> - either the aircraft tail number / ATC call sign or the ICAO number. When the ICAO number is used, it is displayed in grey.
|
||||
<ul class="list-simple">
|
||||
<li><span class="label traffic-style1">1090 ES</span> is displayed with a light blue background.</li>
|
||||
<li><span class="label traffic-style2">978 UAT</span> is displayed with a light tan background.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>Speed</strong> - current reported speed in knots</li>
|
||||
<li><strong>Altitude</strong> - current reported altitude and climb/decent rate if when not reporting level flight</li>
|
||||
<li><strong>Heading</strong> - direction of reported flight</li>
|
||||
<li><strong>Location</strong> - the latitude and longitude reported</li>
|
||||
<li><strong>Time</strong> - the last time (UTC) a report was received</li>
|
||||
</ul>
|
||||
<p class="text-warning">NOTE: When this page becomes active (aka it is selected from the menu) it will display any traffic received up to the last 3 minutes (180 seconds). Older traffic will not appear.</p>
|
||||
<p class="text-warning">NOTE: When this page becomes active (aka it is selected from the menu) it will display only new traffic. Older traffic and existing traffic will not appear until their next report.</p>
|
||||
</div>
|
|
@ -1,9 +1,11 @@
|
|||
<div class="col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="panel_label">Traffic</span> <span class="label" ng-class="ConnectStyle">{{ConnectState}}</span>
|
||||
<span class="panel_label">Traffic</span>
|
||||
<span ng-show="ConnectState == 'Receiving'" class="label label-success">{{ConnectState}}</span>
|
||||
<span ng-hide="ConnectState == 'Receiving'" class="label label-danger">{{ConnectState}}</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body traffic-page">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-3"><strong>Flight</strong></span>
|
||||
|
@ -17,17 +19,20 @@
|
|||
<span class="col-xs-3 text-right">Time</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-repeat="aircraft in traffic | orderBy: -age">
|
||||
<div class="separator"></div>
|
||||
|
||||
<div class="row" ng-repeat="aircraft in data_list | orderBy: -age">
|
||||
<div class="separator"></div>
|
||||
<div class="col-sm-6">
|
||||
<span ng-show="aircraft.tail" class="col-xs-3"><strong>{{aircraft.tail}}</strong></span>
|
||||
<span ng-hide="aircraft.tail" class="col-xs-3 text-muted"><strong>{{aircraft.icao}}</strong></span>
|
||||
|
||||
<span class="col-xs-3">
|
||||
<span ng-show="aircraft.tail" ng-class="'label traffic-style'+aircraft.src"><strong>{{aircraft.tail}}</strong></span>
|
||||
<span ng-hide="aircraft.tail" ng-class="'label traffic-style'+aircraft.src"><strong class="text-muted">{{aircraft.icao}}</strong></span>
|
||||
</span>
|
||||
|
||||
<span class="col-xs-3 text-right">{{aircraft.speed}}KTS</span>
|
||||
<span class="col-xs-3 text-right">{{aircraft.alt}}</span>
|
||||
<span class="col-xs-1 small col-padding-shift-right text-muted">
|
||||
<span ng-show="aircraft.vspeed">(<span ng-show="aircraft.vspeed > 0">+</span>{{aircraft.vspeed}})</span>
|
||||
<span ng-show="aircraft.vspeed > 0"><span class="fa fa-ascent"></span>{{aircraft.vspeed}}</span>
|
||||
<span ng-show="aircraft.vspeed < 0"><span class="fa fa-descent"></span>{{0-aircraft.vspeed}}</span>
|
||||
</span>
|
||||
<span class="col-xs-2 text-right"><span ng-show="aircraft.heading < 10">0</span><span ng-show="aircraft.heading < 100">0</span>{{aircraft.heading}}°</span>
|
||||
</div>
|
||||
|
@ -45,8 +50,8 @@
|
|||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Raw Traffic Data</div>
|
||||
<div class="panel-body">
|
||||
<pre>{{rawTraffic}}</pre>
|
||||
<pre>{{raw_data}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
-->
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<div class="section text-left help-page">
|
||||
<p>The <strong>Weather</strong> page provides a list of recent reports received.</p>
|
||||
<p>There are two lists available for reference:</p>
|
||||
<ul>
|
||||
<li><strong>Watch List</strong> contains all weather received for locations included in your watch list <span class="fa fa-asterisk icon-blue"></span></li>
|
||||
<li><strong>Recent Reports</strong> contains the most recent 10 reports received of any type for any location</li>
|
||||
</ul>
|
||||
<p><span class="fa fa-asterisk icon-blue"></span> The Watch List setting is found on the <strong>Settings</strong> page.</p>
|
||||
<p class="text-warning">NOTE: When this page becomes active (aka it is selected from the menu) it will display only new weather. Older weather and existing weather will not appear until their next report.</p>
|
||||
</div>
|
|
@ -1,13 +1,86 @@
|
|||
<div class="list-group text-center">
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<h2>ADSB Weather</h2>
|
||||
</div>
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<div>
|
||||
<i class="fa fa-cloud feature-icon text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
this space reserved to display weather data
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="panel_label">Weather</span>
|
||||
<span ng-show="ConnectState == 'Receiving'" class="label label-success">{{ConnectState}}</span>
|
||||
<span ng-hide="ConnectState == 'Receiving'" class="label label-danger">{{ConnectState}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-group" ui-state="weatherAccordion" ui-default="1">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" ui-set="{'weatherAccordion':1}">
|
||||
<div class="panel-title">Watching <span class="text-normal">{{watching}}</span> ({{watch_count}})</div>
|
||||
</div>
|
||||
<div ui-if="weatherAccordion == 1">
|
||||
<div class="panel-body weather-page">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-3"><strong>Location</strong></span>
|
||||
<span class="col-xs-3">Type</span>
|
||||
<span class="col-xs-6 text-right">Time</span>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-2"> </span>
|
||||
<span class="col-xs-10">Report</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" ng-repeat="weather in watch_list | orderBy: -age">
|
||||
<div class="separator"></div>
|
||||
<div class="col-sm-12">
|
||||
<span class="col-xs-3"><strong>{{weather.location}}</strong></span>
|
||||
<span class="col-xs-3">{{weather.type}}</span>
|
||||
<span class="col-xs-6 text-right">{{weather.time}}</span>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<span class="col-xs-10">{{weather.data}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" ui-set="{'weatherAccordion':2}">
|
||||
<div class="panel-title">Recent Reports ({{data_count}})</div>
|
||||
</div>
|
||||
<div ui-if="weatherAccordion == 2">
|
||||
<div class="panel-body weather-page">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-3"><strong>Location</strong></span>
|
||||
<span class="col-xs-3">Type</span>
|
||||
<span class="col-xs-6 text-right">Time</span>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-2"> </span>
|
||||
<span class="col-xs-10">Report</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-repeat="weather in data_list | orderBy: -age">
|
||||
<div class="separator"></div>
|
||||
<div class="col-sm-12">
|
||||
<span class="col-xs-3"><strong>{{weather.location}}</strong></span>
|
||||
<span class="col-xs-3">{{weather.type}}</span>
|
||||
<span class="col-xs-6 text-right">{{weather.time}}</span>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<span class="col-xs-10">{{weather.data}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Raw Weather Data</div>
|
||||
<div class="panel-body">
|
||||
<pre>{{raw_data}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
Ładowanie…
Reference in New Issue