A nodejs industrial automation edge gateway with a GraphQL API.
Installation
The best way to get a full featured tentacle install (which includes tentacle-ui and exposes everything on port 80) is using LXD and applying the tentacle-docker profile.
To install tentacle as a global module with all of it's dependencies:
sudo npm install -g --unsafe-perm tentacle-edge
Once installed you can run them command tentacle
to start the server. You can use Ctrl-C
to stop the server.
The graphql api will then be available at http://localhost:4000. You can also access Graphql Playground, a powerful GraphQL IDE, at that at that address.
Starting Tentacle on Boot
The easiest way is to use PM2.
-
Install PM2
sudo npm install -g pm2
-
Determine the exact location of the
tentacle
commandif you have installed tentacle globally, then on linux/OS X the
tentacle
command will probably be either:/usr/bin/tentacle
or/usr/local/bin/tentacle
. The commandwhich tentacle
can be used to confirm the location. -
Tell pm2 to run Tentacle
The following command tells PM2 to run
tentacle
, assuming/usr/bin/tentacle
as the location of thetentacle
command.The
--
argument must appear before any arguments you want to pass to tentacle.pm2 start /usr/bin/tentacle -- -v
This will start tentacle in the background. You can view information about the process and access the log output using the commands:
pm2 info tentacle pm2 logs tentacle
More information about managing processes under PM2 is available here.
-
Tell PM2 to run on boot
pm2 save pm2 startup
This will generate a command that you must copy/paste and run to add the pm2 process to your services.
-
Reboot
Reboot and verify everything is working as expected.
Protocols
Services
GraphQL API
Schema Types
Table of Contents
Query
Read only queries
Field | Argument | Type | Description |
---|---|---|---|
user | User |
Gets user based on authentication header and returns relevant data |
|
tags | [Tag!]! |
Requires a valid authorization token. List of all tags configured in this gateway |
|
scanClasses | [ScanClass!]! |
Requires a valid authorization token. ist of all scan classes configured in this gateway |
|
devices | [Device!]! |
Requires a valid authorization token. List of all devices configured in this gateway |
|
type | String | ||
services | [Service!]! |
Requires a valid authorization token. List of all services configured in this gateway |
|
type | String |
Mutation
Read/Write queries
Field | Argument | Type | Description |
---|---|---|---|
login | AuthPayload |
If a valid username and password is provided, this will return an auth payload with a java web token to be used for future requests and information about the user that successfully logged in. |
|
username | String! | ||
password | String! | ||
changePassword | User |
Allows the user to change their password |
|
oldPassword | String! | ||
newPassword | String! | ||
createScanClass | ScanClass |
Requires a valid authorization token. Creates a new scan class |
|
name | String! | ||
description | String! | ||
rate | Int! | ||
updateScanClass | ScanClass |
Requires a valid authorization token. Updates an existing scan class |
|
id | ID! | ||
name | String | ||
description | String | ||
rate | Int! | ||
deleteScanClass | ScanClass |
Requires a valid authorization token. Deletes a scan class. Will not be successfully if there are tags currently assigned to this scan class. |
|
id | ID! | ||
createTag | Tag |
Requires a valid authorization token. Creates a new tag |
|
name | String! | ||
description | String! | ||
datatype | Datatype! | ||
value | String! | ||
scanClassId | ID! | ||
min | Float | ||
max | Float | ||
deadband | Float | ||
units | String | ||
updateTag | Tag |
Requires a valid authorization token. Updates an existing tag |
|
id | ID! | ||
name | String | ||
description | String | ||
datatype | Datatype | ||
value | String | ||
scanClassId | ID | ||
min | Float | ||
max | Float | ||
deadband | Float | ||
units | String | ||
deleteTag | Tag |
Requires a valid authorization token. Deletes a tag. Will delete any source assigned to this tag, and tag will no longer be scanned. |
|
id | ID! | ||
createOpcua | Device |
Requires a valid authorization token. Creates a opcua device, and automatically starts a connection. |
|
name | String! | ||
description | String! | ||
host | String! | ||
port | Int! | ||
retryRate | Int! | ||
updateOpcua | Device |
Requires a valid authorization token. Updates an existing opcua device and refreshes the connection. |
|
id | ID! | ||
name | String | ||
description | String | ||
host | String | ||
port | Int | ||
retryRate | Int | ||
deleteOpcua | Device |
Requires a valid authorization token. Deletes a opcua device. All sources assigned to this device are deleted and tags using this device as a source will have their sources set to null, making their values static. |
|
id | ID! | ||
createOpcuaSource | OpcuaSource |
Requires a valid authorization token. Creates a OPC UA source. The tag value will then be updated to the value at the source register per the scan class |
|
deviceId | ID! | ||
tagId | ID! | ||
nodeId | String! | ||
updateOpcuaSource | OpcuaSource |
Requires a valid authorization token. Updates a OPC UA source register. The tag value will then update per the new register at the rate of the scan class. |
|
tagId | ID! | ||
nodeId | String! | ||
deleteOpcuaSource | OpcuaSource |
Requires a valid authorization token. Deletes a OPC UA source. The tag value will then be static. |
|
tagId | ID! | ||
createModbus | Device |
Requires a valid authorization token. Creates an Modbus TCP/IP device, and automatically starts a connection. |
|
name | String! | ||
description | String! | ||
host | String! | ||
port | Int! | ||
reverseBits | Boolean! | ||
reverseWords | Boolean! | ||
zeroBased | Boolean! | ||
timeout | Int! | ||
retryRate | Int! | ||
updateModbus | Device |
Requires a valid authorization token. Updates an existing modbus device and refreshes the connection. |
|
id | ID! | ||
name | String | ||
description | String | ||
host | String | ||
port | Int | ||
reverseBits | Boolean | ||
reverseWords | Boolean | ||
zeroBased | Boolean | ||
timeout | Int | ||
retryRate | Int | ||
deleteModbus | Device |
Requires a valid authorization token. Deletes a modbus device. All sources assigned to this device are deleted and tags using this device as a source will have their sources set to null, making their values static. |
|
id | ID! | ||
createModbusSource | ModbusSource |
Requires a valid authorization token. Creates a modbus source. The tag value will then be updated to the value at the source register per the scan class |
|
deviceId | ID! | ||
tagId | ID! | ||
register | Int! | ||
registerType | ModbusRegisterType | ||
updateModbusSource | ModbusSource |
Requires a valid authorization token. Updates a modbus source register. The tag value will then update per the new register at the rate of the scan class. |
|
tagId | ID! | ||
register | Int! | ||
registerType | ModbusRegisterType | ||
deleteModbusSource | ModbusSource |
Requires a valid authorization token. Deletes a modbus source. The tag value will then be static. |
|
tagId | ID! | ||
createEthernetIP | Device |
Requires a valid authorization token. Creates an Ethernet/IP device, and automatically starts a connection. |
|
name | String! | ||
description | String! | ||
host | String! | ||
slot | Int! | ||
updateEthernetIP | Device |
Requires a valid authorization token. Updates an existing Ethernet/IP device and refreshes the connection. |
|
id | ID! | ||
name | String | ||
description | String | ||
host | String | ||
slot | Int | ||
deleteEthernetIP | Device |
Requires a valid authorization token. Deletes an Ethernet/IP device. All sources assigned to this device are deleted and tags using this device as a source will have their sources set to null, making their values static. |
|
id | ID! | ||
createEthernetIPSource | EthernetIPSource |
Requires a valid authorization token. Creates an Ethernet/IP source. The tag value will then be updated to the value at the source register per the scan class |
|
deviceId | ID! | ||
tagId | ID! | ||
tagname | String | ||
updateEthernetIPSource | EthernetIPSource |
Requires a valid authorization token. Updates an Ethernet/IP source tagname. The tag value will then update per the new tagname at the rate of the scan class. |
|
tagId | ID! | ||
tagname | String | ||
deleteEthernetIPSource | EthernetIPSource |
Requires a valid authorization token. Deletes an Ethernet/IP source. The tag value will then be static. |
|
tagId | ID! | ||
createMqtt | Service |
Requires a valid authorization token. Creates an MQTT Sparkplug B service (tied to a single MQTT broker). |
|
name | String! | ||
description | String! | ||
host | String! | ||
port | Int! | ||
group | String! | ||
node | String! | ||
username | String! | ||
password | String! | ||
devices | [ID!]! | ||
rate | Int! | ||
encrypt | Boolean! | ||
recordLimit | Int! | ||
primaryHosts | [String!] | ||
updateMqtt | Service |
Requires a valid authorization token. Updates an MQTT Sparkplug B service and restarts the connection. |
|
id | ID! | ||
name | String | ||
description | String | ||
host | String | ||
port | Int | ||
group | String | ||
node | String | ||
username | String | ||
password | String | ||
rate | Int | ||
recordLimit | Int | ||
encrypt | Boolean | ||
addMqttSource | Service |
Requires a valid authorization token. Adds a device to an MQTT service. All the tags with sources from that device will be published at the rate of the MQTT service configuration. |
|
id | ID! | ||
deviceId | ID! | ||
deleteMqttSource | Service |
Requires a valid authorization token. Deletes a device from an MQTT service. The tags for the removed device will no longer be published to the broker (but the device and tags will still exist). |
|
id | ID! | ||
deviceId | ID! | ||
addMqttPrimaryHost | MqttPrimaryHost |
Requires a valid authorization token. Adds a primary host id to monitor (for store & forward) |
|
id | ID! | ||
name | String | ||
deleteMqttPrimaryHost | MqttPrimaryHost |
Requires a valid authorization token. Deletes a primary host id to monitor (for store & forward) |
|
id | ID! | ||
name | String | ||
deleteMqtt | Service |
Requires a valid authorization token. Deletes an MQTT Service. All devices assigned to this service will no longer have their tags published. |
|
id | ID! |
Objects
AuthPayload
The data returned after a successful login attempt.
Field | Argument | Type | Description |
---|---|---|---|
token | String |
Bearer token to be added to the Authorization header for future requests. |
|
user | User |
User that successfully logged in. |
Device
A Device is a something that can serve data to be used for updating tag values, such as a modbus TCP or Ethernet/IP server.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
name | String! |
Identifier for the device that will be also used for external services, such as MQTT Sparkplug B. |
|
description | String! |
Description to allow for users to give the device more context. |
|
config | DeviceConfig |
Configuration is specific to the protocol used by the device, such as modbus or Ethernet/IP |
|
createdBy | User |
User who created the tag. |
|
createdOn | DateTime! |
Date/time the tag was created. |
EthernetIP
Ethernet/IP is a device config allowing for access to data for updating tag values per the ODVA Ethernet/IP specification.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
device | Device! |
Device for this Ethernet/IP configuration. |
|
host | String! |
Host or IP address of the Ethernet/IP device. Port is fixed at 44818. |
|
slot | String! |
Slot of the PLC. It is typically zero for devices that do no have slots or where the PLC is fixed. |
|
sources | [EthernetIPSource!]! |
List of sources (tag/register) pairs that are using this Ethernet/IP device. |
|
status | String |
Status of the Ethernet/IP device connection. Will be connected if connection is successful or an error message if connection failed. |
EthernetIPSource
An Ethernet/IP source reads an tag from an Ethernet/IP device and updates a tag value per the tags scan class.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
ethernetip | EthernetIP! |
The ethernet/IP device this source uses to get the register values. |
|
tag | Tag! |
The tag to update. |
|
tagname | String! |
The tagname of the tag in the Ethernet/IP device (not to be confused with the name of the tag in this gateway) |
Modbus
Modbus is a device config allowing for access to data for updating tag values per the Modbus TCP specification.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
device | Device! |
Device for this modbus configuration. |
|
host | String! |
Host or IP address of the modbus device. |
|
port | String! |
Port of the modbus device. |
|
reverseBits | Boolean! |
Whether registers are stored as Big Endian (false) or Little Endian (true). |
|
reverseWords | Boolean! |
Whether multiregister sources should use the lowest register first (false) or the highest register first (true). |
|
timeout | Int! |
How long to wait to for connection with the device to complete before throwing an error. |
|
sources | [ModbusSource!]! |
List of sources (tag/register) pairs that are using this modbus device. |
|
status | String |
Status of the modbus device connection. Will be connected if connection is successful or an error message if connection failed. |
|
zeroBased | Boolean! |
Whether registers start from zero or one. Can be used to make sure device addresses and those configured in the gateway match (and are not one off from eachother) |
|
retryRate | Int! |
Milliseconds between retries when connection is interrupted. |
ModbusSource
A Mobus source reads a register from a modbus TCP device and updates a tag value per the tags scan class.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
modbus | Modbus! |
The modbus device this source uses to get the register values. |
|
tag | Tag! |
The tag to update. |
|
register | Int! |
The starting register to read from the modbus device. |
|
registerType | ModbusRegisterType! |
The register type per the modbus specification. Can be |
Mqtt
MQTT is a service that allows for publishing tag values to an MQTT broker using the sparkplug B specification, which will server data to other subscribing nodes. One broker per service.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
host | String! |
Hostname or IP address of the MQTT broker |
|
port | String! |
Port for the service on the MQTT broker |
|
group | String! |
Identifies a logical grouping of edge devices. |
|
node | String! |
Identifies the edge device pushing data to the MQTT broker. |
|
username | String! |
MQTT Broker username. |
|
password | String! |
MQTT Broker password. |
|
sources | [MqttSource!]! |
List of MQTT source devices that will be publishing to this broker. |
|
rate | Int! |
Publishing rate in milliseconds |
|
encrypt | Boolean! |
True if ssl:// is to be used, otherwise tcp:// will be used. |
|
recordLimit | Int! |
Maximum number of records to publish at one time while forwarding historical data. |
|
primaryHosts | [MqttPrimaryHost!]! |
Primary host IDs. This is used for store and forward to detect if the consumers are online. The gateway will store data if any consumer is offline. |
MqttPrimaryHost
MQTT is a service that allows for publishing tag values to an MQTT broker using the sparkplug B specification, which will server data to other subscribing nodes. One broker per service.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
name | String! |
Primary Host ID, used to verify primary host state for store and forward |
|
status | String! |
UKNOWN before STATE has been received from broker, ONLINE/OFFLINE otherwise, indicating status |
|
recordCount | Int! |
Number of historical records stored, awaiting forwarding |
MqttSource
An MQTT source publishes data from all tags with the same device source. The device name will be used as the Device
field in sparkplug B.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
mqtt | Mqtt! |
MQTT service (broker) |
|
device | Device! |
Source device. All tags updating their values from this device will be published at the MQTT services configured scan rate. |
|
recordCount | Int! |
Number of historical records stored, awaiting forwarding |
Opcua
Opcua is a device config allowing for access to data for updating tag values per the Opcua specification.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
device | Device! |
Device for this Opcua configuration. |
|
host | String! |
Host or IP address of the modbus device. |
|
port | String! |
Port of the modbus device. |
|
status | String |
Status of the modbus device connection. Will be connected if connection is successful or an error message if connection failed. |
|
retryRate | Int! |
Milliseconds between retries when connection is interrupted. |
|
nodes | OpcuaNode |
Nodes |
|
flatNodes | [OpcuaNode!]! |
Non-heirarchical list |
|
sources | [OpcuaSource!]! |
List of sources (tag/nodeId) pairs that are using this opcua device. |
OpcuaNode
Field | Argument | Type | Description |
---|---|---|---|
name | String! | ||
id | String! | ||
datatype | String | ||
value | String | ||
organizes | [OpcuaNode!] | ||
hasProperty | [OpcuaNode!] | ||
hasComponent | [OpcuaNode!] | ||
children | [OpcuaNode!]! |
OpcuaSource
An OPC UA source reads an tag from an OPC UA device and updates a tag value per the tags scan class.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
opcua | Opcua! |
The OPC UA device this source uses to get the register values. |
|
tag | Tag! |
The tag to update. |
|
nodeId | String! |
The node id of the tag in the OPC UA device |
ScanClass
A scan class allows for groups of tags to be updated at the same pre-defined rate.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
name | String! |
Identifier for the scan class, used as a brief descriptor |
|
description | String! |
Description to allow for users to give the scan class more context. |
|
rate | Int! |
Rate at which to update that tags assigned to this scan class from their device source. |
|
tags | [Tag!]! |
List of tags assigned to this scan class |
|
scanCount | Int! |
The number of times this scan class has been scanned since the scan class scan started. This values clears to zero when the periodic scan is stopped. |
Service
A service makes data available to external services by acting as a server or publishing the data as is done with MQTT.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
name | String! |
Identifier for the service. |
|
description | String! |
Description to allow for users to give the service more context. |
|
config | Mqtt |
Configuration is specific to the protocol used by the service, such as MQTT |
|
createdBy | User |
User who created the service. |
|
createdOn | DateTime! |
Date/time the service was created. |
Subscription
Field | Argument | Type | Description |
---|---|---|---|
tagUpdate | Tag | ||
deviceUpdate | Device | ||
serviceUpdate | Service |
Tag
A Tag stores data point values. It's value can be updated from a device source per it's scan class, and it's value can be made available to external services like MQTT.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
name | String! |
Identifier for the tag that will be also used for external services, such as MQTT Sparkplug B. |
|
description | String! |
Description to allow for users to give the tag more context. |
|
value | String |
Tag value, which is updated at the scan class rate from the assigned source and also delivered to services that use this tag as a source. |
|
datatype | Datatype! |
Format of that tag value, allowing clients to parse the value appropriately. |
|
scanClass | ScanClass! |
Assigned scan class which determines the rate at which the tag is updated from it's assigned source. |
|
createdBy | User |
User who created the tag. |
|
createdOn | DateTime! |
Date/time the tag was created. |
|
source | Source |
Source from which this tag value is updated. |
|
max | Float |
Maximum tag value (meant for use if the tag is numeric). Can be used to generate out of range indication and for graphical displays |
|
min | Float |
Minimum tag value (meant for use if the tag is numeric). Can be used to generate out of range indication and for graphical displays |
|
deadband | Float |
Deadband, used to determine whether to publish a change or write to history. If the change in value is less than the deadband, the update is ignored. If this value is zero, all changes are published and write to history. |
|
units | String |
Engineering units of the tag. Meant to be used for user displays to give context to a numerical value. |
User
Credentials used to identify who is logging into the gateway.
Field | Argument | Type | Description |
---|---|---|---|
id | ID! | ||
username | String! |
Enums
Datatype
Tag datatypes allowing for clients to properly parse tag values.
Value | Description |
---|---|
BOOLEAN | |
INT16 | |
INT32 | |
FLOAT |
ModbusRegisterType
Modbus register types for use with modbus sources per the modbus specification.
Value | Description |
---|---|
DISCRETE_INPUT | |
COIL | |
INPUT_REGISTER | |
HOLDING_REGISTER |
Scalars
Boolean
The Boolean
scalar type represents true
or false
.
DateTime
Used to deliver timestamp values.
Float
The Float
scalar type represents signed double-precision fractional values as specified by IEEE 754.
ID
The ID
scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as "4"
) or integer (such as 4
) input value will be accepted as an ID.
Int
The Int
scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
String
The String
scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.