/****************************************************************************** * Web based vehicle tracker based on Freematics Hub * Developed by Stanley Huang https://www.facebook.com/stanleyhuangyc * Distributed under BSD license * Visit http://freematics.com/hub/api for Freematics Hub API reference * To obtain your Freematics Hub server key, contact support@freematics.com.au * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ******************************************************************************/ onResize(); $(function () { $(document).ready(function () { USER.load("DASH.load()"); self.setInterval(function () { if (DASH.curLocation && OSMAP.map) OSMAP.setCenter(DASH.curLocation); }, MAP_CENTERING_INTERVAL); /* var options = { enableHighAccuracy: true, timeout: 10000, maximumAge: 10000, }; navigator.geolocation.getCurrentPosition( function (pos) { if (!DASH.curLocation) OSMAP.setCenter([pos.coords.latitude, pos.coords.longitude]); }, null, options); */ }); }); if (window.require) { const shell = require('electron').shell; function openLink(url) { shell.openExternal(url); } } function onResize() { var height = window.innerHeight - document.getElementById("list").offsetHeight - 8; var width = window.innerWidth - document.getElementById("sidebar").offsetWidth - 2; //if (mapHeight < 300) mapHeight = 300; document.getElementById("container").style.height = height + "px"; document.getElementById("map").style.height = height * 2 / 3 + "px"; document.getElementById("map").style.width = width + "px"; document.getElementById("chart").style.height = height / 3 + "px"; document.getElementById("chart").style.width = width+ "px"; } var DASH = { xhr: new XMLHttpRequest(), dataSlideIndex: [0, 1], deviceID: null, curLocation: null, data: null, chart: null, chartPID: null, chartDataTick: 0, selectedPID: 269, lastDataCount: null, parked: null, selectPID: function (pid) { this.selectedPID = pid; }, setText: function(name, text) { document.getElementById("data_" + name).innerText = text; }, setClass: function (name, className) { document.getElementById("data_" + name).className = className; }, setHTML: function(name, html) { document.getElementById("data_" + name).innerHTML = html; }, setTempBar: function(name, temp) { if (temp < 0) temp = 0; if (temp > 80) temp = 80; var i = Math.floor((temp / 80) * 45) * 34; var img = document.getElementById("data_" + name); img.style.marginLeft = (-i) + "px"; img.title = temp + "C"; }, togglePID: function (num) { if (this.data.length > num) { if (++this.dataSlideIndex[num] >= this.data.length) this.dataSlideIndex[num] = 0; if (this.dataSlideIndex[num] == this.dataSlideIndex[1 - num]) { if (++this.dataSlideIndex[num] >= this.data.length) this.dataSlideIndex[num] = 0; } this.updatePID(num); } }, getPIDValue: function (pid) { for (var i = 0; i < this.data.length; i++) { if (this.data[i][0] == pid) { return PID.normalize(pid, this.data[i][1]); } } return null; }, updatePID: function(num) { var dataIndex = this.dataSlideIndex[num]; if (dataIndex < this.data.length) { var pid = this.data[dataIndex][0]; var value = this.data[dataIndex][1]; this.setText("pid_value" + num.toString(), PID.normalize(pid, value)); this.setText("pid_name" + num.toString(), PID.getNameUnit(pid)); } }, updateUserInfo: function (info, devid) { if (!USER.info) { document.getElementById("info").innerHTML = !devid ? "" : ("DEVICE: "); return; } var s = ""; document.getElementById("info").innerHTML = s; }, pickNewestData: function (data) { var index = [-1, -1]; var ts = 0; for (var i = 0; i < data.length; i++) { if (ts == 0 || data[i][2] < ts) { index[0] = i; ts = data[i][2]; } } ts = 0; for (var i = 0; i < data.length; i++) { if (i == index[0]) continue; if (ts == 0 || data[i][2] < ts) { index[1] = i; ts = data[i][2]; } } if (index[0] >= 0) this.dataSlideIndex[0] = index[0]; if (index[1] >= 0) this.dataSlideIndex[1] = index[1]; }, update: function (ch) { this.parked = ch.stats.parked || ch.stats.age.data > TRIP_END_TIMEOUT; if (this.parked) { this.setText("elapsed", getHHMM(Math.floor(ch.stats.age.data / 1000))); var offline = ch.stats.age.ping > DEVICE_OFFLINE_TIMEOUT; if (offline) { this.setText("state", "OFFLINE"); this.setClass("state", "state_offline"); } else { this.setText("state", "PARKED"); this.setClass("state", "state_parked"); } this.setText("rate", "-"); this.setText("delay", "-"); if (!offline) { this.pickNewestData(ch.data); } } else { this.setText("elapsed", getHHMMSS(ch.stats.elapsed)); this.setText("state", "RUNNING"); this.setClass("state", "state_running"); this.setText("rate", ch.stats.rate); this.setText("delay", ch.stats.age.data); this.setText("recv", Math.floor(ch.stats.recv / 1024)); } this.data = ch.live; var deviceTemp = this.getPIDValue(PID.DEVICE_TEMP); if (deviceTemp != null) { this.setTempBar("temp", deviceTemp); } this.updatePID(0); this.updatePID(1); // update data grid var s = "
"; if (this.deviceFlags && (this.deviceFlags & 0xf000) == 0x1000) { if (this.deviceFlags & 0x1) s += "[OBD]"; if (this.deviceFlags & (0x2 | 0x4)) s += "[GNSS]"; if (this.deviceFlags & 0x8) s += "[MEMS] "; s += "
"; } s += "Timestamp " + ch.stats.devtick; if (this.deviceRSSI) { s += "
RSSI " + this.deviceRSSI + "dBm"; } for (var n = 0; n < this.data.length; n++) { var pid = this.data[n][0]; var value = this.data[n][1]; s += "
" + PID.getName(pid) + " " + PID.normalize(pid, value); var unit = PID.getUnit(pid); if (unit) s += " " + unit + ""; } document.getElementById("grid").innerHTML = s; if (this.lastDataCount != this.data.length) { s = "
Chart Data
"; document.getElementById("tools").innerHTML = s; this.lastDataCount = this.data.length; this.selectedPID = parseInt(document.getElementById("chartPIDselect").value); } // update map var lat = this.getPIDValue(PID.GPS.LATITUDE); var lng = this.getPIDValue(PID.GPS.LONGITUDE); if (lat != null && lng != null && lat != 0 && lng != 0) { if (!OSMAP.map) OSMAP.init("map", lat, lng, 15); //if (devid) OSMAP.setTooltip(0, devid); if (!this.curLocation || this.curLocation[0] != lat || this.curLocation[1] != lng) { this.curLocation = [lat, lng]; OSMAP.setMarker(0, this.curLocation); OSMAP.setCenter(this.curLocation); } } }, load: function() { this.updateUserInfo(USER.info, USER.devid); this.lastDataCount = null; // load channel data this.xhr.onreadystatechange = function() { if (this.readyState != 4) return; if (this.status != 200) { if (this.status) { alert("Server under maintenance (status: " + this.status + ")"); } return; } var chdata = JSON.parse(this.responseText); if (chdata && chdata.id) { DASH.deviceID = chdata.devid; DASH.deviceFlags = chdata.flags; DASH.deviceRSSI = chdata.rssi; self.setTimeout("DASH.showChart()", 0); } else { alert("Not an active device. Please check if your device is working or the device ID is correct."); } }; var url = serverURL + "channels/" + USER.devid; this.xhr.open('GET', url, true); this.xhr.send(null); }, showChart: function() { var pid = this.selectedPID; this.xhr.onreadystatechange = function() { if (this.readyState != 4 || this.status != 200) { return; } var pull = JSON.parse(this.responseText); if (pull.error) { alert(pull.error); return; } var mydata = []; // load history data; var d = new Date(); var tm = d.getTime() - d.getTimezoneOffset() * 60000; var lastDataTick = pull.stats.devtick; for (var i = 0; i < pull.data.length; i++) { var value = pull.data[i][2]; var ts = pull.data[i][0]; mydata.push({ x: tm - (lastDataTick - ts), y: PID.toNumber(pid, value) }); } // create chart with loaded data var chart = CreateChart( "chart", PID.getName(pid), "#808080", PID.getUnit(pid), PID.getNameUnit(pid), 100, mydata); // start receiving chart.series[0].setVisible(true, true); DASH.chart = chart; DASH.chartPID = pid; DASH.chartDataTick = lastDataTick; DASH.update(pull); self.setTimeout("DASH.updateData()", DATA_FETCH_INTERVAL); //requestData(); }; this.chart = null; document.getElementById("chart").innerHTML = ""; var rollback = this.parked ? ROLLBACK_TIME_PARKED : ROLLBACK_TIME; this.xhr.open('GET', serverURL + "pull/" + this.deviceID + "?pid=" + pid + "&rollback=" + rollback, true); this.xhr.send(null); }, updateData: function() { this.xhr.onreadystatechange = function() { if (this.readyState != 4) return; if (this.status != 200) { if (this.status) { alert("Server under maintenance (status: " + this.status + ")"); } return; } var pull = JSON.parse(this.responseText); if (pull.data.length > 0) { var lastDataTick = pull.stats.devtick; var d = new Date(); var tm = d.getTime() - d.getTimezoneOffset() * 60000; for (var i = 0; i < pull.data.length; i++) { var ts = pull.data[i][0]; var pid = pull.data[i][1]; var value = pull.data[i][2]; var x = tm - (lastDataTick - ts); var y = PID.toNumber(pid, value); DASH.chart.series[0].addPoint([x, y], false, true); } DASH.chartDataTick = lastDataTick; DASH.chart.series[0].setVisible(true, true); } DASH.update(pull); self.setTimeout("DASH.updateData()", DATA_FETCH_INTERVAL); }; if (this.selectedPID != this.chartPID) { this.showChart(); return; } if (!this.chartPID || !this.chart) return; var url = serverURL + "pull/" + this.deviceID + "?pid=" + DASH.chartPID + "&ts=" + (this.chartDataTick + 1); this.xhr.open('GET', url, true); this.xhr.send(null); }, };