From 29f55de46b80334f33bd698c41a861bc467541ab Mon Sep 17 00:00:00 2001 From: Jim Jacobsen Date: Wed, 16 Nov 2016 04:32:45 +0000 Subject: [PATCH 1/2] This code remembers the stations that were in the favorites when leaving and returning to the web page --- main/gen_gdl90.go | 47 +++++++++++++++- main/managementinterface.go | 31 +++++++++++ web/js/main.js | 1 + web/plates/js/weather.js | 105 +++++++++++++++++++++++++++++++++++- 4 files changed, 181 insertions(+), 3 deletions(-) mode change 100755 => 100644 main/gen_gdl90.go mode change 100755 => 100644 web/plates/js/weather.js diff --git a/main/gen_gdl90.go b/main/gen_gdl90.go old mode 100755 new mode 100644 index 6daedc977..1db611e33 --- a/main/gen_gdl90.go +++ b/main/gen_gdl90.go @@ -755,7 +755,8 @@ func registerADSBTextMessageReceived(msg string) { } var wm WeatherMessage - + var dataStr string + if (x[0] == "METAR") || (x[0] == "SPECI") { globalStatus.UAT_METAR_total++ } @@ -773,12 +774,46 @@ func registerADSBTextMessageReceived(msg string) { wm.Location = x[1] wm.Time = x[2] wm.Data = strings.Join(x[3:], " ") + dataStr = wm.Data wm.LocaltimeReceived = stratuxClock.Time wmJSON, _ := json.Marshal(&wm) // Send to weatherUpdate channel for any connected clients. weatherUpdate.Send(wmJSON) + var wxType string + wxType = x[0] + if wxType == "SPECI" { + wxType = "METAR" + } + if wxType == "TAF.AMD" { + wxType = "TAF" + } + // Update the watch list here + // We look to see if the name is in the list, and if not, we exit + if strings.Contains(globalSettings.WatchList,x[1]) { + // If the list is empty, add this report and return + for wx := range WatchedStations { + // log.Printf("wsplit[1] %s x[1] %s\n",wsplit[1],x[1]) + // If the station ID and type match, then overwrite the string + if WatchedStations[wx].MsgType == wxType && WatchedStations[wx].Location == x[1] { + log.Printf("Updated position %d, station %s to %s\n",wx,x[1],msg) + WatchedStations[wx].Time = x[2] + WatchedStations[wx].Data = dataStr +// weatherWatchedUpdate.SendJSON(WatchedStations) + return + } + } + // The type is not in the list, so lets add the string and return + log.Printf("add %s %s to the list, size is %d\n",x[0],x[1],len(WatchedStations)) + var thisWatch watchedStationType + thisWatch.MsgType=wxType + thisWatch.Location=x[1] + thisWatch.Time=x[2] + thisWatch.Data = dataStr + WatchedStations = append(WatchedStations, thisWatch) +// weatherWatchedUpdate.SendJSON(WatchedStations) + } } func UpdateUATStats(ProductID uint32) { @@ -1039,8 +1074,16 @@ type status struct { Errors []string } +type watchedStationType struct { + MsgType string + Location string + Time string + Data string +} + var globalSettings settings var globalStatus status +var WatchedStations []watchedStationType func defaultSettings() { globalSettings.UAT_Enabled = true @@ -1255,6 +1298,8 @@ func main() { globalStatus.Version = stratuxVersion globalStatus.Build = stratuxBuild globalStatus.Errors = make([]string, 0) + WatchedStations = make([]watchedStationType,0) + //FlightBox: detect via presence of /etc/FlightBox file. if _, err := os.Stat("/etc/FlightBox"); !os.IsNotExist(err) { globalStatus.HardwareBuild = "FlightBox" diff --git a/main/managementinterface.go b/main/managementinterface.go index 290a10b33..427fefcd5 100644 --- a/main/managementinterface.go +++ b/main/managementinterface.go @@ -33,9 +33,33 @@ type SettingMessage struct { } // Weather updates channel. +var weatherWatchedUpdate *uibroadcaster var weatherUpdate *uibroadcaster var trafficUpdate *uibroadcaster +// Situation updates channel. +var situationUpdate *uibroadcaster + +// Raw weather (UATFrame packet stream) update channel. +var weatherRawUpdate *uibroadcaster + +func handleWeatherUpdateWS(conn *websocket.Conn) { + + timer := time.NewTicker(5 * time.Second) +// weatherWatchedUpdate.AddSocket(conn) + // Connection closes when function returns. Since uibroadcast is writing and we don't need to read anything (for now), just keep it busy. + for { + update, _ := json.Marshal(&WatchedStations) + _, err := conn.Write(update) + + if err != nil { + log.Printf("watched weather client disconnected.\n") + break + } + <-timer.C + } +} + /* The /weather websocket starts off by sending the current buffer of weather messages, then sends updates as they are received. */ @@ -482,6 +506,7 @@ func viewLogs(w http.ResponseWriter, r *http.Request) { func managementInterface() { weatherUpdate = NewUIBroadcaster() trafficUpdate = NewUIBroadcaster() + weatherWatchedUpdate = NewUIBroadcaster() http.HandleFunc("/", defaultServer) http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log")))) @@ -505,6 +530,12 @@ func managementInterface() { Handler: websocket.Handler(handleWeatherWS)} s.ServeHTTP(w, req) }) + http.HandleFunc("/weatherwatched", + func(w http.ResponseWriter, req *http.Request) { + s := websocket.Server{ + Handler: websocket.Handler(handleWeatherUpdateWS)} + s.ServeHTTP(w, req) + }) http.HandleFunc("/traffic", func(w http.ResponseWriter, req *http.Request) { s := websocket.Server{ diff --git a/web/js/main.js b/web/js/main.js index fdfbbb025..9c46e1941 100644 --- a/web/js/main.js +++ b/web/js/main.js @@ -9,6 +9,7 @@ var URL_SATELLITES_GET = "http://" + URL_HOST_BASE + "/getSatellites" var URL_STATUS_WS = "ws://" + URL_HOST_BASE + "/status" var URL_TRAFFIC_WS = "ws://" + URL_HOST_BASE + "/traffic"; var URL_WEATHER_WS = "ws://" + URL_HOST_BASE + "/weather"; +var URL_WEATHER_WATCH_WS = "ws://" + URL_HOST_BASE + "/weatherwatched"; var URL_DEVELOPER_GET = "ws://" + URL_HOST_BASE + "/developer"; var URL_UPDATE_UPLOAD = "http://" + URL_HOST_BASE + "/updateUpload"; var URL_REBOOT = "http://" + URL_HOST_BASE + "/reboot"; diff --git a/web/plates/js/weather.js b/web/plates/js/weather.js old mode 100755 new mode 100644 index 1ca6e220b..bb75ad56b --- a/web/plates/js/weather.js +++ b/web/plates/js/weather.js @@ -145,6 +145,37 @@ function WeatherCtrl($rootScope, $scope, $state, $http, $interval) { data_item.data = obj.Data; } + function setDataItemWatched(wx, data_item) { + + var dataString = ""; + var i; + + i=0; + c=0; + data_item.type = wx.MsgType; + data_item.update = false; + + data_item.flight_condition = parseFlightCondition(wx.MsgType, wx.Data); + data_item.location = wx.Location; + + var dNow = new Date(); + var dThen = parseShortDatetime(wx.Time); + data_item.age = dThen.getTime(); + data_item.time = deltaTimeString(dNow - dThen) + " old"; + data_item.data = wx.Data; + } + + function setDataItemTest(Data, data_item) { + var msgSplit = Data.split(" "); + data_item.type = msgSplit[0]; + data_item.update = true; + data_item.flight_condition = "VFR"; + data_item.location=msgSplit[1]; + var dNow = new Date(); + data_item.age = dNow.getTime(); + data_item.data = Data; + } + function connect($scope) { if (($scope === undefined) || ($scope === null)) return; // we are getting called once after clicking away from the status page @@ -181,6 +212,7 @@ function WeatherCtrl($rootScope, $scope, $state, $http, $interval) { 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)) { @@ -195,6 +227,7 @@ function WeatherCtrl($rootScope, $scope, $state, $http, $interval) { $scope.watch_list.unshift(new_data_item); // add to start of array } } + */ // add to scrolling data_list { var new_data_item = {}; @@ -204,10 +237,73 @@ function WeatherCtrl($rootScope, $scope, $state, $http, $interval) { $scope.data_list.pop(); // remove last from array } $scope.data_count = $scope.data_list.length; - $scope.watch_count = $scope.watch_list.length; $scope.$apply(); }; - } + }; + + function connectWatched($scope) { + + if (($scope === undefined) || ($scope === null)) + return; // we are getting called once after clicking away from the status page + + if (($scope.socketWatched === undefined) || ($scope.socketWatched === null)) { + socketWatched = new WebSocket(URL_WEATHER_WATCH_WS); + $scope.socketWatched = socketWatched; // store status socket in scope for enter/exit usage + } + + $scope.ConnectStateStatus = "Disconnected"; + + socketWatched.onopen = function (msg) { + // $scope.ConnectStyle = "label-success"; + $scope.ConnectStateStatus = "Connected"; + }; + + socketWatched.onclose = function (msg) { + // $scope.ConnectStyle = "label-danger"; + $scope.ConnectStateStatus = "Disconnected"; + $scope.$apply(); + setTimeout(connectWatched, 1000); + }; + + socketWatched.onerror = function (msg) { + // $scope.ConnectStyle = "label-danger"; + $scope.ConnectStateStatus = "Problem"; + $scope.$apply(); + }; + + socketWatched.onmessage = function (msg) { + console.log('Received watched weather update.'); + + $scope.raw_data = angular.toJson(msg.data, true); + var watched = JSON.parse(msg.data) + // Update Status + // Copy watched stations + console.log(watched); + console.log(watched[0]); + for (var j = 0; j < watched.length; j++) + { + found = false; + + for (var i = 0; i < $scope.watch_list.length; i++) { + if ((found === false) && ($scope.watch_list[i].type === watched[j].MsgType) && ($scope.watch_list[i].location === watched[j].Location)) { + setDataItemWatched(watched[j], $scope.watch_list[i]); + found = true; + } + } + + if (!found) { + var new_data_item = {}; + setDataItemWatched(watched[j], new_data_item); + $scope.watch_list.unshift(new_data_item); // add to start of array + } + } + + $scope.watch_count = $scope.watch_list.length; + $scope.$apply(); // trigger any needed refreshing of data + + }; + + } // perform cleanup every 5 minutes var clearStaleMessages = $interval(function () { @@ -239,6 +335,10 @@ function WeatherCtrl($rootScope, $scope, $state, $http, $interval) { $scope.socket.close(); $scope.socket = null; } + if (($scope.socketWatched !== undefined) && ($scope.socketWatched !== null)) { + $scope.socketWatched.close(); + $scope.socketWatched = null; + } // stop stale message cleanup $interval.cancel(clearStaleMessages); }; @@ -248,4 +348,5 @@ function WeatherCtrl($rootScope, $scope, $state, $http, $interval) { // Weather Controller tasks updateWatchList(); connect($scope); // connect - opens a socket and listens for messages + connectWatched($scope); }; \ No newline at end of file From ab72887c6c173a423938e1bd34c7c5a1191b6ba8 Mon Sep 17 00:00:00 2001 From: Jim Jacobsen Date: Wed, 16 Nov 2016 04:34:02 +0000 Subject: [PATCH 2/2] Fixed formatting --- main/gen_gdl90.go | 84 ++++++++++++++++++------------------- main/managementinterface.go | 8 ++-- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/main/gen_gdl90.go b/main/gen_gdl90.go index 1db611e33..aae796a9d 100644 --- a/main/gen_gdl90.go +++ b/main/gen_gdl90.go @@ -755,8 +755,8 @@ func registerADSBTextMessageReceived(msg string) { } var wm WeatherMessage - var dataStr string - + var dataStr string + if (x[0] == "METAR") || (x[0] == "SPECI") { globalStatus.UAT_METAR_total++ } @@ -774,46 +774,46 @@ func registerADSBTextMessageReceived(msg string) { wm.Location = x[1] wm.Time = x[2] wm.Data = strings.Join(x[3:], " ") - dataStr = wm.Data + dataStr = wm.Data wm.LocaltimeReceived = stratuxClock.Time wmJSON, _ := json.Marshal(&wm) // Send to weatherUpdate channel for any connected clients. weatherUpdate.Send(wmJSON) - var wxType string - wxType = x[0] - if wxType == "SPECI" { - wxType = "METAR" - } - if wxType == "TAF.AMD" { - wxType = "TAF" - } - // Update the watch list here - // We look to see if the name is in the list, and if not, we exit - if strings.Contains(globalSettings.WatchList,x[1]) { - // If the list is empty, add this report and return - for wx := range WatchedStations { - // log.Printf("wsplit[1] %s x[1] %s\n",wsplit[1],x[1]) - // If the station ID and type match, then overwrite the string - if WatchedStations[wx].MsgType == wxType && WatchedStations[wx].Location == x[1] { - log.Printf("Updated position %d, station %s to %s\n",wx,x[1],msg) - WatchedStations[wx].Time = x[2] - WatchedStations[wx].Data = dataStr -// weatherWatchedUpdate.SendJSON(WatchedStations) - return - } - } - // The type is not in the list, so lets add the string and return - log.Printf("add %s %s to the list, size is %d\n",x[0],x[1],len(WatchedStations)) - var thisWatch watchedStationType - thisWatch.MsgType=wxType - thisWatch.Location=x[1] - thisWatch.Time=x[2] - thisWatch.Data = dataStr - WatchedStations = append(WatchedStations, thisWatch) -// weatherWatchedUpdate.SendJSON(WatchedStations) - } + var wxType string + wxType = x[0] + if wxType == "SPECI" { + wxType = "METAR" + } + if wxType == "TAF.AMD" { + wxType = "TAF" + } + // Update the watch list here + // We look to see if the name is in the list, and if not, we exit + if strings.Contains(globalSettings.WatchList, x[1]) { + // If the list is empty, add this report and return + for wx := range WatchedStations { + // log.Printf("wsplit[1] %s x[1] %s\n",wsplit[1],x[1]) + // If the station ID and type match, then overwrite the string + if WatchedStations[wx].MsgType == wxType && WatchedStations[wx].Location == x[1] { + log.Printf("Updated position %d, station %s to %s\n", wx, x[1], msg) + WatchedStations[wx].Time = x[2] + WatchedStations[wx].Data = dataStr + // weatherWatchedUpdate.SendJSON(WatchedStations) + return + } + } + // The type is not in the list, so lets add the string and return + log.Printf("add %s %s to the list, size is %d\n", x[0], x[1], len(WatchedStations)) + var thisWatch watchedStationType + thisWatch.MsgType = wxType + thisWatch.Location = x[1] + thisWatch.Time = x[2] + thisWatch.Data = dataStr + WatchedStations = append(WatchedStations, thisWatch) + // weatherWatchedUpdate.SendJSON(WatchedStations) + } } func UpdateUATStats(ProductID uint32) { @@ -1075,10 +1075,10 @@ type status struct { } type watchedStationType struct { - MsgType string - Location string - Time string - Data string + MsgType string + Location string + Time string + Data string } var globalSettings settings @@ -1298,8 +1298,8 @@ func main() { globalStatus.Version = stratuxVersion globalStatus.Build = stratuxBuild globalStatus.Errors = make([]string, 0) - WatchedStations = make([]watchedStationType,0) - + WatchedStations = make([]watchedStationType, 0) + //FlightBox: detect via presence of /etc/FlightBox file. if _, err := os.Stat("/etc/FlightBox"); !os.IsNotExist(err) { globalStatus.HardwareBuild = "FlightBox" diff --git a/main/managementinterface.go b/main/managementinterface.go index 427fefcd5..6455a216b 100644 --- a/main/managementinterface.go +++ b/main/managementinterface.go @@ -44,16 +44,16 @@ var situationUpdate *uibroadcaster var weatherRawUpdate *uibroadcaster func handleWeatherUpdateWS(conn *websocket.Conn) { - + timer := time.NewTicker(5 * time.Second) -// weatherWatchedUpdate.AddSocket(conn) + // weatherWatchedUpdate.AddSocket(conn) // Connection closes when function returns. Since uibroadcast is writing and we don't need to read anything (for now), just keep it busy. for { update, _ := json.Marshal(&WatchedStations) _, err := conn.Write(update) if err != nil { - log.Printf("watched weather client disconnected.\n") + log.Printf("watched weather client disconnected.\n") break } <-timer.C @@ -506,7 +506,7 @@ func viewLogs(w http.ResponseWriter, r *http.Request) { func managementInterface() { weatherUpdate = NewUIBroadcaster() trafficUpdate = NewUIBroadcaster() - weatherWatchedUpdate = NewUIBroadcaster() + weatherWatchedUpdate = NewUIBroadcaster() http.HandleFunc("/", defaultServer) http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log"))))