Skip to content

Reading through the API

Pvl files

Pvl files (Published Variable List) are used to manage variable lists exposed by the API. These lists expose a set of variables for other services and the variables can be configured as readable, writable or both.

Creating the list

Start by selecting the ReadAndWrite area in Project Builder and then starting Arrigo Folder Tool.

  • Add a new PublishedVariableListFile and rename it to ReadingValues.
  • Select ReadingValues and pick Create a new file in this user area... via the Published Variable File attribute.
  • Save the changes in Arrigo Folder Tool.

Open the newly created Pvl file for editing.

  • Add a new Published variable and name it CurrentSecond.
  • Enter *EXOop4.Sec in the Variable attribute and leave all other attributes as is.
  • Save the file.

Finding the file using the built-in query builders

Open a browser and navigate to http://localhost/arrigo/api/.

Info

It is sometimes necessary to press Shift+F5 for the content to show. This forces the browser to ignore its cached content and retrieve a fresh copy of the page.

The landing page contains a lot of info regarding the query language and how to access the API either using PowerShell or curl. Make sure to read it!
When you're done reading you can click Log in in the top right corner. Enter a valid username and password and click the Log in button.

Info

There are two built-in query builders (GraphiQL and Playground). They both function nearly identical so selecting which to use is just a question of personal preference. However, only Playground supports subscriptions.

If no content is shown after logging in you might have to do the Shift+F5 trick again.

Delete the information from the left pane (query pane) and paste in the query:

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

Click the Play button in the top left or press Ctrl+Enter to execute the query.
The result should appear in the right pane (result pane):

{
  "data": {
    "folder": {
      "publishedVariableLists": [
        {
          "name": "ReadingValues",
          "path": "UmVhZEFuZFdyaXRlLlJlYWRpbmdWYWx1ZXMuRmlsZQ=="
        }
      ]
    }
  }
}

Explanation of the query

The query you just posted to the API is written using a language called GraphQL. We will not go into the details here but we'll give a brief explanation of what happened.
If you've done some programming before you'll probably notice that GraphQL looks a bit like Javascript and that the result is json. Just like Javascript, GraphQL uses curly braces ({ and }) to define scopes.

The line folder(id: "UmVhZEFuZFdyaXRl") instructs the API to fetch the folder named UmVhZEFuZFdyaXRl. The name/id is simply a Base64 encoded version of the folder name (ReadAndWrite).

... on UserArea is an inline fragment that tells the API to only run the next part of the query if this folder is a UserArea.
UserAreas are folders but with some special powers. Published variable lists only exist in UserAreas, not in folders. In programmatic terms one could say that a UserArea is an implementation of the Folder interface.

The last part instructs the API to fetch the name and path (more on this later on) for the Published variable list it finds.

Investigating the file

Now that we have a path to the Pvl file we can query some more.

Run

{
  node(path: "UmVhZEFuZFdyaXRlLlJlYWRpbmdWYWx1ZXMuRmlsZQ==") {
    content
  }
}

in the query builder to see the actual content of the file:

{
  "data": {
    "node": {
      "content": {
        "Cwl": {
          "type": "PublishedVariables",
          "attributes": {
            "Name": "ReadingValues",
            "Title": "ReadingValues",
            "Description": "",
            "Comment": ""
          },
          "children": [
            {
              "type": "PublishedVariable",
              "attributes": {
                "Name": "CurrentSecond",
                "Title": "CurrentSecond",
                "Description": "",
                "Unit": "",
                "Variable": "((undefined))",
                "Writable": "No",
                "ReadAccess": "Guest",
                "WriteAccess": "Operator",
                "Comment": "",
                "VisualFilter": "0"
              }
            }
          ],
          "Advise": {
            "A": [
              "UmVhZEFuZFdyaXRlLlJlYWRpbmdWYWx1ZXMuRmlsZQ==:0"
            ]
          },
          "AdviseRefs": {
            "A": [
              [
                0
              ]
            ]
          },
          "ElementRefs": [
            [
              [],
              4
            ]
          ]
        }
      }
    }
  }
}

Note

The curious reader might wonder why the Variable property of the PublishedVariable is ((undefined)). This is just an indication that the actual (technical) address of the variable was replaced by a binding. This binding can be seen in the Advise.A section.

Reading the actual value

Now that we have acquainted ourselves with the tools and technologies involved, it is finally time to actually read a value.

Run the query:

{
  data(path: "UmVhZEFuZFdyaXRlLlJlYWRpbmdWYWx1ZXMuRmlsZQ==") {
    variables {
      technicalAddress
      timeStamp
      type
      value
    }
  }
}

and inspect the result:

{
  "data": {
    "data": {
      "variables": [
        {
          "technicalAddress": "EXOop4.Second",
          "timeStamp": "2022-07-11T09:02:49.0870959Z",
          "type": "Response",
          "value": 49
        }
      ]
    }
  }
}

Info

The first time you run the query you will get a value of null and the type will be set to Pending. This means that an advise has been set up but you must run the query again to get the actual value.

Run the query a couple of times and verify that the value is updating.

Reading using PowerShell

After mastering reading using query builders it is time to step up a bit and do the same thing using PowerShell.
You can use any text editor to write the script but we highly recommend that you use Windows PowerShell ISE since it has syntax completion and debugging features, and it is pre-installed on most Windows versions.

Create a new PowerShell script (ReadingValues.ps1) in the ReadAndWrite area or download the script from here.

Paste the following code into the file and save it:

# Set the base URL.
$baseUrl = "http://localhost/arrigo/api/"

# Replace with the actual credentials.
$username = "[username]"
$password = "[password]"

# Encode the folder name as Base64.
$folderName = "ReadAndWrite"
$encodedFolderName = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($folderName))

# The name of the Pvl file we want to use
$pvlFileName = "ReadingValues"

# The content type is always "application/json".
$headers = @{
  "Content-Type" = "application/json"
}

# Set the credentials as payload to the login endpoint.
$body = @"
{
  "username": "$username",
  "password": "$password"
}
"@

# The login endpoint URL.
$loginUrl = $baseUrl + "login"

# Post the payload and convert the response (from json) to a PowerShell object.
$loginResponse = Invoke-WebRequest -Uri $loginUrl -Method POST -Body $body -Headers $headers | ConvertFrom-Json

# Grab the auth token from the response.
# The token will be used in all further posts to the server.
# Read more about this at https://docs.arrigo.se/Reference%20Documentation/GraphQL%20API/01_Authentication/.
$authToken = $loginResponse.authToken

# Prepare the new headers with the correct content type and the auth token from the previous request.
$headers = @{
  "Content-Type" = "application/json"
  "Authorization" = "Bearer $authToken"
}

# Build the query to get the Pvl files.
# This is the same query as you used in the query builder, but with the encoded folder name appended.
$body = @"
{
  "query": 
  "{
    folder(id: \"$encodedFolderName\") {
      ... on UserArea {
        publishedVariableLists {
          name
          path
        }
      }
    }
  }"
}
"@

# The query endpoint URL.
$queryUrl = $baseUrl + "graphql"

# Post the payload and convert the response (from json) to a PowerShell object.
$response = Invoke-WebRequest -Uri $queryUrl -Method POST -Body $body -Headers $headers | ConvertFrom-Json

# Get the path for the Pvl file we're interested in
$pvlPath = $response.data.folder.publishedVariableLists | Where-Object { $_.name -eq $pvlFileName } | Select-Object -ExpandProperty path

# Build the query to get the variable.
# This is the same query as you used in the query builder, but with the pvl path appended.
$body = @"
{
  "query":
  "{
    data(path: \"$pvlPath\") {
      variables {
        technicalAddress
        timeStamp
        type
        value
      }
    }
  }"
}
"@

# Post the payload and convert the response (from json) to a PowerShell object.
$response = Invoke-WebRequest -Uri $queryUrl -Method POST -Body $body -Headers $headers | ConvertFrom-Json

# While (and if) the response type of the variable is "Pending", i.e. an advise has been set up
# but no value has been received yet, we wait for one second and try again.
while ($response.data.data.variables[0].type -eq "Pending") {
  Write-Host "Trying again in one second"
  Start-Sleep -Seconds 1
  $response = Invoke-WebRequest -Uri $queryUrl -Method POST -Body $body -Headers $headers | ConvertFrom-Json
}

# The response is a list of variables, but in this case we know it only has one entry.
# Note that list indexing starts at zero!
Write-Host "The value of $($response.data.data.variables[0].technicalAddress) is $($response.data.data.variables[0].value)"

Either double-click the file to run it or open a PowerShell console, navigate to the file and run it by entering the command .\ReadingValues.ps1.
You should get the following result:

PS C:\EXO Projects\ArrigoDemoProject\ReadAndWrite> .\ReadingValues.ps1
Trying again in one second
The value of EXOop4.Second is 12

Info

If the script won't run it could be due to your current PowerShell Execution Policy. For more information, see https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-5.1.