mirror of
https://github.com/nasa/openmct.git
synced 2025-06-06 01:11:41 +00:00
fix plots
This commit is contained in:
parent
a94c752616
commit
0113ec08db
@ -90,10 +90,12 @@ export default class TelemetryCollection extends EventEmitter {
|
|||||||
this._watchTimeSystem();
|
this._watchTimeSystem();
|
||||||
this._watchTimeModeChange();
|
this._watchTimeModeChange();
|
||||||
|
|
||||||
this._requestHistoricalTelemetry();
|
const historicalTelemetryLoadedPromise = this._requestHistoricalTelemetry();
|
||||||
this._initiateSubscriptionTelemetry();
|
this._initiateSubscriptionTelemetry();
|
||||||
|
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
|
|
||||||
|
return historicalTelemetryLoadedPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,6 +157,7 @@ export default class TelemetryCollection extends EventEmitter {
|
|||||||
options
|
options
|
||||||
);
|
);
|
||||||
historicalData = await historicalProvider.request(this.domainObject, modifiedOptions);
|
historicalData = await historicalProvider.request(this.domainObject, modifiedOptions);
|
||||||
|
console.debug('👴 Requesting historical telemetry data...', historicalData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.name !== 'AbortError') {
|
if (error.name !== 'AbortError') {
|
||||||
console.error('Error requesting telemetry data...');
|
console.error('Error requesting telemetry data...');
|
||||||
|
@ -6,20 +6,26 @@ export default class CompsManager extends EventEmitter {
|
|||||||
#composition;
|
#composition;
|
||||||
#telemetryObjects = {};
|
#telemetryObjects = {};
|
||||||
#telemetryCollections = {};
|
#telemetryCollections = {};
|
||||||
#managerLoadedPromise;
|
|
||||||
#dataFrame = {};
|
#dataFrame = {};
|
||||||
|
#batchedNewData = {};
|
||||||
|
#batchPromises = {};
|
||||||
|
#BATCH_DEBOUNCE_MS = 100;
|
||||||
|
#telemetryLoadedPromises = [];
|
||||||
|
|
||||||
constructor(openmct, domainObject) {
|
constructor(openmct, domainObject) {
|
||||||
super();
|
super();
|
||||||
this.#openmct = openmct;
|
this.#openmct = openmct;
|
||||||
this.#domainObject = domainObject;
|
this.#domainObject = domainObject;
|
||||||
|
|
||||||
// Load the composition
|
|
||||||
this.#managerLoadedPromise = this.#loadComposition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
load() {
|
async load() {
|
||||||
return this.#managerLoadedPromise;
|
await this.#loadComposition();
|
||||||
|
await Promise.all(this.#telemetryLoadedPromises);
|
||||||
|
this.#telemetryLoadedPromises = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getTelemetryObjects() {
|
||||||
|
return this.#telemetryObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #loadComposition() {
|
async #loadComposition() {
|
||||||
@ -28,6 +34,7 @@ export default class CompsManager extends EventEmitter {
|
|||||||
this.#composition.on('add', this.#addTelemetryObject);
|
this.#composition.on('add', this.#addTelemetryObject);
|
||||||
this.#composition.on('remove', this.#removeTelemetryObject);
|
this.#composition.on('remove', this.#removeTelemetryObject);
|
||||||
await this.#composition.load();
|
await this.#composition.load();
|
||||||
|
console.debug('📚 Composition loaded');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,9 +91,40 @@ export default class CompsManager extends EventEmitter {
|
|||||||
return underlyingTelemetry;
|
return underlyingTelemetry;
|
||||||
}
|
}
|
||||||
|
|
||||||
#telemetryProcessor = (newTelemetry, keyString) => {
|
#clearBatch(keyString) {
|
||||||
console.debug(`🎉 new data for ${keyString}!`, newTelemetry);
|
this.#batchedNewData[keyString] = [];
|
||||||
this.emit('underlyingTelemetryUpdated', { [keyString]: newTelemetry });
|
this.#batchPromises[keyString] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#deferredTelemetryProcessor(newTelemetry, keyString) {
|
||||||
|
// We until the next event loop cycle to "collect" all of the get
|
||||||
|
// requests triggered in this iteration of the event loop
|
||||||
|
|
||||||
|
if (!this.#batchedNewData[keyString]) {
|
||||||
|
this.#batchedNewData[keyString] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#batchedNewData[keyString].push(newTelemetry[0]);
|
||||||
|
|
||||||
|
if (!this.#batchPromises[keyString]) {
|
||||||
|
this.#batchPromises[keyString] = [];
|
||||||
|
|
||||||
|
this.#batchPromises[keyString] = this.#batchedTelemetryProcessor(
|
||||||
|
this.#batchedNewData[keyString],
|
||||||
|
keyString
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#batchedTelemetryProcessor = async (newTelemetry, keyString) => {
|
||||||
|
await this.#waitForDebounce();
|
||||||
|
|
||||||
|
const specificBatchedNewData = this.#batchedNewData[keyString];
|
||||||
|
|
||||||
|
// clear it
|
||||||
|
this.#clearBatch(keyString);
|
||||||
|
console.debug(`🎉 new data for ${keyString}!`, specificBatchedNewData);
|
||||||
|
this.emit('underlyingTelemetryUpdated', { [keyString]: specificBatchedNewData });
|
||||||
};
|
};
|
||||||
|
|
||||||
#clearData() {
|
#clearData() {
|
||||||
@ -94,21 +132,33 @@ export default class CompsManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getExpression() {
|
getExpression() {
|
||||||
return 'a * b ';
|
return 'a + b ';
|
||||||
}
|
}
|
||||||
|
|
||||||
#addTelemetryObject = async (telemetryObject) => {
|
#waitForDebounce() {
|
||||||
console.debug('📢 CompsManager: #addTelemetryObject', telemetryObject);
|
let timeoutID;
|
||||||
|
clearTimeout(timeoutID);
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
timeoutID = setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, this.#BATCH_DEBOUNCE_MS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#addTelemetryObject = (telemetryObject) => {
|
||||||
const keyString = this.#openmct.objects.makeKeyString(telemetryObject.identifier);
|
const keyString = this.#openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
this.#telemetryObjects[keyString] = telemetryObject;
|
this.#telemetryObjects[keyString] = telemetryObject;
|
||||||
this.#telemetryCollections[keyString] =
|
this.#telemetryCollections[keyString] =
|
||||||
this.#openmct.telemetry.requestCollection(telemetryObject);
|
this.#openmct.telemetry.requestCollection(telemetryObject);
|
||||||
|
|
||||||
this.#telemetryCollections[keyString].on('add', (data) => {
|
this.#telemetryCollections[keyString].on('add', (data) => {
|
||||||
this.#telemetryProcessor(data, keyString);
|
this.#deferredTelemetryProcessor(data, keyString);
|
||||||
});
|
});
|
||||||
this.#telemetryCollections[keyString].on('clear', this.#clearData);
|
this.#telemetryCollections[keyString].on('clear', this.#clearData);
|
||||||
await this.#telemetryCollections[keyString].load();
|
const telemetryLoadedPromise = this.#telemetryCollections[keyString].load();
|
||||||
|
this.#telemetryLoadedPromises.push(telemetryLoadedPromise);
|
||||||
|
console.debug('📢 CompsManager: loaded telemetry collection', keyString);
|
||||||
};
|
};
|
||||||
|
|
||||||
static getCompsManager(domainObject, openmct, compsManagerPool) {
|
static getCompsManager(domainObject, openmct, compsManagerPool) {
|
||||||
|
@ -51,21 +51,23 @@ export default class CompsTelemetryProvider {
|
|||||||
return this.#lastUniqueID++;
|
return this.#lastUniqueID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line require-await
|
request(domainObject, options) {
|
||||||
async request(domainObject, options) {
|
return new Promise((resolve, reject) => {
|
||||||
const specificCompsManager = CompsManager.getCompsManager(
|
const specificCompsManager = CompsManager.getCompsManager(
|
||||||
domainObject,
|
domainObject,
|
||||||
this.#openmct,
|
this.#openmct,
|
||||||
this.#compsManagerPool
|
this.#compsManagerPool
|
||||||
);
|
);
|
||||||
await specificCompsManager.load();
|
specificCompsManager.load().then(() => {
|
||||||
return new Promise((resolve, reject) => {
|
console.debug('📚 specific comp is ready');
|
||||||
const callbackID = this.#getCallbackID();
|
const callbackID = this.#getCallbackID();
|
||||||
const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry();
|
const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry();
|
||||||
const expression = specificCompsManager.getExpression();
|
const expression = specificCompsManager.getExpression();
|
||||||
// need to create callbackID with a promise for future execution
|
|
||||||
console.debug('🏟️ 1 Telemetry for comps:', telemetryForComps);
|
console.debug('🏟️ 1 Telemetry for comps:', telemetryForComps);
|
||||||
console.debug('🏟️ 2 Telemetry for comps:', specificCompsManager.requestUnderlyingTelemetry());
|
console.debug(
|
||||||
|
'🏟️ 2 Telemetry for comps:',
|
||||||
|
specificCompsManager.requestUnderlyingTelemetry()
|
||||||
|
);
|
||||||
this.#requestPromises[callbackID] = { resolve, reject };
|
this.#requestPromises[callbackID] = { resolve, reject };
|
||||||
this.#sharedWorker.port.postMessage({
|
this.#sharedWorker.port.postMessage({
|
||||||
type: 'calculateRequest',
|
type: 'calculateRequest',
|
||||||
@ -74,12 +76,13 @@ export default class CompsTelemetryProvider {
|
|||||||
callbackID
|
callbackID
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#computeOnNewTelemetry(specificCompsManager, newTelemetry, callbackID) {
|
#computeOnNewTelemetry(specificCompsManager, newTelemetry, callbackID) {
|
||||||
const expression = specificCompsManager.getExpression();
|
const expression = specificCompsManager.getExpression();
|
||||||
const telemetryForComps = specificCompsManager.getFullDataFrame(newTelemetry);
|
const telemetryForComps = specificCompsManager.getFullDataFrame(newTelemetry);
|
||||||
console.debug('🏟️ created new Data frame:', telemetryForComps);
|
// console.debug('🏟️ created new Data frame:', telemetryForComps);
|
||||||
this.#sharedWorker.port.postMessage({
|
this.#sharedWorker.port.postMessage({
|
||||||
type: 'calculateSubscription',
|
type: 'calculateSubscription',
|
||||||
telemetryForComps,
|
telemetryForComps,
|
||||||
@ -125,11 +128,12 @@ export default class CompsTelemetryProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSharedWorkerMessage(event) {
|
onSharedWorkerMessage(event) {
|
||||||
console.log('📝 Shared worker message:', event.data);
|
|
||||||
const { type, result, callbackID } = event.data;
|
const { type, result, callbackID } = event.data;
|
||||||
if (type === 'calculationSubscriptionResult' && this.#subscriptionCallbacks[callbackID]) {
|
if (type === 'calculationSubscriptionResult' && this.#subscriptionCallbacks[callbackID]) {
|
||||||
|
console.log('📝 Shared worker subscription message:', event.data);
|
||||||
this.#subscriptionCallbacks[callbackID](result);
|
this.#subscriptionCallbacks[callbackID](result);
|
||||||
} else if (type === 'calculationRequestResult') {
|
} else if (type === 'calculationRequestResult' && this.#requestPromises[callbackID]) {
|
||||||
|
console.log('📝 Shared worker request message:', event.data);
|
||||||
this.#requestPromises[callbackID].resolve(result);
|
this.#requestPromises[callbackID].resolve(result);
|
||||||
delete this.#requestPromises[callbackID];
|
delete this.#requestPromises[callbackID];
|
||||||
} else if (type === 'error') {
|
} else if (type === 'error') {
|
||||||
|
@ -33,11 +33,45 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section id="telemetryReferenceSection" aria-label="Derived Telemetry References">
|
||||||
|
<div class="c-cs__header c-section__header">
|
||||||
|
<div class="c-cs__header-label c-section__label">Telemetry References</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'c-cs__test-data__controls c-cdef__controls',
|
||||||
|
{ disabled: !telemetryObjectLength }
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<label class="c-toggle-switch">
|
||||||
|
<input type="checkbox" :checked="testDataApplied" @change="applyTestData" />
|
||||||
|
<span class="c-toggle-switch__slider" aria-label="Apply Test Data"></span>
|
||||||
|
<span class="c-toggle-switch__label">Apply Test Values</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="c-cs__content">
|
||||||
|
<div
|
||||||
|
v-show="isEditing"
|
||||||
|
class="hint"
|
||||||
|
:class="{ 's-status-icon-warning-lo': !telemetryObjectLength }"
|
||||||
|
>
|
||||||
|
<template v-if="!telemetryObjectLength"
|
||||||
|
>Drag telemetry into Telemetry References to add variables for an expression</template
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section id="expressionSection" aria-label="Derived Telemetry Expression">
|
||||||
|
<div class="c-cs__header c-section__header">
|
||||||
|
<div class="c-cs__header-label c-section__label">Expression</div>
|
||||||
|
</div>
|
||||||
|
<div class="c-cs__content"></div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { inject, onBeforeUnmount, onMounted } from 'vue';
|
import { inject, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import CompsManager from '../CompsManager';
|
import CompsManager from '../CompsManager';
|
||||||
|
|
||||||
@ -45,10 +79,40 @@ const openmct = inject('openmct');
|
|||||||
const domainObject = inject('domainObject');
|
const domainObject = inject('domainObject');
|
||||||
const compsManagerPool = inject('compsManagerPool');
|
const compsManagerPool = inject('compsManagerPool');
|
||||||
const compsManager = CompsManager.getCompsManager(domainObject, openmct, compsManagerPool);
|
const compsManager = CompsManager.getCompsManager(domainObject, openmct, compsManagerPool);
|
||||||
|
const currentCompOutput = ref(null);
|
||||||
|
const telemetryObjectLength = ref(0);
|
||||||
|
const testDataApplied = ref(false);
|
||||||
|
|
||||||
onMounted(() => {
|
let outputTelemetryCollection;
|
||||||
console.debug('🚀 CompsView: onMounted with compsManager', compsManager);
|
|
||||||
|
defineProps({
|
||||||
|
isEditing: { type: Boolean, required: true }
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {});
|
onMounted(async () => {
|
||||||
|
console.debug('🚀 CompsView: onMounted with compsManager', compsManager);
|
||||||
|
outputTelemetryCollection = openmct.telemetry.requestCollection(domainObject);
|
||||||
|
outputTelemetryCollection.on('add', (data) => {
|
||||||
|
telemetryProcessor(data);
|
||||||
|
});
|
||||||
|
outputTelemetryCollection.on('clear', clearData);
|
||||||
|
await outputTelemetryCollection.load();
|
||||||
|
await compsManager.load();
|
||||||
|
telemetryObjectLength.value = Object.keys(compsManager.getTelemetryObjects()).length;
|
||||||
|
});
|
||||||
|
|
||||||
|
function applyTestData() {}
|
||||||
|
|
||||||
|
function telemetryProcessor(data) {
|
||||||
|
// new data will come in as array, so just take the last element
|
||||||
|
currentCompOutput.value = data[data.length - 1]?.output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearData() {
|
||||||
|
currentCompOutput.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
outputTelemetryCollection.destroy();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -28,7 +28,7 @@ export default function CompsPlugin() {
|
|||||||
|
|
||||||
return function install(openmct) {
|
return function install(openmct) {
|
||||||
openmct.types.addType('comps', {
|
openmct.types.addType('comps', {
|
||||||
name: 'Comps',
|
name: 'Derived Telemetry',
|
||||||
key: 'comps',
|
key: 'comps',
|
||||||
description:
|
description:
|
||||||
'Add one or more telemetry objects, apply a mathematical operation to them, and republish the result as a new telemetry object.',
|
'Add one or more telemetry objects, apply a mathematical operation to them, and republish the result as a new telemetry object.',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user