openmct/API.md
2017-03-28 12:03:00 -07:00

17 KiB

Building Applications With Open MCT

Scope and purpose of this document

This document is intended to serve as a reference for developing an application based on Open MCT. It will provide details of the API functions necessary to extend the Open MCT platform meet common use cases such as integrating with a telemetry source.

The best place to start is with the Open MCT Tutorials. These will walk you through the process of getting up and running with Open MCT, as well as addressing some common developer use cases.

Building From Source

The latest version of Open MCT is available from our GitHub repository. If you have git, and node installed, you can build Open MCT with the commands

git clone https://github.com/nasa/openmct.git
cd openmct
npm install

These commands will fetch the Open MCT source from our GitHub repository, and build a minified version that can be included in your application. The output of the build process is placed in a dist folder under the openmct source directory, which can be copied out to another location as needed. The contents of this folder will include a minified javascript file named openmct.js as well as assets such as html, css, and images necessary for the UI.

Starting an Open MCT application

To start a minimally functional Open MCT application, it is necessary to include the Open MCT distributable, enable some basic plugins, and bootstrap the application. The tutorials walk through the process of getting Open MCT up and running from scratch, but provided below is a minimal HTML template that includes Open MCT, installs some basic plugins, and bootstraps the application. It assumes that Open MCT is installed under an openmct subdirectory, as described in Building From Source.

This approach includes openmct using a simple script tag, resulting in a global variable named openmct. This openmct object is used subsequently to make API calls.

Open MCT is packaged as a UMD (Universal Module Definition) module, so common script loaders are also supported.

<!DOCTYPE html>
<html>
<head>
    <title>Open MCT</title>
    <script src="openmct.js"></script>
</head>
<body>
    <script>
        openmct.setAssetPath('openmct/dist');
        openmct.install(openmct.plugins.LocalStorage());
        openmct.install(openmct.plugins.MyItems());
        openmct.install(openmct.plugins.UTCTimeSystem());
        openmct.install(openmct.plugins.Espresso());
        openmct.start();
    </script>
</body>
</html>

The Open MCT library included above requires certain assets such as html templates, images, and css. If you installed Open MCT from GitHub as described in the section on Building from Source then these assets will have been downloaded along with the Open MCT javascript library. You can specify the location of these assets by calling openmct.setAssetPath(). Typically this will be the same location as the openmct.js library is included from.

There are some plugins bundled with the application that provide UI, persistence, and other default configuration which are necessary to be able to do anything with the application initially. Any of these plugins can, in principle, be replaced with a custom plugin. The included plugins are documented in the Included Plugins section.

Plugins

Defining and Installing a New Plugin

openmct.install(function install(openmctAPI) {
    // Do things here
    // ...
});

New plugins are installed in Open MCT by calling openmct.install, and providing a plugin installation function. This function will be invoked on application startup with one parameter - the openmct API object. A common approach used in the Open MCT codebase is to define a plugin as a function that returns this installation function. This allows configuration to be specified when the plugin is included.

eg.

openmct.install(openmct.plugins.Elasticsearch("http://localhost:8002/openmct"));

This approach can be seen in all of the plugins provided with Open MCT.

Domain Objects and Identifiers

Domain Objects are the basic entities that represent domain knowledge in Open MCT. The temperature sensor on a solar panel, an overlay plot comparing the results of all temperature sensors, the command dictionary for a spacecraft, the individual commands in that dictionary, the "My Items" folder: All of these things are domain objects.

A Domain Object is simply a javascript object with some standard attributes.
An example of a Domain Object is the "My Items" object which is a folder in which a user can persist any objects that they create. The My Items object looks like this:

{
    identifier: {
        namespace: ""
        key: "mine"
    }
    name:"My Items",
    type:"folder",
    location:"ROOT",
    composition: []
}

Object Attributes

The main attributes to note are the identifier, and type attributes.

  • identifier: A composite key that provides a universally unique identifier for this object. The namespace and key are used to identify the object. The key must be unique within the namespace.
  • type: All objects in Open MCT have a type. Types allow you to form an ontology of knowledge and provide an abstraction for grouping, visualizing, and interpreting data. Details on how to define a new object type are provided below.

Open MCT uses a number of builtin types. Typically you are going to want to define your own if extending Open MCT.

Domain Object Types

Custom types may be registered via the addType function on the opencmt Type registry.

eg.

openmct.types.addType('my-type', {
    label: "My Type",
    description: "This is a type that I added!",
    creatable: true
});

The addType function accepts two arguments:

  • A string key identifying the type. This key is used when specifying a type for an object.
  • An object type specification. An object type definition supports the following attributes
    • label: a string naming this object type
    • description: a string specifying a longer-form description of this type
    • initialize: a function which initializes the model for new domain objects of this type. This can be used for setting default values on an object when it is instantiated.
    • creatable: A boolean indicating whether users should be allowed to create this type (default: false). This will determine whether the type appears in the Create menu.
    • cssClass: A string specifying a CSS class to apply to each representation of this object. This is used for specifying an icon to appear next to each object of this type.

The Open MCT Tutorials provide a step-by-step examples of writing code for Open MCT that includes a section on defining a new object type.

Root Objects

In many cases, you'd like a certain object (or a certain hierarchy of objects) to be accessible from the top level of the application (the tree on the left-hand side of Open MCT.) For example, it is typical to expose a telemetry dictionary as a hierarchy of telemetry-providing domain objects in this fashion.

To do so, use the addRoot method of the object API.

eg.

openmct.objects.addRoot({
        namespace: "my-namespace",
        key: "my-key"
    });

The addRoot function takes a single object identifier as an argument.

Root objects are loaded just like any other objects, i.e. via an object provider.

Object Providers

An Object Provider is used to build Domain Objects, typically retrieved from some source such as a persistence store or telemetry dictionary. In order to integrate telemetry from a new source an object provider will need to be created that can build objects representing telemetry points exposed by the telemetry source. The API call to define a new object provider is fairly straightforward. Here's a very simple example:

openmct.objects.addProvider('example.namespace', {
    get: function (identifier) {
        return Promise.resolve({
            identifier: identifier,
            name: 'Example Object',
            type: 'example-object-type'
        });
    }
});

The addProvider function takes two arguments:

  • namespace: A string representing the namespace that this object provider will provide objects for.
  • provider: An object with a single function, get. This function accepts an Identifier for the object to be provided. It is expected that the get function will return a Promise that resolves with the object being requested.

In future, object providers will support other methods to enable other operations with persistence stores, such as creating, updating, and deleting objects.

Composition Providers

The composition of a domain object is the list of objects it contains, as shown (for example) in the tree for browsing. Open MCT provides a default solution for composition, but there may be cases where you want to provide the composition of a certain object (or type of object) dynamically.

Adding Composition Providers

You may want to populate a hierarchy under a custom root-level object based on the contents of a telemetry dictionary. To do this, you can add a new Composition Provider:

openmct.composition.addProvider({
    appliesTo: function (domainObject) {
        return domainObject.type === 'my-type';
    },
    load: function (domainObject) {
        return Promise.resolve(myDomainObjects);
    }
});

The addProvider function accepts a Composition Provider object as its sole argument. A Composition Provider is a javascript object exposing two functions:

  • appliesTo: A function that accepts a domainObject argument, and returns a boolean value indicating whether this composition provider applies to the given object.
  • load: A function that accepts a domainObject as an argument, and returns a Promise that resolves with an array of Identifier. These identifiers will be used to fetch Domain Objects from an Object Provider

Default Composition Provider

The default composition provider applies to any domain object with a composition property. The value of composition should be an array of identifiers, e.g.:

var domainObject = {
    name: "My Object",
    type: 'folder',
    composition: [
        {
            id: '412229c3-922c-444b-8624-736d85516247',
            namespace: 'foo'
        },
        {
            key: 'd6e0ce02-5b85-4e55-8006-a8a505b64c75',
            namespace: 'foo'
        }
    ]
};

Telemetry Providers

When connecting to a new telemetry source, you will need to register a new Telemetry Provider. A Telemetry Provider retrieves telemetry data from some telemetry source, and exposes them in a way that can be used by Open MCT. A telemetry provider typically can support a one off request for a batch of telemetry data, or it can provide the ability to subscribe to receive new telemetry data when it becomes available, or both.

openmct.telemetry.addProvider({
    supportsRequest: function (domainObject) {
        //...
    },
    supportsSubscribe: function (domainObject) {
        //...
    },
    request: function (domainObject, options) {    
        //...
    },
    subscribe: function (domainObject, callback, options) {
        //...
    }
})

A telemetry provider is an object with the following functions defined:

  • supportsRequest: An optional function that accepts a Domain Object and returns a boolean value indicating whether or not this provider supports telemetry requests for the given object. If this returns true then a request function must be defined.
  • supportsSubscribe: An optional function that accepts a Domain Object and returns a boolean value indicating whether or not this provider supports telemetry subscriptions. If this returns true then a subscribe function must also be defined. As with request, the return value will typically be conditional, and based on attributes of domainObject such as its identifier.
  • request: A function that returns a Promise that will resolve with an Array of telemetry in a single query. This function accepts as arguments a Domain Object and an object containing some request options.
  • subscribe: A function that accepts a Domain Object, a callback function, and a telemetry request. The callback is invoked whenever telemetry is available, and

The implementations for request and subscribe can vary depending on the nature of the endpoint which will provide telemetry. In the example above, it is assumed that myAdapter contains the implementation details (such as HTTP requests, WebSocket connections, etc.) associated with some telemetry source.

For a step-by-step guide to building a telemetry adapter, please see the Open MCT Tutorials.

Telemetry Requests

Telemetry requests support time bounded queries. A call to a Telemetry Provider's request function will include an options argument. These are simply javascript objects with attributes for the request parameters. An example of a telemetry request object with a start and end time is included below:

{
    start: 1487981997240,
    end: 1487982897240
}

Telemetry Data

Telemetry data is provided to Open MCT by Telemetry Providers in the form of javascript objects. A collection of telemetry values (for example, retrieved in response to a request) is represented by an Array of javascript objects. These telemetry javascript objects are simply key value pairs.

Typically a telemetry datum will have some timestamp associated with it. This time stamp should have a key that corresponds to some time system supported by Open MCT. If the UTCTimeSystem plugin is installed, then the key utc can be used.

An example of a telemetry provider request function that returns a collection of mock telemtry data is below:

openmct.telemetry.addProvider({
    supportsRequest: function (domainObject) {
        return true
    },
    request: function (domainObject, options) {    
        return Promise.resolve([
            {
                'utc': Date.now() - 2000,
                'value': 1,
            },
            {
                'utc': Date.now() - 1000,
                'value': 2,
            },
            {
                'utc': Date.now(),
                'value': 3,
            }
        ]);
    }
})

Included Plugins

Open MCT is packaged along with a few general-purpose plugins:

  • openmct.plugins.CouchDB is an adapter for using CouchDB for persistence of user-created objects. This is a constructor that takes the URL for the CouchDB database as a parameter, e.g.
openmct.install(openmct.plugins.CouchDB('http://localhost:5984/openmct'))
  • openmct.plugins.Elasticsearch is an adapter for using Elasticsearch for persistence of user-created objects. This is a constructor that takes the URL for the Elasticsearch instance as a parameter. eg.
openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
  • openmct.plugins.Espresso and openmct.plugins.Snow are two different themes (dark and light) available for Open MCT. Note that at least one of these themes must be installed for Open MCT to appear correctly.
  • openmct.plugins.LocalStorage provides persistence of user-created objects in browser-local storage. This is particularly useful in development environments.
  • openmct.plugins.MyItems adds a top-level folder named "My Items" when the application is first started, providing a place for a user to store created items.
  • openmct.plugins.UTCTimeSystem provides a default time system for Open MCT.

Generally, you will want to either install these plugins, or install different plugins that provide persistence and an initial folder hierarchy.

eg.

openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.MyItems());