HTTP Service
HTTP SERVICE
Introduction
This service offers the option to send events (reads, gpi, etc) using an HTTP request.
How it works
The HTTP Service has an internal queue (buffer like) that receives all internal events.
A dedicated execution thread awaits for incoming data in the buffer before sending data out. The send logic works as follow:
The first event that arrives at the queue is served immediately and sent out in a matter of ms.
After a sent operation there is a wait time of 100 ms. This is used to batch events and prevent the system from creating a huge amount of small requests.
Besides the queue logic, there is a timer (TTL) for every unique EPC to filter repetitions of the same EPCs. It works as follows:
The first time an EPC is read, i) the EPC is sent out and ii) a timer starts.
Any other read of the same EPC before the time reaches TTL time is discarded.
New reads after the TTL time will be sent out, and the cycle starts over. Note reads that happen before the timer reaches TTL are not enqueued, will never be sent out.
The logic defined before creates the following conditions:
How data is sent out has a high degree of randomness. It's not possible to predict how batching will happen.
When using Sequential read mode, the HTTP Service won't be sending data batches without the concept of an inventory cycle.
Events
Possible events are:
TAG_READ events: as generated from inventory operations
AdvanPay events:
TAG_ADPY_PAYMENT
TAG_ADPY_RETURN
TAG_ADPY_READ
EAS events
TAG_ALARM
TAG_ALARM_ANTENNA_1
TAG_ALARM_ANTENNA_2
TAG_ALARM_ANTENNA_3
TAG_ALARM_ANTENNA_4
[2.3.18-08+] GPI events
Under ctx_subtype you can find if they are high to low or low to high.
[2.3.18-11+] System timer events:
SYSTEM_1MINUTE_TIMER
SYSTEM_5MINUTE_TIMER
SYSTEM_10MINUTE_TIMER
SYSTEM_30MINUTE_TIMER
SYSTEM_60MINUTE_TIMER
[2.5.3-04+] TAG_DIRECTION events
Possible requests are:
POST
PUT
It supports HTTP/HTTPS and Basic Authentication
Configuration
In order to enable and configure this service go to the system tab and in the Services drop-down select HTTP_SERVICE
Required fields are marked with *
Connection
The connection options are:
Protocol*: options are
HTTP
HTTPS
Host*
Port: port 0 is the default port
80 for http
443 for https
Connection timeout: maximum connection timeout, expressed in ms.
HTTP Request
The HTTP requests options are:
HTTP method*: options are
POST
PUT
Content-type*: options are
text/plain
application-json
application-xml
JSON config*: this defines the complete URI of the request and the body of the request. It's definition is quite elaborate and has a chapter on its own
JSON config*
This is a JSON List of Maps, each Map with the following elements:
event: fully qualified name of the event we want to use
path: path starting with /
params: aditional arguments for the url. Example of the format -> "params": "'param1=value1¶m2=value2'" .
body: javascript expression that defines a variable named body.
The javascript expression is evaluated with an injected context filled with real time data
Correct escaping of " and ' inside the body expression is the most difficult part.
Additional care is required when escaping characters.
Before entering the JSON config in the device it is recommendable to double check it's correctly formed by using a JSON validator like this one: https://jsonlint.com/
Before validating the JSON format please delete all tabulations and row jumps. You can do this by searching "\n" and "\t" in a text editor and deleting them.
Templates for typical use cases.
Possible events
TAG_READ events: as generated from inventory operations
AdvanPay events:
TAG_ADPY_PAYMENT
TAG_ADPY_RETURN
TAG_ADPY_READ
EAS events
TAG_ALARM
TAG_ALARM_ANTENNA_1
TAG_ALARM_ANTENNA_2
TAG_ALARM_ANTENNA_3
TAG_ALARM_ANTENNA_4
The available context injected into the body javascript expression depends on the EVENT TYPE
TAG_READ context
Available context variables are
ctx_devid: device ID
ctx_devip: device IP
ctx_devmac: device MAC address expressed as 6b:31:58:87:a2:3c
ctx_tags: this is an array containing all reads. Every entry has the following method
ctx_tags[i].getEPC(): the hexadecinal read EPC
ctx_tags[i].getSKU(): the TAG EPC SKU if the tag encoding is known
ctx_tags[i].getSerial(): the TAG EPC SKU serial if the tag encoding is known
ctx_tags[i].getTID(): the hexadecimal read TID (may be empty)
ctx_tags[i].getPhase(): the integer phase of the read
ctx_tags[i].getAntenna(): the integer antenna port
ctx_tags[i].getMux1(): the integer level one mux (may be 0)
ctx_tags[i].getMux2(): the integer level two mux (may be 0)
ctx_tags[i].getURI(): the read URI of the EPC (may be empty)
ctx_tags[i].getRSSI(): the integer read RSSI value
ctx_tags[i].getUTC(): as the Unix UTC time stamp of the read
ctx_tags[i].getTime(): as the Unix time stamp of the read with the local TimeZone offset
ctx_tags[i].getUTCFormatted(): as the formatted UTC time of the read expressed as yyyyMMddHHmmss.SSS
ctx_tags[i].getTimeFormatted(): as the formatted time of the read the local TimeZone offset expressed as yyyyMMddHHmmss.SSS
getUTC() and getUTCFormatted() are avilable starting at AdvanNet-2.3.16
In previous versions, the methods getTime() and getTimeFormatted() use UTC values.
getSKU() and getSerial() are available starting at AdvanNet-2.3.17_02
Events context
All other events share the same context variables
ctx_devid: device ID
ctx_devip: device IP
ctx_devmac: device MAC address expressed as 6b:31:58:87:a2:3c
ctx_type: the event type
[2.3.15_09+] ctx_subtype: the event sub-type. For example the alarm type.
ctx_epc: the event EPC (may be empty)
[2.3.17_02+] ctx_sku: the event EPC SKU in case theEPC encoding is known (may be empty)
[2.3.17_02+] ctx_serial: the event EPC SKU serial in case the EPC encoding is known (may be empty)
ctx_uri: the event EPC URI (may be empty)
ctx_utc: Unix timestamp value
ctx_date: Timestamp value corrected using the configured timezone.
[2.3.18-11+] ctx_devstatus: The status of the device
[2.5.3+] ctx_alarms: comma separated list of alarms (error messages, warnings) going on in the reader
[2.6.4-180731+] ctx_locid: location ID of the guessed last known location for the given tag
[2.6.4-180731+] ctx_locx: location X position of the guessed last known location for the given tag
[2.6.4-180731+] ctx_locy: location Y position of the guessed last known location for the given tag
[2.6.4-180731+] ctx_locz: location Z position of the guessed last known location for the given tag
Send options
The send options are:
Send one by one: options are
true: in case of TAG_READ, it sends each reads in a different request
false: in case of TAG_READ, may send several reads in the same request
Inventory tag TTL: in case of TAG_READ, do not send the same combination of EPC+antenna or EPC+TID if they a previous match is found in the defined time window.
Inventory tag TTL is applied only on TAG_READ events.
It has no effect for other events: ADPY_PAYMENT, TAG_ALARM, etc.
To reduce the frequency of repeated events (other than TAG_READ), please change them in the ReadMode page settings (RF & Antenna options).
Re-send: in case of error connections, re-enqueue again the events for later sent
The queue has a capacity of 32000 items
Items can be in the queue for a maximum of 10 minutes, they are then removed permanently
Expected HTTP response: expected HTTP response from the server
Expected HTTP entity: expected HTTP entity from the server, it is not recommended to use it, as it forces to fully read each response from server.
Basic authentication
The basic authentication options are:
username
password
Advanced JSON conf
This setting allows to configure additional parameters:
debug: to enable additional debug information
debugTransport: to enable debug information on the request/response data
customHeaders: array of custom static headers
An example of a JSON conf is
{"debug":true,"debugTransport":true}
Another example could be
{"debug":true,"customHeaders":[{"header":"headerName1:headerValue1"},{"headerName2":"h2:headerValue2"]}}
Persist settings
Once the current settings seems to work as desired, please do not forget to persist system settings using the "Save current" button at the top.
Utiltites
encodeURI
It is possible to use the javascript method encodeURI
For example, to encode the full body part
[{
"event":"TAG_READ",
"path":"'/to/my/url'",
"body":"
var body='reader_name=\"AdvanReader 150\"&';
body+='mac_address=\"'+ctx_devmac+'\"&';
body+='line_ending=&';
body+='field_delim=,&';
body+='field_names=antenna_port,epc,first_seen_timestamp,peak_rssi&';
body+='field_values='+ctx_tags[0].getAntenna()+',\"'+ctx_tags[0].getEPC()+'\",'+ctx_tags[0].getTime()+','+ctx_tags[0].getEPC();
body+=encodeURI(body);
"
}]
Examples
application/xml
Send inventory dta in xml format.
The JSON string is as follows.
[{
"event":"TAG_READ",
"path":"'/to/my/url'",
"body":"
var body='<read no=\"'+ctx_tags.length+'\" id=\"'+ctx_devid+'\" ip=\"'+ctx_devip+'\" mac=\"'+ctx_devmac+'\">';
var i=0;
for(i=0;i<ctx_tags.length;i++){
body+='<tag epc=\"'+ctx_tags[i].getEPC()+'\" port=\"'+ctx_tags[i].getAntenna()+'\" t=\"'+ctx_tags[i].getTimeFormatted()+'\" rssi=\"'+ctx_tags[i].getRSSI()+'\" />';
}
body+='</read>';
"
}
]
application/x-www-form-urlencoded (I)
This will only work in AdvanNet-2.3.15_06 or higher
Send inventory data in as a POST form
The JSON string is as follows.
[{
"event":"TAG_READ",
"path":"'/to/my/url'",
"body":"
var body='reader_name=\"AdvanReader 60\"&';
body+='mac_address=\"'+ctx_devmac+'\"&';
body+='line_ending=&';
body+='field_delim=,&';
body+='field_names=antenna_port,epc,first_seen_timestamp,peak_rssi&';
body+='field_values='+ctx_tags[0].getAntenna()+',\"'+ctx_tags[0].getEPC()+'\",'+ctx_tags[0].getTime()+','+ctx_tags[0].getEPC();
"
}
]
Always enable the send one by one.
Leaving the send one by one disabled may cause inventory data not be be uploaded
Define the header in the Advanced JSON conf as follows
{"Content-type":"application/x-www-form-urlencoded"}
application/x-www-form-urlencoded (II)
Similar example to the previous one but with multi-line parameters
This will only work in AdvanNet-2.3.15_06 or higher
Send inventory data in as a POST form
The JSON string is as follows.
[{
"event":"TAG_READ",
"path":"'/to/my/url'",
"body":"
var body='reader_name=\"Reader 1\"&';
body+='mac_address=\"'+ctx_devmac+'\"&';
body+='line_ending=&';
body+='field_delim=,&';
body+='field_names=antenna_port,epc,first_seen_timestamp,peak_rssi';
var i=0;
for(i=0;i<ctx_tags.length;i++){
body+='&field_values='+ctx_tags[0].getAntenna()+',\"'+ctx_tags[0].getEPC()+'\",'+ctx_tags[0].getTime()+','+ctx_tags[0].getEPC();
}
"
}
]
Define the header in the Advanced JSON conf as follows
{"Content-type":"application/x-www-form-urlencoded"}
Complete example
This is a complete example provided as a starting point when your configuration does not work. This might be due to 3 factors:
Error on AdvanNet HTTP Service settings
Bad configuration of the HTTP server
Bug on AdvanNet firmware
As the AdvanNet firmware bug is the least common source of problems, it is compulsory to check whether the problem is caused by one of the first 2 factors.
Then, in order to ensure that Keonn firmware is working as intended, you must test it against a real HTTP server meant for developing purposes, we recommend:
webhook.site
Go to https://webhook.site web page. This online tool provides an URL that will collect HTTP requests made to it.
When creating a Webhook entry, an URL with a specific path will be provided. For example https://webhook.site/2500a2e2-d84a-4c1e-8761-d1c7160d163d.
The host it: webhook.site
The protocol is https
The path is: /2500a2e2-d84a-4c1e-8761-d1c7160d163d
Alternatively it is possible to use a python script
Local HTTPServer in python:
In the attachment/downloads section at the bottom of the page you can download a tiny python script that you can run to set up a local http server that will receive the POST requests from the reader and will print them onscreen for you to check. The server listens in the port 8080 by default but can be changed by passing it as argument.
To run the script just type python httpServer.py <port number> on your terminal console of choice and you'll see the post requests onscreen
If you don't have python you can install it following these instructions: https://wiki.python.org/moin/BeginnersGuide/Download
Validate HTTP Server
Once the HTTP server is ready, test it.
We assume we are using webhook.site
Open a terminal and execute
curl -X POST -d"fizz=buzz" https://webhook.site/2500a2e2-d84a-4c1e-8761-d1c7160d163d
Check the webhook.site, you should see something like the following. Notice a request fizz=buzz has been received.
At this point AdvanNet can be configured.
Make sure the ReadMode generates TAG_READ events
Configure HTTP Service
Go to the the AdvanNet configuration of your device and inside the System configuration go to the AdvanNet Services HTTPService label.
Change the HTTP put/post settings to the following values:
Enabled: true
Protocol: https
Host: webhook.site
Port: 443
HTTP method: POST
Content-Type: JSON (application/json)
JSON config: -> change the path by the one provided by RequestBin (be careful to not remove the single quotes from the path!)
[{
"event":"TAG_READ",
"path":"'/2500a2e2-d84a-4c1e-8761-d1c7160d163d'",
"body":"
var body='reader_name=\"AdvanReader 160\"&';
body+='mac_address=\"'+ctx_devmac+'\"&';
body+='line_ending=&';
body+='field_delim=,&';
body+='field_names=antenna_port,epc,first_seen_timestamp,peak_rssi&';
body+='field_values='+ctx_tags[0].getAntenna()+',\"'+ctx_tags[0].getEPC()+'\",'+ctx_tags[0].getTime()+','+ctx_tags[0].getEPC();"
}]
Apply service config.
Test complete example
Start the reader so that one RFID tag is read.
Go to your Webhook.site URL and refresh the page by performing CTRL+F5.
A HTTP POST of the TAG READ event should be received and it should look like this:
If after following the whole process it is still not possible to receive any HTTP POST at your webhook.site URL, please contact to support@keonn.com for further help.
FAQ
Is this service resilient to internet outages?
Indeed, requests are cached if cannot be sent due to a timeout to the server. They are not cached if the server fails however. If you want requests to be resent after the server fails please add {"reQueueMismatchedRequests":true} to the Advanced JSON config field.
Do you have examples of the JSON config field.
Yes, we have examples here