Octave API Documentation
Octave is the all-in-one edge-to-cloud solution for connecting your industrial assets. Octave makes it easy to securely extract, orchestrate, and act on data from your assets at the edge to the cloud. If you are new to Octave, start with our Developer Hub at docs.octave.dev then come back here when you are ready for detailed API docs.
API Overview
You can use the API to access Octave API endpoints, which allow you to integrate Octave data into your own solution.
Common Object Members
id
Unique object ID. The first letter of the id denotes the object type.
creationDate
Creation date in milliseconds since epoch.
creatorId
Identity object id for the object's creator.
Company
{
"id": "c5ada40be09159f4dde3411ff",
"adminGroupId": "g5ada40be09159f4dde341209",
"creationDate": 1524252862351,
"creatorId": "i5ada408e90f45d18eea0d51f",
"displayName": "Cook County Filtration",
"name": "cook_county_filtration",
"usersGroupId": "g5ada40be09159f4dde34120b"
}
A Company is the base level of organization in Octave. Think of a company as a private namespace within Octave that contains its own set of Devices, Streams, Actions, Connectors. One or many Identities can have access to a Company. Being a member of a Company is signified by being in its User or Admin group.
adminGroupId
Group containing a list of Identities authorized to administer the Company.
displayName
Mutable, human-friendly Company Name
name
Immutable Company name. Used in API calls and defines the root path
under which all company streams reside. Must only contain lowercase letters, numbers, hyphens (-
), and underscores (_
); if provided, uppercase letters will be converted to lowercase, and other unallowed characters will be replaced by underscores.
usersGroupId
Group containing a list of Identities in the Company.
Identity
{
"id": "i5ada408e90f45d18eea0d51f",
"companies": {
"c5ada40be09159f4dde3411ff": "/my_company/users/alice"
},
"creationDate": 1524252814742,
"creatorId": "i00000000000000000000000c",
"email": "an@e.mail",
"groupIds": [
"g5b6b19d1f2978f55113a8572"
],
"masterToken": "I0f33E3mdG8VcLIqLlORFUSD4eprGs9o",
"name": "alice",
"shares": {
"h5b577ddfbf37615498230846": {
"paths": {
"/my_company": {
"administer": true
}
},
"roles": [
"CLOUD_ACTION_READ",
"CLOUD_ACTION_WRITE",
"CLOUD_ACTION_DELETE",
"LOCAL_ACTION_READ",
"LOCAL_ACTION_WRITE",
"LOCAL_ACTION_DELETE",
"BLUEPRINT_READ",
"BLUEPRINT_WRITE",
"BLUEPRINT_DELETE",
"COMPANY_WRITE",
"COMPANY_DELETE",
"COMPANY_MEMBERSHIP_EDIT"
]
}
}
}
Companies
List of Companies to which the Identity belongs.
email
Identity's email address
groupIds
Groups to which the Identity belongs.
masterToken
Authentication Token which inherits all Identity permissions.
name
Unique short name for the Identity, used for created user-owned path
s. Must only contain lowercase letters, numbers, hyphens (-
), and underscores (_
); if provided, uppercase letters will be converted to lowercase, and other unallowed characters will be replaced by underscores.
shares
Shares which have been granted to the Identity.
Event
{
"path": "/my_company/my_first_stream",
"location": {
"lat": 40.703285,
"lon": -73.987852
},
"elems": {
"temp": {
"redSensor": {
"pressure": {
"temp": {
"value": 38.73
}
}
},
"timestamp": 1.531847525135576E9
},
"accel": {
"x": -0.361192,
"y": 1.020188,
"z": 9.7773
},
"timestamp": 1.53184752511122E9
}
}
An Event represents a single entity of data within Octave. It contains a schemaless map of elements. An Event resides within a Stream.
In practice, an Event might be a reading from a light sensor, the response from an external HTTP endpoint, etc. Any complex assortment of related data elements can map to the elements of an Event.
elems
A schemaless map of data elements for the Event.
path
The path of the Stream where the Event is to be written, optional if the streamId is provided in the url of the POST.
location
An optional location for the Event, perhaps corresponding to the location of the device that emitted the Event.
hash
$ curl -XPOST "https://octave-api.sierrawireless.io/v5.0/my_company/event/s53b1d1600cf27b75148de02e" \
-H "X-Auth-User: <user>" \
-H "X-Auth-Token: <token>" \
-d '{
hash: "uniqueVal",
elems: {
measure: 100
}
}'
A hash
field provides a user-controlled mechanism for enforcing uniqueness within a single Stream. It is somewhat analogous to a guaranteed unique database field, with the important difference that its use is optional.
Set a hash by assigning a unique value to the Event field hash
.
Some important points about using hashes:
- For the purposes of handling
hash
uniqueness each Stream is treated as a separate data store.hash
entries in one Stream have no relationship to hash entries in another Stream. - A
hash
value is a freeform string. - It is possible to include both Events with
hash
values and Events withouthash
values in the same Stream. In that case, Events withouthash
values will not participate in any uniqueness checks. - The
hash
value is maintained outside of the Event elems field. - When posting an Event Create message to a Stream which has an existing Event with the identical
hash
the posted Event will be handled as an update rather than a create. This means the Event addressed will have the sameid
as the existing Event.
The hash
field can be used, for example, to maintain a single "last seen" value for a given field.
We repeatedly post a changing value to a single Stream with the same hash
, posting in succession the following values:
{"hash":"currentValue", "elems":{"measure":100}}
{"hash":"currentValue", "elems":{"measure":200}}
{"hash":"currentValue", "elems":{"measure":300}}
{"hash":"currentValue", "elems":{"measure":400}}
after each post the Stream will hold only a single Event holding the value {"measure" : 400}
. The Event creation date will reflect the time of the last write.
Stream
{
"filter": "EXISTS service_available",
"path": "/my_company/raw_messages",
"description": "Raw data from devices, must contain at least a service_available element",
"capacity": 1000
}
Events live in a Stream. A Stream has an event capacity and is similar to a ring buffer. A Stream exists within a namespace specified by its path
field.
description
Optional human-readable description.
path
Streams exist within an hierarchical namespace. Its location within the namespace is its path. The path is always starts with a /
and a company name, and at least one other identifier, with each identifier is separated by a /
, similar to a file system. Identifiers must only contain lowercase letters, numbers, hyphens (-
), and underscores (_
); if provided, uppercase letters will be converted to lowercase, and other unallowed characters will be replaced by underscores.
capacity
The maximum number of Events that can be stored within the Stream. The default value is 1,000, maximum is 100,000. When the Stream exceeds its capacity of Events, older Events will be deleted automatically.
filter
Filters are used to require that Events written to a Stream have specific data elements and values. See the filtering documentation for for more information.
Cloud Action
{
"description": "my cool project",
"source": "/my_company/my_cool_project/incoming",
"filter": "elems.error_rate > 0.1",
"js": "function(input) {
input.elems['needsAttention'] = true;
return {
'/my_company/my_cool_project/high_priority': [input]
};
}"
}
A Cloud Action transforms Events and routes them between Streams. Transformations are done via optional JavaScript.
A Cloud Action specifies a source
Stream and either a js
function or a destination
Stream. If js
is not provided, the Cloud Action will act as a "dumb pipe". If js
is provided, the incoming Event from the source Stream is evaluated against the js
function.
description
Optional human-readable description.
source
The source Stream path or tag-path. Events that are published into this Stream will be monitored by the Cloud Action.
destination
Must be specified if js
is unspecified. An Event written to source
will be written here, subject to filtering.
filter
Filters whether an Event is evaluated by the Cloud Action. See the filtering documentation for for more information.
js
Must be specified if destination
is unspecified. The function must take an Event as input and return a map of destinations to list of Events.
Cloud Connector (Preview)
Cloud Connectors are typed objects, with distinct connector types providing connectivity for specific cloud services. For example, an http-connector is a general purpose connector type for streaming events to an http(s) services. While the overall connector API is uniform and general in nature, each connector type will have its own required and optional properties. These required properties will be noted in type specific documentation for each supported connector type.
We currently support the following connector types:
http-connector
azure-iothub-http-gateway-connector
azure-iothub-http-device-twin-connector
Common Properties
{
"type": "http-connector",
"displayName": "example http connector",
"description": "basic http connector using x-auth header authorization with custom headers",
"source": "/my_company/my_cool_project/incoming",
"filter": "elems.error_rate > 0.1",
"disabled": false,
"headers": {
"x-auth-user": "x-auth-user-value",
"x-auth-token": "x-auth-token-value",
"x-custom-0": "x-custom-0-value",
"x-custom-1": "x-custom-1-value",
"Content-Type": "applications/json"
},
"properties": {
"successCodes": [201, 202, 203, 204, 205],
"method": "POST"
},
"routingScript": "function(event) { return \"https://my.test.server:77\"; }",
"js": "function(event) {
/* any transformation of input event as required */
return { /* return any json to be exported to the defined route */
\"your-key-0\": \"your-value-0\",
\"your-key-n\": \"your-value-n\"
};
}"
}
Defining cloud-connectors is similar to defining cloud-actions: we identify a stream source for events to be processed and define a JavaScript function to transform events.
Unlike Cloud-Actions, Cloud Connectors publish their result to specified service end-points. This target service is either statically defined or dynamically specified via an optional routingScript. For example, in the case of general HTTP based connectors, we provide a second JavaScript function in the routingScript property that returns the destination URL and any necessary headers and/or properties per specific connector type, whereas routing information for distinguished external services (such as Azure Iot Hub) is derived from the general connector properties.
Headers typically include authorization information and properties are connector type specific.
We'll use a basic http-connector
example to note the general and type specific consideration.
type
Required field. The type
of a connector. Supported types are:
http-connector
azure-iothub-http-gateway-connector
azure-iothub-http-device-twin-connector
description
Optional human-readable description.
displayName
Name used to identify the connector in the UI.
source
The source Stream path or tag-path. Events that are published into this Stream will be monitored by the Cloud Connector.
filter
Filters whether an Event is evaluated by the Cloud Connector. See the filtering documentation for more information. Filters are optional.
headers
Headers are static user defined message metadata, analogous to the 'envelope' metadata of messaging protocols. Elements of the headers map are connector type specific. In general, any header defined is passed directly to the corresponding end-point, unless specifically noted in connector type specific documentation.
properties
Properties are used by connectors to configure and/or modify their operation. Elements of the properties map are connector type specific. For example, all http
protocol based connectors require a provided white-list of status codes indicating a"successful" export of an event, beyond the implicit 200
status code. Required properties for each connector type is noted in connector type specific documentation.
js
{
"js": "function(event) {
return {
\"event\": event,
\"your-key-0\": your_value_0,
...
\"your-key-n\": your_value_n
};
}
Required field. A JavaScript function with a single input argument of an Event, return type is a string.
routingScript
Optional field. A JavaScript function with a single input argument of an Event, returning a string representation of a connector type specific end-point address. This may be a static result ignoring the input event, however dynamic routing can be achieved by using data from the input event to compute the route for each sourced event. As of the preview release, the routing script is subject to the same constraints as general action JavaScript functions.
Specific restrictions may apply per specific connector types.
HTTP-Connector
This is a general purpose HTTP based connector (currently only) supporting the (implicit) POST method connectivity to external HTTP endpoints.
The HTTP Connector API refines the above general connector considerations. These refinements are as follows:
type
Type is "http-connector".
routingScript
{
"routingScript": "function(ignored) { return \"https://my.company.com/my-service\"; }"
}
This is a required field for this type of connector, a JavaScript function returning the string representation of the destinations' URL
.
The simplest routingScript
function is a function ignoring the input event and always returning the same URL
.
While it is possible that entirely distinct end-point URL
s can be returned by this function, typically the variation of the URL is the specification of event specific query parameters or distinct services within the same domain.
headers
{
...
"headers": {
"x-some-header": "header value"
},
...
}
All http-connector
definitions must provide a headers
map minimally specifying the standard Content-Type
header. You may also define any other application specific header. Only static header values are currently supported.
Basic static authentication via headers is also supported as a consequence. Headers and header values defined will be passed directly to the specified end-points.
A minimal header definition for http-connector is shown to the right.
properties
{
...
"properties": {
"successCodes": [201, 203],
"method": "POST"
},
...
}
All http-connector
definitions must provide a properties
map minimally specifying the white list of HTTP
status codes to be considered as OK
or "successful". 200/OK
is implicit.
No other properties are currently supported by the general http-connector
type.
A minimal properties definition for http-connector
connecting to a service that only replies with 200/OK
is as follows:
{
...
"properties": {
"successCodes": []
},
...
}
Azure IotHub HTTP Gateway Connector
Iot Hub Connector types allow for publishing to Azure Iot Hub via Iot Hub HTTP REST endpoint. This connector supports authentication via Shared Access Policy keys. All non-IotHub specific considerations are per general connectors, as defined above.
type
Type is "azure-iothub-http-gateway-connector".
properties
The following standard Iot Hub properties allow for authenticating the connector with Azure via SAS tokens. See Shared Access Policy in your Azure Iot Hub portal for obtaining these properties.
This connector assumes the default Shared Access Policy named 'device'. You may optionally defined the policy name via an optional property element, as indicated below.
{
...
"properties": {
"iothub-name": "<required: your iot hub name>",
"shared-access-key": "<required: your iot hub shared access policy key>",
"shared-access-policy-name": "<optional: default policy name is 'device'>"
},
...
}
Azure IotHub HTTP Device Twin Connector
Iot Hub Device Twin Connector
- publishes events from selected streams to Azure Iot Hub via Iot Hub HTTP REST endpoint
- publishes devices tags to Azure Iot Hub device twins via Iot Hub HTTP REST endpoint
- publishes Octave device summary (repoted properties) to Azure Iot Hub device twins
- subscibes for Azure IoT Hub device twin desired properties ( Octave device state )
- forwards commands from Azure Direct Method to the device command stream in Octave
This connector supports authentication via Shared Access Policy keys and device specific Primary Key. All non-IotHub specific considerations are per general connectors, as defined above.
type
Type is "azure-iothub-http-device-twin-connector".
properties
The following standard Iot Hub properties allow for authenticating the connector with Azure via SAS tokens. See Shared Access Policy in your Azure Iot Hub portal for obtaining these properties.
This connector assumes the default Shared Access Policy named 'device'. You may optionally defined the policy name via an optional property element, as indicated below.
{
...
"properties": {
"iothub-name": "<required: your iot hub name>",
"shared-access-key": "<required: your iot hub shared access policy key>",
"shared-access-policy-name": "<optional: default policy name is 'device'>"
"streams" : [
"<stream ABC>",
"<stream XYZ>"
]}
},
...
}
Device
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "d5b3ab093665c5454445234f4",
"avSystemId": "b6961c66c9b544b787d0065f5d193326",
"blueprintId": {
"id": "b5b3ab9d056525434445264b3",
"version": 44
},
"creationDate": 1530572947298,
"creatorId": "i5b2903f6ff127c1f9d80c601",
"dirty": true,
"displayName": "My MangOH Red",
"lastEditDate": 1535122524739,
"lastSeen": 1535381785410,
"localActions": {
"l000000000000000000000000": {
"version": 5
}
},
"localVersions": {
"batteryService": "1.0",
"blueprintVersion": 0,
"io": "0.0.1",
"cloudInterface": "0.0.22",
"lcd": "1.0.0",
"blueprintId": "",
"dataHub": "656360ee655c81c791a741fbce767107",
"redSensor": "3.0",
"util": "1.0.0",
"changeDate": 1535122524739,
"location": "0.0.1",
"actionRunner": "0.0.1",
"firmware": "SWI9X06Y_02.14.04.00"
},
"location": {
"lat": 40.704067,
"lon": -73.989088
},
"name": "my_mangoh_red",
"observations": {
"/util/cellular/signal/value": {
"rx": {
"destination": "store"
},
"er": {
"destination": "cloudInterface"
},
"ecio": {
"destination": "store"
}
}
},
"path": "/my_company/devices/my_mangoh_red",
"state": {
"/util/cellular/signal/period": 3600,
"/cloudInterface/developer_mode/enable": false,
"/cloudInterface/store_forward/period": 43200,
"/util/cellular/signal/enable": true
},
"summary": {
"/redSensor/pressure/temp/trigger": {
"dt": "trigger",
"t": "output",
"m": false
},
"/util/cellular/statistics/trigger": {
"dt": "trigger",
"t": "output",
"m": false
},
"/cloudInterface/connected/value": {
"dt": "boolean",
"t": "input",
"m": false,
"v": true,
"ts": 1535122655000
}
},
"tags": { "location": "nyc" },
"timeSinceLastSeen": 10923849,
"synced": true
}
}
A Device represents a physical device in the world. It contains attributes that the user will set to configure the physical device, and to assign application code which it will execute (in the form of Edge Actions).
The Device object also contains attributes populated by the physical device, indicating its status, the software deployed to the device, and all of its capabilities.
blueprintId
The Blueprint (and version) assigned to the Device.
dirty
Indicates that the device configuration differs from the assigned Blueprint, or that no Blueprint is assigned.
displayName
A friendly name for the Device.
lastSeen
The time the Device last communicated to the cloud.
localActions
Defines the Local Actions (represented by IDs and Versions) to be deployed to the Device.
localVersions
Reported from the Device; which software versions are currently deployed.
location
The location of the Device, set automatically if a GPS / GNSS resource is observed, otherwise set manually.
name
Device name. Final. Must only contain lowercase letters, numbers, hyphens (-
), and underscores (_
); if provided, uppercase letters will be converted to lowercase, and other unallowed characters will be replaced by underscores.
observations
A collection of "routes" from Resources to other Resources, Local Actions, or the Cloud.
path
The path member can be a string of up to 128 characters.
state
The default values assigned to Resources on the Device.
summary
A collection of Resources available on the Device, their types and their latest values.
tags
Map of "tags", to group and categorizes collections of Devices. This map is of type string -> string.
timeSinceLastSeen
Milliseconds since the Device last communicated with the cloud.
synced
Indicates that the configuration loaded on the Device matches what is defined in this object.
Blueprint
{
"id": "b000000000000000000000000",
"companyId": "c000000000000000000000000",
"creationDate": 1530575312073,
"creatorId": "i000000000000000000000000",
"displayName": "My Blueprint",
"lastEditDate": 1532118204711,
"localActions": {
"l000000000000000000000000": {
"version": 1
}
},
"observations": {
"/redSensor/position/value": {
"position": {
"period": 3600,
"destination": "store",
"description": "Send Position Periodically"
}
}
},
"state": {
"/redSensor/position/period": 60
},
"version": 44
}
Blueprints capture a specific Device configuration as a template, which can be assigned quickly to multiple Devices, ensuring they all share the same configuration and behavior.
Configuration includes the Resource state, Observations and Edge Actions assigned to a Device.
Blueprints are versioned and maintain a version history. Common operations include:
- Creating a new Blueprint from the current configuration of a Device
- Creating a new version of an existing Blueprint from the current configuration of a Device
- Creating a new Blueprint manually
- Assigning an existing Blueprint to a Device, at which time the Device will be updated to mirror the configuration defined in the Blueprint
- Reverting a Device which has been assigned a Blueprint, but has since had its configuration changed manually, to the original Blueprint configuration
A Blueprint alone does nothing - it must be assigned to a Device for it to take effect.
displayName
A friendly name for the Blueprint.
localActions
Defines the Local Actions (represented by IDs and Versions) to be deployed to the Device.
observations
A collection of "routes" from Resources to other Resources, Local Actions, or the Cloud.
state
The default values assigned to Resources on the Device.
Edge Action
An Edge Action is like a Cloud Action but runs on physical devices using the "Octave" Edge Package.
An Edge Action transforms Events from Observations and routes them to other Resources, or to the Cloud. Transformations are done via JavaScript. When an Edge action is assigned to a Device, the JavaScript is sent to the Device and loaded. It is bound to a specific Observation, such that when a new Event is created from the Observation, the JavaScript is executed with the Event as the input parameter.
description
Optional human-readable description.
source
The name of the Observation which triggers execution of the Edge Action. Always prefixed with observation://
.
js
The function must take an Event as input and return a map of destinations to list of Events.
Task
{
"displayName": "My Task",
"description": "Periodic task that runs every minute",
"disabled": false,
"source": {
"eventFind": {
"streamId": "s5e5d6db4772f39d6b996da59",
"options": {
"limit": 1
}
}
},
"js": "function(events, resp) { return {'/my_company/task_output': events}; }",
"lastRun": 1593696976481,
"nextRun": 1593697036481,
"periodicity": 60000,
"runCt": 17,
"status": "OK"
}
Tasks are similar to Cloud Actions, but they are executed periodically instead of being triggered by the creation of a Event in a Stream. Hence, a Task enables the periodic execution of transformations on Events (or data from external systems) and storing the results in Streams.
Tasks have a convenience source
property that allows specifying how to retrieve the data that will be fed to the js
function. Supported sources are eventFind
(equivalent to an Octave.Event.find()
call), and http
(equivalent to an Octave.http.*
call plus optional jsonpath
, xpath
or rss
parsing.) See Source object for more details.
Similar to Cloud Actions, a destination
can be provided instead of js
to have the source Events routed directly to a Stream without transformation.
displayName
Optional human-friendly name.
description
Optional human-readable description.
disabled
Boolean indicating whether the Task is enabled or not, in which case it won't be run.
source
Defines declaratively how data will be ingested into the Task's JavaScript function. If unspecified, the Task JavaScript will be executed with empty input arguments. See Source object for more details.
destination
Must be specified if js
is unspecified. Path where processed events will be written to.
js
Must be specified if destination
is unspecified. The function must take a list of Events (it will contain the retrieved/parsed events if a source was specified) and a raw reponse object (for http
sources, it will contain the raw HTTP response object) as input and return a map of destinations to list of Events.
lastRun
Time of the last Task execution in milliseconds since epoch.
nextRun
Time of the next planned Task execution in milliseconds since epoch.
periodicity
The amount of milliseconds between two succesive task runs. The minimum allowed value is 20000.
runCt
The number of times the Task has been run.
status
State of the last Task execution: OK
(successful run), ERROR
(there was an error executing the Task) or NO_NEW_DATA
(if the events returned from task execution were already contained in the previous execution's results.)
Group
{
"displayName": "Research Team",
"description": "Members of Project Team Y",
"memberIds": [
"i5488db43d4c63a633ad84bcc",
"i5489e275d4c6f62700be9fd6"
]
}
A Group is a collection of identities. Groups exist for the purpose of issuing Shares to them.
A Group's memberIds
field is mutable. Adding or removing an Identity from a Group will update that Identity's permissions automatically. You can only add existing members of the Company to the Group.
memberIds
A list of Identities corresponding to the members of the Group.
displayName
A descriptive name for the Group
description
Further information used to describe the Group
Share
{
"issuedTo": "g548b1c1bd4c607c7716e4ac2",
"paths": {
"/my_company/foo" : {
"read" : true,
"write": true,
"eventRead": true,
"eventWrite": true
},
"/my_company/bar" : {
"read" : true,
"write": false,
"eventRead" : true,
"eventWrite": false
}
}
}
A Share grants access to particular resources and actions to existing Identities. This access is provided through a combination of path-based permissions and non-path-based "roles". Shares may be revoked at any time. They also can be timebound.
issuedTo
An id corresponding to the Group being issued the Share. The Group being issued the Share must be a member of the Company in which the Share is being created. Assigning more than one share to a group is not allowed. Shares without a duration can be merged into one. Shares with a duration should be exclusively assigned to a new group.
paths
A map of paths and tag-paths to their Permissions. In this way, each path can have a unique permission set. Permissions are recursive.
roles
A list of additional, non-path-based actions available to the Identity.
duration
Lifespan of Share in milliseconds.
Token
A Token provides anonymous Event read and write access to a subset of your Company's namespace. They are ideally suited, for example, for web applications which need Event read or write access only to a few specific Streams. Tokens may be revoked at any time. Tokens may also have a duration
.
To use a Token, supply the Token String in the same way as you would supply the Master Token - within the X-Auth-Token
header and omit the X-Auth-User
header.
{
"tokenString": "SSOjDZ4VMHS2JcwT1sIpE8x91QfG",
"paths": {
"/my_company/foo" : {
"eventRead" : true,
"eventWrite": true
},
"/my_company/bar" : {
"eventRead" : false,
"eventWrite": true
}
}
}
paths
A map of paths and tag-paths to their Permissions. In this way, each Path can have a unique Permission set. Permissions are recursive.
duration
Lifespan of Token in milliseconds.
Firmware
{
"version": "1.2.3"
}
A Firmware represents a firmware version that available for edge devices. A Firmware object may be either available for all companies (if its attribute companyId
is null
or not set) or only to a specific to a company (the one indicated by a non-null companyId
.)
version
The firmware version.
Release Note
{
"notes": "# Octave API version 5.3.1....",
"version": "1.0.0"
}
A Release Note contains information about a version of the Octave API. A Release Note object may be either available for all companies (if its attribute companyId
is null
or not set) or only to a specific to a company (the one indicated by a non-null companyId
.)
version
The related Octave API version
notes
A Markdown text describing of the version's release notes.
Authentication
REST and WebSocket requests are authorized using an account name and token combination.
Each account has a Master Token which can be retrieved via the Octave User Interface.
To retrieve your master token, go to the lower left of the user interface and select “Master Token”.
Retrieve Account info with Master Token
curl "https://octave-api.sierrawireless.io/v5.0/global/identity" \
-H "X-Auth-User: <your_user_name>" \
-H "X-Auth-Token: <your_token>"
The above will return:
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
<your identity object>
]
}
You can use the /global/identity
endpoint to easily retrieve all information about your account, including all of the groups, companies, and shares you belong to.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/global/identity
Edge Application Development
Edge Applications
// How to Observe the Temperature
"/sensors/temperature/value": {
"my_temperature_observation": {
// Every 60 seconds
"period" : 60,
// Only if greater than or equal to 30 deg C
"gte" : 30,
// Send directly to the Cloud
"destination" : "cloudInterface"
}
}
Octave allows developers to deploy powerful applications to edge devices without the need to do system programming in a low level language such as C or C++.
Sensors and Actuators attached to the device are treated as first class services known as Resources. It is easy to read from and write to Resources, as though you were reading directly from a file or socket.
Octave leverages the Event Driven model of writing software. Sensors are simply sources (or Resources in our terminology) that generate readings (Events). These Events flow through a pipeline that might contain filters, buffers or rate-limiters (Observations). You may wish to execute arbitrary JavaScript code on Events in the pipeline (Edge Actions), which can transform and perform conditional logic. Finally, Events can be pushed directly to Actuators or sent to the Cloud for further processing.
Rather than writing procedural system-level C code to read a sensor, Octave provides declarative, rules based Observations for defining how and when the sensor should be read, and where the readings should be pushed. Declarative rules are easier to reason about, easily testable, and more flexible than procedural code.
Once the Event has be generated, it can:
- Be sent directly the the Cloud
- Be sent locally to another Resource, such as an LCD or serial port
- Trigger the execution of a JavaScript function, loaded locally on the device
- Stored in a buffer, of arbitrary size, for querying later
Moving data from Device to Cloud is a critical use case for most developers. With Octave, sending data to the Cloud can be as simple as setting a single attribute in an Observation. Developers can also instruct when the data should be sent - immediately, or store and forward when the device next heartbeats.
Glossary
Resource
A sensor (input), an actuator (output), or a variable for storage or configuration. Similar to the unix filesystem.
Resource Tree
The collection of Resources available on a Device
Resource Configuration
The initial value a Resource will take when the Device is powered on, used to configure sensors and actuators.
Event
A timestamped value generated from a Resource (such as a sensor) or sent to a Resources (such as an actuator).
Observation
A pipe from a Resource to another Resource, the Cloud, buffer, or JavaScript function. Events will flow through the Observation
Edge Action
Arbitrary JavaScript function, executed when an Event is generated from an Observation. Can transform or generate further Events.
Store and Forward
Events will be held locally for a set period, before sending as a batch to the Cloud.
Connectivity
Your physical device is not always connected to the cellular network. Cellular connectivity increases power and data consumption of the device, so we want to be certain it is only connected when required.
There are some key concepts to explain how and when a Device is connected:
Pushing Events to the Cloud
If and when an Event is ready to be pushed directly to the Cloud, we immediately establish a connection. The connection will stay open if further Events are available within a short period of time, otherwise it will be closed.
Store and Forward
If the user is using Store and Forward to send Events to the Cloud, we will wait until the specified time period before establishing a connection and sending all stored Events.
Heartbeat
By default, the Device will establish a connection after a specified timeout, regardless of Events waiting to be sent to the Cloud, in order to check in with the server. This can be configured or disabled.
Pushing Configuration to the Device
Configuration changes (Resource Configuration, Observations and Edge Action changes) can only be delivered to the Device when a connection is open.
Developer Mode
The Device, by default, is configured to be in Developer Mode. This keeps a connection open with the server continuously, so that Device Configuration (see above) can be delivered immediately. During Developer Mode, the Device also frequently transmits the Resource Tree to the Octave servers, so the latest information about the Device is available to the user. By default, Developer Mode will remain enabled so long as Device Configuration is being pushed to the Device. After a period of inactivity, it will be disabled and connectivity management will follow the rules described above.
Developer Mode is useful for when writing, testing and debugging Edge applications. In deployment, devices should have Developer Mode disabled.
Device Resources
A Resource is a node in a Resource Tree, representing a "thing" that creates, receives, or stores Events. Because it lives in a tree, each Resource will have a Path that identifies its location, such as /sensors/light/value
or /lcd/line1
.
Resources have a type - they are either Inputs or Outputs. Inputs will generate new Events from the underlying application or hardware. Sensors are tied to inputs. Outputs will forward Events to the application or Hardware. Actuators are outputs.
A Sensor or Actuator will normally expose multiple Resources, for direct access to the hardware, and configuration. Here is an example:
Path | Type | Data Type | Mandatory | Default Value |
---|---|---|---|---|
/sensor/light/value | input | numeric | - | - |
/sensor/light/enable | output | boolean | false | false |
/sensor/light/period | output | numeric | true | - |
/sensor/light/calibration | output | json | false | {min: 1234, max:5678} |
The value
Resource is the standardized naming convention for the Resource which generates the Events the Sensor is named for. So in this example, /sensor/light/value
will generate light readings.
The Sensor also exposes other resources for configuration. The period
Resource accepts a numeric value (in seconds) for how frequently the hardware should be polled, and emit a new Event on the value
Resource. Interrupt-based sensors, such as alarms, might not have this Resource. The Sensor driver has marked this Resource mandatory, indicating that a numeric value must be sent to this Resource for the Sensor to work.
The enable
Resource allows the system to turn the Sensor on or off.
The calibration
Resource allows the system to provide calibration information to the driver. It is marked non-mandatory, so the Sensor can be used without providing this information. If a value is not provided, it will default to the Default Value. The Resource has a Data Type json, indicating that it receives a string value containing valid JSON.
// The Device summary attribute lists the Resources
"summary": {
"/redSensor/light/enable": {
"dt": "boolean",
"t": "output",
"m": true,
"v": true,
"ts": 1535045368000
},
"/redSensor/light/value": {
"dt": "numeric",
"t": "input",
"m": false,
"v": 1700,
"ts": 1535466998000
},
"/redSensor/light/period": {
"dt": "numeric",
"t": "output",
"m": true,
"v": 5,
"ts": 1535045403000
}
...
}
// The Device state attribute sets the values
"state" {
"/redSensor/light/enable" : true,
"/redSensor/light/period" : 60
}
Your Device will initially broadcast its Resource Tree, such that it is available to view using the Octave REST API, on the Device object. See the Devices page for more details.
Resource Configuration
Before the Light Sensor can do work, we must configure the output Resources enable
and period
. To do so, we must push a new Event to the Resource. We have two methods of doing this:
- Push the value now
- Push the value now, and every time the Device powers on
Option 2 is our more preferred approach, and involves adding our values to the Device.state
object.
The Device object has a state
attribute, which contains a map of keys (Resource path) and associated values. Any updates to Resource Configuration, Observations or Edge Actions will be sent to the Device when it is next connected to the cellular network, and then persisted locally such that it will survive restarts.
Device Observations
{
"/redSensor/light/value" : {
"my_observation" : {
"destination" : "cloudInterface",
"period" : 200,
"gte" : 32.1
}
}
}
Once we have configured and enabled our Light Sensor, the Sensor will begin taking readings, but those readings will not go anywhere or do anything. We must create an Observation. Some things we may want an Observation to do:
- Send the Events to the Cloud
- Buffer the Events, to query them later
- Send the Events to another Resource, e.g.
/lcd/txt1
- Send the Events to an Edge Action
- Filter the Events against thresholds, or hysteresis
- Rate-limit the Events
Observations have the following properties:
Property | Mandatory | Data Type | Example | Description |
---|---|---|---|---|
Source | Yes | String | /sensors/light/value |
The Resource which generates the Events |
Name | Yes | String | my_observation |
A unique name |
Destination | No | String | cloudInterface |
Where to send the Events. If empty, the will be stored for later querying |
Period | No | Integer | 200 |
Rate-limits incoming Events |
Less Than Equal | No | Float | 15.5 |
Forward only if Event value is less than or equal to this threshold |
Greater Than Equal | No | Float | 32.1 |
Forward only if Event value is greater than or equal to this threshold |
Step | No | Float | 2.0 |
Forward only if Event value has changed by at least this threshold |
Select | No | String | x |
For Events that are JSON: extract this key from the Event |
Sending an Individual Command
{
"metadata" : {
"ttl" : 60000
},
"elems": {
"/redSensor/light/period" : 10,
"/lcd/txt1" : "Hello World!"
}
}
{
"metadata" : {
"timeout" : 1598292125
},
"elems": {
"/redSensor/light/period" : 10,
"/lcd/txt1" : "Hello World!"
}
}
To send an individual command to a device, such as setting a resource value or configuration, add an Event to the /<company_name>/devices/<device_name>/:command
Stream. Within the Event Elements, keys are the Resource Paths, and values are the values to be pushed.
Values are pushed to each Resource referenced in the Command. However, those values will be applied once-only. When the device reboots, the Resources will be set with their original values as defined in the Device.state
attribute.
The user can specify a timeout
or time-to-live (ttl
). Octave will attempt to deliver the Command to the device until it succeeds, or the timeout is exceeded. Timeout and TTL are defined as attributes of the Event.metadata field:
Property | Description |
---|---|
timeout | Unix Epoch Time (milliseconds). Absolute time, after which we no longer try to deliver the Command |
ttl | Duration (milliseconds). Relative time, after which we no longer try to deliver the Command |
The user may specify one of these attributes, or none (defaults to "no timeout"). If an invalid value is supplied, it is treated as "no timeout". If both attributes are supplied, Octave will use the timeout
value.
Command Notifications
{
"elems": {
"action": "COMMAND_START",
"kind": "NOTIFICATION",
"details" : {
"eventId" : "e5b5203a790f45d5437c4e35c",
"streamId": "s5e4c41c5680fcd35eadf0fc1"
},
"type": "device"
}
},
{
"elems": {
"action": "COMMAND_COMPLETE",
"kind": "NOTIFICATION",
"details" : {
"eventId" : "e5b5203a790f45d5437c4e35c",
"streamId": "s5e4c41c5680fcd35eadf0fc1"
},
"type": "device"
}
},
{
"elems": {
"action": "COMMAND_FAULT",
"kind": "NOTIFICATION",
"details" : {
"reason": "Command not delivered due to expired timeout",
"eventId" : "e5b5203a790f45d5437c4e35c",
"streamId": "s5e4c41c5680fcd35eadf0fc1"
}
"type": "device"
}
}
Notifications are generated in the Device Inbox /<company_name>/devices/<device_name>/:command
Stream for the following:
Action | Description |
---|---|
Command Start | A Command has been created, is awating delivery |
Command Finish | A Command has been delivered and executed |
Command Failed | Octave has failed to deliver the Command |
Analog & Digital IO
IO Service
The Octave edge package provides an IO Service which enables remote and dynamic configuration of the analog and digital inputs and outputs present on the edge device.
Connecting IO pins to Octave is as simple as sending a configuration to the IO Service that defines the settings for the IO pin you'd like to connect (directionality, internal resistors, etc), and how that IO should be mapped as a Resource.
Types of Resources
Digital Input (GPIO)
GPIO pins configured as inputs in Octave will report their value as true
or false
depending on if the voltage is above or below the midpoint of a voltage range (within some tolerance). This range varies by pin and will be specified below. Internal pull-up or pull-down resistors can also be enabled.
If edge detection is enabled, the IO Service will update the value of the digital input and emit an event to any Observation attached to the Resource any time the state changes from high to low, or vice versa. Without edge detection, you must configure a period
on your IO Resource and the IO Service will report a boolean value at the specified periodicity. This "interrupt" functionality can be very useful when detecting events like a button push or switch throw that you might otherwise miss between polls when observing boolean values at a set period
.
Digital Output (GPIO)
Digital Output pins are also represented as boolean values. When these Resources are set, they drive a low or high output voltage over the pin. Common use cases for Digital Output pins include lighting an LED or controlling a relay.
Analog Input (ADC)
Depending on your hardware, 1 or more Analog to Digital Converters are available for converting the sensed voltage on a particular pin to a numeric Resource value.
Identifying GPIO Pins
MangOH Red "Hat"
The RPi Hat pins on the MangOH Red can be used to connect Digital Input and Output. The diagram below illustrates the GPIO pins available to the Octave IO Service (WP_GPIO 1, 2, 3, and 8) as well as current sources and ground. The voltage range for Digital Inputs on these pins is 3.3 volts.
IoT Card Proto Board
Your MangOH red kit will come with a prototyping board that fits into the IoT Expansion Slot. The pins on this card provide access to both digital input/output and a single analog input. The diagram below illustrates the GPIO pins available to the Octave IO Service (GPIO 1, 2, 3, 4 and ADC0) as well as current sources and ground. The voltage range for Digital Inputs on these pins is 1.8 volts.
MangOH Low Power IO
The MangOH Red CN312 pin out has two additional Analog inputs, as well as a 1.8 volt current source. The diagram below documents the Low Power IO pinout.
Configuring (GUI)
The IO Service can be configured at by navigating to Device -> Services and selecting "Configure the IO Service on this Device".
Next select "configure the io service on this device"
In the IO Service configuration view, you can select the type of input to add.
On the next screen, you'll want to pay attention to the "RESOURCE PATH" option. By default the Resource created by the IO service will share the name of the pin that it connects. However, it's usually much more practical to use short name that describes what you are actually connecting. For example red_led
might make sense for a digital output connected to an LED, while photoresistor
might make sense for an analog input name.
Once you've configured your IO you'll return to the IO Service screen, with your newly created IO item listed. Note that the path provided in the previous step has been prepended with /io
.
If we look under /io
in the Resource screen we should see our newly added IO has appeared as a Resource. From here we can treat this Resource like any other. We'll likely want to configure it, set a polling period, and follow that with some Observations.
Device Object
Creating a Device
## Create Device
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/device/provision" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"name": "device name",
"imei": "352653090106733",
"fsn": "VU810385240210"
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "o5df3fd00b03f0746a3bd0dc4",
"action": "PROVISION",
"companyId": "c5b5203a790f45d5437c4e35b",
"complete": false,
"creationDate": 1576271104719,
"creatorId": "i5dea9ae317900a4b57f95b39",
"details": {
"device_details": {
"fsn": "VU810385240210",
"imei": "352653090106733"
}
},
"deviceIds": [
"d5df3fd00b03f0746a3bd0d9f"
],
"state": "STARTED",
"status": {},
"timeout": 86400
}
}
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/device/provision
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Value |
---|---|---|
name | string | Device name. Must only contain lowercase letters, numbers, hyphens (- ), and underscores (_ ); if provided, uppercase letters will be converted to lowercase, and other unallowed characters will be replaced by underscores. |
imei | string | IMEI of the Device |
fsn | string | Serial number of the Device |
Creating Many Devices in Bulk
## Create Devices in Bulk
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/device/provision/bulk" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: multipart/form-data' \
-F 'file=@provision.csv'
{
"head": {
"status": 201,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "o5f735c775811b4d33723d3b7",
"action": "PROVISION",
"companyId": "c5b5203a790f45d5437c4e35b",
"complete": false,
"details": {},
"deviceIds": [],
"state": "UNKNOWN",
"stepCount": 1,
"timeout": 0
}
}
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/device/provision/bulk
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
CSV File Contents
The CSV file contains the following column headers:
Name | Required? | Type | Value |
---|---|---|---|
IMEI | true | string | IMEI of the Device |
FSN | true | string | Serial Number of the Device |
NAME | true | string | Device name |
DISPLAY_NAME | false | string | The Display name of the Device |
BLUEPRINT_ID | false | string | ID of the Blueprint to apply to this Device |
BLUEPRINT_VERSION | false | int | Version of the Blueprint to apply to this Device |
DEPLOY_FIRMWARE | false | bool | Should the firmware attached to the supplied Blueprint be installed? Default = false |
TAG.(key) | false | string | Replace (key) with the Tag key you wish to apply to the Device. Multiple Tag columns can be specified |
METADATA.(key) | false | json | Replace (key) with the Metadata key you wish to apply to the Device. Multiple Metadata columns can be specified |
Required columns must be included in the CSV file, and values must be included for each row. For optional columns, values can be left blank, or alternatively the column may be ommitted entirely.
Column headers are case sensitive.
Tag and Metadata columns are special - the user may supply any number of them so long as they are unique. Examples include:
Example Column | Example Value |
---|---|
TAG.foo | bar |
TAG.location | NYC |
METADATA.color | orange |
METADATA.size | "medium" |
METADATA.foo.bar | ["a",true,1.2] |
Octave will attempt to parse metadata values as JSON. Failing that, they will be read as a string.
Some columns are conditional on others. For example, BLUEPRINT_VERSION and DEPLOY_FIRMWARE cannot be included without BLUEPRINT_ID.
IMEI, FSN, and NAME values must be unique.
Query Parameters
Key | Type | Value |
---|---|---|
simulate | bool | If true, perform validation on CSV input but don't provision Devices. Default = false |
Listing company Devices
## List Devices
curl "https://octave-api.sierrawireless.io/v5.0/my_company/device" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": [
{
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "d5b3ab093665c5454445234f4",
"avSystemId": "b6961c66c9b544b787d0065f5d193326",
"blueprintId": {
"id": "b5b3ab9d056525434445264b3",
"version": 44
},
"creationDate": 1530572947298,
"creatorId": "i5b2903f6ff127c1f9d80c601",
"dirty": true,
"displayName": "My MangOH Red",
"lastEditDate": 1535122524739,
"lastSeen": 1535381785410,
"localActions": {
"l000000000000000000000000": {
"version": 5
}
},
"localVersions": {
"batteryService": "1.0",
"blueprintVersion": 0,
"io": "0.0.1",
"cloudInterface": "0.0.22",
"lcd": "1.0.0",
"blueprintId": "",
"dataHub": "656360ee655c81c791a741fbce767107",
"redSensor": "3.0",
"util": "1.0.0",
"changeDate": 1535122524739,
"location": "0.0.1",
"actionRunner": "0.0.1",
"firmware": "SWI9X06Y_02.14.04.00"
},
"location": {
"lat": 40.704067,
"lon": -73.989088
},
"name": "my_mangoh_red",
"observations": {
"/util/cellular/signal/value": {
"rx": {
"destination": "store"
},
"er": {
"destination": "cloudInterface"
},
"ecio": {
"destination": "store"
}
}
},
"path": "/my_company/devices/my_mangoh_red",
"state": {
"/util/cellular/signal/period": 3600,
"/cloudInterface/developer_mode/enable": false,
"/cloudInterface/store_forward/period": 43200,
"/util/cellular/signal/enable": true
},
"summary": {
"/redSensor/pressure/temp/trigger": {
"dt": "trigger",
"t": "output",
"m": false
},
"/util/cellular/statistics/trigger": {
"dt": "trigger",
"t": "output",
"m": false
},
"/cloudInterface/connected/value": {
"dt": "boolean",
"t": "input",
"m": false,
"v": true,
"ts": 1535122655000
}
},
"tags": { "location": "nyc" },
"timeSinceLastSeen": 10923849,
"synced": true
},
...
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/device
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Reading a Device
## Read Device
curl "https://octave-api.sierrawireless.io/v5.0/my_company/device/d5b730d2f6f3861bb4e95f51c" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "d5b3ab093665c5454445234f4",
"avSystemId": "b6961c66c9b544b787d0065f5d193326",
"blueprintId": {
"id": "b5b3ab9d056525434445264b3",
"version": 44
},
"creationDate": 1530572947298,
"creatorId": "i5b2903f6ff127c1f9d80c601",
"dirty": true,
"displayName": "My MangOH Red",
"lastEditDate": 1535122524739,
"lastSeen": 1535381785410,
"localActions": {
"l000000000000000000000000": {
"version": 5
}
},
"localVersions": {
"batteryService": "1.0",
"blueprintVersion": 0,
"io": "0.0.1",
"cloudInterface": "0.0.22",
"lcd": "1.0.0",
"blueprintId": "",
"dataHub": "656360ee655c81c791a741fbce767107",
"redSensor": "3.0",
"util": "1.0.0",
"changeDate": 1535122524739,
"location": "0.0.1",
"actionRunner": "0.0.1",
"firmware": "SWI9X06Y_02.14.04.00"
},
"location": {
"lat": 40.704067,
"lon": -73.989088
},
"name": "my_mangoh_red",
"observations": {
"/util/cellular/signal/value": {
"rx": {
"destination": "store"
},
"er": {
"destination": "cloudInterface"
},
"ecio": {
"destination": "store"
}
}
},
"path": "/my_company/devices/my_mangoh_red",
"state": {
"/util/cellular/signal/period": 3600,
"/cloudInterface/developer_mode/enable": false,
"/cloudInterface/store_forward/period": 43200,
"/util/cellular/signal/enable": true
},
"summary": {
"/redSensor/pressure/temp/trigger": {
"dt": "trigger",
"t": "output",
"m": false
},
"/util/cellular/statistics/trigger": {
"dt": "trigger",
"t": "output",
"m": false
},
"/cloudInterface/connected/value": {
"dt": "boolean",
"t": "input",
"m": false,
"v": true,
"ts": 1535122655000
}
},
"tags": { "location": "nyc" },
"timeSinceLastSeen": 10923849,
"synced": true
}
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/device/<device_identifier>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Updating a Device
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/device/d5b730d2f6f3861bb4e95f51c" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"displayName": "Testing MangOH Red",
"state": {
"/util/cellular/signal/period": 7200,
"/cloudInterface/developer_mode/enable": true,
"/cloudInterface/store_forward/period": 43200,
"/util/cellular/signal/enable": true
}
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "d5b730d2f6f3861bb4e95f51c",
... <snip> ...
"state": {
"/util/cellular/signal/period": 7200,
"/cloudInterface/developer_mode/enable": true,
"/cloudInterface/store_forward/period": 43200,
"/util/cellular/signal/enable": true
}
}
}
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/device/<device_identifier>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
For a full overview of all Device attributes, see the Device Object Overview.
Key | Type | Value |
---|---|---|
displayName | string | A friendly name for the Device |
state | object | The default values assigned to Resources on the Device |
Moving a Device to another Company
Devices can be moved to other Companies of which the requesting user is a member.
Transforming Device Attributes
When moving a Device between Companies the following tranformations can be specified.
- Device
name
: A new name may be specified. - Device
blueprint
: A Blueprint from the destination Company can designated to be applied as part of the transfer.
Rules for Moving Devices
- The user must have appropriate permissions to delete the Device within the originating Company, and also to create the Device in the destination Company.
- If the user has not requested a Blueprint to be applied to the Device, the Device will retain any Resource value settings (as part of the
state
attribute) and Observations (as part of theobservations
attribute). Edge Actions will not be copied to the Device as part of the transfer, since they are tied to the originating Company. - The Device will retain its original ID, but will be moved to the new Company.
- The full Device Configuration data will be sent to physical device.
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/device/transfer" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"deviceIds" : ["d5f11ecaf1d8f562eb4821ace", "d5bd06e3ebd1f816495786271"],
"companyId" : "c5bae617e90f45d7d11710087",
"transform" : {
"d5f11ecaf1d8f562eb4821ace" : {
"name" : "my_new_device_name",
"blueprintId" : {
"id" : "b5c37879220721249d5c8ffa3",
"version" : 3
},
"deployFirmware" : false
}
}
}
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "o5f189c29dccf28c9f178e576",
"action": "TRANSFER_DEVICE",
"companyId": "c5b5203a790f45d5437c4e35b",
"complete": false,
"creationDate": 1595448361168,
"creatorId": "i5adf463709159f4dde43a86f",
"details": {
"companyId": "c5bae617e90f45d7d11710087",
"transform" : {
"d5f11ecaf1d8f562eb4821ace" : {
"name" : "my_new_device_name",
"blueprintId" : {
"id" : "b5c37879220721249d5c8ffa3",
"version" : 3
},
"deployFirmware" : false
}
}
},
"deviceIds": [
"d5f11ecaf1d8f562eb4821ace",
"d5bd06e3ebd1f816495786271"
],
"lastEditDate": 1595448361168,
"lastEditorId": "i5adf463709159f4dde43a86f",
"state": "UNKNOWN",
"status": {
"d5f11ecaf1d8f562eb4821ace": {
"MOVE_DEVICE": {
"state": "UNKNOWN",
"ts": 1595448361166
},
"PUSH_CONFIGURATION": {
"state": "UNKNOWN",
"ts": 1595448361166
}
},
"d5bd06e3ebd1f816495786271": {
"MOVE_DEVICE": {
"state": "UNKNOWN",
"ts": 1595448361166
},
"PUSH_CONFIGURATION": {
"state": "UNKNOWN",
"ts": 1595448361166
}
}
}
}
}
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/device/transfer
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Value |
---|---|---|
deviceIds | array | Required. A list of Device IDs to be moved |
companyId | string | Required. The ID of the Company the Devices shall be moved to |
transform | map | Optional. Options for per-Device transformations |
transform.<device-id>.name | string | Optional. The new name of the Device |
transform.<device-id>.blueprintId | map | Optional. The Blueprint to apply to the Device |
transform.<device-id>.deployFirmware | bool | Optional. Should the firmware attached to the supplied Blueprint be installed? Default = false |
Query Parameters
Parameter | Default | Description |
---|---|---|
simulate | false | Validate request and show potential response, but don't perform the transfer |
Deleting a Device
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/device/d5b730d2f6f3861bb4e95f51c" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/device/<device_identifier>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Stream Object
Creating a Stream
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/stream" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"path": "/my_company/streamName",
"description": "My New Stream"
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "s5b730d2f6f3861bb4e95f51c",
"capacity": 1000,
"companyId": "c000000000000000000000006",
"creationDate": 1534266671309,
"creatorId": "i000000000000000000000064",
"description": "My New Stream",
"path": "/my_company/streamname"
}
}
You can create a stream at any path where you have permissions.
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/stream
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Value |
---|---|---|
path | string | Required. The path member can be a string of up to 128 characters. Path segments must only contain lowercase letters, numbers, hyphens (- ), and underscores (_ ); if provided, uppercase letters will be converted to lowercase, and other unallowed characters will be replaced by underscores. |
capacity | int | Optional; defaults to 1,000. The maximum number of Events stored within the Stream. |
description | string | Optional. Human-friendly description |
filter | string | Optional. A filter which is used as a pass/fail test for writing new Events to the Stream. |
Listing company Streams
## List Streams
curl "https://octave-api.sierrawireless.io/v5.0/my_company/stream" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "s5b730d2f6f3861bb4e95f51c",
"capacity": 100000,
"companyId": "c000000000000000000000006",
"creationDate": 1534266671309,
"creatorId": "i000000000000000000000064",
"description": "My New Stream",
"lastEditDate": 1534266950758,
"path": "/my_company/streamname"
},
...
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/stream
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Reading a Stream
## Read Stream
curl "https://octave-api.sierrawireless.io/v5.0/my_company/stream/s5b730d2f6f3861bb4e95f51c" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "s5b730d2f6f3861bb4e95f51c",
"capacity": 100000,
"companyId": "c000000000000000000000006",
"creationDate": 1534266671309,
"creatorId": "i000000000000000000000064",
"description": "My New Stream",
"lastEditDate": 1534266950758,
"path": "/my_company/streamname"
}
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/stream/<stream_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Updating a Stream
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/stream/s5b730d2f6f3861bb4e95f51c" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"capacity": 100000
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "s5b730d2f6f3861bb4e95f51c",
"capacity": 100000,
"companyId": "c000000000000000000000006",
"creationDate": 1534266671309,
"creatorId": "i000000000000000000000064",
"description": "My New Stream",
"lastEditDate": 1534266950758,
"path": "/my_company/streamname"
}
}
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/stream/<stream_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Value |
---|---|---|
capacity | int | The maximum number of Events stored within the Stream. |
description | string | Human-friendly description |
filter | string | A filter which is used as a pass/fail test for writing new Events to the Stream. |
Deleting a Stream
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/<company_name>/stream/s5b730d2f6f3861bb4e95f51c" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/stream/<stream_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Event Object
Creating an Event
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/event/s5b7310ae6f38613585853e5b" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"elems": {
"measure": 7
}
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "e5b7311856f38613585853e61",
"streamId": "s5b7310ae6f38613585853e5b",
"creationDate": 1534267781805,
"generatedDate": 1534267781805,
"path": "/my_company/streamname",
"version": 0,
"elems": {
"measure": 7
}
}
}
You can create an event in any stream for which you have eventWrite permission.
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Request JSON Object
Key | Type | Value |
---|---|---|
elems | object | Schemaless event data |
Reading an Event
curl "https://octave-api.sierrawireless.io/v5.0/my_company/event/s5b7310ae6f38613585853e5b/e5b7311856f38613585853e61" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "e5b7311856f38613585853e61",
"streamId": "s5b7310ae6f38613585853e5b",
"creationDate": 1534267781805,
"generatedDate": 1534267781805,
"path": "/my_company/streamname",
"version": 0,
"elems": {
"measure": 7
}
}
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>/<event_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Updating an Event
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/event/s5b7310ae6f38613585853e5b/e5b7311856f38613585853e61" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"elems": {
"measure": 10
}
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "e5b7311856f38613585853e61",
"streamId": "s5b7310ae6f38613585853e5b",
"lastEditDate": 1534268183964,
"path": "/my_company/streamname",
"version": 0,
"elems": {
"measure": 10
}
}
}
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>/<event_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Request JSON Object
Key | Type | Value |
---|---|---|
elems | object | Schemaless event data |
Deleting an Event
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/event/s5b7310ae6f38613585853e5b/e5b7311856f38613585853e61" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>/<event_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Bulk Deleting all Events in Stream
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/event/s5b7310ae6f38613585853e5b" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resources have been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Find Events By Stream ID
curl "https://octave-api.sierrawireless.io/v5.0/my_company/event/s5b7310ae6f38613585853e5b" \
-H 'x-auth-user: <user>' \
-H 'x-auth-token: <token>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "e5b7311856f38613585853e61",
"streamId": "s5b7310ae6f38613585853e5b",
"creatorId": "i000000000000000000000001",
"metadata": null,
"creationDate": 1534267781805,
"generatedDate": 1534267781805,
"lastEditDate": null,
"path": "/my_company/streamname",
"hash": null,
"elems": {
"measure": 7
}
},
[...]
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Find Events By Stream Path
curl "https://octave-api.sierrawireless.io/v5.0/my_company/event?path=/my_company/streamname" \
-H 'x-auth-user: <user>' \
-H 'x-auth-token: <token>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "e5b7311856f38613585853e61",
"streamId": "s5b7310ae6f38613585853e5b",
"creatorId": "i000000000000000000000001",
"metadata": null,
"creationDate": 1534267781805,
"generatedDate": 1534267781805,
"lastEditDate": null,
"path": "/my_company/streamname",
"hash": null,
"elems": {
"measure": 7
}
},
[...]
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event?path=<stream_path>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Description |
---|---|
path | Required. The stream path. |
Cloud Action Object
Creating a Cloud Action
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/action" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"js": "function(event) { return {\\"/my_company/destination\\": [event]} }",
"source": "/my_company/source"
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "a5b7ef06757d988c2d22e6165",
"companyId": "c000000000000000000000006",
"creationDate": 1535045735793,
"creatorId": "i000000000000000000000064",
"js": "function(event) { return {\"/my_company/destination\": [event]} }",
"source": "/my_company/source",
"version": 1
}
}
Permission to create a Cloud Action is governed by the CLOUD_ACTION_WRITE role.
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/action
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
request json object
key | type | description |
---|---|---|
description | string | optional. human-friendly description |
destination | string | optional. event output path. |
disabled | bool | is action disabled? |
source | string | required. path from which to read events. |
js | string | optional. javascript to execute. |
filter | string | optional. a filter which is used as a pass/fail test for evaluating whether to run new events on the source stream through the cloud action |
Listing company Cloud Actions
curl "https://octave-api.sierrawireless.io/v5.0/my_company/action" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "a5b7ef06757d988c2d22e6165",
"companyId": "c000000000000000000000006",
"creationDate": 1535045735793,
"creatorId": "i000000000000000000000064",
"js": "function(event) { return {\"/my_company/destination\": [event]} }",
"source": "/my_company/source",
"version": 1
},
...
]
}
Permission to read Cloud Actions is governed by the CLOUD_ACTION_READ role.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/action
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Reading a Cloud Action
curl "https://octave-api.sierrawireless.io/v5.0/my_company/action/a5b7337e76f38615fb24a4ea8" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "a5b7ef06757d988c2d22e6165",
"companyId": "c000000000000000000000006",
"creationDate": 1535045735793,
"creatorId": "i000000000000000000000064",
"js": "function(event) { return {\"/my_company/destination\": [event]} }",
"source": "/my_company/source",
"version": 1
}
}
Permission to read Cloud Actions is governed by the CLOUD_ACTION_READ role.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/action/<action_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Updating a Cloud Action
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/action/a5b7337e76f38615fb24a4ea8" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"description": "My Cloud Action"
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "a5b7ef06757d988c2d22e6165",
"companyId": "c000000000000000000000006",
"creationDate": 1535045735793,
"creatorId": "i000000000000000000000064",
"description": "My Cloud Action",
"js": "function(event) { return {\"/my_company/destination\": [event]} }",
"lastEditDate": 1535046500099,
"source": "/my_company/source",
"version": 2
}
}
Permission to update a Cloud Action is governed by the CLOUD_ACTION_WRITE role.
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/action/<action_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
request json object
key | type | description |
---|---|---|
description | string | optional. human-friendly description |
destination | string | optional. event output path. |
disabled | bool | is action disabled? |
source | string | required. path from which to read events. |
js | string | optional. javascript to execute. |
filter | string | optional. a filter which is used as a pass/fail test for evaluating whether to run new events on the source stream through the cloud action |
Deleting a Cloud Action
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/action/a5b7337e76f38615fb24a4ea8" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
Permission to delete a Cloud Action is governed by the CLOUD_ACTION_DELETE role.
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/action/<action_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Simulating a Cloud Action
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/action/simulate" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"event": {
"elems": {
"a": 1
}
},
"js": "function (input_event) {
var a = input_event.elems.a;
input_event.elems.b = a * 3;
return {
\\"/my_company/output\\": [input_event]
};
}"
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"events": {
"/my_company/output": [
{
"id": "e5b88567457d988734c4078d1",
"metadata": null,
"creationDate": 1535661684244,
"lastEditDate": null,
"generatedDate": null,
"path": null,
"location": null,
"hash": null,
"elems": {
"a": 1,
"b": 3
}
}
]
},
"log": [
{
"a": 1,
"line_no": 2,
"input_event": {
"elems": {
"a": 1
}
}
},
{
"line_no": 3,
"input_event": {
"elems": {
"a": 1,
"b": 3
}
}
}
],
"errors": []
}
}
This endpoint can be called on either an existing or non-existing Cloud Action. If being called on a non-existing Cloud Action, the js
field must be provided. The endpoint evaluates Cloud Action JavaScript against a given Event. The simulator output will contain the function return value (a map of destinations to list of Events), as well as a log, which is a list of the variables of your running script on each line number in the order they were executed (variables that are unchanged will not be reprinted).
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/action/simulate
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/action/<action_id>/simulate
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
request json object
key | type | description |
---|---|---|
js | string | optional - see note above. function to execute |
event | map | required. event to pass to function |
mocks | map | optional. mocked responses from external services |
Mocks
Cloud Action simulate takes an optional mocks object for mocking out responses from external services, such as HTTP calls. Below is a sample mock map.
{
"http://foo.com": {"data":"somedata", "method":"POST","status":200,"message":"OK"}
}
The key of the map must match the path being used in the external service call. If a mock map is provided and its keys do not match the path of a particular external service call, an error will be generated.
Disabled Cloud Actions
Cloud Actions can become disabled if they raise persistent or systematic errors. For more information, see Disabled Objects
Cloud Connector Object (Preview)
Octave currently supports the following HTTP based connector types:
http-connector
azure-iothub-http-gateway-connector
azure-iothub-http-device-twin-connector
Creating a Cloud Connector
Defining cloud-connectors is similar to defining cloud-actions: we identify a stream source for events to be processed and define a JavaScript function to transform events. We can also, where-required, provide a scripted destination URL (as routingScript), and any necessary headers and/or properties per specific connector type. Headers typically include authorization information and properties are connector type specific.
The key distinctions to keep in mind are that:
scripts defined in the js property of connector objects transform input events into the output format apropriate for the connector type
have connector-type specific headers and properties that can be defined and updated.
connector type specific and optional routing script to dynamically route an event to a specific end-point
Common Fields
- The properties map definition is connector type specific There are no required general connector properties elements.
- The headers map definition is connector type specific There are no required general connector headers elements.
Cloud Connector Uniqueness
What logically distinguishes individual cloud-connectors is precisely the connectivity path from a source to a destination. This maps to a connectors source. For a given company (scope) all cloud connectors must be unique.
Creating an 'http-connector'
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/connector" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"type": "http-connector",
"source": "/my_company/source",
"disabled": false,
"displayName": "example http connector",
"description": "example using custom headers",
"js": "function(event) { return JSON.stringify({'some-key': 'some-value'}) }",
"routingScript": "function(event) { return 'https://some.server:1234/service'}",
"headers": {
"Content-Type": "application/json",
"x-custom": "x-custom-value"
},
"properties": {
"successCodes": [201, 202, 203, 204, 205]
},
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "x5e41c286c80a6459ae7aa8a1",
"companyId": "c5bae617e90f45d7d11710087",
"creationDate": 1581367942891,
"creatorId": "i5c2ce278a25a5f099f95a189",
"description": "example using standard x-auth and custom headers",
"disabled": false,
"displayName": "example http connector",
"headers": {
"Content-Type": "application/json",
"x-custom": "x-custom-value"
},
"js": "function(event) { return JSON.stringify({'some-key': 'some-value'}) }",
"properties": {
"successCodes": [
201,
202,
203,
204,
205
]
},
"routingScript": "function(event) { return 'https://some.server:1234/service'}",
"source": "/test/foo",
"type": "http-connector",
"version": 1
}
}
Creating an 'azure-iothub-http-gateway-connector'
Iot Hub connectors have no header requirements, adhere to the default response status codes of Azure Iot Hub, and also do not require a routingScript
. The key required properties are your Azure Iot Hub application's name, shared access policy key, and an optional shared access policy name.
Note that use of Iot Hub Connectors requires mapping of Azure Iot Hub "device twin" ids to associated Octave device. For each device sending Events to the connector's source
path, make sure the Device's metadata contains the key occIotHubDeviceId
with the value of the IoT Hub device.
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/connector" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"type": "azure-iothub-http-gateway-connector",
"source": "/my_company/source",
"disabled": false,
"displayName": "example IoT Hub Gateway Connector",
"description": "Sends events from Octave Devices to their associated device on Azure IoT Hub",
"js": "function(event) { return event; }",
"properties": {
"iotHubName": "<from your Azure Iot Hub Portal>",
"sharedAccessKey": "<either the default 'device' key for the IoT Hub account or one with similar permissions>",
"sharedAccessPolicyName": "<policy name, only required if not using built-in 'device' key>"
},
Creating an 'azure-iothub-http-device-twin-connector'
Iot Hub connectors have no header requirements, adhere to the default response status codes of Azure Iot Hub, and also do not require a routingScript
. The key required properties are your Azure Iot Hub application's name, shared access policy key, and an optional shared access policy name.
IoT Hub device twin connector is capable of forwarding events from multiple streams. You can select forwarding streams under properties section.
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/connector" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"type": "azure-iothub-http-device-twin-connector",
"source": "/my_company/source",
"disabled": false,
"displayName": "example IoT Hub Device Twin Connector",
"description": "Sends events from Octave Devices to their associated device on Azure IoT Hub",
"js": "function(event) { return event; }",
"properties": {
"iotHubName": "<from your Azure Iot Hub Portal>",
"sharedAccessKey": "<either the default 'device' key for the IoT Hub account or one with similar permissions>",
"sharedAccessPolicyName": "<policy name, only required if not using built-in 'device' key>"
"streams" : [
"<stream ABC>",
"<stream XYZ>"
]}
},
Permission to create a Cloud Connector is governed by the CLOUD_CONNECTOR_WRITE role.
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/connector
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
request json object
key | type | description |
---|---|---|
description | string | optional. human-friendly description |
disabled | bool | is action disabled? (default false ) |
source | string | required. path from which to read events. |
js | string | required. javascript function definition to create exported payload from event. This will be an a function taking 1 argument, returning an arbitrary JSON map. |
properties | map | required-per-type. Typically there are specific properties per distinct connector types. Properties are not passed along with the exported event -- they are only required for parameterizing the operation of specific connector types. |
filter | string | optional. a filter which is used as a pass/fail test for evaluating whether to run new events on the source stream through the cloud action |
Listing company Cloud Connectors
curl "https://octave-api.sierrawireless.io/v5.0/my_company/connector" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "x5e41c286c80a6459ae7aa8a1",
"companyId": "c5bae617e90f45d7d11710087",
"creationDate": 1581367942891,
"creatorId": "i5c2ce278a25a5f099f95a189",
"description": "example using standard x-auth and custom headers",
"disabled": false,
"displayName": "example http connector",
"headers": {
"x-auth-user": "x-auth-user-value",
"x-auth-token": "x-auth-token-value",
"x-custom": "x-custom-value",
"Content-Type": "applications/json"
},
"js": "function(event) { return {\"key-0\": \"value\"}; }",
"properties": {
"success-codes": [
201,
202,
203,
204,
205
]
},
"routingScript": "function(event) { return \"https://my.test.server:77\"; }",
"source": "/test/foo",
"type": "http-connector",
"version": 1
},
...
]
}
Permission to read Cloud Connectors is governed by the CLOUD_CONNECTOR_READ role.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/connector
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Reading a Cloud Connector
curl "https://octave-api.sierrawireless.io/v5.0/my_company/connector/x5e41c286c80a6459ae7aa8a1" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "x5e41c286c80a6459ae7aa8a1",
"companyId": "c5bae617e90f45d7d11710087",
"creationDate": 1581367942891,
"creatorId": "i5c2ce278a25a5f099f95a189",
"description": "example using standard x-auth and custom headers",
"disabled": false,
"displayName": "example http connector",
"headers": {
"x-auth-user": "x-auth-user-value",
"x-auth-token": "x-auth-token-value",
"x-custom": "x-custom-value",
"Content-Type": "applications/json"
},
"js": "function(event) { return {\"key-0\": \"value\"}; }",
"properties": {
"success-codes": [
201,
202,
203,
204,
205
]
},
"routingScript": "function(event) { return \"https://my.test.server:77\"; }",
"source": "/test/foo",
"type": "http-connector",
"version": 1
}
}
Permission to read Cloud Connectors is governed by the CLOUD_CONNECTOR_READ role.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/connector/<connector_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Updating a Cloud Connector
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/connector/a5b7337e76f38615fb24a4ea8" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"description": "My Cloud Connector"
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "x5e4185cc2f2ea07c486d384c",
"companyId": "c000000000000000000000006",
"creationDate": 1581352396959,
"creatorId": "i000000000000000000000064",
"description": "example using standard x-auth and custom headers",
"disabled": true,
"displayName": "My cloud connector",
"headers": {
"x-auth-user": "x-auth-user-value",
"x-auth-token": "x-auth-token-value",
"x-custom": "x-custom-value",
"Content-Type": "applications/json"
},
"js": "function(event) { return {\"key-0\": \"value\"}; }",
"lastEditDate": 1581353594708,
"lastEditorId": "i000000000000000000000064",
"properties": {
"success-codes": [
201,
202,
203,
204,
205
]
},
"routingScript": "function(event) { return \"https://localhost:7777\"; }",
"source": "/test",
"type": "http-connector",
"version": 2
}
}
Permission to update a Cloud Connector is governed by the CLOUD_CONNECTOR_WRITE role.
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/connector/<connector_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
request json object
key | type | description |
---|---|---|
description | string | optional. human-friendly description |
disabled | bool | is action disabled? |
source | string | required. path from which to read events. |
js | string | required. javascript function definition to create exported payload from event. This will be an a function taking 1 argument, returning an arbitrary JSON map. |
routingScript | string | optional. javascript function definition to create a URL string representation from the event. This will be a function taking 1 arument, returning a string. |
headers | string | required-per-type. header passed verbatim to the indicated external end-point via the connector. Typically there are specific headers per distinct connector types. Any additional custom headers not required by the connector-type is also passed verbatim. |
properties | map | required-per-type. Typically there are specific properties per distinct connector types. Properties are not passed along with the exported event -- they are only required for parameterizing the operation of specific connector types. |
filter | string | optional. a filter which is used as a pass/fail test for evaluating whether to run new events on the source stream through the cloud action |
Deleting a Cloud Connector
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/connector/a5b7337e76f38615fb24a4ea8" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
Permission to delete a Cloud Action is governed by the CLOUD_CONNECTOR_DELETE role.
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/connector/<connector_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Disabled Cloud Connectors
Cloud Connectors can become disabled if they raise persistent or systematic errors. For more information, see Disabled Objects
Cloud JavaScript Library
Overview
Octave.js is our server side javascript processing environment. It gives you a library under the Octave
namespace. It also executes your code on our servers, ensuring that your code executes safely–both for you and for everyone else on our platform.
Octave.js provides methods for CRUD operations on select Octave domain objects from within Cloud Action and Task execution environments. These methods are available in the global namespace 'Octave'. The 'Octave' namespace provides 'find' and 'get' under the Stream subnamespace. The Event subnamespace includes 'get', 'find', 'findOne', 'findHash', 'multiFind', and 'aggregate' methods. Lastly, the Device subnamespace provides the methods 'getName', 'get', 'find', and 'update'.
Processing Environment
Strict Mode
The environment that executes your code in strict mode, a restricted subset of javascript. Generally, this shouldn't change that much about how you use javascript. But, it does change some things. Most noticeably, you should avoid declaring global variables (use var x = 1
instead of just simply x = 1
). For more information about strict mode, I'd recommend reading the Mozilla Developer Network article.
ECMAScript 6
We do not support most features of ECMAScript 6. We also disallow the use of eval
.
Lodash
Our environment comes preloaded with lodash. If you're not familiar with lodash, you can read the documentation for our version.
Generally, it provides you with a lot of easy methods that you wish javascript had, but that it doesn't.
CryptoJS
// CryptoJS examples
var a = CryptoJS.AES.encrypt("my message", "secret key 123");
a = CryptoJS.AES.decrypt(a, "secret key 123").toString(CryptoJS.enc.Utf8);
console.log("a = " + a);
var b = CryptoJS.MD5("message");
console.log("b = " + b);
var c = CryptoJS.SHA1("message");
console.log("c = " + c);
var d = CryptoJS.SHA256("message").toString(CryptoJS.enc.Base64);
console.log("d = " + d);
var e = CryptoJS.HmacMD5("message", "passphrase");
console.log("e = " + e);
Cryptographic and hashing functions are provided by the CryptoJS library. It provides encryption algorithms sunch as AES and DES, hashing functions such as MD5, SHA1 and SHA256, signing algorithms such as HMAC, and more. You can read the full documentation for our version here.
The library is available through the global CryptoJS
variable. For example, in order to get the SHA1 hash of a message, you can use: var hash = CryptoJS.SHA1("message").toString();
Event Get
var event = Octave.Event.get("s5b7c2258c4eaa25486be2ed1","e5b7c2f8683ee686657c50aac");
// event now contains the matching event
// event == {elems: { x:1 },creationDate: 1534865286261,...}
Octave.Event.get(streamId, eventId)
Arguments
streamId
: the string value of the event stream ideventId
: the string value of the event id
Return
Returns a json representation of the specified Event.
Event Find
//find the most recent 2 events where x > 1:
var events = Octave.Event.find("s5b7c2258c4eaa25486be2ed1", {"filter": "x > 1", "sort":"creationDate", "limit": 2});
// events now contains an array with matching values
// events == [{elems: { x:1 },creationDate: 1534865286261,...}, {elems: {x:1}, .... }]
Octave.Event.find(streamId, options)
Arguments
streamId
: the string value of the stream's idoptions
: an optional object literal of query options-
filter
- a filter string, for more info see filters -
start
- start index of the search, integer, default value 0 -
limit
- maximum response size, integer, default value 20 -
sort
- string representation of the member key to sort the results over, default valuecreationDate
-
order
- string, available options areasc
anddesc
, default valuedesc
-
Return
Returns an array of json representations of the matching Events
Event FindOne
//find the most recent events where x > 1:
var event = Octave.Event.findOne("s5b7c2258c4eaa25486be2ed1", {"filter": "x > 1", "sort":"creationDate"});
// event now contains the matching event
// event == {elems: { x:1 },creationDate: 1534865286261,...}
Octave.Event.findOne(streamId, options)
Takes the same parameters as Octave.Event.find
, but returns only first result. Value returned as json representation of an Event.
Arguments
streamId
: the string value of the stream's idoptions
: an optional object literal of query options-
filter
- a filter string, for more info see filters -
start
- start index of the search, integer, default value 0 -
sort
- string representation of the member key to sort the results over, default valuecreationDate
-
order
- string, available options areasc
anddesc
, default valuedesc
-
Return
Returns a json representation of a single Event.
Event FindHash
//find the most recent events where x > 1:
var event = Octave.Event.findHash("s5b7c2258c4eaa25486be2ed1", "someUniqueHashValue");
// event now contains the matching event
// event == {elems: { x:1 },hash:"someUniqueHashValue", creationDate: 1534865286261,...}
Octave.Event.findHash(streamId, hashValue)
Function allows for referencing a particular Event by a unique hash value. See hash
documentation for further detail.
Arguments
streamId
: the string value of the stream's idhashValue
:hash
value of some event in the specified stream
Return
Returns a json representation of a single Event.
Event MultiFind
//query from a number of streams.
var events = Octave.Event.multifind([{streamId:"s123456123456123456123456","params":{"sort":"creationDate","limit":1}},
streamId:"s234567234567234567234567","params":{"sort":"creationDate","order":"desc", "limit":1}},
path:/mycompany/mystream", "params":{}]);
Octave.Event.multifind([{streamId:<>, params: {}}, ... ])
Function allows simulatenous access to Events from a number of streams.
Event Aggregate
//fixed value comparison example
var myAggregationResults = Octave.Event.aggregate(myStreamId, {
"filter": "EXISTS cpu_temp",
"rules": {"x":"cpu_temp > 50"},
"groupBy": ["$month"],
"output": [
"$avg:cpu_temp",
"$min:cpu_temp",
"$max:cpu_temp",
"$avg:x",
"$count"
],
"sorts":["$avg:x:desc", "$avg:cpu_temp:asc"]
});
//element values comparison example
var myAggregationResults = Octave.Event.aggregate(myStreamId, {
"filter": "elems.aNumber > elems.bNumber",
"rules": {"x":"elems.aNumber > 0.1"},
"groupBy": ["$month"],
"output": [
"$avg:elems.aNumber",
"$min:elems.aNumber",
"$max:elems.aNumber",
"$avg:x",
"$count"
],
"sorts":["$avg:x:desc", "$avg:elems.aNumber:asc"]
});
Octave.Event.aggregate(streamId, options)
Usage of aggregate
is explained at length here.
Stream Find
Octave.Stream.find(options)
Arguments
options
: an optional object literal of query options
-
filter
- a filter string, for more info see filters -
start
- start index of the search, integer, default value 0 -
limit
- maximum response size, integer, default value 20 -
sort
- string representation of the member key to sort the results over, default valuecreationDate
-
order
- string, available options areasc
anddesc
, default valuedesc
Return
Returns an array of json representations of the matching Streams.
Stream Get
Octave.Stream.get(streamId)
Arguments
streamId
- the string value of the Stream's Id
Return
Returns the json representation of the Stream
Device Get Name
Octave.Device.getName()
Arguments
Return
Returns the name of the Device associated with the Event that triggered the Cloud Action. Returns null if called outside of the Cloud Action javascript context.
Device Get
Octave.Device.get(deviceId)
Arguments
deviceId
- the string value of the Device's Id
Return
Returns the json representation of the Device
Device Find
Octave.Device.find(options)
Arguments
options
: an optional object literal of query options
-
filter
- a filter string, for more info see filters -
start
- start index of the search, integer, default value 0 -
limit
- maximum response size, integer, default value 20 -
sort
- string representation of the member key to sort the results over, default valuecreationDate
-
order
- string, available options areasc
anddesc
, default valuedesc
Return
Returns an array of json representations of the matching Devices.
Device Update
Octave.Device.update(deviceId, deviceDiff)
Return
Returns the json representation of the updated Device
HTTP GET (webhook)
var getHeaders = {'header1':'1','header2':'2'};
var result = Octave.Http.get('http://httpbin.org/get', getHeaders);
Octave.Http.get(url, headers)
Arguments
url
- url to GETheaders
- a mapping of header names and values
Return
Returns a response object with the following keys:
-
headers
- Map of header keys and values -
status
- HTTP status code (integer) -
message
- HTTP status message (string) -
contentType
- Value of HTTP Content-Type header -
content
- Response Body (string)
HTTP POST (webhook)
var url = 'http://httpbin.org/post';
var postBody = JSON.stringify(payload);
var postHeaders = {
'Content-Type': 'application/json',
'header2': '2'
};
var result = Octave.Http.post(url, postHeaders, postBody);
Octave.Http.post(url, headers, data)
Arguments
url
- url to POSTheaders
- a mapping of header names and valuesdata
- the POST body
Return
Returns a response object with the following keys:
-
headers
- Map of header keys and values -
status
- HTTP status code (integer) -
message
- HTTP status message (string) -
contentType
- Value of HTTP Content-Type header -
content
- Response Body (string)
HTTP PUT (webhook)
var url = 'http://httpbin.org/put';
var putBody = JSON.stringify(payload);
var putHeaders = {
'Content-Type': 'application/json',
'header2': '2'
};
var result = Octave.Http.put(url, putHeaders, putBody);
Octave.Http.put(url, headers, data)
Arguments
url
- url to POSTheaders
- a mapping of header names and valuesdata
- the POST body
Return
Returns a response object with the following keys:
-
headers
- Map of header keys and values -
status
- HTTP status code (integer) -
message
- HTTP status message (string) -
contentType
- Value of HTTP Content-Type header -
content
- Response Body (string)
HTTP DELETE (webhook)
var url = 'http://httpbin.org/delete'
var deleteHeaders = {'header1':'1','header2':'2'};
var result = Octave.Http.delete(url, deleteHeaders);
Octave.Http.delete(url, headers)
Arguments
url
- url to DELETEheaders
- a mapping of header names and values
Return
Returns a response object with the following keys:
-
headers
- Map of header keys and values -
status
- HTTP status code (integer) -
message
- HTTP status message (string) -
contentType
- Value of HTTP Content-Type header -
content
- Response Body (string)
Edge Action Object
{
"description": "Transform temperature",
"source": "observation://temperature_sensor",
"js": "function(input) {
var celsius = input.value;
var fahrenheit = celsius * 9 / 5 + 32;
var result = {
c : celsius,
f : fahrenheit
};
return {
'dh://lcd/txt1' : ['Temp is ' + fahrenheit],
'cl://' : [result]
};
}"
}
An Edge Action specifies a source
Observation name and js
function.
Input
{
"value" : {
"lat" : 40.704067,
"lon" : -73.989088,
"alt" : 1,
"vAcc" : 10,
"hAcc" : 11,
"fixType" : "GNSS"
},
"timestamp" : 1530572947298
}
The input to an Edge Action is an Event generated by an Observation. Observations are attached to Resources in the Resource Tree. So an Observation on /position/coordinates/value
will generate an Event containing the GNSS location of the Device in the value
attribute, and the timestamp the reading was taken in the timestamp
attribute:
Input Types
"/location/coordinates/value": {
"dt": "json",
"s": "{\"lat\":0.1,\"lon\":0.2,\"alt\":0.3,\"hAcc\":0.4,\"vAcc\":0.5,\"fixType\":\"GNSS\"}",
"t": "input",
"m": false
}
The value generated from /position/coordinates/value
is a JS Object type. We know this by looking in the Device.summary
for the same key:
The attribute dt
can be one of trigger, boolean, numeric, string, json
.
The attribute s
shows a "sample" value, so we know what to expect as an input.
Creating an Edge Action
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/local-action" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"source": "observation://temperature_sensor",
"js": "function(input) {
var celsius = input.value;
var fahrenheit = celsius * 9 / 5 + 32;
var result = {
c : celsius,
f : fahrenheit
};
return {
\\"dh://lcd/txt1\\" : [\\"Temp is \\" + fahrenheit],
\\"cl://\\" : [result]
};
}"
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "l5b86acd38c633a1add9e427e",
"companyId": "c000000000000000000000000",
"creationDate": 1535552723513,
"creatorId": "i000000000000000000000000",
"js": "function(input) {\n var celsius = input.value;\n var fahrenheit = celsius * 9 / 5 + 32;\n\n var result = {\n c : celsius,\n f : fahrenheit\n };\n\n return {\n \"dh://lcd/txt1\" : [\"Temp is \" + fahrenheit],\n \"cl://\" : [result]\n };\n }",
"source": "observation://temperature_sensor",
"version": 1
}
}
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/local-action
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Description |
---|---|---|
source | string | Required. The name of the Observation which triggers execution of the Edge Action. Always prefixed with observation:// |
js | string | Required. The function must take an Event as input and return a map of destinations to list of Events. |
Listing company Edge Actions
## List Edge Actions
curl "https://octave-api.sierrawireless.io/v5.0/my_company/local-action" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "l5b86acd38c633a1add9e427e",
"companyId": "c000000000000000000000000",
"creationDate": 1535552723513,
"creatorId": "i000000000000000000000000",
"js": "function(input) {\n var celsius = input.value;\n var fahrenheit = celsius * 9 / 5 + 32;\n\n var result = {\n c : celsius,\n f : fahrenheit\n };\n\n return {\n \"dh://lcd/txt1\" : [\"Temp is \" + fahrenheit],\n \"cl://\" : [result]\n };\n }",
"source": "observation://temperature_sensor",
"version": 1
},
...
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/local-action
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Reading an Edge Action
## Read Edge Action
curl "https://octave-api.sierrawireless.io/v5.0/my_company/local-action/l5b730d2f6f3861bb4e95f51c" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "l5b86acd38c633a1add9e427e",
"companyId": "c000000000000000000000000",
"creationDate": 1535552723513,
"creatorId": "i000000000000000000000000",
"js": "function(input) {\n var celsius = input.value;\n var fahrenheit = celsius * 9 / 5 + 32;\n\n var result = {\n c : celsius,\n f : fahrenheit\n };\n\n return {\n \"dh://lcd/txt1\" : [\"Temp is \" + fahrenheit],\n \"cl://\" : [result]\n };\n }",
"source": "observation://temperature_sensor",
"version": 1
}
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/local-action/<action_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Updating an Edge Action
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/local-action/l5b81acd31c613a1add9e427e" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"js": "function(input) {
var celsius = input.value;
var fahrenheit = celsius * 9 / 5 + 32;
var result = {
c : celsius,
f : fahrenheit
};
return {
\\"dh://lcd/txt1\\" : [\\"Temp is \\" + fahrenheit],
\\"dh://lcd/txt2\\" : [\\"Celsius is \\" + celsius],
\\"cl://\\" : [result]
};
}"
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "l5b81acd31c613a1add9e427e",
"companyId": "c000000000000000000000000",
"creationDate": 1535552723513,
"creatorId": "i000000000000000000000000",
"js": "function(input) {\n var celsius = input.value;\n var fahrenheit = celsius * 9 / 5 + 32;\n\n var result = {\n c : celsius,\n f : fahrenheit\n };\n\n return {\n \"dh://lcd/txt1\" : [\"Temp is \" + fahrenheit],\n \"dh://lcd/txt2\" : [\"Celsius is \" + celsius],\n \"cl://\" : [result]\n };\n }",
"lastEditDate": 1535560013994,
"source": "observation://temperature_sensor",
"version": 2
}
}
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/local-action/<action_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
For a full overview of all Edge Action attributes, see the Edge Action Object Overview.
Key | Type | Value |
---|---|---|
js | string | Required. The function must take an Event as input and return a map of destinations to list of Events. |
Deleting an Edge Action
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/local-action/l5b730d2f6f3861bb4e95f51c" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/local-action/<action_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Simulating an Edge Action
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/local-action/simulate" \
-H 'x-auth-user: <user> \
-H 'x-auth-token: <token> \
-d $'{
"event": {
"value": {
"x": 1,
"y": 2,
"z": 3
},
"timestamp": 1532546501162
},
"resources": {
"read://redSensor/light/value": {
"value": 1100,
"timestamp": 999999
},
"read://redSensor/accel/value": {
"value": {
"x": 4,
"y": 5,
"z": 6
}
},
"stddev(3.1)://my_temperature_observation": {
"value": 12.2
}
},
"js": "function(input) {
// Read our first mock:
// Returns : { value : 1100, timestamp: <current time in millis> }
var light = Datahub.read(\\"/redSensor/light/value\\", 0);
// Read our second mock:
// Returns : { value : {\\"x\\" : 4, \\"y\\" : 5, \\"z\\" : 6}, timestamp: <current time in millis> }
var accel = Datahub.read(\\"/redSensor/accel/value\\", 2.0);
// If we don'"'"'t supply a mock, we return null immediately:
// Returns : null
var position = Datahub.read(\\"/redSensor/position/value\\", 1.0);
// Return our third mock
// Returns : { value : 12.2, timestamp: <current time in millis> }
var sdev_temp = Datahub.query(\\"my_temperature_observation\\", \\"stddev\\", 3.1);
return {
// Direct to Data Hub (path mandatory)
\\"dh://lcd/txt1\\" : [\\"hi mom!\\"],
// Direct to Cloud (path optional)
\\"cl://\\" : [
{
input : input,
light : light,
accel : accel,
position : '"'"'value is : '"'"' + position,
sdev_temp : sdev_temp,
}
],
// Store and Forward (path optional)
\\"st://\\" : [222222],
// Set a virtual resource (a single key, mandatory)
\\"vr://kjl\\" : [33333],
// Debug (no path)
\\"debug://\\" : [4444]
}
}"
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"events": {
"debug://": [
4444
],
"st://": [
222222
],
"cl://": [
{
"input": {
"value": {
"x": 1,
"y": 2,
"z": 3
},
"timestamp": 1532546501162
},
"light": {
"value": 1100,
"timestamp": 999999
},
"position": "value is : null",
"accel": {
"value": {
"x": 4,
"y": 5,
"z": 6
},
"timestamp": 1545249013757
}
}
],
"dh://lcd/txt1": [
"hi mom!"
],
"vr://kjl": [
33333
]
},
"log": [
{
"input": {
"value": {
"x": 1,
"y": 2,
"z": 3
},
"timestamp": 1.532546501162E12
},
"light": {
"value": 1100,
"timestamp": 999999
},
"Datahub": {},
"line_no": 9
},
{
"line_no": 17,
"accel": {
"value": {
"x": 4,
"y": 5,
"z": 6
},
"timestamp": 1.545249013757E12
}
},
{
"line_no": 29
}
],
"mocks": null,
"errors": []
}
}
This endpoint can be called on either an existing or non-existing Edge Action. If being called on a non-existing Edge Action, the js
field must be provided. The endpoint evaluates Edge Action JavaScript against a given Event. (Note: unlike the Event used in Cloud Actions, this Event does not wrap its values in an elems
map.) The simulator output will contain the function return value (a map of destinations to values), as well as a log, which is a list of the variables of your running script on each line number in the order they were executed (variables that are unchanged will not be reprinted).
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/local-action/simulate
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/local-action/<edge_action_id>/simulate
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
request json object
key | type | description |
---|---|---|
js | string | optional - see note above. function to execute |
event | map | required. event to pass to function |
resources | map | optional. used for mocking responses from calls to Datahub.read(), Datahub.query(), etc. |
Task Object
Creating a Task
## Create Task
## Task #1: Find all devices and add them as event elements on a destination stream
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/task" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"destination": "/my_company/task_output/find_devices",
"periodicity": "20000",
"js": "function(events, raw) { var devices = 'EMPTY'; try { devices = Octave.Device.find({});} catch (e) { devices = e.name + ' ' + e.message;} return {'/my_company/task_output/find_devices': [{'elems': {'devices': devices}}]}; }",
"displayName": "A sample task-1"
}'
## Response for Task #1
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "t5e5d3e8d772f39d6b996d143",
"companyId": "c5bae617e90f45d7d11710087",
"creationDate": 1583169165597,
"creatorId": "i5dea9ae317900a4b57f95b39",
"destination": "/my_company/task_output/find_devices",
"displayName": "A sample task-1",
"js": "function(events, raw) { var devices = 'EMPTY'; try { devices = Octave.Device.find({});} catch (e) { devices = e.name + ' ' + e.message;} return {'/my_company/task_output/find_devices': [{'elems': {'devices': devices}}]}; }",
"lastRun": 0,
"periodicity": 20000,
"runCt": 0
}
}
## Task #2: Generate one event every hour and use eventFind
curl -X "POST" \ "https://octave-api.sierrawireless.io/v5.0/my_company/task" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"destination": "/my_company/task_output/everyday",
"displayName": "Generate one event every hour",
"js": "function(events, raw) {var ev = {elems: {}}; if (events && events[0] != null) { ev.elems.hour = (events[0].elems.hour + 1) % 24; } else { ev.elems.hour = 1; } return {'/my_company/test/periodictasks/everyday': [event] }}",
"periodicity": 3600000,
"source": {
"eventFind": {
"streamPath": "/my_company/task_output/everyday",
"options": {
"limit": 1
}
}
}
}'
## Response for Task #2
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "t5eff44ec14c322021cd812be",
"companyId": "c000000000000000000000006",
"creationDate": 1593787628423,
"creatorId": "i000000000000000000000064",
"destination": "/my_company/task_output/everyday",
"displayName": "Generate one event every hour",
"js": "function(events, raw) {var ev = {elems: {}}; if (events && events[0]) { ev.elems.hour = (events[0].elems.hour + 1) % 24; } else { ev.elems.hour = 1; } return {'/my_company/task_output/everyday': [ev] }}",
"lastEditDate": 1593787628423,
"lastEditorId": "i000000000000000000000064",
"lastRun": 0,
"periodicity": 3600000,
"runCt": 0,
"source": {
"eventFind": {
"streamPath": "/my_company/task_output/everyday",
"options": {
"limit": 1
}
}
}
}
}
## Task #3: Reading JSON HTTP response
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/task" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"destination": "/my_company/task_output/task3",
"displayName": "Task with HTTP jsonpath parser source",
"periodicity": 20000,
"source": {
"http": {
"parser": {
"jsonpath": {
"nodes": {
"elems": {
"headers": "headers.Accept",
"a": "args.a"
}
},
"root": "$"
}
},
"get": {
"url": "http://httpbin.org/get?a=b"
}
}
}
}'
## Response for Task #3
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "t5eff495a14c322021cd812cd",
"companyId": "c000000000000000000000006",
"creationDate": 1593788762600,
"creatorId": "i000000000000000000000064",
"destination": "/my_company/task_output/task3",
"displayName": "Task with HTTP jsonpath parser source",
"lastEditDate": 1593788762600,
"lastEditorId": "i000000000000000000000064",
"lastRun": 0,
"periodicity": 20000,
"runCt": 0,
"source": {
"http": {
"parser": {
"jsonpath": {
"nodes": {
"elems": {
"headers": "headers.Accept",
"a": "args.a"
}
},
"root": "$"
}
},
"get": {
"url": "http://httpbin.org/get?a=b"
}
}
}
}
}
Permission to create a Task is governed by the TASK_WRITE role.
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/task
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Request JSON Object
key | type | description |
---|---|---|
description | string | optional. human-friendly description |
destination | string | optional. event output path. |
disabled | bool | is task disabled? |
displayName | string | optional. human-friendly display name |
source | object | optional. JS ingest procedure |
js | string | optional. javascript to execute. |
periodicity | number | task execution period in milliseconds. |
Listing company Tasks
curl "https://octave-api.sierrawireless.io/v5.0/my_company/task" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "t5eff44ec14c322021cd812be",
"companyId": "c000000000000000000000006",
"creationDate": 1593787628423,
"creatorId": "i000000000000000000000064",
"destination": "/my_company/task_output/everyday",
"displayName": "Generate one event every hour",
"js": "function(events, raw) {var ev = {elems: {}}; if (events && events[0]) { ev.elems.hour = (events[0].elems.hour + 1) % 24; } else { ev.elems.hour = 1; } return {'/my_company/task_output/everyday': [ev] }}",
"lastEditDate": 1593787628423,
"lastEditorId": "i000000000000000000000064",
"lastRun": 1593787688513,
"nextRun": 1593791288513,
"periodicity": 3600000,
"runCt": 4,
"source": {
"eventFind": {
"streamPath": "/my_company/task_output/everyday",
"options": {
"limit": 1
}
}
}
},
...
]
}
Permission to read Tasks is governed by the TASK_READ role.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/task
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Reading a Task
curl "https://octave-api.sierrawireless.io/v5.0/my_company/task/t5eff44ec14c322021cd812be" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "t5eff44ec14c322021cd812be",
"companyId": "c000000000000000000000006",
"creationDate": 1593787628423,
"creatorId": "i000000000000000000000064",
"destination": "/my_company/task_output/everyday",
"displayName": "Generate one event every hour",
"js": "function(events, raw) {var ev = {elems: {}}; if (events && events[0]) { ev.elems.hour = (events[0].elems.hour + 1) % 24; } else { ev.elems.hour = 1; } return {'/my_company/task_output/everyday': [ev] }}",
"lastEditDate": 1593787628423,
"lastEditorId": "i000000000000000000000064",
"lastRun": 1593787768508,
"nextRun": 1593791368508,
"periodicity": 3600000,
"runCt": 8,
"source": {
"eventFind": {
"streamPath": "/my_company/task_output/everyday",
"options": {
"limit": 1
}
}
}
}
}
Permission to read Tasks is governed by the TASK_READ role.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/task/<task_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Updating a Task
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/task/t5eff44ec14c322021cd812be" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"description": "My Task"
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "t5eff44ec14c322021cd812be",
"companyId": "c000000000000000000000006",
"creationDate": 1593787628423,
"creatorId": "i000000000000000000000064",
"destination": "/my_company/task_output/everyday",
"description": "My Task",
"displayName": "Generate one event every hour",
"js": "function(events, raw) {var ev = {elems: {}}; if (events && events[0]) { ev.elems.hour = (events[0].elems.hour + 1) % 24; } else { ev.elems.hour = 1; } return {'/my_company/task_output/everyday': [ev] }}",
"lastEditDate": 1593787628423,
"lastEditorId": "i000000000000000000000064",
"lastRun": 1593787768508,
"nextRun": 1593791368508,
"periodicity": 3600000,
"runCt": 8,
"source": {
"eventFind": {
"streamPath": "/my_company/task_output/everyday",
"options": {
"limit": 1
}
}
}
}
}
Permission to update a Task is governed by the TASK_WRITE role.
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/task/<task_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Request JSON Object
key | type | description |
---|---|---|
description | string | optional. human-friendly description |
destination | string | optional. event output path. |
disabled | bool | is task disabled? |
displayName | string | optional. human-friendly display name |
source | object | optional. JS ingest procedure |
js | string | optional. javascript to execute. |
periodicity | number | task execution period in milliseconds. |
Deleting a Task
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/task/t5eff44ec14c322021cd812be" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
Permission to delete a Task is governed by the TASK_DELETE role.
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/task/<task_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Simulating a Task
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/task/simulate" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json' \
-d $'{
"js": "function (events, response){console.log(events);console.log(response)}",
"source": {
"http": {
"parser": {
"jsonpath": {
"nodes": {
"elems": {
"headers": "headers.Accept",
"a": "args.a"
}
},
"root": "$"
}
},
"get": {
"url": "http://httpbin.org/get?a=b"
}
}
}
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"events": null,
"task": {
"js": "function (events, response){console.log(events);console.log(response)}",
"periodicity": 20000,
"source": {
"http": {
"parser": {
"jsonpath": {
"nodes": {
"elems": {
"headers": "headers.Accept",
"a": "args.a"
}
},
"root": "$"
}
},
"get": {
"url": "http://httpbin.org/get?a=b"
}
}
}
},
"log": [
[
{
"path": null,
"metadata": null,
"streamId": null,
"elems": {
"headers": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2",
"a": "b"
},
"lastEditDate": null,
"generatedDate": null,
"location": null,
"id": null,
"creationDate": null,
"hash": null,
"tags": {}
}
],
{
"response": {
"headers": {
"Server": [
"gunicorn/19.9.0"
],
"Access-Control-Allow-Origin": [
"*"
],
"Access-Control-Allow-Credentials": [
"true"
],
"Connection": [
"keep-alive"
],
"Content-Length": [
"321"
],
"Date": [
"Fri, 03 Jul 2020 14:57:58 GMT"
],
"Content-Type": [
"application/json"
]
},
"message": "OK",
"contentType": "application/json",
"content": "{\n \"args\": {\n \"a\": \"b\"\n }, \n \"headers\": {\n \"Accept\": \"text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\", \n \"Host\": \"httpbin.org\", \n \"User-Agent\": \"Brooklyn\", \n \"X-Amzn-Trace-Id\": \"Root=1-5eff4776-6bf977d5f0a0651141aa6653\"\n }, \n \"origin\": \"176.129.161.48\", \n \"url\": \"http://httpbin.org/get?a=b\"\n}\n",
"status": 200
},
"line_no": 1,
"events": [
{
"path": null,
"metadata": null,
"streamId": null,
"elems": {
"headers": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2",
"a": "b"
},
"lastEditDate": null,
"generatedDate": null,
"location": null,
"id": null,
"creationDate": null,
"hash": null,
"tags": {}
}
]
},
{
"headers": {
"Server": [
"gunicorn/19.9.0"
],
"Access-Control-Allow-Origin": [
"*"
],
"Access-Control-Allow-Credentials": [
"true"
],
"Connection": [
"keep-alive"
],
"Content-Length": [
"321"
],
"Date": [
"Fri, 03 Jul 2020 14:57:58 GMT"
],
"Content-Type": [
"application/json"
]
},
"message": "OK",
"contentType": "application/json",
"content": "{\n \"args\": {\n \"a\": \"b\"\n }, \n \"headers\": {\n \"Accept\": \"text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\", \n \"Host\": \"httpbin.org\", \n \"User-Agent\": \"Brooklyn\", \n \"X-Amzn-Trace-Id\": \"Root=1-5eff4776-6bf977d5f0a0651141aa6653\"\n }, \n \"origin\": \"176.129.161.48\", \n \"url\": \"http://httpbin.org/get?a=b\"\n}\n",
"status": 200
}
],
"errors": []
}
}
This endpoint can be called on either an existing or non-existing Task. The endpoint performs the action specified in the Source field and then evaluates the parsed output against the Task JavaScript (if any); however, events are not persisted. (Note that this behavior is different than the behavior of Cloud Action Simulate.)
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/task/simulate
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/task/<task_id>/simulate
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Task Simulate using a non-existing Task takes as input a Task object, using the parameters outlined above.
Source Object
## Create task with source object eventFind
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/task" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"destination": "my_company/task_output/sampleTask",
"periodicity": "20000",
"js": "function(ds, raw){return {\"my_company/task_output/findEvend\":ds};}",
"source": {
"eventFind": {
"streamId": "s5e5d6db4772f39d6b996da59",
"options": {
"limit": 1
}
}
},
"displayName": "A sample task with eventFind source"
}'
## Response for task with eventFind source
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "t5e5f2ae6772f39d6b9977d2e",
"companyId": "c5bae617e90f45d7d11710087",
"creationDate": 1583295206808,
"creatorId": "i5dea9ae317900a4b57f95b39",
"destination": "my_company/task_output/sampleTask",
"displayName": "A sample task with eventFind source",
"js": "function(ds, raw){return {\"my_company/task_output/findEvend\":ds};}",
"lastRun": 0,
"periodicity": 20000,
"runCt": 0,
"source": {
"eventFind": {
"streamId": "s5e5d6db4772f39d6b996da59",
"options": {
"limit": 1
}
}
}
}
}
## Create task with source object http
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/task" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"destination": "my_company/task_output/sampleHttpTask",
"periodicity": "20000",
"js":
"function f(events,response){ return {\"my_company/task_output/sampleHttpTask": [{\"elems\":{\"a\":response.status, \"b\":a}}]};}",
"source": {
"http": {
"get": {
"url": "http://httpbin.org/get?a=b"
},
"parser": {"jsonpath": {"root": "$", "nodes":{"headers":"headers.Accept", "a":"args.a"} } }
}
},
"displayName": "A sample task with http source"
}'
## Response for task with http source
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "t5e5fdd9dd6f7e7f7f9d3c955",
"companyId": "c5bae617e90f45d7d11710087",
"creationDate": 1583340957885,
"creatorId": "i5dea9ae317900a4b57f95b39",
"destination": "my_company/task_output/sampleHttpTask",
"displayName": "A test task-3.2",
"js": "function f(events,response){ return {\"my_company/task_output/sampleHttpTask\": [{\"elems\":{\"a\":response.status, \"b\":a}}]};}",
"lastRun": 0,
"periodicity": 20000,
"runCt": 0,
"source": {
"http": {
"parser": {
"jsonpath": {
"nodes": {
"elems": {
"headers": "headers.Accept",
"a": "args.a"
}
},
"root": "$"
}
},
"get": {
"url": "http://httpbin.org/get?a=b"
}
}
}
}
}
The Source object defines declaratively how data will be ingested into the Task's JavaScript function. Retrieved elements will be converted into the form of events if necessary (e.g, for http
sources). If Source is unspecified, the Task JavaScript will be executed with empty input arguments.
Name | Description |
---|---|
eventFind or http | required. configuration object |
HTTP Configuration Object
Name | Description |
---|---|
parser | required. possible values are jsonpath, xpath, rss |
get, put, post, or delete | required. value is an HTTP Method object |
HTTP Method Object
name | description |
---|---|
url | required. |
headers | optional. |
data | optional. request body. |
EventFind Configuration Object
name | description |
---|---|
streamId or streamPath | required. |
options | optional. EventFind options object. |
EventFind Options Object
Name | Description |
---|---|
limit | optional. |
start | optional. |
sort | optional. |
order | optional. |
filter | optional. |
Disabled Tasks
Tasks can become disabled if they raise persistent or systematic errors. For more information, see Disabled Objects
Blueprint Object
Creating a Blueprint
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/blueprint" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"displayName": "My Blueprint",
"localActions": {
"l000000000000000000000000": {
"version": 1
}
},
"observations": {
"/redSensor/position/value": {
"position": {
"period": 3600,
"destination": "store",
"description": "Send Position Periodically"
}
}
},
"state": {
"/redSensor/position/period": 60
}
}"
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "b5b86d4d88c633a1add9f181d",
"companyId": "c5adf465baa02b35e0cce78c2",
"creationDate": 1535562968521,
"creatorId": "i5adf463709159f4dde43a86f",
"displayName": "My Blueprint",
"localActions": {
"l000000000000000000000000": {
"version": 1
}
},
"observations": {
"/redSensor/position/value": {
"position": {
"period": 3600,
"destination": "store",
"description": "Send Position Periodically"
}
}
},
"state": {
"/redSensor/position/period": 60
},
"version": 1
}
}
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/blueprint
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Request JSON Object
Key | Type | Description |
---|---|---|
displayName | string | A friendly name for the Device |
localActions | object | Defines the Local Actions (represented by IDs and Versions) to be deployed to the Device |
observations | object | A collection of "routes" from Resources to other Resources, Local Actions, or the Cloud |
state | object | The default values assigned to Resources on the Device |
Listing company Blueprints
curl "https://octave-api.sierrawireless.io/v5.0/my_company/blueprint" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "b5b86d4d88c633a1add9f181d",
"companyId": "c5adf465baa02b35e0cce78c2",
"creationDate": 1535562968521,
"creatorId": "i5adf463709159f4dde43a86f",
"displayName": "My Blueprint",
"localActions": {
"l000000000000000000000000": {
"version": 1
}
},
"observations": {
"/redSensor/position/value": {
"position": {
"period": 3600,
"destination": "store",
"description": "Send Position Periodically"
}
}
},
"state": {
"/redSensor/position/period": 60
},
"version": 1
},
...
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/blueprint
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Reading a Blueprint
curl "https://octave-api.sierrawireless.io/v5.0/my_company/blueprint/b5b86d4d88c633a1add9f181d" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "b5b86d4d88c633a1add9f181d",
"companyId": "c5adf465baa02b35e0cce78c2",
"creationDate": 1535562968521,
"creatorId": "i5adf463709159f4dde43a86f",
"displayName": "My Blueprint",
"localActions": {
"l000000000000000000000000": {
"version": 1
}
},
"observations": {
"/redSensor/position/value": {
"position": {
"period": 3600,
"destination": "store",
"description": "Send Position Periodically"
}
}
},
"state": {
"/redSensor/position/period": 60
},
"version": 1
}
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/blueprint/<blueprint_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Updating a Blueprint
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/blueprint/b5b86d4d88c633a1add9f181d" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"state": {
"/redSensor/position/period": 60
"/cloudInterface/developer_mode/enable": false,
}
}"
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "b5b86d4d88c633a1add9f181d",
"companyId": "c5adf465baa02b35e0cce78c2",
"creationDate": 1535562968521,
"creatorId": "i5adf463709159f4dde43a86f",
"displayName": "My Blueprint",
"localActions": {
"l000000000000000000000000": {
"version": 1
}
},
"observations": {
"/redSensor/position/value": {
"position": {
"period": 3600,
"destination": "store",
"description": "Send Position Periodically"
}
}
},
"state": {
"/redSensor/position/period": 60
"/cloudInterface/developer_mode/enable": false,
}
"version": 2
}
}
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/blueprint/<blueprint_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Value |
---|---|---|
state | object | The default values assigned to Resources on the Device |
Deleting a Blueprint
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/blueprint/b5b86d4d88c633a1add9f181d" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/blueprint/<blueprint_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Apply a Blueprint
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/blueprint/apply" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"blueprint": {"id": "b8732940842676ddddd9f181d", "version": 1},
"deviceIds": ["d000000000000000000000d82"]
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "o5f735faec7106cef8889cdef",
"action": "APPLY_BLUEPRINT",
"companyId": "c00000000000000000000005b",
"complete": false,
"creationDate": 1601396654451,
"creatorId": "i000000000000000000000001",
"details": {},
"deviceIds": [
"d000000000000000000000d82"
],
"lastEditDate": 1601396654451,
"lastEditorId": "i000000000000000000000001",
"state": "UNKNOWN",
"status": {
"d000000000000000000000d82": {
"PUSH_CONFIGURATION": {
"state": "UNKNOWN",
"ts": 1601396654448
}
}
},
"stepCount": 1,
"timeout": 86400
}
}
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/blueprint/apply
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Value |
---|---|---|
blueprint.id | string | The Blueprint ID |
blueprint.version | number | The Blueprint Version |
deviceIds | array | The list of Device IDs that will receive the Blueprint |
Group Object
Creating a Group
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/group" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"displayName": "My Group",
"memberIds": [
"i000000000000000000000065"
],
"description": "My Group'"'"'s description"
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request ... has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "g5b71d2db6f38616bd1ae41f3",
"companyId": "c000000000000000000000006",
"creationDate": 1534186203872,
"creatorId": "i000000000000000000000064",
"description": "My Group's description",
"displayName": "My Group",
"memberIds": [
"i000000000000000000000065"
]
}
}
Groups are used to combine multiple identities into a single object for purposes of issuing a share. All identities must be members of the company as the company that owns the group.
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/group
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Request JSON Object
Key | Type | Description |
---|---|---|
memberIds | array | List of identity ids |
displayName | string | Succint name |
description | string | Description |
Listing company Groups
curl "https://octave-api.sierrawireless.io/v5.0/my_company/group" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "g5b71d2db6f38616bd1ae41f3",
"companyId": "c000000000000000000000006",
"creationDate": 1534186646683,
"creatorId": "i000000000000000000000064",
"description": "My Group's description",
"displayName": "My Group",
"memberIds": [
"i000000000000000000000065"
]
},
...
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/group
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Reading a Group
curl "https://octave-api.sierrawireless.io/v5.0/my_company/group/g5b71d2db6f38616bd1ae41f3" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "g5b71d2db6f38616bd1ae41f3",
"companyId": "c000000000000000000000006",
"creationDate": 1534186646683,
"creatorId": "i000000000000000000000064",
"description": "My Group's description",
"displayName": "My Group",
"memberIds": [
"i000000000000000000000065"
]
}
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/group/<group_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Updating a Group
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/group/g5b71d2db6f38616bd1ae41f3" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"memberIds": [
"i000000000000000000000065",
"i000000000000000000000064"
]
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "g5b71d2db6f38616bd1ae41f3",
"companyId": "c000000000000000000000006",
"creationDate": 1534186203872,
"creatorId": "i000000000000000000000064",
"description": "My Group's description",
"displayName": "My Group",
"lastEditDate": 1534186394487,
"memberIds": [
"i000000000000000000000065",
"i000000000000000000000064"
]
}
}
HTTP Request
PUT https://octave-api.sierrawireless.io/v5.0/<company_name>/group/<group_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Deleting a Group
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/group/g5b71d2db6f38616bd1ae41f3" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/group/<group_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Share Object
Creating a Share
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/share" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"paths": {
"/my_company/devices": {
"eventWrite": true,
"write": true,
"read": true,
"eventRead": true
}
},
"roles": [
"CLOUD_ACTION_READ",
"CLOUD_ACTION_WRITE",
"CLOUD_ACTION_DELETE"
],
"issuedTo": "g6036a25d1112f85e83806624"
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "h5b719e696f386161e7eda042",
"companyId": "c000000000000000000000006",
"creationDate": 1534172777742,
"creatorId": "i000000000000000000000064",
"issuedBy": "i000000000000000000000064",
"issuedTo": "g6036a25d1112f85e83806624",
"paths": {
"/my_company/devices": {
"read": true,
"write": true,
"eventRead": true,
"eventWrite": true
}
},
"roles": [
"CLOUD_ACTION_READ",
"CLOUD_ACTION_WRITE",
"CLOUD_ACTION_DELETE"
]
}
}
You can create a share and issue it to the group to assign permissions to all group members.
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/share
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Request JSON Object
Key | Type | Description |
---|---|---|
issuedTo | string | Required. Group ID of the recipient of the Share. Must be a member of the same company. |
paths | object | Required. Specifies the path-based permissions to grant. |
roles | array | Optional; defaults to empty. Specifies the roles to grant. |
description | string | Optional. Human-friendly description |
duration | int | Optional. In milliseconds. |
Available path-based permissions
Permission | Description |
---|---|
read | Read objects within the given hierarchy |
write | Write objects within the given hierarchy |
eventRead | Read events within the given hierarchy |
eventWrite | Write events within the given hierarchy |
administer | Shorthand for having all above flags |
Available roles
Role | Description |
---|---|
CLOUD_ACTION_READ | Read Cloud Actionx |
CLOUD_ACTION_WRITE | Create and Edit Cloud Actions |
CLOUD_ACTION_DELETE | Delete Cloud Actions |
CLOUD_CONNECTOR_READ | Read Cloud Connectors |
CLOUD_CONNECTOR_WRITE | Create and Edit Cloud Connectors |
CLOUD_CONNECTOR_DELETE | Delete Cloud Connectors |
LOCAL_ACTION_READ | Read Local Actions |
LOCAL_ACTION_WRITE | Create and Edit Local Actions |
LOCAL_ACTION_DELETE | Delete Local Actions |
BLUEPRINT_READ | Read Blueprints |
BLUEPRINT_WRITE | Create and Edit Blueprints |
BLUEPRINT_DELETE | Delete Blueprints |
TASK_READ | Read Tasks |
TASK_WRITE | Create and Edit Tasks |
TASK_DELETE | Delete Tasks |
COMPANY_WRITE | Edit Company Object |
COMPANY_MEMBERSHIP_EDIT | Allows Identity to control Company Membership |
Listing company Shares
curl "https://octave-api.sierrawireless.io/v5.0/my_company/share" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "h5b71a4f66f38616bd1ae41db",
"companyId": "c000000000000000000000006",
"creationDate": 1534174454553,
"creatorId": "i000000000000000000000064",
"issuedBy": "i000000000000000000000064",
"issuedTo": "g6036a25d1112f85e83806624",
"paths": {
"/my_company/devices": {
"read": true,
"write": true,
"eventRead": true,
"eventWrite": true
}
},
"roles": [
"CLOUD_ACTION_READ",
"CLOUD_ACTION_WRITE",
"CLOUD_ACTION_DELETE"
]
},
...
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/share
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Reading a Share
curl "https://octave-api.sierrawireless.io/v5.0/my_company/share/h5b71a4f66f38616bd1ae41db" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "h5b71a4f66f38616bd1ae41db",
"companyId": "c000000000000000000000006",
"creationDate": 1534174454553,
"creatorId": "i000000000000000000000064",
"issuedBy": "i000000000000000000000064",
"issuedTo": "g6036a25d1112f85e83806624",
"paths": {
"/my_company/devices": {
"read": true,
"write": true,
"eventRead": true,
"eventWrite": true
}
},
"roles": [
"CLOUD_ACTION_READ",
"CLOUD_ACTION_WRITE",
"CLOUD_ACTION_DELETE"
]
}
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/share/<share_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Query Parameters
Parameter | Default | Description |
---|---|---|
refs | 0 | 0 or 1, to disable/enable return of objects referenced by the created object |
Updating a Share
curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/share" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"paths": {
"/my_company/devices": {
"eventWrite": false,
"write": false,
"read": true,
"eventRead": true
}
},
"roles": [
"CLOUD_ACTION_READ",
"CLOUD_ACTION_WRITE"
],
"issuedTo": "g6036a25d1112f85e83806624"
}'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "h5b719e696f386161e7eda042",
"companyId": "c000000000000000000000006",
"creationDate": 1534172777742,
"creatorId": "i000000000000000000000064",
"issuedBy": "i000000000000000000000064",
"issuedTo": "g6036a25d1112f85e83806624",
"paths": {
"/my_company/devices": {
"read": false,
"write": false,
"eventRead": true,
"eventWrite": true
}
},
"roles": [
"CLOUD_ACTION_READ",
"CLOUD_ACTION_WRITE"
]
}
}
Deleting a Share
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/share/h5b719e696f386161e7eda042" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/share/<share_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Token Object
Creating a Token
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/my_company/token" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"paths": {
"/my_company/devices": {
"eventWrite": true,
"eventRead": true
}
},
"duration": "60000000"
}'
{
"head": {
"status": 201,
"ok": true,
"messages": [
"Your request has been processed successfully. A new resource has been created."
],
"errors": [],
"references": {}
},
"body": {
"id": "k5b71eec26f38616bd1ae4214",
"companyId": "c000000000000000000000006",
"creationDate": 1534193346844,
"creatorId": "i000000000000000000000064",
"duration": 60000000,
"paths": {
"/my_company/devices": {
"eventRead": true,
"eventWrite": true
}
},
"tokenString": "uLFm4qCIXUKSVAj6SbmKwpk9iOOV",
"expiresInMs": 59999998
}
}
Tokens expose a limited set of path-based permissions on an anonymous basis (dissociated from any particular identity). They are particularly suited for event reading and writing by applications and devices.
HTTP Request
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/token
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Description |
---|---|---|
paths | object | Required. Specifies the path-based permissions to grant. |
description | string | Optional. Human-friendly description |
duration | int | Optional. In milliseconds. |
Available path-based permissions
Permission | Description |
---|---|
eventRead | Read events within the given hierarchy |
eventWrite | Write events within the given hierarchy |
Listing company Tokens
curl "https://octave-api.sierrawireless.io/v5.0/my_company/token" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "k5b71eec26f38616bd1ae4214",
"companyId": "c000000000000000000000006",
"creationDate": 1534193346844,
"creatorId": "i000000000000000000000064",
"duration": 60000000,
"paths": {
"/my_company/devices": {
"eventRead": true,
"eventWrite": true
}
},
"tokenString": "uLFm4qCIXUKSVAj6SbmKwpk9iOOV",
"expiresInMs": 59992978
},
...
]
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/token
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Reading a Token
curl "https://octave-api.sierrawireless.io/v5.0/my_company/token/k5b71ed846f38616bd1ae420d" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "k5b71eec26f38616bd1ae4214",
"companyId": "c000000000000000000000006",
"creationDate": 1534193346844,
"creatorId": "i000000000000000000000064",
"duration": 60000000,
"paths": {
"/my_company/devices": {
"eventRead": true,
"eventWrite": true
}
},
"tokenString": "uLFm4qCIXUKSVAj6SbmKwpk9iOOV",
"expiresInMs": 59992978
}
}
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/token/<token_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Updating a Token
Deleting a Token
curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/token/k5b71eec26f38616bd1ae4214" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [
"Your request has been processed successfully. The requested resource has been deleted."
],
"errors": [],
"references": {}
},
"body": {}
}
HTTP Request
DELETE https://octave-api.sierrawireless.io/v5.0/<company_name>/token/<token_id>
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Firmware versions
Listing system-wide Firmware versions
curl "https://octave-api.sierrawireless.io/v5.0/firmware"
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"creationDate": 1586187115697,
"creatorId": "i000000000000000000000001",
"id": "y5e8b4b6b043f2a1b4bdcd4b9",
"version": "1.2.3"
},
{
"creationDate": 1586188358741,
"creatorId": "i000000000000000000000001",
"id": "y5e8b5046043f2a2d6d4e4fbb",
"version": "1.2.4"
}
]
}
Listing system-wide (i.e, available for all companies) Firmware versions doesn't require authentication, so this call doesn't need auth headers.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/firmware
Listing company Firmware versions
curl "https://octave-api.sierrawireless.io/v5.0/my_company/firmware" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"creationDate": 1586187115697,
"creatorId": "i000000000000000000000001",
"companyId": "c000000000000000000000006",
"id": "y5e8b4b6b043f2a1b4bdcd4b9",
"version": "1.2.2"
},
{
"creationDate": 1586187115697,
"creatorId": "i000000000000000000000001",
"id": "y5e8b4b6b043f2a1b4bdcd4b9",
"version": "1.2.3"
},
{
"creationDate": 1586188358741,
"creatorId": "i000000000000000000000001",
"id": "y5e8b5046043f2a2d6d4e4fbb",
"version": "1.2.4"
}
]
}
This call returns company-specific Firmware versions in addition to system-wide ones.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/my_company/firmware
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Release Notes
Listing system-wide Release Notes
curl "https://octave-api.sierrawireless.io/v5.0/release-note"
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"creationDate": 1586187115697,
"creatorId": "i000000000000000000000001",
"id": "y5e8b4b6b043f2a1b4bdcd4b9",
"version": "5.3.1",
"notes": "# Octave API version 5.3.1....",
},
{
"creationDate": 1586188358741,
"creatorId": "i000000000000000000000001",
"id": "y5e8b5046043f2a2d6d4e4fbb",
"version": "5.4.0",
"notes": "# Octave API version 5.4.0....",
}
]
}
Listing system-wide (i.e, available for all companies) Release Notes doesn't require authentication, so this call doesn't need auth headers.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/release-note
Listing company Release Note versions
curl "https://octave-api.sierrawireless.io/v5.0/my_company/release-note" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"creationDate": 1586187115697,
"creatorId": "i000000000000000000000001",
"companyId": "c000000000000000000000006",
"id": "y5e8b4b6b043f2a1b4bdcd4b9",
"version": "5.3.0",
"notes": "# Octave API version 5.3.0...."
},
{
"creationDate": 1586187115697,
"creatorId": "i000000000000000000000001",
"id": "y5e8b4b6b043f2a1b4bdcd4b9",
"version": "5.3.1",
"notes": "# Octave API version 5.3.1...."
},
{
"creationDate": 1586188358741,
"creatorId": "i000000000000000000000001",
"id": "y5e8b5046043f2a2d6d4e4fbb",
"version": "5.4.0",
"notes": "# Octave API version 5.4.0...."
}
]
}
This call returns company-specific Release Notes in addition to system-wide ones.
HTTP Request
GET https://octave-api.sierrawireless.io/v5.0/my_company/release-note
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Location Data
Full Example
{
"path": "/my_company/my_first_stream",
"location": {
"lat": 40.703285,
"lon": -73.987852,
},
"elems": {
"name": "my location"
}
}
The location field is optional but, if provided, the lat
and lon
fields are required. All other fields are optional.
Location Map Fields
lat
Latitude
lon
Longitude
alt
Altitude
vAcc
Vertical accuracy
hAcc
Horizontal accuracy
fixType
For internal use
detail
A map of additional optional data
Querying by Location
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=location WITHIN 500 MILES OF [40.8, 74]
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=location.$latitude > 0.09
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=location.$longitude > 0.18
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=EXISTS location
Filtering
Filters can be used for explicit object matching, as well as within members of Stream and Cloud Action objects, where they control the types of Events that can enter a Cloud Action or Stream.
Operator List
Comparison Type | Syntax |
---|---|
Fixed Value Comparison | aMemberName (< or <= or == or > or >= or !=) aValue |
Element Value Comparison | aMemberName (< or <= or == or > or >= or !=) bMemberName |
Modulo | aMemberName % X (== or !=) Y |
Regex | aMemberName =~ aJavaRegex |
IN | aMemberName IN ["value1", "value2", "value3"] |
CONTAINS | aMemberName CONTAINS ["value1", "value2", "value3"] |
WITHIN (distance) | location WITHIN 5 MILES OF [40.703987, -73.986759] |
WITHIN (bounds) | location WITHIN [[0,0],[0,10],[10,10],[10,0]] |
EXISTS | EXISTS aMemberName |
AGE | AGE (< or <= or == or > or >=) msSinceCreated (TIMEUNIT) or AGE('fieldname') (< or <= or == or > or >=) msSinceCreated (TIMEUNIT) |
MATCHES | MATCHES /aJavaRegex/ |
NOT | NOT aFilterRule |
Fixed Value Comparison
Matches objects with member values that evaluate to true given the specified comparison to a fixed value:
Find all Events in a given Stream where the element "aNumber" has a value less than or equal to 1:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=elems.aNumber<=1
Find all Events in a given Stream where the element "shipped" is false:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=elems.shipped!=true
Find all Streams where the description is equal to "myFirstStream":
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/stream?filter=description=="myFirstStream"
Element Value Comparison
Matches objects with member values that evaluate to true given the specified comparison to the value of another member:
Find all Events where the value of the element "length" equals the value of the element "width":
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=elems.length<=elems.width
Find all Streams where the value of the description member equals the value of the path member:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event?filter=path==description
Modulo
Matches objects with member values that match the given modulo
Find all Events where the counter is a multiple of 100:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=elems.counter % 100 == 0
Regex
Matches objects with member values that evaluate to true when compared to the given regex.
Find all Events in the given Stream where the value of the element "title" matches the regex /[cC]lojure/:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=elems.title=~/[cC]lojure/
Find all Streams where the value of the path starts with /acme/:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/stream?filter=path=~/^\/acme\//
Find child Streams of the Stream whose path is /acme/:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/stream?filter=path=~/^\/acme\/[^\/]*$
Find all Cloud Actions feeding Streams whose path starts with /acme/:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/stream?filter=destination=~/^\/acme\//
IN
Matches objects with member values that equal any item of the provided list.
Find all Events where the value of the "status" element is either "shipped" or "delivered":
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=elems.status IN ["shipped","delivered"]
Find all Cloud Actions where the value of the "destination" element is either "/acme/myFirstStream" or "/acme/mySecondStream":
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/action/<stream_id>?filter=destination IN ["/acme/myFirstStream","/acme/mySecondStream"]
CONTAINS
Matches objects with a list member whose values contain all items of the provided list.
Find all Events where the value of the "ingredients" element contains "vodka":
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=elems.ingredients CONTAINS ["vodka"]
Find all Events where the value of the "ingredients" element contains both "vodka" AND "gasoline":
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=elems.ingredients CONTAINS ["vodka","gasoline"]
WITHIN (by distance)
Matches objects with an element location that lies within the specified distance of the given location.
Find all Events with a location element that lies within 500 miles of 40.703987, -73.986759:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=location WITHIN 500 MILES OF [40.703987, -73.986759]
Available distance units are MILES, FEET, METERS, KILOMETERS
WITHIN (bounding box)
Matches objects with an element location that lies within the specified bounding box. The provided bounding box must have at least 3 distinct points but more can be provided.
Find all Events with a location element that lies within the bounds of points [40.703901,-73.996716],[40.704709,-73.979468],[40.694882,-73.984347]:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=location WITHIN [[40.703901,-73.996716],[40.704709,-73.979468],[40.694882,-73.984347]]
EXISTS
Matches objects with where the member or Event element exists and is not empty.
Find all Events where the element "title" exists:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=EXISTS elems.title
Find all Streams where the member "filter" exists:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/stream?filter=EXISTS filter
AGE
Matches objects with a date that evaluates to true when compared with the given specifiers. By default, AGE will compare the Event's creationDate
. The AGE()
macro allows age queries on other date fields such as lastEditDate
.
Find all Events with a creation date in the last 3600000 miliseconds:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=AGE < 3600000
Find all Cloud Actions which were created over a 2 weeks ago:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/action?filter=AGE < 2 WEEKS
This can also be used to search in other date fields:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/action?filter=AGE("lastEditDate") < 42 HOURS
Timeunits supported are MILLISECONDS | SECONDS | MINUTES | HOURS | DAYS | WEEKS. If no timeunit is appended MILLISECONDS is assumed.
MATCHES
Matches thedescription
or displayName
field in Events.
Find all Events in the given Stream where the value of "description" field ( part of "elems") matches the regex /[cC]lojure/:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=MATCHES /[cC]lojure/
NOTE: id fields will not be searched, instead use one or more combined regex filters.
NOT
Provides the inverse functionality of any filter rule.
Finds all Events in the given Stream where the value of element "title" does not match [cC]lojure:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>?filter=NOT elems.title =~ /[cC]lojure/
Finds all Streams where the value of "description" member does not match [cC]lojure:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/stream?filter=NOT description =~ /[cC]lojure/
Combining Filters
Filters can be combined using logical &&, logical || and grouped.
Finds all Cloud Actions to a Stream whose path is "/acme/destStream" that contain a filter:
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/action?filter=destination=="/acme/destStream" && EXISTS filter
Finds all Events in the given Stream with a "on-hand" element whose value is over 100 and "state" is not "cancelled":
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/event/stream_id>?filter=elems.on-hand>100 && NOT elems.state=="canceled"
Finds all Cloud Actions to "/acme/sourceStream" from Streams whose paths start with "/a" or end with "b"
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/action?filter=source=="/acme/sourceStream" && (destination=~/^\/a/ || to=~/b$/)
Paging
Controling the number of results
$ curl -G "https://octave-api.sierrawireless.io/v5.0/my_company/event/<stream_id>" \
> -H "X-Auth-Token: 2R5xwhmlmb9r6z90XCUYqOu1ScJJuPMr" \
> --data-urlencode 'limit=2'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [{
"id": "d585827455caf784b9ef99ba3",
"streamId": "f53b1d1600cf27b75148de02e",
"creationDate": 1482172229772,
"path": "/my_company/lightSensor",
"version": 0,
"elems": {
"measure": 2
}
}, {
"id": "d585827455caf784b9ef99b9f",
"streamId": "f53b1d1600cf27b75148de02e",
"creationDate": 1482172229516,
"path": "/my_company/lightSensor",
"version": 0,
"elems": {
"measure": 1
}
}]
}
Append the URL parameter limit=N
, where N is the maximum number of Events, defaulting to 20.
Skipping Results
$ curl -G "https://octave-api.sierrawireless.io/v5.0/my_company/event/<stream_id>" \
> -H "X-Auth-Token: 2R5xwhmlmb9r6z90XCUYqOu1ScJJuPMr" \
> --data-urlencode 'start=2'
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [{
"id": "d585827455caf784b9ef99ba3",
"streamId": "f53b1d1600cf27b75148de02e",
"creationDate": 1482172229772,
"path": "/my_company/lightSensor",
"version": 0,
"elems": {
"measure": 2
}
}, {
"id": "d585827455caf784b9ef99b9f",
"streamId": "f53b1d1600cf27b75148de02e",
"creationDate": 1482172229516,
"path": "/my_company/lightSensor",
"version": 0,
"elems": {
"measure": 1
}
}]
}
Append the URL parameter start=N
, where N is the starting index, defaulting to 0.
Analyzing Events
Event data within a Stream can be grouped and aggregated in powerful ways.
For example:
- Get the average wind speed in the last 10 minutes, by town
- Get the maximum temperature within 5 miles of New York City
- Get the percentage of sensors that are currently online
Event Aggregate calls can be made through the REST API and within the Cloud Action environment. The examples below use the REST interface as a convention. However, the same information can be retrieved by a Cloud Action by using the JavaScript function Octave.Stream.Event.aggregate
.
Request Format
POST https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>/aggregate
Request Headers
Name | Description |
---|---|
X-Auth-Token | Token with appropriate permissions |
X-Auth-User | Identity name performing action |
Request JSON Object
Key | Type | Value |
---|---|---|
filter |
string | Optional. For defining the parameters of the search, the filter will only include the Events whose data you're interested in aggregating, see the Filter Language documentation for more details |
rule |
object | Optional. You can create rules based on boolean filters, for example, "x": "a > 1", or "x" : "location WITHIN 50 MILES OF [40.5,-73.5]" , (in this case you'd refer to these fields in your groupBy or output as the named key of the field, 'x'. Make sure your named fields are unique). The output of a rule will always be 1 for true or 0 for false, so $avg:x will return the % that passed the rule. |
groupBy |
list | Required. A list of the fields by which you'd like the results grouped. Results can be grouped by any literal element within a Event, or by a Date Selector, e.g. "$month:creationDate" |
output |
list | Required. The fields you want to output in your query. These must make use of the Selectors, e.g. "$avg:temperature" |
sorts |
list | Optional. The order in which the results are returned. Multiple fields can be specified. Fields must match those specified in the "groupBy" or "output" attributes. |
Selectors
Functions that wrap an Event element
Dates
For any field that is specified as a date, you can use a Date Selector to retrieve part of that date. This can be useful for grouping purposes.
The selectors are:
-
$year
-
$month
-
$day
-
$hour
-
$minute
-
$second
Example: $month:lastEditDate
will return only the month component from the date. Use this to group results by the month they were last edited.
By omitting the element name, creationDate
will be automatically chosen. E.g. $year
returns the year the Event was created.
Aggregate
Specifies an aggregation function applied to a field.
-
$sum:field
The sum of the field values for the defined grouping -
$avg:field
The average value of the field for the defined grouping -
$unique:field
A list of unique values for the field within the defined grouping -
$max:field
The maximum value of the field for the defined grouping -
$min:field
The minimum value of the field for the defined grouping -
$all:field
All values of the field for the defined grouping, includes duplicates -
$count
matching count of found records.
Distance
If you have specified a rule
element that utilizes a location, e.g. x : location WITHIN 20 MILES of [123,-321]
, you can use the distance selector distance:x
to retrieve the distance this Event is from [123,-321]
.
This can be used to sort or group the results, or as a general output.
Example
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/<company_name>/event/<stream_id>/aggregate" \
-H 'X-Auth-Token: <token>' \
-H 'X-Auth-User: <user>' \
-d $'{
"filter":"EXISTS cpu_temp",
"rules":{"x":"cpu_temp > 50"},
"groupBy":["$month"],
"output":["$avg:cpu_temp","$min:cpu_temp","$max:cpu_temp","$avg:x","$count"],
"sorts":["$avg:x:desc", "$avg:cpu_temp:asc"]
}'
{
"head" : {
"status" : 200,
"ok" : true,
"messages" : [ {
"query" : {
"filter":"EXISTS cpu_temp",
"rules": {"x":"cpu_temp > 50"},
"groupBy":["$month"],
"output":["$avg:cpu_temp","$min:cpu_temp","$max:cpu_temp","$avg:x","$count"],
"sorts":["$avg:x:desc", "$avg:cpu_temp:asc"]}
} ],
"errors" : [ ],
"references" : { }
},
"body" : [
{ "_id": { "month": 2, "year": 2015},
"$avg:cpu_temp": 49.75333333333331,
"$avg:x": 0.3333333333333333,
"$count": 120,
"$max:cpu_temp": 56.2,
"$min:cpu_temp": 45.5},
{ "_id": { "month": 1, "year": 2015},
"$avg:cpu_temp": 49.10580204778171,
"$avg:x": 0.2832764505119454,
"$count": 293,
"$max:cpu_temp": 98.6,
"$min:cpu_temp": 39.0}
]
}
For example, if there was a Stream that contained Events indicating the processor's temperature as a 'cpu_temp' elem, in order to obtain the average, minimum and maximum temperatures on a monthly basis:
"filter":"EXISTS cpu_temp"
This uses a sample set which ensures that all Events selected for this aggregate query contain a cpu_temp, all others will be excluded."rules":{"x":"cpu_temp > 50"}
This specifies a rule to define how often the cpu_temp is above the ideal temperature, in this case 50."groupBy":["$month"]
I want the response to provide numbers on a monthly basis."output":["$avg:cpu_temp","$min:cpu_temp","$max:cpu_temp","$avg:x","$count"]
Here the maximum, minimum, and average temperature values will be returned in the grouping for each month. The last data point in the output,$avg:x
, will return the percentage of Events that pass the rule that was defined inrules
.$count
will return the size of the sample set of Events that satisfied the filter within each grouping."sorts":["$avg:x:desc", "$avg:cpu_temp:asc"]
The results will be sorted by the$avg:x
field in descending order first, then by the$avg:cpu_temp
field in ascending order.
Versions
curl "https://octave-api.sierrawireless.io/v5.0/my_company/versions/action/a5b5a5b7d32d67b1856414575" \
-H 'x-auth-user: <user>' \
-H 'x-auth-token: <token>
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "a5b5a5b7d32d67b1856414575",
"companyId": "c5b280e48c939467de918e7f3",
"creationDate": 1532648317243,
"creatorId": "i5b1050dd83ee687bb03fb454",
"description": "Versions demo",
"js": "function(input){ return { \"/my_company/output\": [input]} }",
"source": "/my_company/input",
"version": 1
},
{
"id": "a5b5a5b7d32d67b1856414575",
"companyId": "c5b280e48c939467de918e7f3",
"creationDate": 1532648317243,
"creatorId": "i5b1050dd83ee687bb03fb454",
"description": "Rennamed action",
"js": "function(input){ return { \"/my_company/output\": [input]} }",
"source": "/my_company/input",
"lastEditDate": 1533823574532,
"version": 2
}
]
}
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/versions/<object_type>/<object_id>
Certain domain objects (e.g., Cloud Actions, Edge Actions, Blueprints, etc.) are versioned. When they are updated, the previous instance of the object is not deleted. Instead, a version field on the object is incremented and the previous version of the object is preserved for later retrieval. Versions of an object can be queried using the following REST API endpoints.
Valid object_type are action
, local-action
, and blueprint
.
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/versions/<object_type>/<object_id>/<version_number>
curl "https://octave-api.sierrawireless.io/v5.0/my_company/versions/action/a5b5a5b7d32d67b1856414575/2" \
-H 'x-auth-user: <user>' \
-H 'x-auth-token: <token>
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": {
"id": "a5b5a5b7d32d67b1856414575",
"companyId": "c5b280e48c939467de918e7f3",
"creationDate": 1532648317243,
"creatorId": "i5b1050dd83ee687bb03fb454",
"description": "Rennamed action",
"js": "function(input){ return { \"/my_company/output\": [input]} }",
"source": "/my_company/input",
"lastEditDate": 1533823574532,
"version": 2
}
}
Websockets
Establishing a WebSockets connection to Octave is a two step process:
- Request a
session id
via authenticated HTTP Post - Use the
session id
in the WSS url
A quick way to get started with WebSockets is to use an interactive command-line tool. In the following examples we'll use wscat
, which is a node.js based tool. You can download and install wscat via npm using the following command:
npm install -g wscat
Requesting a Session ID
$ curl -XPOST https://octave-ws.sierrawireless.io/session \
-H "X-Auth-User: <user>" \
-H "X-Auth-Company: <company_name>" \
-H "X-Auth-Token: <token>"
{
"head": {
"ok": true,
"status": 201,
"errors": []
},
"body": {
"id": "n2fBC9YeE6g.qsQNPOZfoSRP3brEY_9QWapawcjXl04Y"
}
}
Send a POST request to https://octave-ws.sierrawireless.io/session
to request a session. When using a restricted token, one would omit the X-Auth-User
header.
Establishing a WSS Connection
$ wscat -c "wss://octave-ws.sierrawireless.io/session/n2fBC9YeE6g.rQzrm_RDmpaiDKcyAYEwzZnQ9EU6ukN5/ws"
connected (press CTRL+C to quit)
>
We'll take the session id provided above and add that to the wss://
url we use to connect. Note that the session ids provided in the POST request expire if there is not an active connection, so make sure to have wscat
ready to connect before you request a session id.
When you see the >
propt above, you are connected.
Subscribing to Events in a Stream
{
"msgId": "my-request",
"object": "event",
"type": "subscribe",
"streamId": "s53b1d1600cf27b75148de0ac"
}
{
"msgId": "my-path-request",
"object": "event",
"type": "subscribe",
"path": "/my/stream/path"
}
WebSockets is a "push" based transport mechanism, and so you can subscribe to one or many Streams and receive all Events in realtime by issuing a subscription request for an individual Stream. You can subscribe by path
or id
.
Subscription Acknowledgement
{
"head": {
"msgId": "my-path-request",
"ok": true,
"errors": [],
"messages": [ "Your request has been processed successfully." ]
},
"body": {}
}
Each subscription request will receive and acknowledgement which echos the user-supplied msgId
.
Incoming Events
{
"type": "message",
"resource": "s53b1d1600cf27b75148de0ac",
"value": {
// <... Event object here ...>
}
}
When an Event is sent to the specified Stream, it will be delivered in the following message format:
Unsubscribing
{
"msgId": "my-request",
"object": "event",
"type": "unsubscribe",
"streamId": "s53b1d1600cf27b75148de0ac"
}
To unsubscribe from a Stream, just send the same message with the type "unsubscribe," instead of subscribe.
Heatbeat
{
"type": "heartbeat"
}
The client should periodically send a heartbeat message to keep the session alive. Sessions have a timeout of 6 minutes. Sending a heartbeat will touch the timeout and keep it from expiring.
Notifications
Notifications are generated based upon various actions, and are represented as Events that get written to predefined Streams. When a notification is generated, two notification Events are generated. A redacted notification gets written to the redacted notification location, and the unredacted notification gets written to the unredacted notification location. Redaction is performed because a notification might contain sensitive information that a user without permissions shouldn't be able to view. All users have access to the summary notifications stream; only users with the permissions for the object that generated the notification are able to view the unredacted notification.
Redacted notifications are written to the path /my_company/:summary-inbox
. This Stream contains notifications for all objects and stores only the most recent action for each particular object.
Unredacted notifications for objects other than devices are written to the path /my_company/:inbox/<object_type>
, where valid object types are blueprint
, cloud-action
, cloud-connector
, external
, group
, local-action
, share
, stream
, task
, and token
.
Unredacted notifications for devices are written to /my_company/devices/<device_name>/:inbox
.
Unredacted Notifications
curl "https://octave-api.sierrawireless.io/v5.0/my_company/notifications/device/d5b291fc6ff127c21fdce280b" \
-H 'x-auth-user: <user>' \
-H 'x-auth-token: <token>
{
"head": {
"status": 200,
"ok": true,
"messages": [],
"errors": [],
"references": {}
},
"body": [
{
"id": "e5b730c9b83ee68665795b5a2",
"streamId": "s5b291fc6ff127c21fdce281b",
"creationDate": 1534266523583,
"generatedDate": 1534266523583,
"path": "/my_company/devices/my_device/:inbox",
"version": 0,
"elems": {
"sourceId": "d5b291fc6ff127c21fdce280b",
"actor": {
"name": "alice",
"id": "5b2903f6ff127c1f9d80c601"
},
"kind": "NOTIFICATION",
"action": "UPDATE",
"details": {
"lastEditDate": {
"before": 1534266523580,
"after": 1534266506338
},
"state": {
"before": {
"/deviceServices/cellular/signal/enable": true,
"/redSensor/gyro/enable": true,
"/redSensor/accel/enable": true,
"/deviceServices/counter/enable": true,
"/redSensor/light/period": 10,
"/cloudInterface/store_forward/period": 600,
"/redSensor/gyro/period": 200,
"/deviceServices/cellular/signal/period": 10,
"/cloudInterface/status_line/enable": false,
"/redSensor/accel/period": 0.5,
"/deviceServices/counter/period": 0.2,
"/cloudInterface/developer_mode/enable": false,
"/util/counter/period": 0.2
},
"after": {
"/deviceServices/cellular/signal/enable": true,
"/deviceServices/cellular/signal/period": 10,
"/redSensor/gyro/enable": true,
"/redSensor/accel/enable": true,
"/cloudInterface/status_line/enable": false,
"/redSensor/accel/period": 0.5,
"/deviceServices/counter/enable": true,
"/deviceServices/counter/period": 0.2,
"/redSensor/light/period": 10,
"/cloudInterface/developer_mode/enable": false,
"/redSensor/gyro/period": 200,
"/util/counter/period": 0.2
}
}
},
"type": "device"
}
}
]
}
GET https://octave-api.sierrawireless.io/v5.0/<company_name>/notifications/<object_type>/<object_id>
A user that has permission to the Stream /my_company/:inbox
would be able to see all notifications for all objects. By default, only users that have Admin Group access will be able to read from this Path. Update notifications provide a diff of fields that have changed. This diff could contain potentially sensitive information, hence why access to unredacted notifications is restricted by permissions.
Users that do not have access to this Path can view notifications for which they are permissioned by using a special REST API endpoint:
Redacted Notifications
{
"id" : "e000000009e2d492e73356234",
"streamId" : "s5b4ce3c79e182f53e4f52e02",
"creationDate" : 1531765704081,
"lastEditDate" : 1531765705135,
"generatedDate" : 1531765705133,
"path" : "/my_company/:inbox",
"version" : 0,
"hash" : "s5b4ce3c89e182f53e4f52e39",
"elems" : {
"sourceId" : "s5b4ce3c89e182f53e4f52e39",
"actor" : {
"name" : "system",
"id" : "i000000000000000000000001"
},
"kind" : "NOTIFICATION",
"action" : "UPDATE",
"type" : "device",
"full" : {
"eventId" : "e5b859992e23a21558f31ab7b",
"streamId" : "s5b3ab093665c545444523500"
}
}
}
At right is an example redacted notification. Potentially sensitive information is unavailable. The redacted notification contains a reference to the unredacted notification (the Stream in which it is located and its Event object id).
Errors
HTTP Responses
The Octave REST API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request is invalid. |
403 | Forbidden -- You do not have access to the given object/namespace. |
404 | Not Found -- The specified resource could not be found. |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
Disabled Objects
{
"id": "a5d14b0e19ecf7e616d8486a8",
"description" : "A bad Action",
"disabled" : true,
...
}
Octave Objects that act autonomously can also produce errors, either transient or systematic. For example a Cloud Action might fail due to a bug in the accompanying JavaScript code, or a Cloud Connector might be configured incorrectly. Sometimes errors will occur due to some issue outside of Octave, such as an unreachable remote server targeted by a Cloud Connector.
Persistent or unrecoverable errors will trigger the Object to be disabled and require corrective action from the user. Objects that can be disabled automatically include:
- Cloud Actions
- Cloud Connectors
- Tasks
When an Object is disabled by the system, the Object's disabled
field will be set to true
and it will no longer function. Cloud Actions and Cloud Connectors will no longer be triggered on any input Events, while Tasks will no longer trigger periodically.
Disable Notifications
{
"creationDate": 1601301755714,
"creatorId": "i000000000000000000000001",
"elems": {
"action": "DISABLE",
"actor": {
"firstName": null,
"id": "i5cfe411cfc3da877623ee684",
"lastName": null,
"name": "frank_smith"
},
"details": {
"lastErrors": [
{
"message": "TypeError: Cannot read property \"lat\" from undefined",
"timestamp": 1601301664875
},
{
"message": "TypeError: Cannot read property \"lat\" from undefined",
"timestamp": 1601301680023
},
{
"message": "TypeError: Cannot read property \"lat\" from undefined",
"timestamp": 1601301710121
},
{
"message": "TypeError: Cannot read property \"lat\" from undefined",
"timestamp": 1601301725548
},
{
"message": "TypeError: Cannot read property \"lat\" from undefined",
"timestamp": 1601301755647
}
],
"message": "TypeError: Cannot read property \"lat\" from undefined",
"source": "/foo/devices/bar/:default"
},
"kind": "NOTIFICATION",
"sourceId": "a5f6e26152940dfc3af59ecf4",
"type": "action"
},
...
}
A Notification will be generated in the Company Inbox Stream, according to the Object type:
Type | Stream |
---|---|
Cloud Action | /<company_name>/:inbox/cloud-actions |
Cloud Connector | /<company_name>/:inbox/cloud-connectors |
Task | /<company_name>/:inbox/tasks |
The Notification will contain the ID of the Object (in elems.sourceId
) and details of why the Object was disabled (in elems.details.message
and/or elems.details.lastErrors
).
Remediation
In order to resume operation, users should first correct the source of the error either by updating the JavaScript or some other property, then set the disabled
property to false
. The Object will then begin functioning.
Causes
There are two kinds of error that will cause an Object to be disabled:
Critical Error
Non-transient errors that must be corrected immediately before operation can resume. For example, a Cloud Action that writes to a bad destination (non-existent or outside the company-scope).
An Object will be disabled immediately when a single unrecoverable error is raised.
Standard Error
All other errors, which could either be systematic or transient, such as JavaScript errors or HTTP connection errors.
Octave will continue operate the Object until it has failed repeatedly (at least 4 consecutive failures).
Dash Visualization Example
Visualization Overview
In this example we'll set up some MangOH Reds to stream gyro and accelerometer data to the cloud, and then use the Dash framework to build a custom visualization.
Setup MangOH Observations
First we'll set up two observations on all of the MangOHs to be used in the visualization. Ensure that the /redSensor/accel
and /redSensor/gyro
resources are configured to poll regularly (5 seconds should be fine). Then create an observation to send data to the cloud immediately.
Setup MangOH Tags
Next we'll set up a tag on the MangOHs to include in the demo. I'll use dashdemo: true
.
Get a Mapbox access Token
We'll be using Mapbox for our map. Head over there and get an access token.
Setup python and modules
certifi==2018.10.15
chardet==3.0.4
Click==7.0
dash==0.28.2
dash-core-components==0.39.0rc4
dash-html-components==0.13.2
dash-renderer==0.14.3
decorator==4.3.0
Flask==1.0.2
Flask-Caching==1.4.0
Flask-Compress==1.4.0
idna==2.7
ipython-genutils==0.2.0
itsdangerous==0.24
Jinja2==2.10
jsonschema==2.6.0
jupyter-core==4.4.0
MarkupSafe==1.0
nbformat==4.4.0
numpy==1.16.1
pandas==0.24.1
plotly==3.3.0
python-dateutil==2.8.0
pytz==2018.5
requests==2.19.1
retrying==1.3.3
six==1.11.0
traitlets==4.3.2
urllib3==1.23
Werkzeug==0.14.1
A complete list of modules can be found to the right. You can install them directly or use virtualenv
to keep your system python modules untouched. You'll need to use Python 3.
Create Token for Demo
curl -X "POST" "https://octave-api.sierrawireless.io/v5.0/<my_company>/token" \
-H 'X-Auth-User: <my_username>' \
-H 'X-Auth-Token: <my_master_token>' \
-H 'Content-Type: application/json; charset=utf-8' \
-d $'{
"paths": {
"/<my_company>/devices": {
"eventWrite": false,
"write": false,
"read": true,
"eventRead": true
}
},
"description": "Token to read devices and device streams for Demo"
}'
Since our application does not require full read/write access to Octave, we are going to create a token with limited access. The POST
command to the right will create a token that can only read devices and their streams.
The code
# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly
import plotly.graph_objs as go
import requests
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
from dash.dependencies import Input, Output, State
from datetime import datetime
from flask_caching import Cache
from os import getenv
from time import sleep
default_location = {'lat': 49.172477, 'lon': -123.071298}
creds = { 'X-Auth-Token': getenv('TOKEN', '<snip>') }
mapbox_access_token = getenv('MAPBOX_ACCESS', '<snip>')
company = getenv('COMPANY', '<snip>')
device_update_interval = int(getenv('DEVICE_UPDATE_INTERVAL', '20'))
external_stylesheets = ['https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
cache = Cache(app.server, config={
'CACHE_TYPE': 'filesystem',
'CACHE_DIR': 'cache-directory'
})
def update_devices():
global devices
print('Updating Devices')
url = 'https://octave-api.sierrawireless.io/v5.0/{}/device/?filter=tags.dashdemo%3D%3D%22true%22'.format(company)
all_devs = [d for d in requests.get(url, headers=creds).json()['body']]
for d in all_devs:
if 'location' not in d.keys():
d.update(location=default_location)
devices = all_devs
def update_devices_every(period=device_update_interval):
while True:
update_devices()
sleep(period)
update_devices()
executor = ThreadPoolExecutor(max_workers=1)
executor.submit(update_devices_every)
sleep(2) # make sure devices get loaded
@cache.memoize(timeout=2)
def get_events_for_device_stream(device_name, stream_name):
url = 'https://octave-api.sierrawireless.io/v5.0/%s/event/?path=/%s/devices/%s/%s' % (company,company, device_name, stream_name)
return sorted([e for e in requests.get(url, headers=creds).json()['body']], key=lambda x: x['generatedDate'])
def get_gyro_for_device(device_name):
events = get_events_for_device_stream(device_name, 'gyro2c')
def scatter_for_dimension(dim):
return go.Scatter(
x=[datetime.fromtimestamp(e['generatedDate']/1000.0) for e in events],
y=[e['elems']['redSensor']['gyro'][dim] for e in events],
name='Gyro %s' % dim
)
return [scatter_for_dimension(i) for i in ['x', 'y', 'z']]
def get_accel_for_device(device_name):
events = get_events_for_device_stream(device_name, 'accel2c')
def scatter_for_dimension(dim):
return go.Scatter(
x=[datetime.fromtimestamp(e['generatedDate']/1000.0) for e in events],
y=[e['elems']['redSensor']['accel'][dim] for e in events],
name='Accel %s' % dim
)
return [scatter_for_dimension(i) for i in ['x', 'y', 'z']]
def get_map_data_from_devices():
return [ dict(
type = 'scattermapbox',
lon = [d['location']['lon'] for d in devices],
lat = [d['location']['lat'] for d in devices],
text = [d['name'] for d in devices],
mode = 'markers',
marker = dict(
size = 8,
))]
def generate_layout():
return html.Div(children=[
html.Div(className='row', children=[
html.Div(className='col-12', children=[
dcc.Graph(id='live-update-map'),
dcc.Interval(
id='interval-component',
interval=10*1000,
n_intervals=0
)
]),
]),
html.Div(className='row', children=[
html.Div(className='col-6', children=[
dcc.Graph(id='gyro-time-series')
]),
html.Div(className='col-6', children=[
dcc.Graph(id='accel-time-series')
]),
])
])
app.layout = generate_layout()
@app.callback(
Output('live-update-map', 'figure'),
[Input('interval-component', 'n_intervals')],
[State('live-update-map', 'relayoutData')]
)
def update_location_map(n, mapdata):
fig = {
'data': get_map_data_from_devices(),
'layout': {
'autosize': True,
'title': '{} MangOHs tagged with dashdemo: true'.format(company),
'mapbox': {
'center': {},
'accesstoken': mapbox_access_token,
'center': {
'lat': 39.8283,
'lon': -98.5795
},
'zoom': 2,
},
'uirevision': 1
},
}
if not mapdata or 'mapbox.center' not in mapdata.keys(): mapdata = {}
fig['layout']['mapbox']['center'] = mapdata.get('mapbox.center', { 'lat': 39.8283, 'lon': -98.5795 })
fig['layout']['mapbox']['zoom'] = mapdata.get('mapbox.zoom', 2)
fig['layout']['mapbox']['bearing'] = mapdata.get('mapbox.bearing', 0)
fig['layout']['mapbox']['pitch'] = mapdata.get('mapbox.pitch', 0)
return fig
@app.callback(
Output('gyro-time-series', 'figure'),
[Input('live-update-map', 'hoverData')]
)
def update_gyro(hoverData):
if not hoverData: return {}
device_name = hoverData['points'][0]['text']
gyro_data = get_gyro_for_device(device_name)
return {
'data': gyro_data,
'layout': {
'title': 'Gyro Data for "%s"' % device_name
}
}
@app.callback(
Output('accel-time-series', 'figure'),
[Input('live-update-map', 'hoverData')]
)
def update_accel(hoverData):
if not hoverData: return {}
device_name = hoverData['points'][0]['text']
accel_data = get_accel_for_device(device_name)
return {
'data': accel_data,
'layout': {
'title': 'Accel Data for "%s"' % device_name
}
}
if __name__ == '__main__':
app.run_server(host='127.0.0.1')
Environmental Variables
TOKEN
: token from the previous stepMAPBOX_ACCESS
: access token created at Mapbox siteCOMPANY
: company nameDEVICE_UPDATE_INTERVAL
: how often we will update devices in the background
update_devices
functions
We use a background thread here to refresh the devices and their locations and store them in a global variable. This avoids having every page load trigger a new GET for the device list.
get_accel|gyro_for_device
functions
These functions gather data from the Octave Event API and transform them into a format suitable for the line plots.
get_map_data_from_devices
function
This function transforms the global device data into a format suitable for rendering in the map plot.
generate_layout
function
This is the main layout skeleton. The data is returned by the update
functions described below.
update
functions
Each of these functions are tied to events that occur on the page; either a periodic timer for the map, or a hover event on a device point. They call the get_
functions above to gather data over REST or use the memoized function return if under the timeout
number of seconds.
Running the demo
Save and execute the python code and browse to http://127.0.0.1:8050/.