mirror of
https://github.com/nasa/openmct.git
synced 2025-06-17 22:58:14 +00:00
[Examples] #359 Cleaned up REMS data integration example.
This commit is contained in:
@ -28,6 +28,9 @@ define(
|
||||
* source and its data types. The data dictionary will be parsed by a custom
|
||||
* server provider for this data source (in this case
|
||||
* {@link RemsTelemetryServerAdapter}).
|
||||
*
|
||||
* Typically a data dictionary would be made available alongside the
|
||||
* telemetry data source itself.
|
||||
*/
|
||||
function () {
|
||||
return {
|
||||
|
@ -28,6 +28,18 @@ define(
|
||||
var TAXONOMY_ID = "msl:curiosity",
|
||||
PREFIX = "msl_tlm:";
|
||||
|
||||
/**
|
||||
* Function that is executed on application startup and populates
|
||||
* the navigation tree with objects representing the MSL REMS
|
||||
* telemetry points. The tree is populated based on the data
|
||||
* dictionary on the provider.
|
||||
*
|
||||
* @param {RemsTelemetryServerAdapter} adapter The server adapter
|
||||
* (necessary in order to retrieve data dictionary)
|
||||
* @param objectService the ObjectService which allows for lookup of
|
||||
* objects by ID
|
||||
* @constructor
|
||||
*/
|
||||
function RemsTelemetryInitializer(adapter, objectService) {
|
||||
function makeId(element) {
|
||||
return PREFIX + element.identifier;
|
||||
|
@ -27,43 +27,53 @@ define (
|
||||
|
||||
var SOURCE = "rems.source";
|
||||
|
||||
function RemsTelemetryProvider(adapter, $q){
|
||||
/*
|
||||
Filters requests for telemetry so that it only handles requests for
|
||||
this source
|
||||
*/
|
||||
function RemsTelemetryProvider(adapter, $q) {
|
||||
this.adapter = adapter;
|
||||
this.$q = $q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve telemetry from this telemetry source.
|
||||
* @memberOf example/msl
|
||||
* @param {Array<TelemetryRequest>} requests An array of all request
|
||||
* objects (which needs to be filtered to only those relevant to this
|
||||
* source)
|
||||
* @returns {Promise} A {@link Promise} resolved with a {@link RemsTelemetrySeries}
|
||||
* object that wraps the telemetry returned from the telemetry source.
|
||||
*/
|
||||
RemsTelemetryProvider.prototype.requestTelemetry = function (requests) {
|
||||
var packaged = {},
|
||||
relevantReqs = requests.filter(matchesSource),
|
||||
adapter = this.adapter;
|
||||
|
||||
function matchesSource(request) {
|
||||
return (request.source === SOURCE);
|
||||
}
|
||||
|
||||
return {
|
||||
requestTelemetry: function(requests) {
|
||||
var packaged = {},
|
||||
relevantReqs = requests.filter(matchesSource);
|
||||
|
||||
function addToPackage(history) {
|
||||
packaged[SOURCE][history.id] =
|
||||
new RemsTelemetrySeries(history.values);
|
||||
}
|
||||
|
||||
function handleRequest(request) {
|
||||
var key = request.key;
|
||||
return adapter.history(key).then(addToPackage);
|
||||
}
|
||||
packaged[SOURCE] = {};
|
||||
return $q.all(relevantReqs.map(handleRequest))
|
||||
.then(function () {
|
||||
return packaged;
|
||||
});
|
||||
},
|
||||
subscribe: function (callback, requests) {
|
||||
return function() {};
|
||||
},
|
||||
unsubscribe: function (callback, requests) {
|
||||
return function() {};
|
||||
}
|
||||
function addToPackage(history) {
|
||||
packaged[SOURCE][history.id] =
|
||||
new RemsTelemetrySeries(history.values);
|
||||
}
|
||||
|
||||
function handleRequest(request) {
|
||||
var key = request.key;
|
||||
return adapter.history(key).then(addToPackage);
|
||||
}
|
||||
packaged[SOURCE] = {};
|
||||
return this.$q.all(relevantReqs.map(handleRequest))
|
||||
.then(function () {
|
||||
return packaged;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This data source does not support real-time subscriptions
|
||||
*/
|
||||
RemsTelemetryProvider.prototype.subscribe = function (callback, requests) {
|
||||
return function() {};
|
||||
},
|
||||
RemsTelemetryProvider.prototype.unsubscribe = function (callback, requests) {
|
||||
return function() {};
|
||||
}
|
||||
|
||||
return RemsTelemetryProvider;
|
||||
|
@ -24,18 +24,59 @@ define(
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @typedef {Object} RemsTelemetryValue
|
||||
* @memberOf example/msl
|
||||
* @property {number} date The date/time of the telemetry value. Constitutes the domain value of this value pair
|
||||
* @property {number} value The value of this telemetry datum.
|
||||
* A floating point value representing some observable quantity (eg.
|
||||
* temperature, air pressure, etc.)
|
||||
*/
|
||||
|
||||
/**
|
||||
* A representation of a collection of telemetry data. The REMS
|
||||
* telemetry data is time ordered, with the 'domain' value
|
||||
* constituting the time stamp of each data value and the
|
||||
* 'range' being the value itself.
|
||||
*
|
||||
* TelemetrySeries will typically wrap an array of telemetry data,
|
||||
* and provide an interface for retrieving individual an telemetry
|
||||
* value.
|
||||
* @memberOf example/msl
|
||||
* @param {Array<RemsTelemetryValue>} data An array of telemetry values
|
||||
* @constructor
|
||||
*/
|
||||
function RemsTelemetrySeries(data) {
|
||||
return {
|
||||
getPointCount: function(){
|
||||
return data.length;
|
||||
},
|
||||
getDomainValue: function(index) {
|
||||
return data[index].date;
|
||||
},
|
||||
getRangeValue: function(index){
|
||||
return data[index].value;
|
||||
}
|
||||
}
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number} A count of the number of data values available in
|
||||
* this series
|
||||
*/
|
||||
RemsTelemetrySeries.prototype.getPointCount = function() {
|
||||
return this.data.length;
|
||||
};
|
||||
/**
|
||||
* The domain value at the given index. The Rems telemetry data is
|
||||
* time ordered, so the domain value is the time stamp of each data
|
||||
* value.
|
||||
* @param index
|
||||
* @returns {number} the time value in ms since 1 January 1970
|
||||
*/
|
||||
RemsTelemetrySeries.prototype.getDomainValue = function(index) {
|
||||
return this.data[index].date;
|
||||
};
|
||||
|
||||
/**
|
||||
* The range value of the REMS data set is the value of the thing
|
||||
* being measured, be it temperature, air pressure, etc.
|
||||
* @param index The datum in the data series to return the range
|
||||
* value of.
|
||||
* @returns {number} A floating point number
|
||||
*/
|
||||
RemsTelemetrySeries.prototype.getRangeValue = function(index) {
|
||||
return this.data[index].value;
|
||||
}
|
||||
|
||||
return RemsTelemetrySeries;
|
||||
|
@ -25,20 +25,20 @@ define(
|
||||
["./MSLDataDictionary"],
|
||||
function (MSLDataDictionary) {
|
||||
"use strict";
|
||||
|
||||
|
||||
var TERRESTRIAL_DATE = "terrestrial_date";
|
||||
|
||||
/**
|
||||
* Fetches historical data from the REMS instrument on the Curiosity
|
||||
* Rover. Exposes two services to client code, one
|
||||
* Rover.
|
||||
* @memberOf example/msl
|
||||
* @param $q
|
||||
* @param $http
|
||||
* @param REMS_WS_URL
|
||||
* @returns {{dictionary: exports, history: Function}}
|
||||
* @param REMS_WS_URL The location of the REMS telemetry data.
|
||||
* @constructor
|
||||
*/
|
||||
function RemsTelemetryServerAdapter($q, $http, REMS_WS_URL) {
|
||||
this.histories = {},
|
||||
this.historyData = {},
|
||||
this.deferreds = {};
|
||||
this.REMS_WS_URL = REMS_WS_URL;
|
||||
this.$q = $q;
|
||||
@ -46,48 +46,69 @@ define(
|
||||
}
|
||||
|
||||
/**
|
||||
* The data dictionary for this data source.
|
||||
* @type {MSLDataDictionary}
|
||||
*/
|
||||
RemsTelemetryServerAdapter.prototype.dictionary = MSLDataDictionary;
|
||||
|
||||
/**
|
||||
* Fetches historical data from source, and associates it with the
|
||||
* given request ID.
|
||||
* @private
|
||||
*/
|
||||
RemsTelemetryServerAdapter.prototype.requestHistory = function(id) {
|
||||
var self = this;
|
||||
|
||||
return this.$http.get(this.REMS_WS_URL).then(function(response){
|
||||
self.histories = {};
|
||||
/**
|
||||
* All history is fetched in one go, cache it all to save round trips to the server on subsequent requests
|
||||
/*
|
||||
* Refresh history data on each request so that it's always
|
||||
* current.
|
||||
*/
|
||||
self.historyData = {};
|
||||
/*
|
||||
* History data is organised by Sol. Iterate over sols...
|
||||
*/
|
||||
response.data.soles.forEach(function(solData){
|
||||
for (var prop in solData){
|
||||
self.histories[prop] = self.histories[prop] || [];
|
||||
/*
|
||||
* Each sol contains a number of properties for each
|
||||
* piece of data available, eg. min ground temperature,
|
||||
* avg air pressure, etc.
|
||||
*/
|
||||
Object.keys(solData).forEach(function (prop) {
|
||||
self.historyData[prop] = self.historyData[prop] || [];
|
||||
/*
|
||||
* Check that valid data exists
|
||||
*/
|
||||
if (!isNaN(solData[prop])) {
|
||||
self.histories[prop].unshift({
|
||||
/*
|
||||
* Append each data point to the array of values
|
||||
* for this data point property (min. temp, etc).
|
||||
*/
|
||||
self.historyData[prop].unshift({
|
||||
date: Date.parse(solData[TERRESTRIAL_DATE]),
|
||||
value: solData[prop]
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
self.deferreds[id].resolve({id: id, values: self.histories[id]});
|
||||
self.deferreds[id].resolve({id: id, values: self.historyData[id]});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {exports}
|
||||
*/
|
||||
RemsTelemetryServerAdapter.prototype.dictionary = MSLDataDictionary;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @returns {p.promise|{then, fail, end}|performPromise|deferred.promise|{}|*}
|
||||
* Requests historical telemetry for the named data attribute. In
|
||||
* the case of REMS, this data source exposes multiple different
|
||||
* data variables from the REMS instrument, including temperature
|
||||
* and others
|
||||
* @param id The telemetry data point key to be queried.
|
||||
* @returns {Promise | Array<RemsTelemetryValue>} that resolves with an Array of {@link RemsTelemetryValue} objects for the request data key.
|
||||
*/
|
||||
RemsTelemetryServerAdapter.prototype.history = function(id) {
|
||||
this.deferreds[id] = this.deferreds[id] || this.$q.defer();
|
||||
if (this.histories[id]) {
|
||||
this.deferreds[id].resolve({id: id, values: this.histories[id]});
|
||||
if (this.historyData[id]) {
|
||||
this.deferreds[id].resolve({id: id, values: this.historyData[id]});
|
||||
} else {
|
||||
this.histories = {};
|
||||
this.historyData = {};
|
||||
this.requestHistory(id);
|
||||
}
|
||||
return this.deferreds[id].promise;
|
||||
|
Reference in New Issue
Block a user