Skip to content

In the API

Info

All the examples in this document assume you are using an instance of Arrigo Local installed on your local computer. Remember to change hostname and protocol (both http and ws) if you are testing against another computer:
http://localhost/arrigo/apihttps://myserver.com/arrigo/api
ws://localhost/arrigo/apiwss://myserver.com/arrigo/api

List files

After logging in you need to get hold of the folderId of the folder you're interested in. Once you have the id you can query for the Pvl files in it. Only UserAreas have Pvl lists in them so you need to use an inline fragment on the folder in order to access the fields. The list exposes two fields:

Name Type Description
name String The technical name of the file is specified (as read from ArrigoFolder.ExoXml).
path String! A base64 encoded node path, later used for getting the contents of the file or setting up subscriptions.

Example:

{
  folder(id: "RXhhbXBsZUFyZWE=") {
    name
    ...on UserArea {
      publishedVariableLists {
        name
        path
      }
    }
  }
}

returns

{
  "data": {
    "folder": {
      "name": "RXhhbXBsZUFyZWE=",
      "publishedVariableLists": [
        {
          "name": "Examples",
          "path": "RXhhbXBsZUFyZS5FeGFtcGxlcy5maWxl"
        }
      ]
    }
  }
}

Getting file data

With the path and the node query you can request the rest of the static data from the Pvl:

{
  node(path: "RXhhbXBsZUFyZS5FeGFtcGxlcy5maWxl") {
    content
    hash
  }
}

returns

{
  "data": {
    "node": {
      "content": {
        "Cwl": {
          "type": "PublishedVariables",
          "attributes": {
            "Name": "Examples",
            "Title": "Examples",
            "Description": "",
            "Comment": ""
          },
          "children": [
            {
              "type": "PublishedVariable",
              "attributes": {
                "Name": "Second",
                "Title": "Second",
                "Description": "Real time clock: Second (0-59)",
                "Unit": "s",
                "Variable": "((undefined))",
                "Writable": "Yes",
                "ReadAccess": "Guest",
                "WriteAccess": "Guest",
                "Comment": "",
                "VisualFilter": "1"
              }
            }
          ],
          "Advise": {
            "A": [
              "0:0"
            ]
          },
          "AdviseRefs": {
            "A": [
              [
                0
              ]
            ]
          },
          "ElementRefs": [
            [
              [
                0
              ],
              4
            ]
          ]
        }
      },
      "hash": "ED9C0F49"
    }
  }
}

Subscriptions

The path also lets you set up subscriptions for updates/advises from a Pvl file. There is a limit in the API of one update per second per variable to prevent clients from choking on massive and rapid update bursts. If you have a lot of bound variables in a file you can still get bursts of multiple updates simultaneously, but we guarantee that they don't come more frequent than in 1 second intervals.

You are also guaranteed to get an initial value/state for each bound variable directly when you start a subscription. If there is (or just recently has been) another ongoing subscription (by you or another user) which include one of "your" bound variables you will get the last sent update for that variable, otherwise you'll probably get a "Value pending" result.

Note

To consume subscriptions you need to have a GraphQL subscription compliant client (there are WebSockets and protocols and stuff driving it all in the background). Apollo Client is a nice one for javascript environments. You can also use the built-in Playground UI of the API to do some exploratory testing (go to http://localhost/arrigo/api to try it out).

Authentication

When you set up a subscription you need to authenticate using the Auth Token you got when logging in. This is to make the subscription stream unique.

The following snippet shows how to pass the AT when subscribing using Apollo Client:

import { WebSocketLink } from 'apollo-link-ws';

const wsLink = new WebSocketLink({
  uri: `ws://localhost/arrigo/api/graphql/ws`,
  options: {
    connectionParams: {
      Authorization: "Bearer [your authToken]"
    },
});

Token expiration

When an AT expires, the subscription stream is closed by the API and an error code is returned (INVALID_AUTH_TOKEN). If this happens you have refresh the AT and setup the subscription again.

If you do a preemptive refresh you have to manually close the subscription and set it up again with the new AT.

Starting a subscription

You start a subscription by passing the path to the subscription/data query:

subscription {
  data(path: "TGFuZHNrcm9uYS5zeXN0ZW1haXIuZmlsZQ==") {
    value
    path
    technicalAddress
    type
    timestamp
  }
}

Each advise update is then delivered, one at a time, in the following format:

{
  "data": {
    "data": {
      "value": 12,
      "path": "Cwl.Advise.A[0]",
      "technicalAddress": "ExampleController.QSystem.Sec",
      "type": "Update",
      "timeStamp": "2019-09-26T12:00:12"
    }
  }
}

See Value updates for more info.

Update types

Each update contains a type field. The possible values are:

Name Description
Response Normal response
Update Published advise update
ErrorNotExist The requested variable doesn't exist in the current domain
ErrorUnreachable The requested variable exists but isn't reachable at this point in time
Pending The requested variable exists and is reachable but the Scada Function is waiting for an initial value
UnknownError An unknown error occurred when processing the request

Gray- and blacklisted variable

The Scada Function running in the background has lists containing variables that cannot be reached for the moment (gray-listed) and variables that cannot be resolved (black-listed).

When subscribing to path's containing gray- or black-listed variables, the time stamp field indicates when the variable was put in the list. Please note that gray-listed variables might start publishing updates if they become available at a later point in time.

Errors

If the path you're using is invalid an Invalid path error message is returned.

If the AT is invalid or has expired the stream is closed and an INVALID_AUTH_TOKEN error message is returned.

Polling

The data query has two other fields (besides content) that are used when for polling variable values:

Field Description
variables List of Value updates
minPollingInterval The minimum polling interval you need to use (in seconds)
hash Hash code for the file

With a valid path you poll all the exposed variables by with the query:

{
  data(path: "TGFuZHNrcm9uYS5zeXN0ZW1haXIuZmlsZQ==") {
    variables {
        value
        path
        technicalAddress
        type
        timestamp
    }
    hash
  }
}

and get a response:

{
  "data": {
    "data": {
      "variables": [{
        "value": 14,
        "path": "Cwl.Advise.A[0]",
        "technicalAddress": "ExampleController.QSystem.Hour",
        "type": "Update",
        "timeStamp": "2019-09-26T14:26:44"
      }],
      "hash": "ED9C0F49"
    }
  }
}

Please note that you'll probably get a Pending result as a response to the first poll. Subsequent polls should return the actual value of the variables.

Hash check (check if the file has been changed )

The hash field for the data query should be compared to the hash field for node query to verify that the file hasn't been changed. If the hashes differ, the source file has been changed and the content (node query) needs to be reloaded/re-queried for full synchronization between content and the data.

{
  node(path:"TGFuZHNrcm9uYS5zeXN0ZW1haXIuZmlsZQ==") {
    content
    hash
  }
}

Poll interval

It is recommended that you poll at least every minPollingInterval seconds to avoid variables from being un-advised in the Scada Function (and thus needing extra resources at the next poll to set up advises again). There is no limit on how often you can poll but the API is throttled to 1 update/second/variable.

Value updates

Each update contains the following fields:

Field Description
path The path (in the tree) to the updated variable reference
value The actual value
type Type of update.
See Update types for more info
timeStamp Timestamp of the update
technicalAddress Technical address of the variable

Note! The technicalAddress field might be removed in future versions so do not rely on it! Instead you should focus on using the path field in combination with the actual Pvl content (from node) to update your tree.

Writing values

With the nodePath and a path you can use the setData mutation to change the value of variables:

mutation {
  setData(
    nodePath: "TGFuZHNrcm9uYS5zeXN0ZW1haXIuZmlsZQ==",  
    path: "Cwl.Advise.A[0]", 
    value: "5")
}

It is not possible to mutate multiple paths/variables in one single query.

The mutation returns true if value could be set, otherwise false.

Note

It is up to you as the implementer to make sure that the correct datatype is used when writing to variables. Writing the string 5 to an integer will work fine but five will definitely fail.