mirror of
https://github.com/nasa/openmct.git
synced 2025-06-01 15:10:50 +00:00
can take arbitrary expressions
This commit is contained in:
parent
0326e38f5d
commit
413338d3e2
@ -29,10 +29,27 @@ export default class CompsManager extends EventEmitter {
|
|||||||
this.persist();
|
this.persist();
|
||||||
}
|
}
|
||||||
|
|
||||||
getDomainObjectForParameter(keyString) {
|
getParameters() {
|
||||||
|
const parameters = this.#domainObject.configuration.comps.parameters;
|
||||||
|
const parametersWithTimeKey = parameters.map((parameter) => {
|
||||||
|
return {
|
||||||
|
...parameter,
|
||||||
|
timeKey: this.#telemetryCollections[parameter.keyString]?.timeKey
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return parametersWithTimeKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTelemetryObjectForParameter(keyString) {
|
||||||
return this.#telemetryObjects[keyString];
|
return this.#telemetryObjects[keyString];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMetaDataValuesForParameter(keyString) {
|
||||||
|
const telemetryObject = this.getTelemetryObjectForParameter(keyString);
|
||||||
|
const metaData = this.#openmct.telemetry.getMetadata(telemetryObject);
|
||||||
|
return metaData.valueMetadatas;
|
||||||
|
}
|
||||||
|
|
||||||
deleteParameter(keyString) {
|
deleteParameter(keyString) {
|
||||||
this.#domainObject.configuration.comps.parameters =
|
this.#domainObject.configuration.comps.parameters =
|
||||||
this.#domainObject.configuration.comps.parameters.filter(
|
this.#domainObject.configuration.comps.parameters.filter(
|
||||||
@ -54,6 +71,10 @@ export default class CompsManager extends EventEmitter {
|
|||||||
'configuration.comps',
|
'configuration.comps',
|
||||||
this.#domainObject.configuration.comps
|
this.#domainObject.configuration.comps
|
||||||
);
|
);
|
||||||
|
console.debug(
|
||||||
|
`📦 CompsManager: persisted domain object`,
|
||||||
|
this.#domainObject.configuration.comps
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
@ -170,7 +191,7 @@ export default class CompsManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getExpression() {
|
getExpression() {
|
||||||
return this.#domainObject.configuration.expression;
|
return this.#domainObject.configuration.comps.expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
#waitForDebounce() {
|
#waitForDebounce() {
|
||||||
|
@ -8,12 +8,12 @@ onconnect = function (e) {
|
|||||||
port.onmessage = function (event) {
|
port.onmessage = function (event) {
|
||||||
console.debug('🧮 Comps Math Worker message:', event);
|
console.debug('🧮 Comps Math Worker message:', event);
|
||||||
try {
|
try {
|
||||||
const { type, callbackID, telemetryForComps, expression } = event.data;
|
const { type, callbackID, telemetryForComps, expression, parameters } = event.data;
|
||||||
if (type === 'calculateRequest') {
|
if (type === 'calculateRequest') {
|
||||||
const result = calculateRequest(telemetryForComps, expression);
|
const result = calculateRequest(telemetryForComps, parameters, expression);
|
||||||
port.postMessage({ type: 'calculationRequestResult', callbackID, result });
|
port.postMessage({ type: 'calculationRequestResult', callbackID, result });
|
||||||
} else if (type === 'calculateSubscription') {
|
} else if (type === 'calculateSubscription') {
|
||||||
const result = calculateSubscription(telemetryForComps, expression);
|
const result = calculateSubscription(telemetryForComps, parameters, expression);
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
port.postMessage({ type: 'calculationSubscriptionResult', callbackID, result });
|
port.postMessage({ type: 'calculationSubscriptionResult', callbackID, result });
|
||||||
}
|
}
|
||||||
@ -38,31 +38,48 @@ function getFullDataFrame(telemetryForComps) {
|
|||||||
return dataFrame;
|
return dataFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateSubscription(telemetryForComps, expression) {
|
function calculateSubscription(telemetryForComps, parameters, expression) {
|
||||||
const dataFrame = getFullDataFrame(telemetryForComps);
|
const dataFrame = getFullDataFrame(telemetryForComps);
|
||||||
return calculate(dataFrame, expression);
|
return calculate(dataFrame, parameters, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateRequest(telemetryForComps, expression) {
|
function calculateRequest(telemetryForComps, parameters, expression) {
|
||||||
const dataFrame = getFullDataFrame(telemetryForComps);
|
const dataFrame = getFullDataFrame(telemetryForComps);
|
||||||
return calculate(dataFrame, expression);
|
return calculate(dataFrame, parameters, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculate(dataFrame, expression) {
|
function calculate(dataFrame, parameters, expression) {
|
||||||
const sumResults = [];
|
const sumResults = [];
|
||||||
// Iterate over the first dataset and check for matching utc in the other dataset
|
// ensure all parameter keyStrings have corresponding telemetry data
|
||||||
const firstDataSet = Object.values(dataFrame)[0];
|
if (!expression) {
|
||||||
const secondDataSet = Object.values(dataFrame)[1];
|
|
||||||
if (!firstDataSet || !secondDataSet) {
|
|
||||||
return sumResults;
|
return sumResults;
|
||||||
}
|
}
|
||||||
|
// take the first parameter keyString as the reference
|
||||||
for (const [utc, item1] of firstDataSet.entries()) {
|
const referenceParameter = parameters[0];
|
||||||
if (secondDataSet.has(utc)) {
|
const otherParameters = parameters.slice(1);
|
||||||
const item2 = secondDataSet.get(utc);
|
// iterate over the reference telemetry data
|
||||||
const output = evaluate(expression, { a: item1.sin, b: item2.sin });
|
const referenceTelemetry = dataFrame[referenceParameter.keyString];
|
||||||
sumResults.push({ utc, output });
|
referenceTelemetry.forEach((referenceTelemetryItem) => {
|
||||||
|
const scope = {
|
||||||
|
[referenceParameter.name]: referenceTelemetryItem[referenceParameter.valueToUse]
|
||||||
|
};
|
||||||
|
const referenceTime = referenceTelemetryItem[referenceParameter.timeKey];
|
||||||
|
// iterate over the other parameters to set the scope
|
||||||
|
let missingData = false;
|
||||||
|
otherParameters.forEach((parameter) => {
|
||||||
|
const otherDataFrame = dataFrame[parameter.keyString];
|
||||||
|
const otherTelemetry = otherDataFrame.get(referenceTime);
|
||||||
|
if (!otherTelemetry) {
|
||||||
|
missingData = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scope[parameter.name] = otherTelemetry[parameter.valueToUse];
|
||||||
|
});
|
||||||
|
if (missingData) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
const output = evaluate(expression, scope);
|
||||||
|
sumResults.push({ [referenceParameter.timeKey]: referenceTime, output });
|
||||||
|
});
|
||||||
return sumResults;
|
return sumResults;
|
||||||
}
|
}
|
||||||
|
@ -59,21 +59,16 @@ export default class CompsTelemetryProvider {
|
|||||||
this.#compsManagerPool
|
this.#compsManagerPool
|
||||||
);
|
);
|
||||||
specificCompsManager.load().then(() => {
|
specificCompsManager.load().then(() => {
|
||||||
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();
|
||||||
console.debug('🏟️ 1 Telemetry for comps:', telemetryForComps);
|
const parameters = specificCompsManager.getParameters();
|
||||||
console.debug(
|
|
||||||
'🏟️ 2 Telemetry for comps:',
|
|
||||||
specificCompsManager.requestUnderlyingTelemetry()
|
|
||||||
);
|
|
||||||
console.debug('🏟️ expression:', expression);
|
|
||||||
this.#requestPromises[callbackID] = { resolve, reject };
|
this.#requestPromises[callbackID] = { resolve, reject };
|
||||||
this.#sharedWorker.port.postMessage({
|
this.#sharedWorker.port.postMessage({
|
||||||
type: 'calculateRequest',
|
type: 'calculateRequest',
|
||||||
telemetryForComps,
|
telemetryForComps,
|
||||||
expression,
|
expression,
|
||||||
|
parameters,
|
||||||
callbackID
|
callbackID
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -83,11 +78,12 @@ export default class CompsTelemetryProvider {
|
|||||||
#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);
|
const parameters = specificCompsManager.getParameters();
|
||||||
this.#sharedWorker.port.postMessage({
|
this.#sharedWorker.port.postMessage({
|
||||||
type: 'calculateSubscription',
|
type: 'calculateSubscription',
|
||||||
telemetryForComps,
|
telemetryForComps,
|
||||||
expression,
|
expression,
|
||||||
|
parameters,
|
||||||
callbackID
|
callbackID
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -120,7 +116,6 @@ export default class CompsTelemetryProvider {
|
|||||||
this.#sharedWorker.port.onmessageerror = this.onSharedWorkerMessageError.bind(this);
|
this.#sharedWorker.port.onmessageerror = this.onSharedWorkerMessageError.bind(this);
|
||||||
this.#sharedWorker.port.start();
|
this.#sharedWorker.port.start();
|
||||||
|
|
||||||
// send an initial message to the worker
|
|
||||||
this.#sharedWorker.port.postMessage({ type: 'init' });
|
this.#sharedWorker.port.postMessage({ type: 'init' });
|
||||||
|
|
||||||
this.#openmct.on('destroy', () => {
|
this.#openmct.on('destroy', () => {
|
||||||
@ -131,10 +126,10 @@ export default class CompsTelemetryProvider {
|
|||||||
onSharedWorkerMessage(event) {
|
onSharedWorkerMessage(event) {
|
||||||
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);
|
console.debug('📝 Shared worker subscription message:', event.data);
|
||||||
this.#subscriptionCallbacks[callbackID](result);
|
this.#subscriptionCallbacks[callbackID](result);
|
||||||
} else if (type === 'calculationRequestResult' && this.#requestPromises[callbackID]) {
|
} else if (type === 'calculationRequestResult' && this.#requestPromises[callbackID]) {
|
||||||
console.log('📝 Shared worker request message:', event.data);
|
console.debug('📝 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') {
|
||||||
|
@ -55,30 +55,26 @@
|
|||||||
:class="{ 's-status-icon-warning-lo': !domainObject.configuration.comps.parameters }"
|
:class="{ 's-status-icon-warning-lo': !domainObject.configuration.comps.parameters }"
|
||||||
>
|
>
|
||||||
<div v-for="parameter in parameters" :key="parameter.name">
|
<div v-for="parameter in parameters" :key="parameter.name">
|
||||||
<div class="c-cs__telemetry-reference">
|
<div>
|
||||||
<input
|
Reference
|
||||||
v-model="parameter.name"
|
<input v-model="parameter.name" @change="compsManager.persist" />
|
||||||
class="c-cs__telemetry-reference__label"
|
|
||||||
@change="compsManager.persist"
|
|
||||||
/>
|
|
||||||
<ObjectPath
|
<ObjectPath
|
||||||
:domain-object="compsManager.getDomainObjectForParameter(parameter.keyString)"
|
:domain-object="compsManager.getTelemetryObjectForParameter(parameter.keyString)"
|
||||||
/>
|
/>
|
||||||
{{ compsManager.getDomainObjectForParameter(parameter.keyString).name }}
|
{{ compsManager.getTelemetryObjectForParameter(parameter.keyString).name }}
|
||||||
<!-- drop down to select value from telemetry -->
|
<!-- drop down to select value from telemetry -->
|
||||||
<select
|
<select v-model="parameter.valueToUse" @change="persistParameters">
|
||||||
v-model="parameter.value"
|
|
||||||
class="c-cs__telemetry-reference__value"
|
|
||||||
@change="compsManager.persist"
|
|
||||||
>
|
|
||||||
<option
|
<option
|
||||||
v-for="parameterValueOption in compsManager.getDomainObjectForParameter(
|
v-for="parameterValueOption in compsManager.getMetaDataValuesForParameter(
|
||||||
parameter.keyString
|
parameter.keyString
|
||||||
)"
|
)"
|
||||||
:key="parameterValueOption"
|
:key="parameterValueOption.key"
|
||||||
:value="parameterValueOption"
|
:value="parameterValueOption.key"
|
||||||
/>
|
>
|
||||||
|
{{ parameterValueOption.name }}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
<input v-model="parameter.testValue" @change="compsManager.persist" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="!domainObject.configuration.comps.parameters"
|
<template v-if="!domainObject.configuration.comps.parameters"
|
||||||
@ -92,13 +88,12 @@
|
|||||||
<div class="c-cs__header-label c-section__label">Expression</div>
|
<div class="c-cs__header-label c-section__label">Expression</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-cs__content">
|
<div class="c-cs__content">
|
||||||
<div v-if="!isEditing">{{ domainObject.configuration.comps.expression }}</div>
|
<div>
|
||||||
<div v-else>
|
|
||||||
<textarea
|
<textarea
|
||||||
v-model="domainObject.configuration.comps.expression"
|
v-model="expression"
|
||||||
class="c-cs__expression__input"
|
class="c-cs__expression__input"
|
||||||
placeholder="Enter an expression"
|
placeholder="Enter an expression"
|
||||||
@change="compsManager.persist"
|
@change="persistExpression"
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -119,6 +114,7 @@ const compsManager = CompsManager.getCompsManager(domainObject, openmct, compsMa
|
|||||||
const currentCompOutput = ref(null);
|
const currentCompOutput = ref(null);
|
||||||
const testDataApplied = ref(false);
|
const testDataApplied = ref(false);
|
||||||
const parameters = ref(null);
|
const parameters = ref(null);
|
||||||
|
const expression = ref(null);
|
||||||
|
|
||||||
let outputTelemetryCollection;
|
let outputTelemetryCollection;
|
||||||
|
|
||||||
@ -135,9 +131,20 @@ onBeforeMount(async () => {
|
|||||||
outputTelemetryCollection.on('clear', clearData);
|
outputTelemetryCollection.on('clear', clearData);
|
||||||
await outputTelemetryCollection.load();
|
await outputTelemetryCollection.load();
|
||||||
await compsManager.load();
|
await compsManager.load();
|
||||||
parameters.value = domainObject.configuration.comps.parameters;
|
parameters.value = compsManager.getParameters();
|
||||||
|
expression.value = compsManager.getExpression();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function persistParameters() {
|
||||||
|
domainObject.configuration.comps.parameters = parameters.value;
|
||||||
|
compsManager.persist();
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistExpression() {
|
||||||
|
domainObject.configuration.comps.expression = expression.value;
|
||||||
|
compsManager.persist();
|
||||||
|
}
|
||||||
|
|
||||||
function applyTestData() {}
|
function applyTestData() {}
|
||||||
|
|
||||||
function telemetryProcessor(data) {
|
function telemetryProcessor(data) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user