Using Tasks

A Task is an entity that executes JavaScript periodically to pull data from external systems and "inject" it into Octave as Events. For example, a Task can periodically look for new events is an RSS feed and then inject those as Events into a Stream. A Cloud Action can then invoke Octave.Event.find() from the Octave Cloud Action Runner API to find, sort, and order Events. For example, a Cloud Action can query a Stream of light readings created every five minutes, report on bad devices, and push data to an external service such as a dashboard.

A Task can be created and managed either through the Octave Dashboard or programmatically from an external system. A Tasks runs when it is first created, every time its configured period elapses, and when the Task is updated.

Creating and Managing Tasks Through the Octave Dashboard

Creating and Managing a Task

Follow the steps below to create or mange a Task:

  1. Navigate to Cloud > Tasks (1) and click Add Task (2), or click on the name of an existing Task (3) to edit it. Alternatively you can click on the Trashcan icon (4) to delete an existing Task.
  1. Define the Periodicity in the popup using the time duration controls.
  2. Enter your JavaScript in the code section. In the following example, a Task is created that periodically returns a list of devices and writes their information to the /task_output Stream:
  1. Click Save.

Testing and Debugging a Task Using the Simulator

The Simulator tab allows you to create one or more simulations to test or debug your Task. Doing so allows you try experiment with the Task's code (e.g., to display debugging information), and to see both the complete request and response.

Follow the steps below to simulate a Task:

  1. Create a new Task or edit an exiting one with JavaScript.
  2. Click Run to simulate the Task. The results of the simulation are displayed below it. You can expand the results to display additional details:
  1. (Optional) Hover your mouse over the result icons (1) to highlight the code (2) that generated that portion of the result:

Creating and Managing Tasks Programmatically

You can create and manage Tasks programmatically from an external system using Octave's REST API. The following subsections provide more detail about these operations.

Fields of a Task

When working with the REST API, you will include some or all of the following fields in the body of the request:

  • js: defines the JavaScript function to execute in the Task.

📘

Note

Note the use of '\'' as escape characters for instances of single quotes within the JavaScript function definition when passing it through cURL.

The source from which to read data is specified by invoking Octave Cloud APIs (e.g., Octave.Event.find() within the Task's JavaScript.

  • destination: the Stream where the Events are to be placed in Octave,
  • periodicity: specifies how often, in milliseconds, to execute the JavaScript.

Creating a Task

A new Task is created by invoking the POST /task endpoint. In the following example, a Task is created that periodically returns a list of devices and writes their information to the /task_output Stream:

Request

## Create Task
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":"/iot/task_output",
       "displayName":"My Task",
       "js":"\t\tfunction (events, raw)\n\t\t{\n\t\t\tvar devices = 'EMPTY'; try { devices = Octave.Device.find({});} catch (e) { devices = e.name + ' ' + e.message;} return {'/my_company/task_output/find_devices': [{'elems': {'devices': devices}}]};\n\t\t}",
       "periodicity":3680000
}'

📘

Note

You can find your username and master token on the user screen in the Octave Dashboard. These values used for the X-Auth-Token and X-Auth-User headers.

Response

The messages field indicates the result of request and the body field provides details about the new task such as its unique id:

{
   "head":{
      "status":200,
      "ok":true,
      "messages":[
         
      ],
      "errors":[
         
      ],
      "references":{
         
      }
   },
   "body":{
      "id":"t5f6...",
      "companyId":"c5b2...",
      "creationDate":1600979048852,
      "creatorId":"i5c75...",
      "destination":"/iot/task_output",
      "disabled":false,
      "displayName":"My Task",
      "js":"\t\tfunction (events, raw)\n\t\t{\n\t\t\tvar devices = 'EMPTY'; try { devices = Octave.Device.find({});} catch (e) { devices = e.name + ' ' + e.message;} return {'/my_company/task_output/find_devices': [{'elems': {'devices': devices}}]};\n\t\t}",
      "lastEditDate":1610049695207,
      "lastEditorId":"i5c75...",
      "lastRun":1610049524361,
      "nextRun":1610049544361,
      "periodicity":3680000,
      "runCt":453445,
      "status":"OK"
   }
}

Reading a Task

Information about an existing Task can be obtained at any time by invoking GET /tasks/{id} and passing the ID of the Task as a path parameter:

curl "https://octave-api.sierrawireless.io/v5.0/my_company/task/t5d2df800c2b092ef7a3475d3" \
     -H 'X-Auth-Token: <token>' \
     -H 'X-Auth-User: <user>'

Response

The body field provides details about the task:

{
   "head":{
      "status":200,
      "ok":true,
      "messages":[
         
      ],
      "errors":[
         
      ],
      "references":{
         
      }
   },
   "body":{
      "id":"t5f6...",
      "companyId":"c5b2...",
      "creationDate":1600979048852,
      "creatorId":"i5c75...",
      "destination":"/iot/task_output",
      "disabled":false,
      "displayName":"My Task",
      "js":"\t\tfunction (events, raw)\n\t\t{\n\t\t\tvar devices = 'EMPTY'; try { devices = Octave.Device.find({});} catch (e) { devices = e.name + ' ' + e.message;} return {'/my_company/task_output/find_devices': [{'elems': {'devices': devices}}]};\n\t\t}",
      "lastEditDate":1610049695207,
      "lastEditorId":"i5c75...",
      "lastRun":1610049524361,
      "nextRun":1610049544361,
      "periodicity":3680000,
      "runCt":453445,
      "status":"OK"
   }
}

Updating a Task

An existing Task can be updated by invoking the PUT /task/{endpoint} endpoint and passing the ID of the Task as a path parameter; the new Task property values are passed as body parameters. In the following example, the description property is updated to "My Task":

curl -X "PUT" "https://octave-api.sierrawireless.io/v5.0/my_company/task/t5d2df800c2b092ef7a3475d3" \
     -H 'X-Auth-Token: <token>' \
     -H 'X-Auth-User: <user>' \
     -d $'{
   "id":"t5f6d00680940dec3af571ad8",
   "companyId":"c5b280e48c939467de918e7f3",
   "creationDate":1600979048852,
   "creatorId":"i5c75885f6a31c10d1f728c7c",
   "destination":"/iot_solutions/task_output",
   "disabled":false,
   "displayName":"Dana Task",
   "js":"\t\tfunction (events, raw)\n\t\t{\n\t\t\tvar devices = 'EMPTY'; try { devices = Octave.Device.find({});} catch (e) { devices = e.name + ' ' + e.message;} return {'/my_company/task_output/find_devices': [{'elems': {'devices': devices}}]};\n\t\t}",
   "lastEditDate":1610049695207,
   "lastEditorId":"i5c75885f6a31c10d1f728c7c",
   "lastRun":1610049524361,
   "nextRun":1610049544361,
   "periodicity":3680000,
   "runCt":453445,
   "status":"OK"
}'

Response

{
   "head":{
      "status":200,
      "ok":true,
      "messages":[
         
      ],
      "errors":[
         
      ],
      "references":{
         
      }
   },
   "body":{
      "id":"t5f6...",
      "companyId":"c5b2...",
      "creationDate":1600979048852,
      "creatorId":"i5c75...",
      "destination":"/iot/task_output",
      "disabled":false,
      "displayName":"My Task",
      "js":"\t\tfunction (events, raw)\n\t\t{\n\t\t\tvar devices = 'EMPTY'; try { devices = Octave.Device.find({});} catch (e) { devices = e.name + ' ' + e.message;} return {'/my_company/task_output/find_devices': [{'elems': {'devices': devices}}]};\n\t\t}",
      "lastEditDate":1610049695207,
      "lastEditorId":"i5c75...",
      "lastRun":1610049524361,
      "nextRun":1610049544361,
      "periodicity":3680000,
      "runCt":453445,
      "status":"OK"
   }
}

Deleting a Task

An existing task can be deleted by invoking the DELETE /task/{id} endpoint and passing the ID of the Task as a path parameter:

curl -X "DELETE" "https://octave-api.sierrawireless.io/v5.0/my_company/task/t5d2df800c2b092ef7a3475d3" \
     -H 'X-Auth-Token: <token>' \
     -H 'X-Auth-User: <user>'

Response

The messsages field in the response indicates the result of the request:

{
   "head":{
      "status":200,
      "ok":true,
      "messages":[
         "Your request has been processed successfully. The requested resource has been deleted."
      ],
      "errors":[

      ],
      "references":{

      }
   },
   "body":{

   }
}

Simulating a Task

A Task can be "simulated" to show what an Event from a given source would look like, by invoking the POST /task/simulate endpoint. This is a way to check what the task would write to a Stream without actually writing to it. Similar to the Create Task endpoint, the simulate endpoint requires a source stream, periodicity, and destination stream.

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: text/plain; charset=utf-8' \
     -d $'{
   "js":"function() {\n\n\tvar O_1610050881884 = (function(methods) {\n    return function(path, args, startLine, startColumn, endLine, endColumn, context) {\n      var method = _.get(methods, path);\n      var result, error;\n      try {\n        result = method.apply(null, args);\n      } catch (exception) {\n        error = exception;\n      }\n      console.log({\n        method: path,\n        location: {\n          start: { line: startLine, column: startColumn },\n          end: { line: endLine, column: endColumn }\n        },\n        args: args,\n        result: result,\n        error: error ||\n          (_.startsWith(path, 'Octave.Http.') &&\n          ((_.get(result, 'status', 0) / 100) | 0) !== 2\n            ? result.message\n            : undefined),\n        context: context\n      });\n      if (error != null) {\n        throw error;\n      }\n      return result;\n    }\n  })({\n    Octave: Octave,\n    console: {\n      log: function(value) {\n        return value instanceof Error\n          ? _.pick(value, ['name', 'message', 'stack'])\n          : value;\n      }\n    },\n    return: _.identity\n  });\n\n\treturn (function (events, raw) {\n  var devices = 'EMPTY';\n  try {\n    devices = O_1610050881884(\"Octave.Device.find\", [{}], 3, 43, 3, 65, \"code\");\n  } catch (e) {\n    devices = e.name + ' ' + e.message;\n  }\n  return O_1610050881884(\"return\", [{\n    '/my_company/task_output/find_devices': [{\n      'elems': {\n        'devices': devices\n      }\n    }]\n  }], 3, 117, 3, 200, \"code\");\n})()\n}"
}'

Response

The events field in the response provides a preview of the event JSON that would be generated by Octave from the source data:

{
   "head":{
      "status":200,
      "ok":true,
      "messages":[         
      ],
      "errors":[         
      ],
      "references":{         
      }
   },
   "body":{
      "events":{
         "/my_company/task_output/find_devices":[
            {
               "metadata":null,
               "creationDate":1610050882766,
               "lastEditDate":null,
               "generatedDate":null,
               "path":null,
               "location":null,
               "hash":null,
               "tags":null,
               "elems":{
                  "devices":[
                     {
                        "broadcastDate":1590772784541,
                        "displayName":"WP7702 MangOH Red",
                        "path":"/iot/devices/mangoh_red",
                        "provisioningStatus":"OPERATIONAL",
                        "observations":{
                           "/redSensor/imu/temp/value":{
                              "imutemp":{
                                 "description":""
                              }
                           },
                           "/redSensor/light/value":{
                              "light_test":{
                                 "period":30,
                                 "destination":"actionRunner",
                                 "description":"",
                                 "step":20
                              }
                           },
                           "/util/cellular/signal/value":{
                              "rssi":{
                                 "select":"rxLevel",
                                 "destination":"cloudInterface",
                                 "description":""
                              }
                           },
                           "/location/coordinates/value":{
                              "dogps":{
                                 "destination":"actionRunner",
                                 "description":""
                              }
                           }
                        },
                        "id":"d5bd2...",
                        "state":{
                           "/location/coordinates/enable":true,
                        ...