Usage: ./reader [-d #] [-subVw]
-d Debuglevel (overrides config, syslog levels)
-s Debug output to stdout (overrides config)
-u Unbuffered debug output (try this if reader stops at start)
-w Write values to config file and exit
-V Version info
For example, if you want to view logging only locally you can start
with -s -d7
.
In a typical setup, libraries cannot be copied to system search paths, so they are installed to installation folder. For this reason, the installation path must be specified with LD_LIBRARY_PATH environment variable when running application manually. For example:
LD_LIBRARY_PATH=/data/custom-application/vilantnode /data/custom-application/vilantnode/reader
Configuration file path is hardcoded. NOTE! Editing configurations using config file is not recommended. Preferred way to modify configuration is using Web UI.
RFID_CONNECTED_ANTENNAS
bitmask parameter is not
limiting the set of RFID antennas that can be controlled. The
RFID_READER module, HTTP/REST or MQTT interfaces can activate or
deactivate antennas even without being explicitly tracked with
RFID_CONNECTED_ANTENNAS
./tvs/<id>/status
/tvs/<id>/config
/tvs/<id>/cmd/config/get
/tvs/<id>/cmd/config/set
/tvs/<id>/cmd/rfid/start
/tvs/<id>/cmd/rfid/stop
/tvs/<id>/gpio
/tvs/<id>/cmd/gpio
RFID reading can be operated using 1) RFID_READER
module, 2) HTTP REST/JSON Interface.
RFID_READER
module configures RFID reader antennas as
data source to module program. RFID_READER module can start antennas
during module startup (default behaviour) or use triggering sources like
INPUT modules. For more information, see RFID_READER module
documentation in Modules Section.
HTTP REST/JSON Interface
can be used to start or stop
RFID reading on specific antennas. See more in the HTTP REST interface
specification.
NOTE: Triggers are not mutually exclusive, i.e., reading state of antennas can be controlled with multiple triggers simultaneously.
RFID reader power levels are configured in Configuration page in WebUI under RFID Section.
This is the native tag data representation in JSON format. It is used by many internal functions and exposed in STORE. Empty/default fields are left out from the JSON.
{
"EPC": "301588F858009D4473D8D797", // Raw EPC hex data as in the tag
"URI": "urn:epc:id:sgtin:6438422.000629.19123459991", // Decoded URN format
"direction": "OUT", // Results of direction detection if it was used
"readcount": 1, // How many times the tag was read. Usually, 1 since reads are individually processed
"rssi": -39, // Received signal strength, in dBm
"antenna": 1, // Antenna which read the tag
"freq": 3, // Hardware dependent, frequency used for tag read (Note: Q180/Q300 report read slot)
"phase": 3732, // Phase angle if supported by hardware
"dopplerfreq": 7, // Doppler frequency if supported by hardware
"timestamp": "2019-09-23T07:40:05.520Z" // Timestamp when tag was seen
}
RFID_CONNECTED_ANTENNAS config parameter is a bitmask of connected antennas so one number tells state for all the antennas. The value is used to enable antenna status reporting for defined antennas.
Lowest bit means antenna 1, second lowest means antenna 2 and so on.
In Q180/Q300 the antennas 1-4 are the external antenna ports. Internal antenna is ports 5-8 with different polarizations: 5 RHCP, 6 LHCP, 7 horizontal, 8 vertical.
Some examples:
Config | Antenna numbers |
---|---|
1 | 1 |
2 | 2 |
3 | 1, 2 |
15 | 1, 2, 3, 4 |
16 | 5 |
240 | 5, 6, 7, 8 |
255 | 1, 2, 3, 4, 5, 6, 7, 8 |
App contains internal HTTP server that by default responds in port
8080 and 8081 (SSL). Both are configurable (HTTPD_PORT
/
HTTPSD_PORT
).
In Impinj R700 readers the default ports are 8088 and 8089 (SSL) due to Impinj reserving 8080 for its internal use.
Accessing any URL in above ports requires basic authentication. There is one, hard-coded, user, ‘admin’ and a configurable password, with default value ‘vilantnode’.
Starts RFID reading with reader.
Parameters | Name | Type | Description | Mandatory | |——|——|————-|———–| | reader | integer | Index of the reader. Defaults to internal reader. | | | antennas | array of integers | Antennas to be started. If empty or not defined, then all antennas are activated. | |
Example: Activate all antennas on internal reader
{}
Example: Activate antennas 1 & 2 on reader 1
{
"reader": 1,
"antennas": [1, 2]
}
Response | Code | Description | Response type | |——|—————|———–| | 200 | RFID reading was started successfully | JSON |
{
"message": "RFID reading was started successfully."
}
Error response | Code | Description | Response type | |——|—————|———-| | 409 | Failed to start RFID reading | JSON |
{
"message": "Failed to start RFID reading."
}
Stops RFID reading.
Parameters No parameters. Request must be supplied with empty JSON.
Example
{}
Response | Code | Description | Response type | |——|—————|———–| | 200 | RFID reading was stopped successfully | JSON |
{
"message": "RFID reading was stopped successfully."
}
Error response | Code | Description | Response type | |——|—————|———-| | 409 | Failed to stop RFID reading | JSON |
{
"message": "Failed to stop RFID reading."
}
Writes an EPC (Electronic Product Code) into a tag. Tag can be
defined or selected by the reader. Writing RF power is configured with
RFID_WRITE_POWER
configuration parameter. Write operation
will use all connected antennas defined with
RFID_CONNECTED_ANTENNAS
.
NOTE! Write command will interrupt any reading operation and will not resume reading automatically.
Parameters | Name | Type | Description | Mandatory | |——|——|————-|———–| | newEpc | string | EPC to be written to the tag. | X | | oldEpc | string | EPC of the old tag. If undefined or empty string, then reader will select the first tag it sees. | |
Example
{
"newEpc": "300C69F6BC7115D9DEBD01C7"
}
Response | Code | Description | |——|—————| | 200 | operation was successful | JSON |
{
"message": "Writing was successful"
}
Error response | Code | Description | Response type | |——|—————|———-| | 400 | Parsing request or parameters has failed | JSON |
{
"message": "Mandatory json element '}' is missing at position..."
}
Error response | Code | Description | Response type | |——|—————|———-| | 409 | Write operation has failed | JSON |
{
"message": "Failed to write <newEpc>."
}
Returns list of tags currently in all STORE modules. This can be used for querying buffered tags from the Node application.
Response | Code | Description | Response type | |——|————–|———-| | 200 | Tags in STORE module’s buffer are returned with the response. | JSON |
{
"tags": {
"<firstmoduleid>": [
{
"EPC":"300C69F6BC7115D9DEBD01C7",
"URI":"urn:epc:id:sgtin:111111111.1111.111111111111",
"readerid": 0,
"readcount":1,
"rssi":-39,
"antenna":1,
"freq":3,
"phase":3732,
"dopplerfreq":7,
"timestamp":"2023-08-23T07:40:05.520Z",
}
...
],
"<secondmoduleid>": [
{
"EPC":"300C69F6BC7115D9DEBD01C7",
"URI":"urn:epc:id:sgtin:111111111.1111.111111111111",
"readerid": 0,
"readcount":1,
"rssi":-39,
"antenna":1,
"freq":3,
"phase":3732,
"dopplerfreq":7,
"timestamp":"2023-08-23T07:42:10.124Z",
}
...
]
}
}
Returns list of tags buffered in the specific STORE module.
Returns status of reader, errors, GPIO devices and RFID antennas. Antenna state reporting is reader dependent feature and is not reliable. Antenna and GPIO names come from config file.
Response | Code | Description | Response type | |——|————–|—————| | 200 | Current reader status is returned with response | JSON |
{
"reader": {
"location": "VilantNode",
"deviceid": "1213361d",
"error": 0,
"time": "2023-08-23T10:41:31.405+0000",
"uptime": 51,
"version": "TEST-0.1.0.c3535074-TEST",
"driver": "LLRP",
"license": false,
"model": "Impinj Speedway R420",
"serial": "370-17-14-0279",
"licenseId": ""
},
"antenna": [
{
"port": 1,
"enabled": 1,
"state": 1,
"name": "",
"action": "TRANSIT"
},
...
],
"iodevs": [
[
{
"device": 0,
"port": 1,
"state": 0,
"name": "GPI 1",
"type": "GPIO_IN",
"inverted":1
},
...
{
"device": 0,
"port": 1,
"state": 1,
"name": "GPO 1",
"type": "GPIO_OUT",
"inverted":1
},
...
],
[
{
"device": 1,
"port": 0,
"name": "C0/1",
"type": "GPIO_IN",
"state": 0,
"inverted":1
},
...
]
],
"dm": [
{
"name": "DEVICE",
"status": "OK",
"message": ""
},
{
"name": "Reader",
"status": "OK",
"message": ""
},
...
]
}
Controls GPO statuses of the reader or external GPIO devices. Reader
GPOs are controlled with device id 0
. External devices
start by index 1
and get IDs based on order they are
configured in IO_DEVICES
config.
Request type JSON body
Parameters | Name | Type | Description | Mandatory | |—–|——-|————-|———–| | device | integer | Which device is controlled. Can be reader (device number 0) or external GPIO devices. If undefined, then reader will be selected | | | port | integer | Defines which port is controlled. | X | | state | integer | Defines to which state port is changed to. 1 = ON, 0 = OFF. | X |
Example
{
"device": 0,
"port": 1,
"state": 0
}
Response | Code | Description | Response type | |——|—————|————| | 200 | GPO was successfully changed. | JSON |
Response body
{
"message": "Output was changed successfully."
}
Error response | Code | Description | Response type | |——|—————|———-| | 400 | Parsing request or parameters has failed | JSON |
{
"message": "Parameter <paramName> is missing or is not integer"
}
Error response | Code | Description | Response type | |——|—————|———-| | 409 | Failed to change gpo state | JSON |
{
"message": "Failed to change output."
}
Allows user to control reader state using url query arguments: -
/kill
- Disconnect LLRP reader connection. Easy to use with
multireader. (Only works with LLRP readers) -
/kill?value=stop
- Stop app (after a few seconds). -
/kill?value=reboot
- Execute “reboot” i.e., reboot the
whole reader.
Response | Code | Description | Response type | |——|—————|———–| | 200 | Request is received and has been handled | TEXT |
Example response: Stop app
OK, Stopping app, bye
Allows you to inject tag reads as if they come from reader normally.
Use POST with JSON data in common tag data format as described above.
Supports both single tag data and array of tags in the message. If
timestamp is specified as now
it will be replaced with
current time when processing.
NOTE - Extra fields can be left out, they default to zero. Note that customdata is not free()’d by default and specifying it will typically cause memory leak.
Parameters
The endpoint uses the common tag data JSON format provided above. While some of the fields are not necessary, there are a few mandatory fields that need to be supplied with the request:
Name | Type | Description | Mandatory |
---|---|---|---|
EPC | string | EPC to be written to the tag. | X |
timestamp | string | ISO 8601 formatted timestring or “now” indicating current reader time | X |
antenna | integer | Source antenna which identified tag | X |
Example
{
"EPC": "341588F50C6A94D74F4318BA",
"timestamp":"now",
"antenna": 3
}
Response | Code | Description | Response type | |——|—————|———–| | 200 | Request is received and has been handled | TEXT |
Example response:
OK
Generic reader configuration interface. This can be used to change
any parameter similarly as in config.json
file. GET method
returns list of all parameters and POSTing same data changes them (only
name
and value
used in POST). New parameters
are saved to config.json and reader is reconfigured or restarted to
apply new configs.
Response | Code | Description | Response type | |——|—————|———–| | 200 | Configs are successfully returned | JSON |
{
"configs": [
{
"name": "MY_NAME",
"value": "FORKLIFT",
"type": "string",
"description": "Reader name/Location ID"
},
{
"name": "RFID_POWER",
"value": "1200",
"type": "string",
"description": "Transmit power. Either single number in mBm or for each antenna separated with ,"
},
....
]
}
Generic reader configuration interface. This can be used to change
any parameter similarly as in config.json
file. GET method
returns list of all parameters and POSTing same data changes them (only
name
and value
used in POST). New parameters
are saved to config.json and reader is reconfigured or restarted to
apply new configs.
NOTE: When Provisioning (DM_ENABLED) is used it will overwrite these configs after a while.
Parameters
Top level message structure: | Name | Type | Description | Mandatory |
|——|——|————-|———–| | configs | Array of ConfigParam objects | | X |
ConfigParam structure: | Name | Type | Description | Mandatory | |——|——|————-|———–| | name | string | Config name | X | | value | string or integer | New value for the config | X |
Example
{
"configs": [
{
"name": "MY_NAME",
"value": "FORKLIFT",
},
{
"name": "RFID_POWER",
"value": "1200",
},
....
]
}
Response | Code | Description | Response type | |——|—————|———–| | 200 | Request has been handled. Errors are indicated in the message structure. | JSON |
Response body
{
"ret": "Config set OK",
"success": true
}
Code | Description | Response type |
---|---|---|
400 | Reader failed to parse request body or found problems with configs. | JSON |
Error response
{
"ret": "Param parsing failed at ...",
"success": false
}
Code | Description | Response type |
---|---|---|
403 | Reader forbids the use of advanced features with Lite license | JSON |
Error response
{
"ret": "Module 'REMAP_ANTENNA' in 'MODULES.MODULES_JSON' requires Pro license.",
"success": false
}
Code | Description | Response type |
---|---|---|
409 | Reader failed to store new config | JSON |
Error response
{
"ret": "Configs applied but failed to save. Disk might be full.",
"success": false
}
Vilant Node provides some standard functionality over MQTT for status monitoring, configuration management and RFID controls.
Standard configuration parameters:
COMMUNICATIONS.MQTT.MQTT_SERVER
is the address where to
connect in URL format. For example mqtt://server
or
mqtts://server:8886
.COMMUNICATIONS.MQTT.MQTT_USERNAME
and
COMMUNICATIONS.MQTT.MQTT_PASSWORD
. If left empty then
unauthenticated connection is made.<ID>
in topics is replaced with the ID of the
reader. ID is same what is used for license activation.
Default client side Keep Alive time is set to 400 seconds.
/tvs/<ID>/status
Periodically updated with the latest status of the reader and Last
Will and Testament (LWT) is used to provide status offline
on unexpected disconnect.
Status update period can be changed with parameter
DM.DM_UPDATE_INTERVAL
. This parameter controls how often
Vilant Node will send status updates to DM and MQTT interfaces.
Example contents:
{
"name": "Testdev-1733733138.811968",
"id": "5d9d1d2a",
"application": "VilantNode/Turck",
"version": "1.0.0.6d9d683d",
"status": "online",
"last_updated": "2024-12-09T10:47:28Z",
"last_tag_read": "2024-12-09T10:46:47Z",
"components": [
{
"name": "DEVICE",
"status": "ERROR",
"message": "Component(s) with errors: Modules"
},
{
"name": "Ambient temperature",
"status": "OK",
"message": ""
},
...
]
}
Tag events are sent from the MQTT
sender
module.
/tvs/<ID>/config
Receives app configuration when: 1) Requested with
cmd/config/get
topic. 2) Configuration gets changed. 3)
Vilant Node starts up.
Configurations are as in following example, in JSON format:
{
"configs": [
{
"hiername": "GENERAL.MY_NAME",
"name": "MY_NAME",
"value": "RFID_Gate_1",
"type": "string",
"description": "Reader name/Location ID"
},
{
"hiername": "RFID.RFID_POPULATION",
"name": "RFID_POPULATION",
"value": 10,
"type": "integer",
"description": "Gen2 population size"
},
{
"hiername":"DM.ENABLED",
"name":"DM_ENABLED",
"value":false,
"type":"boolean",
"description":"Enables Device Manager features, including sending of device status updates, remote configuration and software updates"
},
{
"hiername": "GPIO.IO_DEVICES_JSON",
"name": "IO_DEVICES_JSON",
"value": [{"id": 0, "type": "DEBUS", "dxpPinDirection": "0011"}],
"type": "array",
"description": "IO device configuration data. See README for instructions."
},
{
"hiername":"MODULES.JSON",
"name":"MODULES_JSON",
"value":{"modules": {}, "connections": []},
"type":"json",
"description":"Module program configuration. See README for instructions."
},
...
]
}
/tvs/<ID>/cmd/config/get
Request current configuration to be sent to
/tvs/<ID>/config
topic. Message format is not
specified, so any data sent to topic will result configuration being
sent.
/tvs/<ID>/cmd/config/set
Setting configs can be done with the same data format as received from config-topic. If both name and shortname are specified shortname takes precedence.
Note: Reader will immediately take new configs into use and might reboot, if required.
/tvs/<ID>/cmd/rfid/start
Will start RFID reading on specific antennas on specific reader.
Name | Type | Description | Mandatory |
---|---|---|---|
reader | integer | Index of the reader. If empty or not defined, then internal reader will be used. | |
antennas | array of integers | Antennas to be started. If empty or not defined, then all antennas are activated. |
Example: Activate all antennas
{}
Example: Activate specific antennas on specific reader
{
"reader": 0,
"antennas":[1,3]
}
/tvs/<ID>/cmd/rfid/stop
Will stop RFID reading on specific antennas on specific reader.
Name | Type | Description | Mandatory |
---|---|---|---|
reader | integer | Index of the reader. If empty or not defined, then internal reader will be used. | |
antennas | array of integers | Antennas to be started. If empty or not defined, then all antennas are activated. |
Example: Deactivate all antennas on internal reader
{}
Example: Deactivate antennas 1 & 3 on reader 0 (internal reader)
{
"reader": 0,
"antennas":[1,3]
}
/tvs/<ID>/gpio
GPIO events for detected inputs and set outputs will be sent here.
{
"type": "output",
"dev": 0,
"pin": 1,
"state": 1
}
/tvs/<ID>/cmd/gpio
Will control GPIO ports. Contents same as in
/tvs/<ID>/gpio
topic. Specifying type: input will
generate fake input events.
Modules should be defined with WebUI or DM in param
MODULES.MODULES_JSON
. Structure is:
{
"modules": {
"id1": {... first module ...},
"id2:" {... second module ...},
...
},
"connections": [
{... first connection ...},
{... second connection ...},
...
]
}
Common parameters for modules:
Field | Type (value range) | Description | Required |
---|---|---|---|
id | str | Unique id for the module. | X |
type | str | Module type | X |
loglevel | integer (1 - 8) | Module specific log level. NOTE! Modules use their own log level, not the application log level. 6 = INFO (default), 7 = DEBUG, 8 = TRACE. |
{
"type": "RFID_READER",
"logLevel": 6,
"data": {
... module type specific data ...
}
}
NOTE! Invalid values in configuration can result in incorrect operation.
Field | Type (value range) | Description | Required |
---|---|---|---|
reader | integer (Only ID 0 allowed for now) | Unique id for the reader | X |
antennas | array of integers | Antennas used by the module. Module will accept events only from the specified antennas. Accepted values for antennas are 1 - 32. | X |
readingActive | bool | Starting state for antennas. Default is true (= constant reading) |
{
"type": "RFID_READER",
"data": {
"reader": 0,
"antennas": [1, 2],
"readingActive": true
}
}
Duplicate filters tags based on 1) time window or 2) count of unique tags.
Field | Type (value range) | Description | Required |
---|---|---|---|
count | integer (0 - 2147483647) | Duplicate buffer. If the maximum number of tags is exceeded, oldest tags are removed from the first. | Either “count” or “timeWindowMs” is required. |
timeWindowMs | integer (0 - 2147483647) | Same tag is filtered until “timeWindowMs” amount of time. Every new read will restart timewindow. Value should be given in milliseconds. | Either “count” or “timewindow” is required. |
first | boolean | Extra mode for “timeWindowMs” mode. If enabled, timestamp is taken from first time tag is seen and not updated with new events until “timewindow” amount of time has passed. Disabled by default. |
{
"type": "DUPLICATE",
"data": {
"timeWindowMs": 10000,
"first": true,
}
}
The EVENTSENDER is sending tag events to a specified endpoint. The message structure follows the TVS REST/JSON asset interface.
Field | Type | Description | Required |
---|---|---|---|
endpoint | string | Endpoint address to HTTP REST Server including protocol, credentials, hostname and path. | X |
operation | string | Operation used for asset event. Can be any but if sending to TVS servers, then need to follow interface specification. If undefined or empty, then defaults to MOVE. | |
site | string | Site parameter for the TVS asset event. Describes higher level detail of location. | |
username | string | HTTP basic authentication username. | |
password | string | HTTP basic authentication password. | |
locations | object | Define location to antennas mapping. Keys object properties is the location name and value is the antenna. | X |
locations.{key} | string | Key value of the property defines location name. | X |
locations.{value} | array of integers | Value of the property defines antenna numbers for the location defined in key field. Allowed antenna values are 1 - 32. | X |
{
"type": "EVENTSENDER",
"data": {
"endpoint": "https://username:password@some.host/path/to/endpoint",
"operation": "MOVE",
"locations": {
"Loc1": [1,3],
"Loc2": [2,4],
...
// Usable only with SEEN module's lost events
"LostLoc1": [101,103],
"LostLoc2": [102,104],
}
}
}
Stores tag events that can be collected with the HTTP REST interface. The module collects tag events, meaning that the same tag can be stored multiple times.
Supports either time window based or count based mode.
See section 4.4 for more information on REST calls.
Field | Type (value range) | Description | Required |
---|---|---|---|
timeWindowMs | integer (1 - 2147483647) | “timewindow” field defines how long tag event is accessible by STORE module. Tag event will be dropped after expiration. | X |
keep | boolean | “keep” field defines whether a call to HTTP interface would remove tag event or should module keep it in memory until expiration. Defaults to false. | |
count | integer (1 - 2147483647) | “count” field defines how many tag events can be stored by module. |
{
"type": "STORE",
"data": {
"timeWindowMs": 10000,
"count": 100,
"keep": false, // Optional
}
}
The RSSI module drops tag events based on the Received Signal Strength Indicator (RSSI) values.
Field | Type | Description | Required |
---|---|---|---|
limits | array of integers | “limits” field collects threshold limits for RSSI values. Each value entry reflects a value for antenna. If value is not defined, 1st value is used for missing antennas. Value range for limits is -128 - 0. | X |
max | boolean | “max” field inverses threshold. By default, threshold drops tags smaller than limit (=MIN limit). Max inversion would include tag events weaker than limit. |
{
"type": "RSSI",
"data": {
"limits": [-50, -55, -50], // Antenna 1 = -50, Ant2 = -55, Ant3 = -50, Ant4 = -50 (because Ant1 = -50)
"max": false
}
}
The EPCHEX module can be used to filter RFID tag reads based on EPC features. The module supports filtering based on regex patterns or lengths.
Field | Type (value range) | Description | Required |
---|---|---|---|
pattern | string | RegEx pattern for filtering data. | |
not | boolean | Extension for pattern field.
By default, pattern finds for matching data. With this field set to
true, pattern will find for not matching data. |
|
epcLength | integer (0 - 2147483647) | Allowed length of the EPC in bits. Exact match. Length value must be multiple of 8, i.e. length is defined in even bytes. |
{
"type": "EPCHEX",
"data": {
"pattern": "^(30|31)",
"not": false,
"epcLength": 96
}
}
Examples of RegEx use:
"pattern": "1234" i.e. EPC should contain 1234, at any place in the EPC
"pattern": "^34" i.e. EPC should start with 34
"pattern": "000000", "not": true i.e. EPC should not contain 000000
"pattern": "(333|444|555)" i.e. EPC should contain 333 or 444 or 555
"pattern": "^(333|444)" i.e. EPC should start with 333 or 444
"pattern": "^341(333|444)" i.e. EPC should start with 341 which is followed by 333 or 444
"pattern": "(333|444)", "not": true i.e. EPC should not contain 333 or 444
Module implementing direction detection. There are four modes:
Field | Type (value range) | Description | Required |
---|---|---|---|
stateTimeoutMs | integer (1 - 2147483647) | State timeout milliseconds. Depends on mode. | X |
flushTimeoutMs | integer (1 - 2147483647) | Flush timeout milliseconds. At any time in the process, if the tag is not seen since ‘flush’ milliseconds, it is removed from memory. | X |
mode | integer (1 - 4) | Mode selected. Accepts only values 1-4, according to description above. | X |
zones | Object | Defines antenna & zone mapping. Key value defines the zone name and value defines a list of antennas mapped represent the zone. Antennas can be assigned to only one zone each. Allowed antenna value range is 1 - 32. | X |
readCount | integer (1 - 2147483647) | Extension to MODE3D functionality. Required if using MODE3D. | X |
sendExtraEvents | bool | Extension to MODE3 & MODE3D functionality. Defaults to enabled. | |
useUserMemory | bool | Singulate tags based on user memory instead of EPC. Tag is dropped if user memory is missing. | |
debug | bool | Enable websocket debugging of direction detection. |
{
"type": "DIRECTION",
"data": {
"stateTimeoutMs": 1000,
"flushTimeoutMs": 18000,
"mode": 1, // One of [1, 2, 3, 4]
"zones": {
"IN": [2,4], // Antennas
"OUT": [1,3]
...
}
}
}
Module passing tags whose rssi and phase-angle median absolute deviation (MAD) are within thresholds.
Field | Type (value range) | Description | Required |
---|---|---|---|
readcount | integer (1 - 1023) | Minimum size of population from where MAD is calculated. | X |
timewindowMs | integer (1 - 2147483647) | Millseconds, how long to keep tag in population. | X |
phase | Object | Phase angle set thresholds. | x |
phase.lowThreshold | integer (0 - 127) | Low threshold for phase angle. | X |
phase.highThreshold | integer (0 - 127) | High threshold for phase angle. | X |
rssi | Object | Rssi set thresholds. | x |
rssi.lowThreshold | integer (0 - 127) | Low threshold for rssi. | X |
rssi.highThreshold | integer (0 - 127) | High threshold for rssi. | X |
Accept tags if there are enough reads within timewindow on same antenna and calculated deviations for reads are within configured thresholds for either phase angle, RSSI or both.
Note: Config must contain at least one of ‘phase’ or ‘rssi’ objects. Both thresholds must be supplied. Keeping timewindow too wide may slow down calculation, series limit is 1023 data points per EPC per antenna. If, during the time limit, more entries than 1023 would enter the series, then new entries are added and oldest are dropped.
{
"type": "TAGMOVEMENT",
"data": {
"readcount": 10,
"timewindowMs": 3000,
"phase": {
"lowThreshold": 0,
"highThreshold": 10
},
"rssi": {
"lowThreshold": 0,
"highThreshold": 1
}
}
}
The ANTENNA module filters RFID tag data based on accepted antennas.
Field | Type | Description | Required |
---|---|---|---|
accept | array of integers | Events from defined antennas are accepted to pass. Allowed antenna values are 1 - 32. | X |
{
"type": "ANTENNA",
"data": {
"accept": [1, 2, 3]
}
}
The INPUT module provides functionality to listen input events from a specific IO device. NOTE! IO devices need to be configured separately.
Field | Type (value range) | Description | Required |
---|---|---|---|
device | integer (0 - 8) | The target IO device ID. | X |
port | integer (0 - 31) | The target IO port. | X |
inverted | boolean | Defines if status should be inverted. Useful, for instance, for adjusting triggering edge. |
{
"type": "INPUT",
"data": {
"device": 0,
"port": 1,
"inverted": false
}
}
The OUTPUT module is used for pulsing a specific output port on an IO device. Duration will configure the period for ON and OFF signals in pulse.
Field | Type | Description | Required |
---|---|---|---|
ioDeviceId | integer (0 - 8) | The target IO device ID. If undefined, will default to internal reader (0). | |
port | integer (0 - 31) | The target IO port. | X |
pulses | integer (0 - 2147483647) | Defines the number of pulses to output
port. One pulse includes 1 ON and 1 OFF signal, each lasting
durationMs (total time 2* durationMs ). |
X |
durationMs | integer (1 - 2147483647) | Defines the duration for both ON or OFF signals during pulse. Value in milliseconds. Default duration is 500 milliseconds. |
{
"type": "OUTPUT",
"data": {
"port": 1,
"pulses": 10,
// Optional values
"ioDeviceId": 0,
"durationMs": 10000, // milliseconds
}
}
The EPCMANGLE module can be used to sanitize some parts of the EPC for the next module’s use. The module is not modifying the EPC on the tag itself.
NOTE! Indexing starts from the beginning, so remember to pad both mask and replacement values with zeroes until the desired position.
Field | Type | Description | Required |
---|---|---|---|
mask | string | Hex string defining what bits are selected for modifying. | X |
replacement | string | Hex string defining new bit values for the fields. | X |
{
"type": "EPCMANGLE",
"data": {
"mask": "FFFF",
"replacement": "0000"
}
}
The SEEN module provides a way to get events from both when RFID tag appears and disappears.
Module will send lost tags to next modules with antenna set to 100 + antenna number. For instance, if a tag has been first identified with antenna 2, then lost event will be sent to next modules having antenna number 102.
Field | Type (value range) | Description | Required |
---|---|---|---|
lostTimeMs | integer (0 - 2147483647) | How long time to wait without tag events until RFID tag is considered to have disappeared. Value in milliseconds. | X |
antennaUnique | boolean | Should each RFID tag be monitored on antenna level. Disabled by default. |
{
"type": "SEEN",
"data": {
"lostTimeMs": 1000, // milliseconds
// Optional
"antennaUnique": false
}
}
The MQTT Sender module can be used for sending RFID tag events to specific MQTT topic. Connection details are defined in configuration page under MQTT and are common for all instances of MQTT sender modules. Message format is the common tag data format as described in Section 2.
Field | Type (value range) | Description | Required |
---|---|---|---|
topic | string | MQTT topic to send the RFID tag event.
Using placeholder value <ID> would be replaced with
device ID, e.g. value /tvs/ |
X |
qos | integer (0 - 2) | Quality of Service parameter for MQTT message. Defaults to 0. |
{
"type": "MQTT",
"data": {
"topic": "tvs/reader1",
"qos": 0, // Optional, defaults to 0
}
}
The TIMEOUT module allows you to create timeout-based activations of
triggers. After receiving a trigger with the activeTrigger
event, the module will send that trigger and wait until timeout. After
timeout, the module will send a non-active trigger. One useful scenario
for this module is to create a trigger for the RFID_READER module that
is activating RFID reading only for the specified timeout period. If new
active trigger is received when timeout period is still active, then the
timeout period is restarted.
NOTE! The TIMEOUT module supports only TRIGGER connections.
Field | Type (value range) | Description | Required |
---|---|---|---|
timeoutMs | integer (10 - 2147483647) | How long to keep trigger active until timeout. | X |
activeTrigger | integer (0 - 1) | Defines whether active trigger with timeout is ON (1) or OFF (0). Defaults to ON (1). | |
allowCancellation | bool | Defines whether timeout period can be cancelled before timeout with non-active trigger events. Defaults to disabled. |
{
"type": "TIMEOUT",
"data": {
"timeoutMs": 1000,
"activeTrigger": 1, // Optional, defaults to 1
"allowCancellation": false, // Optional, defaults to false
}
}
The DELAY module allows to delay trigger signal sent to next modules.
If delayed activation is ongoing, then each new trigger signal will
reset delay timer. By default, the trigger status opposite to
delayedTrigger
will be ignored if activation is ongoing.
However, if allowCancellation
is enabled, then delayed
trigger is cancelled if opposite trigger status is captured during delay
period.
This module is useful to delay handling of data buffer. For instance, one use case could be delaying send action of RFID events in EVENTSENDER module until all relevant data has been processed.
NOTE! DELAY module supports only TRIGGER connections.
Field | Type (value range) | Description | Required |
---|---|---|---|
delayTimeMs | integer (0 - 2147483647) | How long to delay sending of the delayed trigger event. | X |
delayedTrigger | integer (0 - 1) | Defines whether delayed trigger event is ON (1) or OFF (0). Defaults to ON (1). | |
allowCancellation | bool | Defines whether delayed trigger will be cancelled if receiving non-delayed trigger event before delay timeout. Defaults to disabled. |
{
"type": "DELAY",
"data": {
"delayTimeMs": 1000,
"delayedTrigger": 1, // Optional, defaults to 1
"allowCancellation": false, // Optional, defaults to false
}
}
The AND & OR modules allow creating logical gates for triggering. These modules will forward trigger with the value calculated from current state of system.
For instance, - AND module requires that all input trigger modules are active for AND module to send active event. - OR module requires that any of the input trigger modules is active for OR module to pass active event during state changes.
Field | Type | Description | Required |
---|---|---|---|
timeoutMs | integer (0 - 2147483647) | How frequently triggering events should occur, i.e. max time difference between trigger events. Enabled when value greater than zero. Defaults to 0. Value in milliseconds. |
{
"type": "OR",
"data": {}
}
{
"type": "AND",
"data": {
"timeoutMs": 5000,
}
}
The MIN_READCOUNT module filters RFID tag data based on whether enough read events are seen within the time window.
Note: Specifying multiple readcounts/timewindows without
antennaSeparation
set to true will result in
strange behavior (limits checked by last seen antenna).
Field | Type | Description | Required |
---|---|---|---|
readCounts | array of object
readCount |
Array of entries defining read count and
time limitations for antennas. Entry #0 defines ant 1, entry #1 defines
Ant 2, … Undefined antennas will use limits defined in first entry.
Note: Specifying multiple readcounts/timewindows without
antennaSeparation set to true will result in
strange behavior (limits checked by last seen antenna). |
X |
antennaSeparation | boolean | Antenna separation for RFID tags. If this mode is used, then read are checked against based on antenna and tag records. If not used, then statistics are based only on tag level meaning all antennas accumulate shared statisctics. Default is False. | |
tidSeparation | boolean | TID separation mode will singulate tags based on TID instead of EPC. Tag read is dropped if TID is missing, so check that RFID reader(s) are configured to send TID information of tags. Default is False. |
readCount | Field | Type | Description | Required | | :— | :— | :———————– | :—- | | timewindowMs | integer (1 - 2147483647) | Time window, or period, to include reads. Value in milliseconds. | X | | readCount | integer (1 - 2147483647) | Limit of how many reads are at least required within the time window to let tags pass filtering. | X |
The TAGDATA module adds extra info fields to RFID tag data.
Field | Type | Description | Required |
---|---|---|---|
assetExtraInfo1 | string | Data to be put into TAGDATA’s assetExtraInfo1 field. Max length is 20 characters. The empty string value is ignored. | |
assetExtraInfo2 | string | Data to be put into TAGDATA’s assetExtraInfo2 field. Max length is 20 characters. The empty string value is ignored. | |
assetExtraInfo3 | string | Data to be put into TAGDATA’s assetExtraInfo3 field. Max length is 20 characters. The empty string value is ignored. | |
eventExtraInfo1 | string | Data to be put into TAGDATA’s eventExtraInfo1 field. Max length is 20 characters. The empty string value is ignored. | |
eventExtraInfo2 | string | Data to be put into TAGDATA’s eventExtraInfo2 field. Max length is 20 characters. The empty string value is ignored. | |
eventExtraInfo3 | string | Data to be put into TAGDATA’s eventExtraInfo3 field. Max length is 20 characters. The empty string value is ignored. |
Connections are also defined in MODULES.MODULES_JSON
.
See Section 6.
Field | Type | Description | Required |
---|---|---|---|
type | string | Connection type. Either “TRIGGER” or “DATA”. | X |
source | string | ID of the source module | X |
target | string | ID of the target module | X |
fail | boolean | Defines if source is connected to data parsing success or fail output. |
{
"type": "TRIGGER",
"source": "module1",
"target": "module2"
}
{
"type": "DATA",
"source": "module1",
"target": "module2"
}
{
"type": "TRIGGER",
"source": "module1",
"target": "module2",
"fail": true
}
{
"type": "DATA",
"source": "module1",
"target": "module2",
"fail": true
}
{
"modules": {
"rdr": {
"type": "RFID_READER",
"data": {
"reader": 0,
"antennas": [
1,
2,
3,
4
]
}
},
"epchex": {
"type": "EPCHEX",
"data": {
"pattern": "^30",
"epcLength": 96
}
},
"duplicate": {
"type": "DUPLICATE",
"data": {
"timeWindowMs": 60000
}
},
"sender": {
"type": "EVENTSENDER",
"data": {
"endpoint": "https://example.server.com/path/to/endpoint",
"username": "username",
"password": "password",
}
}
},
"connections": [
{
"type": "TRIGGER",
"source": "rdr",
"target": "epchex"
},
{
"type": "DATA",
"source": "rdr",
"target": "epchex"
},
{
"type": "TRIGGER",
"source": "epchex",
"target": "duplicate"
},
{
"type": "DATA",
"source": "epchex",
"target": "duplicate"
},
{
"type": "TRIGGER",
"source": "duplicate",
"target": "sender"
},
{
"type": "DATA",
"source": "duplicate",
"target": "sender"
}
]
}
{
"modules": {
"rdr": {
"type": "RFID_READER",
"data": {
"reader": 0,
"antennas": [
1,
2,
3,
4
]
}
},
"epchex": {
"type": "EPCHEX",
"data": {
"pattern": "^31",
"epcLength": 96
}
},
"duplicate": {
"type": "DUPLICATE",
"data": {
"timeWindowMs": 60000
}
},
"store": {
"type": "STORE",
"data": {
"timeWindowMs": 60000
}
}
},
"connections": [
{
"type": "TRIGGER",
"source": "rdr",
"target": "epchex"
},
{
"type": "DATA",
"source": "rdr",
"target": "epchex"
},
{
"type": "TRIGGER",
"source": "epchex",
"target": "duplicate"
},
{
"type": "DATA",
"source": "epchex",
"target": "duplicate"
},
{
"type": "TRIGGER",
"source": "duplicate",
"target": "store"
},
{
"type": "DATA",
"source": "duplicate",
"target": "store"
}
]
}
{
"modules": {
"input": {
"type": "INPUT",
"data": {
"device": 0,
"port": 1
}
},
"rdr": {
"type": "RFID_READER",
"data": {
"reader": 0,
"antennas": [
1,
2,
3,
4
]
}
},
"epchex": {
"type": "EPCHEX",
"data": {
"pattern": "^30",
"epcLength": 96
}
},
"duplicate": {
"type": "DUPLICATE",
"data": {
"timeWindowMs": 60000
}
},
"sender": {
"type": "EVENTSENDER",
"data": {
"endpoint": "https://example.server.com/path/to/endpoint",
"username": "username",
"password": "password",
}
}
},
"connections": [
{
"type": "TRIGGER",
"source": "input",
"target": "rdr"
},
{
"type": "DATA",
"source": "input",
"target": "rdr"
},
{
"type": "TRIGGER",
"source": "rdr",
"target": "epchex"
},
{
"type": "DATA",
"source": "rdr",
"target": "epchex"
},
{
"type": "TRIGGER",
"source": "epchex",
"target": "duplicate"
},
{
"type": "DATA",
"source": "epchex",
"target": "duplicate"
},
{
"type": "TRIGGER",
"source": "duplicate",
"target": "sender"
},
{
"type": "DATA",
"source": "duplicate",
"target": "sender"
}
]
}
App has generic support for extra GPIO devices. Actual usage depends on the custom logic but the devices itself are configured in common configuration.
[
{
"id": 0,
"type": "LLRP",
"initialState": "0110",
"gpoInverted": [1,2,3,4],
"gpiDebounce": {
"1": 1000,
"4": 2000
}
},
{
"id": 1,
"type":"TBEN-S2-8DXP",
"hostAddress": "10.7.0.120",
"initialState":"001100111011",
"dxpPinDirection": "00110011",
"gpiDebounce": {
"1": 1000,
"4": 2000
}
}
]
Field | Type | Description | Required | Values |
---|---|---|---|---|
id | integer | Device identifier. Only RFID reader (internal) can have index 0 | X | |
type | string | Device type | X | LLRP, DEBUS, TBEN-S2-8DXP, TBEN-L5-16DXP |
hostAddress | string | IPv4 or host address for IO device | Required by external IO devices | |
intialState | string | Initial state for GPOs. One character represents one entry. If pins are bidirectional, include GPIs also in string. | 1 = ON, 0 = OFF, example 1100 means 1st & 2nd GPO are active and 3rd & 4th off. | |
dxpPinDirection | string | Pin direction setting for Turck devices (Q180/Q300 & TBENs). | Required by Turck devices. | 1 = OUTPUT, 0 = INPUT, example 1100 means 1st & 2nd port are outputs and 3rd & 4th inputs. |
gpiDebounce | object with key-value pairs | Defines GPI debouncing used for ports. | Port number must be string integer e.g., “1”. Debounce values are given in milliseconds. | |
gpoInverted | array of integers | Defines which GPOs are used as inverted values. For instance, some wirings require that activation is done with sink wiring. LLRP readers will most likely need outputs inverted. |
Config parameter contains comma separated list of GPIO-devices. Each device entry contains IP=TYPE config.
Supported IO devices:
IO ports are same as in the device Modbus interface. M12 connector pin 4 is the first IO and pin 2 is the second. For example, reader port 0 is C0 pin 4, reader port 1 is C0 pin 2, reader pin 2 is C1 pin 4 and so on. More details can be seen in the device manual.
TBEN Vaux port control is supported only with TBEN-S2-8DXP device.
If you want to set initial state of outputs, you can use the following config:
IO_INITIAL_OUTPUT=0=000011
This means for device 0 the outputs 0-3 are turned off and 4-5 are turned on. This corresponds to Q180/Q300 having Vaux pins on and other DXP pins off. In this scenario sensors get their power from Vaux and sensor outputs can be seen in input pins.
If you connect traffic lights to reader then you probably want to
turn everything off, e.g. IO_INITIAL_OUTPUT=0=000000
Vilant Node will use GPI signals only for triggering reading. If the
expected logic requires signal inversion, Vilant Node can monitor
inversed GPI signal values from all IO devices when a global config
GPI_INVERTED
is enabled.
Q180 and Q300 have two DXP ports for IO. They are like DXP ports in other Turck devices.
NOTE: If PoE power input is used then output will work only from DXP aux pins. Other output pins will toggle just fine but no actual voltage is output. Inputs work just fine.
Devices: - Turck Q180 - Turck Q300 - TBEN-S2-8DXP - TBEN-L5-16DXP
Reader port | Connector | M12 Pin | Description |
---|---|---|---|
0 | DXP 0/1 | 4 | DXP 0 |
1 | DXP 0/1 | 2 | DXP 1 |
2 | DXP 2/3 | 4 | DXP 2 |
3 | DXP 2/3 | 2 | DXP 3 |
4 | DXP 0/1 | 1 | Vaux |
5 | DXP 2/3 | 1 | Vaux |
Physical connector DXP 0/1 is mapped to reader pin numbers 0, 1 and 4
Similarly, for DXP 2/3 is mapped to reader pins 2, 3 and 5. Turck documentation DXP Channels match port numbers. Vaux pins are added after DXP pins in reader port numbering.
Since DXP pins are both input and output the inputs will “see” output as well. Output turning on is masked but when output is turned off it will generate input low event on reader IO.
The reader will default to use port direction as input
type. Reader will change port direction on DXP ports after any of these
events: 1) DXP port output is activated with
IO_INITIAL_OUTPUT
configuration. 2) DXP port output is
inverted with READER_GPO_INVERTED
. (Only reader GPO are
supported) 3) HTTP REST call on /gpo
endpoint. See more
information in REST documentation above.
DXP ports work simultaneously as input and output ports whereas Vaux ports are output-only.
App will also log “DXP chan %d Aux power overcurrent” diagnostic messages from Q180/Q300 ports. In case aux power is turned off this event is generated by hardware and can be ignored.
Impinj R700 has documented ports 0-based whereas we have decided to use 1-based indexing in Vilant applications.
Vilant | Impinj |
---|---|
1 | IN 0 |
2 | IN 1 |
1 | OUT 0 |
2 | OUT 1 |
3 | OUT 2 |
Some GPIO events can be received and sent over a WebSocket. WebSocket
path is /gpio
(e.g. ws://reader:8080/gpio
).
NOTE! DXP directions need to be configured in Node application in GPIO configuration. Trying to change output for the GPIO port defined as input port will fail due to invalid direction.
Example output messages:
{ "type":"output", "dev":0, "pin":4, "state":0, "timestamp":"2021-01-13T14:35:46.484Z" }
{ "type":"output", "dev":0, "pin":5, "state":1, "timestamp":"2021-01-13T14:36:51.170Z" }
{ "type":"input", "dev":0, "pin":2, "state":1, "timestamp":"2021-01-13T14:36:56.760Z" }
{ "type":"input", "dev":0, "pin":2, "state":0, "timestamp":"2021-01-13T14:36:57.815Z" }
{ "type":"input", "dev":0, "pin":2, "state":1, "timestamp":"2021-01-13T14:36:59.862Z" }
{ "type":"input", "dev":0, "pin":2, "state":0, "timestamp":"2021-01-13T14:37:00.227Z" }
Sending similarly formatted messages (without timestamp) will cause outputs to be set and fake input messages generated.
Dev refers to IO_DEVICE number. 0 means IO ports integrated to the device.
This feature is supported only by Turck Q180 & Q300 readers. In this mode the application will forward communication from external client application to RF chip on the reader.
Configuration parameters: -
GENERAL.DEBUS_PASSTHRU_ENABLED
will disable or enable the
feature. - GENERAL.DEBUS_PASSTHRU_PORT
will set the port
for accepting new connections for TCP communication between external
client and Node application. -
RFID.DEBUS_PASSHTRU.DEBUS_PASSTHRU_CONNECTION_ERROR_ALERT
will disable or enable passthru connection alerts feature on Node. See
more feature specific configurations in configuration page. To see
parameters, passthru mode needs to be enabled.
GPIO of the reader can be controlled with websocket interface defined in Section 9.4.
NOTE! DXP directions need to be configured in Node application in GPIO configuration. Trying to change output for the GPIO port defined as input port will fail due to invalid direction.