How To: Work with Asset Subsystems Using the GQL API

What Are Subsystems?
Asset Subsystems (currently in beta, documentation here) is an ExoSense feature which allows a user to tag Asset signals. The user first creates a subsystem, assigning a full name, a short name, a color, and an icon to the subsystem. Once a subsystem exists, it can be used to tag Asset signals. Examples of a subsystem might be “Electrical”, or “Hydraulic”, or “Basement”, or “Backup” - whatever makes sense to the user. Tagging signals has multiple benefits: it provides a visual indicator of which subsystem a signal belongs to, and allows the signal lists to be filtered, thereby reducing the number of signals a user needs to look through. For a full explanation of the feature, please check out the documentation.

This post will focus on how to interact with the Subsystems feature through the GraphQL API. Some familiarity with GraphQL is assumed. If you are not already familiar with GraphQL, you can find the official tutorial at https://graphql.org/learn/. If you are not already familiar with a GraphQL-capable client, such as Insomnia or Postman, please see our quick-start guide here: How To: Get Started with the GraphQL API Using Insomnia.

Should You Use GraphQL for Subsystems?
Before we dive into the details about how to use GQL to interact with ExoSense’s Subsystem feature, let’s discuss why you might want to do this in the first place. I will note that, for simple Assets, it is probably easier to perform these operations using the ExoSense UI. Fully configuring a Subsystem through GQL requires that you have Asset and Signals IDs, know the hex strings for the colors you want to assign to your Subsystems, and know the icon strings for the icons you want to associate. It is also important to know that Subsystems work with Asset Templates, meaning that Assets created from a Template or migrated onto a Template will inherit the Template’s Subsystem structure and configuration. Because of this, many users will find it simpler to implement Subsystems through the regular ExoSense interface.

GQL starts to make things easier when working with large, complex, non-templatable Assets. Users working with custom-built, one-off Assets with hundreds of Signals will find that creating scripts to automate the process to be well worth their time. If you aren’t sure what’s best for your situation, we recommend starting with the UI. If you would like further guidance, please get in touch with Exosite Support by emailing support@exosite.com.

The Subsystem Object
Before we look at how to create a Subsystem, let’s start by examining the Subsystem Object and what fields it contains.

asset
Type: Object
The Asset object with which the Subsystem is associated. Assets are complex objects, so we won’t go into them in detail here. In many cases, you will likely just want to request the name and ID of the associated Asset.

assetId
Type: String
The ID of the Asset with which the Subsystem is associated. Allows you to avoid requesting an Asset object if you only need the ID.

createdAt
Type: String
The date and time at which the Subsystem was created. Returned in the following format: “Thu May 11 2023 18:02:28 GMT+0000 (Coordinated Universal Time)”

dashboard
Type: Object
If the Subsystem has an associated Dashboard (they are not required to), this will return the Dashboard object. Like Assets, Dashboards are complex objects and we won’t go into them in detail in this post.

id
Type: String
The ID of the Subsystem. You will need this if you want to update the Subsystem through GraphQL.

locked
Type: Boolean
A Boolean denoting whether the Subsystem is locked for editing. This will be true if the Subsystem was created as part of a Template.

meta
Type: Object
The SubsystemMeta object containing configuration options for the Subsystem. This object contains four fields:
color: A hex code string denoting the color of the Subsystem tags. Example: “#6495ed
icon: A string denoting the icon associated with the Subsystem. Example: “icon-asset-soil”
order: An integer denoting the order in which Subsystems will be listed in the sidenav. 0 represents the Subsystem at the top of the list.
shortName: A string that will be used on the Subsystem tag itself.

name
Type: String
The full name of the Subsystem.

signals
Type: Array (of objects)
An array containing the Signal objects associated with the Subsystem. These are the signals that have been tagged with the Subsystem.

updatedAt
Type: String
Denotes when the Subsystem was last modified.

Querying a Subsystem
We will look at thee methods of querying a Subsystem: As part of an Asset, using the asset query, directly, using the subsystem query with a Subsytem ID, and finally using the subsystems query with a SubsystemFilters object. There are many other possible ways to retrive information about a Subsystem, but they will all follow a similar pattern.

The asset query
If you don’t have the ID for the Subsystem you want to query, you can find it by requesting a target Asset. The following query will return the name of the requested Asset along with an array of any Subsystems associated with the asset. All we need to supply is an asset ID.

Body

query asset($id: ID!) {
	asset(id: $id) {
		name
		subsystems {
			id
			name
			meta {
				icon
				color
				shortName
				order
			}
		}
	}
}

Variables

{
	"id": "2828eca7..."
}

Result

{
	"data": {
		"asset": {
			"name": "Asset 1",
			"subsystems": [
				{
					"meta": {
						"order": 0,
						"shortName": "TSYS",
						"icon": "icon-asset-soil",
						"color": "#6495ed"
					},
					"name": "Test System",
					"id": "aa700d8c..."
				}
			]
		}
	}
}

The subsystem query
If you have the ID of your target Subsystem and want to get more information about that Subsystem, you can use the following query.

Body

query subsystem($id: ID!) {
  subsystem(id: $id) {
		asset {
			name
			id
		}
		assetId
		createdAt
		dashboard {
			id
		}
		id
		meta {
			color
			icon
			order
			shortName
		}
		name
		signals {
			name
			id
		}
		updatedAt
  }
}

Variables

{
	"id": "aa700d8c..."
}

Result

{
	"data": {
		"subsystem": {
			"assetId": "2828eca7...",
			"meta": {
				"order": 0,
				"shortName": "TSYS",
				"icon": "icon-asset-soil",
				"color": "#6495ed"
			},
			"signals": [
				{
					"name": "Test Channel",
					"id": "29053264..."
				}
			],
			"id": "aa700d8c-7eb1-4e97-be77-539ad7197957",
			"updatedAt": "Thu May 11 2023 18:02:28 GMT+0000 (Coordinated Universal Time)",
			"createdAt": "Thu May 11 2023 18:02:28 GMT+0000 (Coordinated Universal Time)",
			"name": "Test System",
			"asset": {
				"name": "Asset 1,
				"id": "2828eca7..."
			}
		}
	}
}

The Subsystems Query (with SubsystemFilters Argument)
The folllowing query takes a slightly different approach. Rather than querying a Subsystem or Asset directly using an ID, this query accepts a SubsystemFilters argument and returns Subsystems that match the variables in the filter. You can provide one or more Asset IDs, an array of Dashboard IDs, or an array of Subsystem IDs, and it returns an array containing Subsystem objects. In the following example, we will supply the query with just one Asset ID.

Body

query subsystems($filters: SubsystemFilters) {
  subsystems(filters: $filters) {
    id
    name
		asset {
			name
			id
		}
  }
}

Variables

{
	"filters": {
		"assetId": "2828eca7..."
	}
}

Result

{
	"data": {
		"subsystems": [
			{
				"asset": {
					"name": "Asset 1",
					"id": "2828eca7..."
				},
				"name": "Test System",
				"id": "aa700d8c..."
			}
		]
	}
}

Creating Subsystems Through Mutations
The following mutations are available for Subsystem operations:
subsystemCreate
subsystemsCreate
subsystemUpdate
subsystemsUpdate
subsystemRemove
subsystemsRemove
subsystemAssociate
subsystemDisassociate

Implementing a Subsystem is done is two steps: first, we create the Subsystem, then we associate the Subsystem with one or more Signals. Subsystems can be create one at a time or in batches. We will only discuss how to create a single Subsystem, using the subsystemCreate mutation, but the process for creating multiple systems at once is very similar. Once our Subsystem is created, we will look at how to associate Signals with it.

The subsystemCreate mutation
The subsystemCreate mutation takes two arguments: an Asset ID (required) and a SubsystemCreate object (required). The SubsystemCreate object contains the following fields:

dashboardId
Type: String
The ID of the dashboard with which you wish to associate the new Subsystem. This field is not required.

meta
Type: Object
A SubsystemMetaInput object contains four fields, color, icon, order, and shortName, which are described above. None are required, and neither is the meta object itself.

name!
Type: String
The name of the Subsystem. This field is required.

The following mutation will create a Subsystem associated with the Asset whose ID starts with “2828eca7…”. We’ll name the Subsystem “Elecrtrical” and assign it a color, icon, and short name. Our next step will be to associate Signals with the Subsystem, so let’s request the assetId and Subsystem id as the return fields for our mutation.

Body

mutation subsystemCreate($assetId: ID!, $subsystem: SubsystemCreate!) {
	subsystemCreate(assetId: $assetId, subsystem: $subsystem) {
		assetId
		id
	}
}

Variables

{
	"assetId": "2828eca7...",
	"subsystem": {
		"name": "Electical",
		"meta": {
			"color": "#0AC410",
			"icon": "icon-asset-energy",
			"shortName": "Elec"
		}
	}
}

Result

{
	"data": {
		"subsystemCreate": {
			"assetId": "2828eca7-efbe-4942-ac46-fab13d36aec5",
			"id": "db151f7c-96c9-46c4-b805-420eb0acc506"
		}
	}
}

The subsystemAssociate Mutation
Now that we have created a Subsystem, we’ll want to associate some Signals with it. The associateSubsystem mutation takes three arguments: an assetId (required), a subsystemId (required), and an array of signalIds (required). In our case, we will supply an array with just one signalId. For return fields, we’ll request the assetId, subsystem id, and the list of signals objects so we can confirm that the Subsystem was associated with the signal we chose. The mutation is as follows:

Body

mutation subsystemAssociate($assetId: ID!, $subsystemId: ID!, $signalIds: [ID!]!) {
	subsystemAssociate(assetId: $assetId, subsystemId: $subsystemId, signalIds: $signalIds) {
		assetId
		id
		signals {
			name
			id
		}
	}
}

Variables

{
	"assetId": "2828eca7...",
	"subsystemId": "db151f7c...",
	"signalIds": ["29053264..."]
}

Result

{
	"data": {
		"subsystemAssociate": {
			"assetId": "2828eca7-efbe-4942-ac46-fab13d36aec5",
			"signals": [
				{
					"name": "Test Channel",
					"id": "29053264-67cd-47f3-950b-d3641923cc46"
				}
			],
			"id": "db151f7c-96c9-46c4-b805-420eb0acc506"
		}
	}
}

Conclusions
In this post, we have examined a Subsystem object, learned how to request information about Subsystems through several different queries, learned how to create a Subsytem using a mutation, and learned how to associated Signals with a Subsystem. If you have further questions, please contact Exosite Support by emailing support@exosite.com.