The following sections describe the key entities of Octave that you will use to represent and work with your assets.

Resources

Resources are the heart of Octave. The Resources of a device define the services, sensors, and actuators that make up a solution, and are defined and organized as a tree on a device, similar to that of a file system on your computer.

More generally Resources represents "things" that create, receive, or store Events. Since resources are organized into a tree, each Resource will have a path that identifies its location. For example, a sensor defined as a resource, might be represented as /redSensor/light, an actuator defined by the LCD driver might be called /lcd/txt, and the configuration for a GPIO service might be defined in /io/config.

Your Device will initially broadcast its Resource Tree, such that it is available to view in the Octave Dashboard as well as through the Device object in the Octave REST API.

All resources are either an input or output, and are stateful (i.e. they hold the last single value sent to them). Inputs are tied to sensors and generate new Events from the underlying application or hardware (e.g. the temperature data from a temperature sensor). Outputs (actuators) forward Events to the application or hardware (e.g. to move a robotic arm.)

Inputs move data from the application to the Data Hub and Outputs move data from the DataHub, to the application. However, the direction is not strictly enforced and is used primarily to advertise the expected direction of flow. Applications may read / subscribe to Inputs if they want to and they may also write values to Outputs.

Each Resource is also of a particular data type which can be a trigger, boolean, numeric, string, or JSON. Values of the wrong type are sometimes coerced to the right type. For example, if you send any non-zero number to a boolean type, it will be coerced to true.

Additional Resources

A Sensor or Actuator will normally expose multiple Resources - both for direct access to the hardware and for configuration purposes. For example, a light sensor might expose the following resources:

PathTypeData TypeMandatoryDefault Value
/sensor/light/valueinputnumeric--
/sensor/light/enableoutputbooleanfalsefalse
/sensor/light/periodoutputnumerictrue-
/sensor/light/calibrationoutputJSONfalse{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. For additional information about naming see Resource Names and Data Representations Across Contexts below.

A 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. For example, a temperature sensor might have a polling frequency. If the sensor exposes a numeric Output called /polling_frequency, it can then receive values pushed to that Resource, and update its polling frequency accordingly.

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's data type is JSON, indicating that it receives a string value containing valid JSON.

Initial Configuration

Before a Resource such as light sensor can do work, you must configure the output Resources enable and period. To do so, you must push a new Event to the Resource, either immediately or every time the Device powers on. The latter is the 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.

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, which varies by pin, is above or below the midpoint of a voltage range (within some tolerance). 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, one or more analog-to-digital converters are available for converting the sensed voltage on a particular pin to a numeric Resource value.

Virtual Resources

Virtual Resources are used on a device to store:

  • the state of a device;
  • a JSON document of the parameters to be reported to the Cloud; or
  • configuration parameters which can be updated from the Cloud.

A Virtual Resource can be used, for example, with a setpoint for an asset controller, or an alert threshold, which must be configured per device and can change over time.

The value of a Virtual Resource can be modified from the cloud by sending an event to the stream :command of the device.

Resource Names and Data Representations Across Contexts

Octave features various ways of naming resources and representing data depending on the context of use.

Data

Event in Stream

A Virtual Resource is represented in the following form within events: /cloudInterface/virtual/NAME/value. For example:

{
  "elems": {
    "cloudInterface": {
      "virtual": {
        "NAME": value
      }
    }
  },
  "tags": {},
  "metadata": null
}

Event in Action

When an Event is received in an Edge or Cloud action, the event parameter is deserialized from the following JSON.

{
  "value": value,
  "tags": {},
  "metadata": null
}

For example, the code can read the value of a light sensor Resource from event.value:

function(event){
  var lightReading = event.value;
  var lightDescription;

  if (lightReading > 1500) {
    lightDescription = "bright";
  } else if (lightReading > 300) {
    lightDescription = "a bit dim";
  } else {
    lightDescription = "dark";
  }

  var s = "It's " + lightDescription + " in here.";

  return {
    "dh://lcd/txt3":[s]
  }
}

Resource Names

Virtual Resources

ContextValue
Resource Name/cloudInterface/virtual/NAME/value
Action Result Objectvr://NAME
Datahub.read() / Datahub.query()NAME

Resource Trigger

The following shows example naming for a Modbus resource:

ContextValue
Resource Name/modbus/slaveName/registerGroup
Action Result Objectdh://app/modbus/slaveName/registerGroup/request/send

Observations

Observations "connect" Resources to each other. They are the bridge that allows Events to flow from one application to another.

Observations represent rules that define:

  • How often Octave polls a Resource (e.g. every 10 seconds).
  • The data to collect (e.g. latest value, average of the last 10 readings, etc.)
  • When an Action should be taken (e.g. when a value execeeds 10, changes by 2, etc.)
  • The next task to perform with data (e.g. forward to the cloud now).

Whenever the rules defined in an Observation are met, a new Event is generated.

Observations describe how we want to sample/store Resource data and what we should do when the data meets a specified condition.

For example, to stream data from the redSensor/temperature/value Resource to the lcd/txt1 Resource, you must use an Observation.

📘

Note

Applications cannot write outside their own namespace.

Observations are also technically Resources, so you can also read / write directly to an Observation. Their data type is defined and set when the first value arrives, and they have the path: /obs/<observation_name>.

📘

Note

Although Observations are also Resources, they do not appear on the Device > Resources screen in the Octave dashboard.

Additional Features

Observations also feature:

  • Filters such as high and low filters that discard values which fall outside of a given range.
  • Buffers which store more than a single value as state. Buffers are bounded FIFO queues and can be queried with Octave APIs. This functionality is known as Storing and Forwarding Events.

Edge Actions

An Edge Action transforms Events from Observations and routes them to other Resources, or to the Cloud. Transformations are done via JavaScript embedded within the Edge Action.

The JavaScript can be written using Action Runner in the Octave dashboard, or done programmatically via the Edge Action of the Octave REST API.

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.

📘

Note

An Edge Action is like a Cloud Action but runs on physical devices using the "Octave" Edge Package.

The JavaScript within an Edge Action can output new events to be sent to the cloud and set the values of Resources. While an Edge action is executing, it has full access to read and write data from resources. Edge actions are most commonly used to route and/or process data on the edge using locally-available sensor and configuration data.

Reading Events in an Edge Action

When an Event is received in an Edge Action, the event parameter is deserialized from the following JSON.

{
  "value": value,
  "timestamp": 1582827837.235676
}

The JavaScript in an Edge Action can read information about the event via the event parameter. For example, the following code reads the value of a light sensor:

function(event) {
  var lightReading = event.value;
  // ...
}

Creating Events in an Edge Action

The JavaScript in an Edge Action can create an Event by returning a key/value pair where the key specifies the target (e.g. dh for Data Hub).

For example, the following Edge Action sets the value on the LCD screen Resource of a mangOH Red to "Hello!" via the device's Data Hub:

function(event) {
   // Do something with the event
   // ...

   return {
     "dh://lcd/txt1": ["Hello!"]
   }
}

For a list of targets see Output.