Appearance
Adding HTTP, JSON, XML and Raw TCP Devices
Last updated
These drivers have no tags until you describe them. For HTTP/REST, Custom JSON and Custom XML, fill in Base URL, HTTP method and the Tag map table under Settings → Driver Settings (or in the Add Device wizard): one row per tag with its Tag name, Endpoint or URL (a path such as /status is added to the base URL; a full http://… URL replaces it), the JSON path or XPath, and the Data type. Raw TCP, and request headers or a POST body, are set with Advanced Driver Settings. Until a tag is mapped, subscribing it reads Bad.
HTTP / REST API and Custom JSON
The two cards are the same driver. It polls JSON endpoints and extracts values by dot path or JSONPath.
json
{
"driverConfig": {
"base_url": "http://192.168.1.80/api",
"headers": { "Authorization": "Bearer abc123" },
"tags": [
{ "path": "Oven/Temp", "endpoint": "/status", "json_path": "zones.0.temperature", "data_type": "float" },
{ "path": "Oven/Door", "endpoint": "/status", "json_path": "door.open", "data_type": "bool" },
{ "path": "Oven/Recipe", "url": "http://192.168.1.80/api/recipe", "json_path": "name", "data_type": "string" }
]
}
}| Key | Meaning |
|---|---|
base_url | Default http://<IP Address>:<Port>. HTTPS URLs work; certificates are verified, so a self-signed certificate fails. |
method | GET (default) or POST; POST sends body as JSON. |
headers | Extra request headers (API keys). |
tags[].path | Tag path in Scada.Ink. |
tags[].endpoint / tags[].url | Appended to base_url, or a full URL that overrides it. |
tags[].json_path | Dot path; numeric parts index arrays (zones.0.temperature). Empty = whole response. Or a JSONPath starting with $ — see below. |
tags[].data_type | float, int, bool (true/1/yes/on), string. |
JSONPath (when the path starts with $). The tag's value is the first match.
| Path | Selects |
|---|---|
$.data.temperature | a key |
$['odd key'].value | a key with spaces or dots in it |
$.zones[0].temp, $.zones[-1].temp | an array element (negative counts from the end) |
$.zones[*].temp | every element (the first is used) |
$..temperature | the key at any depth |
$.zones[?(@.name=='Zone 2')].temp | a filter: ==, !=, <, <=, >, >= against a quoted string, number, true, false or null; && and || combine terms; [?(@.on)] keeps elements whose on is present and true |
A JSONPath that can't be parsed is logged and reads Uncertain.
- Each poll fetches each distinct URL once, however many tags use it.
- Connect (and a liveness check before every poll) sends
GET base_url; any status below 500 counts as up. - A missing JSON path reads Uncertain; a failed request reads Bad. Timeout 10 seconds.
- Read-only.
Custom XML
Same idea for XML responses:
json
{
"driverConfig": {
"base_url": "http://192.168.1.81/status.xml",
"tags": [
{ "path": "Chiller/SupplyTemp", "xml_path": "//SupplyTemp", "attr": "value", "data_type": "float" },
{ "path": "Chiller/Mode", "xml_path": "Status.Mode", "data_type": "string" }
]
}
}- An
xml_pathwith no/,[or@is a dot-separated path of child elements from the root, matched case-insensitively (Status.Mode). - Anything else is XPath. Element names match on their local name, so namespaces never need to be spelled out (
mt:prefixes are ignored). The first match is the value. attrreads an attribute of the matched element instead of its text.methodandheadersas for HTTP.namespaceis still accepted but no longer needed. Read-only.
XPath supported
| Path | Selects |
|---|---|
//Temperature | the first Temperature element anywhere |
/Status/Zone/Temp, Zone/Temp | a path from the root (a relative path starts at the root element) |
//Sensor[@name='oven']/Value | attribute test: =, !=, <, <=, >, >= (numbers compare as numbers) |
//Zone[Name='Soak']/Temp | child element text test; [text()='x'] tests the element's own text |
//Zone[2], //Zone[last()], //Zone[last()-1] | position, counted among that step's matches (so //Zone[1] is the first Zone in the document) |
//Item[@id], //Item[Name] | has the attribute / child |
//Item[contains(@id,'load')], [starts-with(@id,'X')], [not(@x='1')] | functions |
//Item[@a='1' and @b='2'], [@a='1' or @a='2'] | combined (no parentheses) |
/Status/Zone[2]/@setpoint, //Mode/text() | an attribute or the text itself |
//*[@id='x'], . | any element; the current element |
Raw TCP
Opens one TCP connection and, for each tag on every poll, sends a request and parses the reply.
json
{
"driverConfig": {
"encoding": "ascii",
"delimiter": "\n",
"tags": [
{ "path": "Sensor/Temp", "request": "READ TEMP\r\n", "response_offset": 0, "response_length": 6, "data_type": "float" },
{ "path": "Sensor/Setpoint", "request": "READ SP\r\n", "data_type": "float", "write_request": "SET SP {value}\r\n" }
]
}
}| Key | Meaning |
|---|---|
encoding | ascii: requests are text, the reply is read up to delimiter, offsets are character positions after trimming. hex: requests are hex bytes ("A5 01 03 00"), up to 1024 reply bytes are read, offsets are byte positions. |
delimiter | ASCII mode: the text that ends a reply. Default \n; use \r\n or \r to match your device. Empty reads up to 1024 bytes instead. |
request | What to send. Empty = read the next message the device sends on its own, one delimited line in ASCII mode. |
response_offset, response_length | Slice of the reply to use. |
data_type | int, float, bool, string. In hex mode int is an unsigned integer of the slice, float needs 4 (float32) or 8 (float64) bytes. |
byte_order | big (default) or little, hex mode. |
write_request | Template for writes; {value} is replaced. Without it the tag isn't writable. |
connect_timeout, read_timeout | Seconds, default 10 and 5. |
Tags are polled in order on one connection, so a slow reply delays the rest.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| All tags Bad right after creating | No tags configured, or tag paths don't match tags[].path. | Add the mapping; subscribe the exact path. |
| HTTP Error at connect | base_url unreachable or returns 5xx. | Open the URL from a PC; check headers. |
| HTTP value Uncertain | The JSON path doesn't exist in the response, or a JSONPath has a syntax error (logged as Bad JSON path). | Check the response structure; array indexes are numbers. |
| XML value Uncertain | Nothing matched the path, or the XPath has a syntax error (logged as Bad path). | Open the URL in a browser and check element names and attribute values; quotes in predicates must be paired. |
| XML log Fetch/parse error | Response isn't valid XML. | Check the URL returns XML, not HTML. |
| Raw TCP values Bad after a timeout | The ASCII reply never contains delimiter, or wrong request. | Set delimiter to what the device ends replies with; use hex encoding for binary protocols. |