Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add child objects to Events & Commands #489

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ const openmct = window.openmct;

openmct.install(openmct.plugins.FaultManagement());
openmct.install(openmct.plugins.BarChart());
const timeLinePlugin = openmct.plugins.Timeline();
openmct.install(timeLinePlugin);
openmct.install(openmct.plugins.EventTimestripPlugin(timeLinePlugin.extendedLinesBus));

// setup example display layout
openmct.on('start', async () => {
Expand Down
127 changes: 127 additions & 0 deletions example/make-example-events.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import process from 'process';

const INSTANCE = "myproject";
const URL = `http://localhost:8090/api/archive/${INSTANCE}/events`;

const events = [
{
type: "PRESSURE_ALERT",
message: "Pressure threshold exceeded",
severity: "CRITICAL",
source: "PressureModule",
sequenceNumber: 1,
extra: {
pressure: "150 PSI",
location: "Hydraulic System"
}
},
{
type: "PRESSURE_WARNING",
message: "Pressure nearing critical level",
severity: "WARNING",
source: "PressureModule",
sequenceNumber: 2,
extra: {
pressure: "140 PSI",
location: "Hydraulic System"
}
},
{
type: "PRESSURE_INFO",
message: "Pressure system check completed",
severity: "INFO",
source: "PressureModule",
sequenceNumber: 3,
extra: {
checkType: "Routine Inspection",
duration: "10m"
}
},
{
type: "TEMPERATURE_ALERT",
message: "Temperature threshold exceeded",
severity: "CRITICAL",
source: "TemperatureModule",
sequenceNumber: 4,
extra: {
temperature: "100°C",
location: "Engine Room"
}
},
{
type: "TEMPERATURE_WARNING",
message: "Temperature nearing critical level",
severity: "WARNING",
source: "TemperatureModule",
sequenceNumber: 5,
extra: {
temperature: "95°C",
location: "Engine Room"
}
},
{
type: "TEMPERATURE_INFO",
message: "Temperature nominal",
severity: "INFO",
source: "TemperatureModule",
sequenceNumber: 6,
extra: {
temperature: "35°C",
location: "Life Support"
}
},
{
type: "TEMPERATURE_INFO",
message: "Temperature nominal",
severity: "INFO",
source: "TemperatureModule",
sequenceNumber: 7,
extra: {
temperature: "30°C",
location: "Life Support"
}
},
{
type: "TEMPERATURE_SEVERE",
message: "Temperature nominal",
severity: "SEVERE",
source: "TemperatureModule",
sequenceNumber: 8,
extra: {
temperature: "200°C",
location: "Engine Room"
}
}
];

async function postEvent(event, delaySeconds) {
const eventTime = new Date(Date.now() + delaySeconds * 1000).toISOString();
event.time = eventTime;

try {
const response = await fetch(URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(event)
});

if (response.ok) {
console.log(`Event posted successfully: ${event.type}`);
} else {
console.error(`Failed to post event: ${event.type}. HTTP Status: ${response.status}`);
}
} catch (error) {
console.error(`Error posting event: ${event.type}.`, error);
}
}

export async function postAllEvents() {
for (let i = 0; i < events.length; i++) {
await postEvent(events[i], i * 5);
}
}

// If you still want to run it standalone
if (import.meta.url === `file://${process.argv[1]}`) {
postAllEvents();
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"test:e2e:quickstart": "npm test --workspace tests/e2e/opensource -- --config=../playwright-quickstart.config.js --project=chromium tests/e2e/yamcs/",
"test:e2e:quickstart:local": "npm test --workspace tests/e2e/opensource -- --config=../playwright-quickstart.config.js --project=local-chrome tests/e2e/yamcs/",
"test:e2e:watch": "npm test --workspace tests/e2e/opensource -- --ui --config=../playwright-quickstart.config.js",
"wait-for-yamcs": "wait-on http-get://localhost:8090/ -v"
"wait-for-yamcs": "wait-on http-get://localhost:8090/ -v",
"make-example-events": "node ./example/make-example-events.mjs"
},
"keywords": [
"openmct",
Expand Down
7 changes: 5 additions & 2 deletions src/const.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
*****************************************************************************/

export const OBJECT_TYPES = {
COMMANDS_OBJECT_TYPE: 'yamcs.commands',
EVENTS_OBJECT_TYPE: 'yamcs.events',
COMMANDS_ROOT_OBJECT_TYPE: 'yamcs.commands',
COMMANDS_QUEUE_OBJECT_TYPE: 'yamcs.commands.queue',
EVENTS_ROOT_OBJECT_TYPE: 'yamcs.events',
EVENT_SPECIFIC_OBJECT_TYPE: 'yamcs.event.specific',
EVENT_SPECIFIC_SEVERITY_OBJECT_TYPE: 'yamcs.event.specific.severity',
TELEMETRY_OBJECT_TYPE: 'yamcs.telemetry',
IMAGE_OBJECT_TYPE: 'yamcs.image',
STRING_OBJECT_TYPE: 'yamcs.string',
Expand Down
26 changes: 22 additions & 4 deletions src/openmct-yamcs.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,33 @@ export default function install(
cssClass: 'icon-telemetry'
});

openmct.types.addType(OBJECT_TYPES.EVENTS_OBJECT_TYPE, {
openmct.types.addType(OBJECT_TYPES.EVENTS_ROOT_OBJECT_TYPE, {
name: "Events",
description: "To view events",
description: "To view all events",
cssClass: "icon-generator-events"
});

openmct.types.addType(OBJECT_TYPES.COMMANDS_OBJECT_TYPE, {
openmct.types.addType(OBJECT_TYPES.EVENT_SPECIFIC_OBJECT_TYPE, {
name: "Event",
description: "To view events from a specific source",
cssClass: "icon-generator-events"
});

openmct.types.addType(OBJECT_TYPES.EVENT_SPECIFIC_SEVERITY_OBJECT_TYPE, {
name: "Event",
description: "To view events from a specific source with a specific severity or greater",
cssClass: "icon-generator-events"
});

openmct.types.addType(OBJECT_TYPES.COMMANDS_QUEUE_OBJECT_TYPE, {
name: "Command Queue",
description: "To view command history in a specific queue",
cssClass: "icon-generator-events" // TODO: replace
});

openmct.types.addType(OBJECT_TYPES.COMMANDS_ROOT_OBJECT_TYPE, {
name: "Commands",
description: "To view command history",
description: "To view the whole command history",
cssClass: "icon-generator-events" // TODO: replace
});

Expand Down
59 changes: 50 additions & 9 deletions src/providers/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,42 @@
import { OBJECT_TYPES, METADATA_TIME_KEY } from "../const.js";
import { flattenObjectArray } from "../utils.js";

export function createCommandsObject(openmct, parentKey, namespace) {
export function createRootCommandsObject(openmct, parentKey, namespace) {
const rootCommandsIdentifier = {
key: OBJECT_TYPES.COMMANDS_ROOT_OBJECT_TYPE,
namespace
};
const rootCommandsObject = createCommandObject(openmct, parentKey, namespace, rootCommandsIdentifier);

return rootCommandsObject;
}

export function createCommandObject(openmct, parentKey, namespace, identifier, queueName = null) {
const isRoot = queueName === null;
const location = openmct.objects.makeKeyString({
key: parentKey,
namespace
});

const identifier = {
key: OBJECT_TYPES.COMMANDS_OBJECT_TYPE,
namespace: namespace
};
const name = isRoot ? 'Commands' : queueName;
const type = isRoot
? OBJECT_TYPES.COMMANDS_ROOT_OBJECT_TYPE
: OBJECT_TYPES.COMMANDS_QUEUE_OBJECT_TYPE;

const commandObject = {
identifier,
location,
name: 'Commands',
type: OBJECT_TYPES.COMMANDS_OBJECT_TYPE,
name,
type,
telemetry: {
values: [
{
key: 'commandName',
name: 'Command',
format: 'string'
format: 'string',
hints: {
label: 0
}
},
{
key: 'utc',
Expand Down Expand Up @@ -164,9 +179,35 @@ export function createCommandsObject(openmct, parentKey, namespace) {
}
};

if (isRoot) {
commandObject.composition = [];
}

return commandObject;
}

export async function getCommandQueues(url, instance, processor = 'realtime') {
const commandQueuesURL = `${url}api/processors/${instance}/${processor}/queues`;
const response = await fetch(commandQueuesURL, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});

if (!response.ok) {
console.error(`🛑 Error fetching command queues: ${response.statusText}`);

return [];
}

const commandQueueJson = await response.json();
const { queues } = commandQueueJson;
const queueNames = queues.map(queue => queue.name);

return queueNames;
}

/**
* Convert raw command data from YAMCS to a format which
* can be consumed by Open MCT as telemetry.
Expand All @@ -177,7 +218,7 @@ export function commandToTelemetryDatum(command) {
const { generationTime, commandId, attr, assignments, id } = command;
const { origin, sequenceNumber, commandName } = commandId;
let datum = {
id: OBJECT_TYPES.COMMANDS_OBJECT_TYPE,
id: OBJECT_TYPES.COMMANDS_QUEUE_OBJECT_TYPE,
generationTime,
origin,
sequenceNumber,
Expand Down
4 changes: 3 additions & 1 deletion src/providers/event-limit-provider.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* CSS classes for Yamcs parameter monitoring result values. */

import { OBJECT_TYPES } from "../const";

const SEVERITY_CSS = {
'WATCH': 'is-event--yellow',
'WARNING': 'is-event--yellow',
Expand Down Expand Up @@ -65,6 +67,6 @@ export default class EventLimitProvider {
}

supportsLimits(domainObject) {
return domainObject.type.startsWith('yamcs.events');
return [OBJECT_TYPES.EVENTS_ROOT_OBJECT_TYPE, OBJECT_TYPES.EVENT_SPECIFIC_OBJECT_TYPE, OBJECT_TYPES.EVENT_SPECIFIC_SEVERITY_OBJECT_TYPE].includes(domainObject.type);
}
}
Loading
Loading