UNPKG

signalk-provider-vor1415

Version:

This provider takes the VOR2014/2015 JSON stream and transforms it into Signal K vessel information

274 lines (220 loc) 6.2 kB
var debug = require('debug')('provider-vor1415') , Readable = require('stream').Readable , util = require('util') , _ = require('lodash') , request = require('request-promise') ; function Race(url, opts) { if(!(this instanceof Race)) { return new Race(opts); } if(!url) { throw new Error("Please provide JSON URL"); } this.url = url; this.options = opts || {}; if(!this.options.interval) { this.options.interval = (30 * 60) * 1000; // 30 minutes } if(!this.options.stream) { this.options.stream = {}; } this.options.stream.objectMode = true; Readable.call(this, this.options.stream); this._lastDownload = -1; this._lastData = null; this._codes = {}; this._vessels = {}; setInterval(this.__check.bind(this), 1000); } util.inherits(Race, Readable); module.exports = Race; Race.prototype._read = function(size) {}; Race.prototype.__check = function() { debug("Checking when we last downloaded a VOR update"); if(this._lastData !== null && this._lastDownload > 0 && (Date.now() - this._lastDownload) < this.options.interval) { debug("Data is (quite) recent, idling.\n"); return; } debug("Data is not recent, getting ready to download a new copy.\n"); this.__fetch(); }; Race.prototype.__fetch = function() { if(this._lastData === null) { this._lastData = {}; } this._lastDownload = Date.now(); request .get(this.url) .then(this.__handleData.bind(this)) .catch(this.__handleError.bind(this)) ; }; Race.prototype.__handleData = function(data) { if(_.isString(data)) { data = JSON.parse(data); } if(!_.isEqual(this._lastData, data)) { this._lastData = data; this.__reduce(); } this._lastDownload = Date.now(); }; Race.prototype.__handleError = function(err) { debug("ERROR"); debug(err); }; Race.prototype.__reduce = function() { if(!this.__isValid()) { return; } var data = this._lastData; var fields = data.data.fields; var tracks = data.data.trackslatest; var self = this; _.each(data.codes, function(vessel) { self._codes[vessel.code.toUpperCase()] = { color: ('#' + vessel.color).toUpperCase(), name: vessel.name, uuid: 'VOR0' + vessel.code }; }); _.each(tracks, function(track) { var obj = {}; for(var i in fields) { obj[fields[i]] = track[i]; } obj.vessel = self._codes[obj.code.toUpperCase()]; obj.uuid = obj.vessel.uuid; self._vessels[obj.code] = obj; }) this.__generateDeltas(); }; Race.prototype.__generateUpdate = function(path, vessel, key, type) { type = type || 'string'; var val; switch(type) { case 'float': val = parseFloat(vessel[key]); break; default: val = String(vessel[key]); break; } if(typeof vessel[key] === "undefined") { if(type === 'float') { val = 0.0; } else { val = ""; } } if(val === null || typeof val === 'undefined' || val === "null" || val === "NULL") { if(type === 'float') { val = 0.0; } else { val = ""; } } return { path: path, value: val }; }; Race.prototype.__generateDeltas = function() { // return debug(JSON.stringify(this._vessels, null, 2)); /* "TBRU": { "code": "TBRU", "reportdate": "2014-12-11 12:55:00", "timeoffix": "2014-12-11 12:55:00", "status": "RAC", "latitude": "24.38333", "longitude": "58.14517", "dtf": "00321.50", "dtlc": "+00000", "legstanding": "1", "twentyfourhourrun": "515.0", "legprogress": 94, "dul": "00000.00", "boatheadingtrue": "315", "smg": "04.3", "seatemperature": 27.545454545455, "truwindspeedavg": "3", "speedthrowater": "6", "truewindspeedmax": "4", "truewinddirection": "42", "latestspeedthrowater": "4", "vessel": { "color": "#AED13F", "name": "Team Brunel", "uuid": "VOR-TBRU" }, "uuid": "VOR-TBRU" } */ var self = this; var legLength = parseFloat(this._lastData.leglength); _.each(this._vessels, function(vessel) { var delta = { context: 'vessels.' + vessel.uuid, updates: [] }; delta.updates.push({ path: 'name', value: vessel.vessel.name }); delta.updates.push({ path: 'uuid', value: vessel.uuid }); delta.updates.push({ path: 'navigation.state', value: self.__getStatus(vessel.status) }); if((legLength - parseFloat(vessel.dtf)) !== null) { delta.updates.push({ path: 'navigation.logTrip', value: legLength - parseFloat(vessel.dtf) }); } delta.updates.push(self.__generateUpdate('navigation.position.longitude', vessel, 'longitude', 'float')); delta.updates.push(self.__generateUpdate('navigation.position.latitude', vessel, 'longitude', 'float')); delta.updates.push(self.__generateUpdate('navigation.headingTrue', vessel, 'boatheadingtrue', 'float')); delta.updates.push(self.__generateUpdate('navigation.speedThroughWater', vessel, 'speedthrowater', 'float')); delta.updates.push(self.__generateUpdate('environment.wind.directionTrue', vessel, 'truewinddirection', 'float')); delta.updates.push(self.__generateUpdate('environment.wind.speedTrue', vessel, 'truewindspeedavg', 'float')); delta.updates.push(self.__generateUpdate('environment.waterTemp', vessel, 'seatemperature', 'float')); self.push(delta); }); }; Race.prototype.__getStatus = function(status) { status = status.toUpperCase(); if(status === "RAC") { return "Under way sailing"; } else if(status === "SUS") { return "Aground"; } else { return "Not defined"; } } Race.prototype.__isValid = function() { if(this._lastData === null) { return false; } if(!_.isObject(this._lastData.codes)) { return false; } if(!_.isObject(this._lastData.data)) { return false; } if(!_.isObject(this._lastData.data.fields)) { return false; } if(!_.isArray(this._lastData.data.fields)) { return false; } if(!_.isArray(this._lastData.data.trackslatest)) { return false; } return true; };