####ARDI Concepts and APIs

###Concepts and Terms

##Assets
ARDI combines information about topics into **assets**. An asset represents single topic of interest - often pieces of equipment, but also machines, systems, departments, locations or human resources.
Assets have **properties** that describe individual pieces of information about the asset. There are several types of properties, such as MEASUREMENTs which represent analogue measurements such as pressure and temperature, STATUSes which are simple boolean values, and ENUMs which are discrete values that change between certain set values.
Assets also have **types** that describe what they are and how they are grouped. For example, a single valve may have several types, such as 'Ball Valve', 'On/Off Valve', 'Solenoid Operated Valve' and 'Fail Closed'.
Types are themselves part of a hierarchy - asking for everything with the 'valve' type will also include all of the various sub-types of valve (ie, Ball Valve, Globe Valve, Butterfly Valve etc.)

##Relationships
Assets also have **relationships**. These describe the connections between them. All assets appear in a central, organisation hierarchy known as the Location relationship, but they might also have relationships representing their power, air, water and gas connections. Some relationships represent logical (ie. non-physical) connections, such as control and sequence relationships.

##Sites
ARDI sites are located on web servers. A single server may contain multiple different databases. You select the database with the url - https://myserver/s/demo is the **demo** site on the **myserver** server.

###Finding Assets
If you're looking for asset information, you should first search for and verify the existance of an asset. Never blindly assume unless you know for a fact that an asset exists.
You can find an asset using the /selector/api/selector endpoint (ie. https://myserver/s/demo/selector/api/selector). It takes the parameter 'query', which contains your ARDI Asset Selector Expression.

##Selectors

ARDI Asset Selector Expressions are similar in concept to CSS selectors, although the syntax is slightly different.

In asset selectors, names can have spaces. The selector 'Main Pump' will search for any asset with a name or ID number of 'Main Pump'.
A period indicates the start of the name of a **property**. The expression '.Temperature' will search for all instances of property named 'Temperature'. Note that there may be multiple variations of temperature, such as 'Temperature - Actual' and 'Temperature - Target'.
An '@' symbol indicates a type. '@Pump' would search for all assets that are pumps.
A } symbol followed by a relationship name searches children down-stream one level from the asset. For example, 'Main Pump}Location' searches for all assets directly located inside the Main Pump. More symbols add more depth - 'Main Pump}}}Location' searches for children, grandchildren and great-grandchildren.
You can search for ALL of the children - regardless of depth - with '}:'. 'Gas System}:Natural Gas' searches for EVERY asset fed gas from the Gas System.
A '^' followed by the name of a relationship finds the assets at the lowest/starting point of that relationship - for example, the '^Location' selector will find the root of your Location hierarchy.
You can combine expressions - 'Main Pump.Temperature' looks for a Temperature property on an asset called Main Pump, '.Temperature - Actual.Temperature - Target' asks for all assets that have **both** an Actual and Target temp, and '@Pump.Speed' searches for any asset of the Pump type that has a Speed property.

The final query to find if 'Main Pump' exists would be a POST to 'https://mysever/s/mysite/selector/api/selector?query=Main%20Pump'. It returns a JSON response like the following...

```
[
      {
          "id": 100,
          "name": "Main Pump"
      }
]
```

If looking for specific properties on assets, you can add the 'restype=point' parameter to the function.

A POST to 'https://mysever/s/mysite/selector/api/selector?query=Main%20Pump.Temperature&restype=point'. returns a more detailed JSON file...

```
[
    {
		"id":5,
		"name":"Pump",
		"propid":26,
		"propname":"Temperature"
	}
]
```

Once you've verified the existance of the asset, you can use the query language to get once-off live values or history.

##Checking Asset Information

You can get information about an asset from /api/asset/detail by passing an 'id' of the assets ID number (discovered with the selector endpoint). For example, For example, 'https://mysever/s/mysite/api/asset/detail?id=5&format=json'

```
[
  {
    "isolation": "Unknown",
    "name": "Paint Line",
    "fullname": "Optrix Metal Painting Line / Paint Line",
    "id": 5,
    "description": "This is your initial ARDI site",
    "properties": [
      {
        "name": "Speed - Actual",
        "id": 26,
        "origin": 5,
        "origintype": "local",
        "value": {
          "measurement": "^",
          "_dynamics": [
            "measurement"
          ],
          "units": "m/min",
          "min": "0",
          "max": "80",
          "places": "1",
          "live": "^m/min"
        },
        "group": ""
      },
      {
        "name": "Speed - Target",
        "id": 27,
        "origin": 5,
        "origintype": "local",
        "value": {
          "measurement": "^",
          "_dynamics": [
            "measurement"
          ],
          "units": "m/min",
          "min": "0",
          "max": "80",
          "places": "1",
          "live": "^m/min"
        },
        "group": ""
      },
		,
    "media": [
      {
        "name": "Productcodes",
        "path": "/s/op/proxy/mediaitem/5/1/Paint+Line+Productcodes.json"
      }
    ],
    "alerts": [
      {
        "name": "Running",
        "desc": "",
        "media": 0,
        "relationship": 0,
        "status": 1,
        "id": 4
      }
    ],
    "relationships": [{
      "name": "Location",
      "id": 2,
      "upname": "Inside",
      "downname": "Contains",
      "upstream": [
        [
          155,
          "Optrix Metal Painting Line"
        ]
      ],
      "downstream": [
        [
          8,
          "Cleaning Section"
        ],
        [
          9,
          "Coating Section"
        ],
        [
          10,
          "Entry Section"
        ]     
      ]
    },
	{
      "name": "Powers",
      "id": 55,
      "upname": "Powered By",
      "downname": "Powers",
      "upstream": [
        [
          144,
          "Main Incomer"
        ]
      ],
      "downstream": [
        [
          8,
          "Distribution Board 1"
        ]    
      ]
    }],
    "tags": [
      "Location",
      "Optrix Metal Painting Line"
    ]
  }
]	
```

##Query Language (Current)

To get the live status of a point, you can build the following AQL query...

```
'selector' SELECTPOINTS
```

Where 'selector' is a selector that results in one or more points. For example, '.Speed - Actual' would return values for all 'actual speed' values across the system.

To get a response, send the request to /aql/api/query with the query as the 'query' parameter, and a format parameter of 'json'. For example, 'https://mysever/s/mysite/aql/api/query?query='Main%20Pump.Temperature'%20SELECTPOINTS&format=json'

This will return a result similar to the one below...

```
{  
	"query": "'.Speed - Actual' SELECTPOINTS",
	"results": [ 
		{ 
			"type": "pointlist",
			"value": [{"assetid":5,"sourceid":5,"value":59.89,"rawvalue":59.89,"propid":26,"fullvalue":"","type":"MEASUREMENT","name":"Paint Line","code":"5:26:measurement","units":"m\/min","min":"0","max":"80","places":"1","propname":"Speed - Actual","colours":{"0":"0000a8","17":"5b5bff","30":"00c588","52":"14d700","70":"31ff1c","77":"e8ff1c","80":"ff5d5d"},"ern":""}]
		}
	]
}
```

The useful data appears in **results.value[0]**. Note that not all points have 'units' or 'places'. 

##Query Language (History)

To get the historical status of a point, you can build the following AQL query...

```
'selector' SELECTPOINTS {"start": "YYYY-MM-DD hh:mm:ss","end": "YYYY-MM-DD hh:mm:ss","grain": -1000} GETHISTORY
```

To get a response, send the request to /aql/api/table with the query as the 'query' parameter, and a format parameter of 'csv'. For example, 'https://mysever/s/mysite/aql/api/table'

This will return a result similar to the one below...

```
Time,Main Speed - Actual,Secondary Speed - Actual
2029-10-10 10:00:00:00,92.22,93
2029-10-10 10:00:00:00,91,92
...
```

This request will return columns for every selector match - if the selector matches 10 points, you'll get 10 columns in the CSV file. Values will be interpolated/filled where possible, but you may get a '^' string value if a sensor was offline or unavailable. You may want to convert this to NaN or None.

The 'start' and 'end' parameters must have dates in UTC time and YYYY-MM-DD hh:mm:ss format. When the grain option is negative, it controls how many samples of data are expected back (ie. -1000 means that you should get approximiately 1000 records). A positive number indicates the number of seconds between samples. This value must be an integer.

As an alternative to 'start' and 'end', you can use 'range' followed by a human-readable time range. For example, **'selector' SELECTPOINTS {"range": "1 hour","grain": 1} GETHISTORY** gets the data for the last hour at 1-second resolution.

##Live Data

You can subscribe to live data via the subscription system. First, connect to the server at the /api/connect endpoint (ie. https://mysever/s/mysite/api/connect?format=json') with a format of 'json' to read in the port number of the live data service. It will look like this...

```
{ 
  "auth": "no",  "sites": [  { "url":"default","name":"Bakery" }, 
      { "url":"bf","name":"Blast Furnace" }, 
      { "url":"bm","name":"Building Management" }, 
      { "url":"war","name":"Coal Washery" }, 
      { "url":"coke","name":"Coke Ovens" }, 
      { "url":"gas","name":"Gas Liquifier" }, 
      { "url":"long","name":"Longwall Mine" }, 
      { "url":"win","name":"Mine Winder" }, 
      { "url":"pl","name":"Optrix Paintline" }, 
      { "url":"ex","name":"Small Examples" }, 
      { "url":"train","name":"Training Example" } ],
  "name":"Optrix Paintline",
  "version":"1.0.1",
   "services": [  { 
      "name": "data",
      "port": "8096"},
 { 
      "name": "contextdata",
      "port": "8096",
      "id": "1",
      "context": "Actual" },
 { 
      "name": "web",
      "port": "80"}
  ], 
   "settings": [ { "name": "isolation", "value": "disabled" }, 
 { "name":"zeroenergy", "value": "disabled" }],
  "dynalertsources": [{"name": "Agency", "id": "1"}]
}
```

You'll find the port under 'services' with the name 'data'. In this example, it's 8096.

Then call /api/lookuppoints, passing an semi-colon delimited list of points you want to read in 'asset.property' format (if you wanted the properties 'Speed - Actual' and 'Speed - Target' from the Paint Line asset, you'd send 'Paint Line.Speed - Actual;Paint Line.Speed - Target'). and a format of 'json'.

You'll get a response like the one below...

```
[
  {
    "name": "Paint Line.Speed - Actual",
    "asset": "Paint Line",
    "assetid": 5,
    "property": "Speed - Actual",
    "propertyid": 26,
    "type": "MEASUREMENT",
    "min": "0",
    "max": "80",
    "units": "m/min",
    "decimals": "1",
    "code": "5:26:measurement"
  },
  {
    "name": "Paint Line.Speed - Target",
    "asset": "Paint Line",
    "assetid": 5,
    "property": "Speed - Target",
    "propertyid": 27,
    "type": "MEASUREMENT",
    "min": "0",
    "max": "80",
    "units": "m/min",
    "decimals": "1",
    "code": "5:27:measurement"
  }
]
```

Take the **code** from each of these and concatenate them into a string separated by commas. In this case, it would be '5:26:measurement,5:27:measurement"'.

Make a POST request to /data/livedata (ie. https://mysever/s/mysite/data/livedata) with a 'format' of 'json', a 'port' of the value you captured earlier from the response to /api/connect, the 'action' parameter set to 'subscribe', and a 'codes' parameter containing the string you generated earlier.

You'll get a response like the one below...

```
{
   "id": "JZQ8MA8B",
   "items": [
    { "code": "5:26:measurement",
     "value" : "60.1647742794927" },
    { "code": "5:27:measurement",
     "value" : "60.0" }   ],
   "messages": [
   ] }
```

The 'id' should be saved - this is your subscription identifier and will be used to keep your data up-to-date. The 'items' list contains live values for each of the measured channels.

You can then - with a delay of at least 1 second - follow up with more requests to **livedata**, this time with the 'action' parameter being set to 'update' instead, and an 'id' parameter of your subscription id.

Output will be the same, but only the items that have changed will be included. After 30 seconds - if there is no change to any of the data points you're subscribed to - your call will time-out. 

Unless specifically asked to run in the background, you should stop your subscription when a user closes windows or the page loses focus. You can do this with a call to **livedata** with the same parameters as 'update'. This will close and delete your subscription. The answer to an unsubscribe call is not always valid JSON - you can assume that the call is successful. You'll need to get a new subscription ID and send a new 'subscribe' request to get live data again.

