Introduction
This is the documentation for the 2.2 release of Impinj ItemSense, which was released on October 28, 2019.
ItemSense is a key element of the Impinj platform. It streamlines the configuration, management, and maintenance of RAIN hardware devices, and simplifies the effort to make RAIN RFID data accessible to business and consumer applications. It can be used to:
- discover and configure RAIN readers and gateways
- monitor device health
- filter and process incoming tag data
- automate firmware updates
Through its REST APIs and the ItemSense Management Console (IMC), Impinj ItemSense provides system management, intelligent event processing, and flexible data access; its event publication interface provides integration with real-time item events, reader health events, and threshold transition events.
Changes in this Release
- Installation
- Added new Hardware Sizing Guidelines, with validated configurations as low as 6GB of RAM
- Restricted installation and running permissions to users with sudo privileges only. Root users no longer have permission to install or run ItemSense
- Note that the version of Docker currently supplied through the Snap package manager is not compatible with ItemSense. If you installed Docker using the Snap package manager, your installation of ItemSense will fail
- Data and Algorithms
- Added support for reader-level RxSensitivity filter for inventory mode
- Added support for passing channel configuration to readers in location mode
- Improved validation of channel configuration settings
- Management and Configuration
- Added a system host health monitoring feature in the IMC
- Added the ability to test web-hook broker connections
- Bug Fixes
- Minor installation issues
- Threshold monitor confidence values are shown with too much precision
- Not all form values are reverted when breadcrumb, back, or cancel buttons are pushed in the IMC
Installation Guide
This document describes the installation process for Impinj ItemSense.
Introduction
The Impinj ItemSense software is provided in a setup package for customers who are installing the software within their company-managed network. The package contains a number of files, but the primary components are delivered as a series of docker containers.
The following section describes the process for installing ItemSense using the setup package.
Installation Prerequisites
Before starting the ItemSense installation process, the following steps must be completed:
- Obtain an ItemSense Instance ID from your Impinj representative.
- Download the ItemSense setup package from the link in the welcome email.
- Install the following software on the server where ItemSense will be installed:
- Linux operating system with ONLY these specific versions:
- Ubuntu version
16.04
or version18.04
, with the latest kernel version for that distribution - Centos version
7
with the latest kernel version for that distribution - Docker, version
18.09.2
or later - Docker Compose, version
1.23.2
or later
- Ensure that all of the RAIN RFID readers are configured with an NTP server. See Clock Synchronization and NTP Configuration for more details.
- Ensure that the user installing ItemSense is a valid Linux user. Make a note of this user's login name and password as you will need it for most support-related procedures.
- The setup package will require approximately
3GB
of temporary space to extract the compressed images. Ensure that the target directory has at least this amount of free space available. - Ensure that the host has the required ItemSense ports open. See Requirements for more details.
- If you are installing ItemSense 2018r2 or earlier, please be aware that the aufs storage driver configured by default on some Docker releases has been observed to cause failures under load. The newer overlay2 storage driver is recommended. To check which Docker storage driver you have, execute the "docker info" command. If the reported value for "Storage Driver" is "aufs", you must first uninstall any previous version of ItemSense, if it exists, then uninstall Docker and reinstall with the "overlay2" driver option. (If necessary, your configuration for a previous version of ItemSense can be exported and then imported into the new setup.) For more information about Docker storage drivers and storage driver configuration, please refer to the online documentation at the Docker website.
Install ItemSense
Pre-checks
Run the following commands in a terminal on the target server to confirm if the server is in the correct state to begin installation:
-
Check that nothing is listening on port 80, 3010, 443 or 5672.
For example, this command should not show any output:
sudo ss -tlnp | grep ':80\W\\|:3010\W\\|:443\W\\|:5672\W'
-
If this is a clean install and not an upgrade from an earlier ItemSense version, check that no previous docker images already exist.
sudo docker images
If this command shows that some ItemSense docker images already exist, follow the Uninstall Itemsense Via Automated Process or the Uninstall Itemsense Via Manual Process instructions below to remove them.
-
Check that docker is installed and is at the version specified in Installation Prerequisites:
docker -v
Example output:
Docker version 18.09.2, build 23cf638
-
Check that docker-compose is installed and is at the version specified in Installation Prerequisites:
docker-compose -v
Example output:
docker-compose version 1.23.2, build c7bdf9e
-
Check that there is at least
8GB
of available disk space:df -h ~
Details:
- The setup package itself will require
500MB
of space. This package can potentially be removed once the installation is complete - The setup package will require approximately
1GB
of temporary space to extract the compressed images. This space will be reclaimed automatically at the end of the installation - The initial installation consumes approximately
1.5GB
of space but will grow over time as ItemSense data and logs are written to disk
See our Resource Requirements Guide for more information about System Requirements.
- The setup package itself will require
Installation Instructions
To install ItemSense, you will need to have already downloaded the setup package. This file will be named similar to the following: itemsense-2.2.0+XXX-setup.run
When the setup package file has been obtained:
-
Copy the file to the target server. The following is an example of copying the file from a Linux host to the target server.
scp itemsense-2.2.0+XXX-setup.run USERNAME@TARGET_SERVER:.
Where:
USERNAME
is replaced with the user on the target server.TARGET_SERVER
is replaced with the hostname or IP address of the server on which you intend to install ItemSense. When the file transfer to the target server is complete, log on to the target server and navigate to the location where you placed the file. If you followed the command above, the file will be in the home directory of the user used to transfer the file on to the target server.
-
Make the setup package file executable with the following command:
chmod +x itemsense-2.2.0+XXX-setup.run
-
From the same directory as the ItemSense setup package, run the setup package with the argument "install".
sudo ./itemsense-2.2.0+XXX-setup.run install
The installer script provides the option to choose the location at which ItemSense is installed. At the start of the Installation, you will be prompted to:
- Press enter to accept the default directory provided by ItemSense
- Provide an absolute path to the directory in which you will install ItemSense
- Type "exit" to quit
The default path is /opt, which creates the installation directory, /opt/impinj/itemsense/2_2_0. If you choose to create your own directory, be aware that ItemSense appends the path, impinj/itemsense/2_1_0, to your location during installation.You will be asked to confirm if you would like to continue with the installation. Select
y
to continue with the installation orn
to back out of the installation.Example output:
[user@localhost~]$ sudo ./itemsense-2.2.0+XXX-setup.run install INFO: Host: Ubuntu 16.04.6 LTS INFO: Docker storage driver: overlay2 INFO: Confirmed Impinj ItemSense host has 4 cores available. Please choose a path for Impinj ItemSense 2.2.0 or press enter to use the default value or type "exit" to quit. Path [/opt]: /newPath About to install Impinj ItemSense into path "/newPath". The following directories will be created "impinj/itemsense/2_1_0" Ready to proceed (y/n)? y INFO: Generating compose file: /newPath/impinj/itemsense/2_2_0/itemsense-prod.yml INFO: Unpacking docker images Loaded image: isreg/imc:2.2.0.737 ... INFO: Unpacking firmware images ... Creating 2_2_0_isv2_1 ... done ... INFO: Installation action complete using path: /newPath/impinj/itemsense/2_2_0 INFO: Setting permissions on /newPath/impinj/itemsense/2_2_0/containers INFO: Waiting up to 120 seconds for the Impinj ItemSense services to initialize and respond Testing service endpoints [=> ] Testing service endpoints [=> ] Testing service endpoints [==> ] Testing service endpoints [===> ] Testing service endpoints [====> ] Testing service endpoints [=====> ] Testing service endpoints [======> ] Testing service endpoints [======> ] 14/120s INFO: IPv4 and IPv6 connectivity to all Impinj ItemSense services successfully established! INFO: ItemSense endpoints test passed INFO: Waiting up to 30 seconds for the Impinj ItemSense Management Console (IMC) to initialize and respond Testing IMC endpoint [=> ] 0/30s INFO: Found IMC HTTP endpoint INFO: To open the Impinj ItemSense Management Console and complete the setup process, open a supported web browser and browse to http://
:3010. For more information, consult the ItemSense Management Console section on the Impinj Developers Portal at https://platform.impinj.com/site/developer/itemsense. INFO: Impinj ItemSense install operation complete at path /newPath/impinj/itemsense/2_2_0
In a browser, navigate to the IMC using the server IP address or host name and port 3010:http://TARGET_SERVER:3010/
Upgrade ItemSense
Upgrade Using Separate Hosts
These instructions explain how to stand up a separate instance of ItemSense and run a migration script to copy over the configuration. Note that historical item, health, and job data will be lost using this upgrade method. If you need to retain your historical item data across the upgrade, then please follow the instructions for Upgrade on the Same Host.
Side-by-Side Prerequisites
- Your current ItemSense build has been installed and is up and running on
TARGET_SERVER_XXX
.
- ItemSense-2.2.0 has been installed according to the Installation instructions, and is up and running on
TARGET_SERVER_YYY
Side-by-Side Upgrade Instructions
The configuration migration is executed through the ItemSense Management Console (IMC).
In a browser on
TARGET_SERVER_XXX
, navigate to the IMC using the server IP address or host name and port 3010:From the landing page navigation menu, click More | Configuration Import/Export. This will take you to the Configuration Migration page.
Click the Export Configuration button.
Select and copy the exported configuration, including both the beginning and ending brackets.
-
Navigate to the IMC Configuration Migration page on
TARGET_SERVER_YYY
. Click in the
Import Configuration
text box and paste the content you copied.Select
Overwrite
and click theImport Configuration
button.
After upgrading ItemSense, you must also upgrade your Reader Agent and Firmware. You can do this from within the ItemSense Management Console (IMC).
- On the navigation bar, click More | Admin Panel.
- Click Software Installation.
- For Software to Install, select Reader Agent
- For Version to Install, select the latest version of the reader agent.
- Select Reader Firmware, and select the latest version of the reader firmware.
Upgrade on the Same Host
This installs the new release of ItemSense over an existing instance.
In-Place Prerequisites
- The Impinj ItemSense setup package has been obtained
- Your current ItemSense build is up and running on
TARGET_SERVER
.ItemSense 2018r2 Limited Availability
and any later builds are valid. - Docker, version
18.09.2
or later - Docker Compose, version
1.23.2
or later
In-Place Upgrade Instructions
-
(Optional) As a precaution, backup your configuration and database.
- From the IMC navigation menu, click More | Configuration Import/Export
- On the Configuration Import/Export page, click the Export Configuration button.
- Select and copy the exported configuration, including both the beginning and ending brackets.
-
Backup the ItemSense database. The database is stored in:
~/containers/is-db
sudo cp -r ~/containers/is-db ~/IS_DB_BACKUP
-
Copy the ItemSense setup package file to the target server. The following is an example of copying the file from a Linux host to the target server.
scp itemsense-2.2.0+XXX-setup.run USERNAME@TARGET_SERVER:.
Where:
-
USERNAME
should be replaced with the designated user on the target server -
TARGET_SERVER
should be replaced with the hostname or IP address of the server on which ItemSense will be installed
-
When the file transfer to the target server has completed, log on to the target server and navigate to the location where you placed the file. If you followed the command above, the file will be in the home directory of the designated user.
-
Make the setup package file executable:
chmod +x itemsense-2.2.0+XXX-setup.run
-
From the same directory as the ItemSense setup package, run the setup package with the argument "upgrade".
ItemSense 2.2.0 allows you to configure the maximum number of records you want to retain, in addition to the previous feature that retained records based on their age. The types of records affected by this new feature are:
- items
- item history
- threshold transitions
- task
- health
The config.yml file provided with ItemSense 2.2.0 contains default values for maxAge and maxCount that have been performance tested and are recommended by Impinj. However, if applied, these new defaults can result in the loss of older data. During the upgrade, you will be warned about this feature and required to make a choice to:
- Proceed using the recommended maximum row counts (y)
- Proceed with the feature disabled (n)
- Abort
To avoid losing data, we provide an alternative config.yml, in which you can customize the settings or effectively disable the new feature. For more information about these files and how they allow you to customize ItemSense, see Configuration and Logging Files.
If you are at all uncertain, please abort the upgrade and contact Impinj Customer Support.
The installation script provides the option to choose the location at which ItemSense is installed. At the start of the Installation, you will be prompted to:
- Press enter to accept the default directory provided by ItemSense,
- Provide an absolute path to the directory in which you will install ItemSense, or
- Type "exit" to quit
The default path is /opt, which creates the installation directory, /opt/impinj/itemsense/2_2_0. If you choose to create your own directory, be aware that ItemSense appends the path, impinj/itemsense/2_1_0, to your location during installation.
You will be asked to confirm if you would like to continue with the installation. Select y
to continue with the installation or n
to back out of the installation.
Example output:
Path [/opt]: /MyDir
About to install Impinj ItemSense into path "/MyDir". The following directories will be created "impinj/itemsense/2_1_0"
Ready to proceed (y/n)? y
INFO: Removing old Impinj ItemSense backups (if any)
INFO: Stopping and removing previous installation
INFO: Removing container images from local docker registry
INFO: ...Removing isreg/is-proxy:0.1.1
Untagged: isreg/is-proxy:0.1.1
...
INFO: ...Removing isreg/is-mariadb:10.0.28-3
Untagged: isreg/is-mariadb:10.0.28-3
...
INFO: ...Removing isreg/is-ntp:0.0.3
Untagged: isreg/is-ntp:0.0.3
...
INFO: ...Removing rabbitmq:3.7.8-alpine
Untagged: rabbitmq:3.7.8-alpine
...
INFO: ...Removing isreg/imc:2.0.1.5
Untagged: isreg/imc:2.0.1.5
...
INFO: ...Removing isreg/isv2:0.0.89-4ca42257
Untagged: isreg/isv2:0.0.89-4ca42257
...
INFO: ...Removing isreg/itemsense:2.0.3_34-caf860cf
Untagged: isreg/itemsense:2.0.3_34-caf860cf
...
INFO: Copying data from your old Impinj ItemSense installation. Depending on the size of your database, this can be a lengthy process.
INFO: Re-integrating previous data files for migration
INFO: Importing reader agent SSL certificates from previous installation
INFO: Restoring IMC config data
INFO: Setting permissions on /MyDir/impinj/itemsense/2_2_0/containers
INFO: Generating compose file: /MyDir/impinj/itemsense/2_2_0/itemsense-prod.yml
INFO: Unpacking docker images
Loaded image: isreg/imc:2.2.0.743
Loaded image: isreg/is-mariadb:2.2.1
Loaded image: isreg/is-ntp:0.0.3
Loaded image: isreg/is-proxy:0.2.2
Loaded image: isreg/isv2:0.0.108-a0f0d84b
Loaded image: isreg/itemsense:2.2.0_1661-26c6a4de
Loaded image: rabbitmq:3.7.8-alpine
INFO: Unpacking firmware images
INFO: Installing nginx container configuration
INFO: Installing rabbitmq container configuration
INFO: Installing Impinj ItemSense support tools
INFO: Starting the new docker composition
Creating network "2_2_0_itemsense" with driver "bridge"
Creating 2_2_0_isv2_1 ... done
Creating 2_2_0_imc_1 ... done
Creating 2_2_0_itemsense_1 ... done
Creating 2_2_0_is-ntp_1 ... done
Creating 2_2_0_is-db_1 ... done
Creating 2_2_0_is-rabbit_1 ... done
Creating 2_2_0_nginx_1 ... done
INFO: Installation action complete using path: /MyDir/impinj/itemsense/2_2_0
...
INFO: Database migrations started. Depending on the size of your database, this can be a lengthy process.
Interrupting this may corrupt Impinj ItemSense and render your system unusable.
Please allow the process to complete normally. If you believe it is taking too long, contact support.
INFO: Data migrations completed.
INFO: Migrating TLS settings from previous installation
INFO: Checking for previous TLS settings
INFO: Upgrading and Restoring Impinj ItemSense config store
INFO: Removing temporary files
...
INFO: upgrade action complete
INFO: Setting permissions on /MyDir/impinj/itemsense/2_2_0/containers
INFO: Waiting up to 120 seconds for the Impinj ItemSense services to initialize and respond
...
INFO: Found IMC HTTP endpoint
INFO: To open the Impinj ItemSense Management Console and complete the setup process,
open a supported web browser and browse to http://:3010.
For more information, consult the ItemSense Management Console section on the
Impinj Developers Portal at https://platform.impinj.com/site/developer/itemsense.
INFO: Impinj ItemSense upgrade operation complete at path /MyDir/impinj/itemsense/2_2_0
At this point all configuration has been migrated to the new instance but the readers are still provisioned against the old instance. You will need to go through the provisioning flow to associate the defined readers with the new instance.
- Add a network
- Find a network to add by looking at the Address field of a reader definition
- In the navigation menu, click More | Admin Panel.
- Click Scanner Configuration
- Register readers
- From the Definitions page, click the Scanner tab. This will take you to the SCANNER page.
- Click the DISCOVER READERS button.
- Select only the readers flagged with the triangle exclamation point
- Click the REGISTER SELECTED READERS button
- Upgrade reader firmware
- Return to the Definitions" page. In the navigation menu, click *More | Admin Panel**.
- Click SOFTWARE INSTALL.
- Under Software Installation,
Software to Install
, selectReader Firmware
. - Select your set of readers to update
- Click START INSTALLATION.
The readers are now registered, upgraded, and ready to start jobs. If the upgrade was successful, remove the backups:
sudo rm -rf ~/IS_DB_BACKUP
rm is-<filename>
Upgrade Earlier Versions of ItemSense
If you are runnning a version of ItemSense that is older than 2018r2, please contact Impinj support.
Uninstall ItemSense via Automated Process
To uninstall ItemSense via the automated process, follow these steps:
Go to the directory where you put the ItemSense installer file.
-
Run the installer with the
remove
subcommand to remove the ItemSense software:sudo ./itemsense-2.2.0+XXX-setup.run remove
Example output:
[issupport@localhost ~]$ sudo ./itemsense-2.2.0+XXX-setup.run remove
Verifying archive integrity... 100% All good.
ItemSense 2.2.0 Build 1661 Setup Package 100%
...
About to completely remove Impinj ItemSense containers, backups, and data from path /opt/impinj/itemsense/2_1_0.
Ready to proceed (y/n)? y
INFO: Stopping and removing containers
Stopping 2_1_0_is-rabbit_1 ... done
Stopping 2_1_0_isv2_1 ... done
Stopping 2_1_0_itemsense_1 ... done
Stopping 2_1_0_imc_1 ... done
Stopping 2_1_0_nginx_1 ... done
Stopping 2_1_0_is-ntp_1 ... done
Stopping 2_1_0_is-db_1 ... done
Removing 2_1_0_is-rabbit_1 ... done
Removing 2_1_0_isv2_1 ... done
Removing 2_1_0_itemsense_1 ... done
Removing 2_1_0_imc_1 ... done
Removing 2_1_0_nginx_1 ... done
Removing 2_1_0_is-ntp_1 ... done
Removing 2_1_0_is-db_1 ... done
Removing network 2_1_0_itemsense
INFO: Removing container images from local docker registry
INFO: ...Removing isreg/is-proxy:0.2.1
Untagged: isreg/is-proxy:0.2.1
…
INFO: ...Removing isreg/is-mariadb:10.0.28-3
Untagged: isreg/is-mariadb:10.0.28-3
…
INFO: ...Removing isreg/is-ntp:0.0.3
Untagged: isreg/is-ntp:0.0.3
…
INFO: ...Removing isreg/is-rabbitmq-runit:3.6.15-alpine
Untagged: isreg/is-rabbitmq-runit:3.6.15-alpine
…
INFO: ...Removing isreg/imc:1.0.523
Untagged: isreg/imc:1.0.523
…
INFO: ...Removing isv2:0.0.59-e740b050
Untagged: isv2:0.0.59-e740b050
…
INFO: ...Removing isreg/itemsense:master-7850a
Untagged: isreg/itemsense:master-7850a
…
INFO: Impinj ItemSense remove operation complete at path...
Uninstall ItemSense via Manual Process
To manually uninstall ItemSense, follow these steps:
-
Check that nothing is listening on port 80, 3010, 443 or 5672. For example, the following command should not show any output:
sudo docker ps
If you see seven containers listed like the following:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 165601415c7e isreg/is-proxy:0.1.0 "/bin/sh -c /bin/d..." 13 minutes ago Up 13 minutes issupport_nginx_1 63d6bb6e4287 isreg/is-mariadb:10.0.28-3 "docker-entrypoint..." 13 minutes ago Up 13 minutes issupport_is-db_1 0c704cc5a15a isv2:0.0.59-e740b050 "/opt/itemsense/i..." 13 minutes ago Up 13 minutes issupport_isv2_1 8f09717bf79c isreg/itemsense:master-7850a "/sbin/my_init" 13 minutes ago Up 13 minutes issupport_itemsense_1 411dd4d4b572 isreg/is-rabbitmq-runit:3.6.15-alpine "docker-entrypoint..." 13 minutes ago Up 13 minutes issupport_is-rabbit_1 5fdf343d83ca isreg/imc:1.0.523 "/etc/sv/is-webapp..." 13 minutes ago Up 13 minutes issupport_imc_1 b88c7e88fc27 isreg/is-ntp:0.0.3 "/bin/sh /usr/loca..." 13 minutes ago Up 13 minutes issupport_is-ntp_1
Then navigate to the installation directory of ItemSense and run:
sudo docker-compose -f itemsense-prod.yml down
Example output:
Stopping issupport_nginx_1 ... done Stopping issupport_is-db_1 ... done Stopping issupport_isv2_1 ... done Stopping issupport_itemsense_1 ... done Stopping issupport_is-rabbit_1 ... done Stopping issupport_imc_1 ... done Stopping issupport_is-ntp_1 ... done Removing issupport_nginx_1 ... done Removing issupport_is-db_1 ... done Removing issupport_isv2_1 ... done Removing issupport_itemsense_1 ... done Removing issupport_is-rabbit_1 ... done Removing issupport_imc_1 ... done Removing issupport_is-ntp_1 ... done
-
Remove the containers directory and the itemsense-prod.yml file from the installation directory.
sudo rm -rf containers/
sudo rm -f itemsense-prod.yml
-
Find the ItemSense docker images
sudo docker images
Example output:
REPOSITORY TAG IMAGE ID CREATED SIZE isreg/itemsense 2.1.0_1661-26c6a4de 452fbdaede7d 6 days ago 421MB isreg/imc 2.1.0.743 92db33343fb7 6 days ago 131MB isreg/isv2 0.0.108-a0f0d84b 1bfe9846efa9 2 weeks ago 122MB isreg/is-mariadb 2.1.1 22e7e735e86c 3 weeks ago 200MB isreg/is-proxy 0.2.1 661688be09b6 5 weeks ago 16.9MB rabbitmq 3.7.8-alpine b84c00eb4aee 8 months ago 46.8MB isreg/is-ntp 0.0.3 ca74798da8b8 12 months ago 4.5MB
-
Remove the ItemSense docker images.
sudo docker rmi IMAGEID
Where IMAGEID is the IMAGE ID listed in your output for step 4 above. Example output:
Untagged: isreg/is-mariadb:10.0.28-3 Deleted: sha256:b46cf84d5e294a0953254ca5e06e5aaac3752a9d366667671dcb3a7bdf23cb53 Deleted: sha256:0d1e183a06690ee796292e74e57b0a24b13a2b068c1a4b3793af31e18e51cef6 Deleted: sha256:cb28cd83346263cb6edb1f6f056c1b575b7d4013ffee8527144c4ef2950d32ce Deleted: sha256:5671e0f4505e12a9217c13f5dc4353b5cc25a3bff58591ea884addb200f63a9f Deleted: sha256:120c9add60e3fa4f42d3dbc465d6e783c94ba8a08f32de2985856c01e8038c92 Deleted: sha256:b5a9489a383edacf6330dbc1e53a727f421b824778bfca65e0f69911bba7df8e Deleted: sha256:80c44837b8b4f546ccd99a8e348c65cd39610fbc2f9c4701388a8b3afca6fb0a Deleted: sha256:baa7a423070394fed311ccc47b6e6450a828062d8014cdb894cf8358e7dc67e7 Deleted: sha256:d7852a97e12d6c3d318ec4af1a65c5898b55fdc3600430b3fa0fa807fb1bcc23 Deleted: sha256:d5a98345467828bd6cfbebbddb88ed64b2b84304155774317505fdc389c62960 Deleted: sha256:7f6799f430961cfd0adb6af81aa60bb66a7c42da081a5a844b2a6ec96f94c996 Deleted: sha256:e85bddc133b6addb199a81941cf9f9a580d226180fccd71eac0c6c89dcc653ec Deleted: sha256:ca76ebbabd672ad4c5dd8ce3659dcd0794df9b11329359aa74d9461f15a47844 Deleted: sha256:a3928699dfa0d33e65f302e3176d054aec7a50bbe5c2e7e0b53a68541b89dac5 Deleted: sha256:23672a5ac8fb00f5963174353f4fea163a43b23b7814ba3d7efb8cf9803f7010 Deleted: sha256:9042efb93af5246dbc36ffd103a8b87e8d39e797e06656fb5df053ca77378eb9 Deleted: sha256:c08bac17c414ebfb8d22b46b79d4c1fc41d16a4452c924c306cbec673d215d43 Deleted: sha256:30499d7d4e67556242cabe7be7b1bac2a94d7ff00972c6236475858a91b4b2a7 Deleted: sha256:b6ca02dfe5e62c58dacb1dec16eb42ed35761c15562485f9da9364bb7c90b9b3
Uninstall is now complete.
Clock Synchronization and NTP Configuration
The integrity of ItemSense's item data relies heavily on network clock synchronization. If a reader's clock is more than ten seconds out of sync with the ItemSense host's clock, that reader's reports will be ignored and a health event will be triggered (See the Health API) in the Impinj API Reference.
In order for readers to generate reliable reports, all of the readers being utilized in a job must be synchronized with each other and with ItemSense. Prior to collecting tag data from ItemSense for the first time, you should ensure that all of the RAIN RFID reader clocks are configured to synchronize with an NTP server.
If your network does not automatically provide an NTP source, you have a number of options to ensure that all reader clocks are configured to synchronize with an NTP server. The easiest method is through the ItemSense Management Console (IMC). The following steps install an NTP server on the host running ItemSense and configure the readers to use that host as their NTP source.
- Connect to ItemSense via the ItemSense Management Console at:
http://TARGET_SERVER:3010
. - From the Home Page menu bar, click More|NTP Reader Sync.
- Click the NTP Reader Sync toggle button to enable or disable reader synchronization.
Alternatively, you can use the following instructions to manually configure each reader and the ItemSense host to use an external NTP server.
Configure a Reader to Use an external NTP Server
Perform the following steps to configure a reader to use an external NTP server:
- Log in to the reader RShell command prompt using SSH.
-
Disable NTP:
config network ntp disable
-
(Optional) Prevent the reader from dynamically configuring its NTP servers through DHCP:
config network ntp dynamicservers disable
-
Delete any configured NTP servers:
config network ntp delall
-
Add the external NTP server hostname or IP address:
config network ntp add <NTP Server hostname or IP>
-
Re-enable NTP:
config network ntp enable
-
Check that the reader synchronizes (this can take a little while):
show network ntp
Configure ItemSense to Use Encrypted TLS Communications for HTTPS, AMQPS, and MQTTS
You can install your own certificate in the ItemSense server to secure communication between your clients and ItemSense. The only prerequisite is a valid certificate and its corresponding private key. The two files must be accessible to the utility script that enables https
, amqps
, and mqtts
in ItemSense.
A utility script named enable_tls.sh
in the itemsense_support folder helps you safely install your certificate.
Assuming the certificate files, my-cert.crt
and my-cert.key
, are stored in the itemsense_support
folder, the following command sets ItemSense to https
, amqps
, and mqtts
:
sudo ${BASE_LOCATION}/impinj/itemsense/2_2_0//itemsense_support/enable_tls.sh ./my-cert.crt ./my-cert.key
The script asks you whether you want to proceed. If yes, the script switches ItemSense to https
, amqps
, and mqtts
.
Impinj ItemSense supports TLS 1.1, TLS 1.2, and TLS 1.3. Following are basic settings to set your host firewall for specific configurations, whether running in TLS or in non-TLS mode.
Configure Ports to Use HTTP
Port | Setting | Use |
---|---|---|
80/tcp | enable | API |
443/tcp | enable | Must be enabled for readers to connect, whether using HTTP or HTTPS. In both cases, readers connect via HTTPS. |
1883/tcp | enable | MQTT |
3010/tcp | enable | ItemSense Management Console (IMC) |
5672/tcp | enable | AMQP |
123/udp | enable | NTP |
Configure Ports to Use HTTPS
Port | Setting | Use |
---|---|---|
80/tcp | disable | API |
443/tcp | enable | Readers connect to ItemSense via HTTPS in either case |
1883/tcp | disable | MQTT |
3010/tcp | enable | ItemSense Management Console (IMC) -- HTTPS |
5671/tcp | enable | AMQPS |
5672/tcp | disable | AMQP |
8883/tcp | enable | MQTTS |
123/udp | enable | NTP |
Configure Ports to Migrate from HTTP to HTTPS
Port | Setting | Use |
---|---|---|
80/tcp | disable | API |
1883/tcp | disable | MQTT |
5671/tcp | enable | AMQPS |
5672/tcp | disable | AMQP |
8883/tcp | enable | MQTTS |
Tailor the Communication Protocols
If you need to tailor communication protocols to be encrypted and/or to redirect http to https, you can find more script options by executing:
sudo ${BASE_LOCATION}/impinj/itemsense/2_2_0/containers/itemsense_support/enable_tls.sh --advanced-help
Revert to HTTP, AMQP, and MQTT
If you encounter any problems setting up ItemSense to https
, amqps
and mqtts
you can switch ItemSense back to http
, amqp
and mqtt
with the following command:
sudo ${BASE_LOCATION}/impinj/itemsense/2_2_0/itemsense_support/enable_tls.sh disable
Configuration and Logging Files
The config.yml and logback.xml files have been externalized to make them more accessible to users. These files can be found at:
{BASE_LOCATION}/impinj/itemsense/2_2_0/containers
To edit these files, you must first escalate the permissions using either chmod, chmod +x config.yml
or sudo, sudo gedit config.yml
.
The log configuration file, logback.xml, manages ItemSense system log files and is a useful diagnostic tool when working with Impinj Support. It is important to note that incorrect changes to the format of this file could cause a loss of logging altogether. ItemSense will still run, but it could affect your system's performance and disk usage.
The most common use of the config.yml file is management of the pruning configurations. This file contains default values for maxAge and maxCount that have been tested and are recommended by Impinj to preserve performance. However, if you have a large quantity of data in your previous ItemSense installation, applying these new default values may result in the loss of older data. To avoid this, you can set the maxCount values to the largest possible value, which effectively disables pruning.
Be aware that if incorrect changes are made to config.yml, ItemSense will not run.
API Reference Guide
This is the API reference guide for the 2.2 release of Impinj ItemSense, which was released on October 28, 2019. It describes all publicly-visible API endpoints and the data structures used for parameters and return values.
All REST API endpoints in this document are specified using a BASE_URL
placeholder. To call the API, replace this placeholder with the concatenation
of the hostname or IP address of the Impinj ItemSense server and the string
itemsense
. For example, if the ItemSense server is running at:
http://itemsense.company.com
, then the BASE_URL is:
http://itemsense.company.com/itemsense
.
System Configuration, Monitoring and Management
Users are added to the system. Users can be configured with authorization roles, which gives them access to different parts of the API.
The Health of the configured readers is monitored, either via the REST query interface, or the event publishing interface.
Reader Software (firmware) versions can be queried and upgraded.
The Support endpoints are used to aid troubleshooting. They include:
- Configuration
- Log Requests
- Factory Reset
- ItemSense Time Sync
- Item Reset
- Iteration Data
- Reader Reboot
RFID Configuration
RFID configuration consists of specifying Reader Definitions (one per reader) and associated Reader Configurations.
Readers (and the items that they identify, locate and track) can be associated with a Facility, a Floor and a Zone within that facility.
A Recipe specifies the association between the readers and their configurations. Many readers can share the same configuration.
A Job is used to start and stop recipes.
Item Data Query and Events
Once the readers and their configurations have been specified, and a job is running within a facility, information about the Items canbe returned, either via the REST API, or by configuring and subscribing to a Message Queue.
Authorization
Access to the endpoints of the APIs is restricted by the roles of the user performing the call to the API.
ItemSense users can have one or more of the following roles:
- Admin: has access to all endpoints
- ConfigManager: has access to all configuration endpoints
- JobRunner: has access to all job endpoints
- DataReader: has access to all item data endpoints
The roles of a user are configured when the user is created or updated. Specific authorizations are shown for each endpoint.
Users
ItemSense users can be created with full or limited permissions to access each API. A user's role(s) determine which permissions they do and do not have. A user can have multiple roles. A role is one of DataReader, JobRunner, ConfigManager, Admin. Only a user with the Admin role can list and manipulate users.
Create
Create a user
Authorized Roles
Admin
HTTP Request
POST http://BASE_URL/configuration/v1/users/create
Request Body
Parameter | Type | Description |
---|---|---|
name | String | Name of the user to create. |
password | String | Password for the user. |
roles | Array | A set of roles to assign to the user. |
Response
Parameter | Type | Description |
---|---|---|
name | String | The Username |
roles | Array of: String | The roles corresponding to the user |
Sample Code
var user = {};
user.name = "ItemSenseUser";
user.password = "1mp1njer";
user.roles = ["DataReader"];
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/users/create", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(user));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/users/create");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
user = "ItemSense",
password = "1mp1nj!",
roles = {"DataReader"}
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name":"ItemSenseUser", "roles":["DataReader"] }
Create or Replace
Replace an existing user, or create a new one
Authorized Roles
Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/users/createOrReplace
Request Body
Parameter | Type | Description |
---|---|---|
name | String | Name of user to create. |
password (optional) |
String | Password for the user. Optional during updates. |
roles | Array | A set of roles to assign to the user. |
Response
Parameter | Type | Description |
---|---|---|
name | String | The Username |
roles | Array of: String | The roles corresponding to the user |
Sample Code
var user = {};
user.name = "ItemSenseUser";
user.password = "1mp1nj!";
user.roles = ["DataReader", "Admin", "JobRunner"];
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/users/createOrReplace", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(user));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/users/create");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
user = "ItemSense",
password = "1mp1nj!",
roles = { "DataReader",
"Admin",
"JobRunner"
}
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name":"ItemSenseUser", "roles":["DataReader"] }
Delete
Delete a specific user
Authorized Roles
Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/users/destroy/{username}
Parameters
Parameter | Type | Description |
---|---|---|
username | String | The name of the user to delete |
Response
This endpoint returns an empty response
Sample Code
var userName = "ItemSenseUser";
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/users/destroy/" + userName, true);
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string userName = "ItemSenseUser";
Uri uri = new Uri("http://BASE_URL/configuration/v1/users/destroy" + userName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get
Retrieve a specific user
Authorized Roles
Admin
Http Request
GET http://BASE_URL/configuration/v1/users/show/{username}
Parameters
Parameter | Type | Description |
---|---|---|
username | String | The username of the user to retrieve |
Response
Parameter | Type | Description |
---|---|---|
name | String | The name of the user |
roles | Array of: String | The roles corresponding to the user |
Sample Code
var userName = "ItemSenseUser";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/users/show/" + userName, true);
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string specificUser = "ItemSenseUser";
Uri uri = new Uri("http://BASE_URL/configuration/v1/users/show" + specificUser);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "ItemSenseUser", "roles": [ "DataReader" ] }
Get All
Retrieve all of the users
Authorized Roles
Admin
HTTP Request
GET http://BASE_URL/configuration/v1/users/show
Parameters
Parameter | Type | Description |
---|---|---|
role | String | An optional role name. Only users with this role will be returned. |
Response
Array of:
Parameter | Type | Description |
---|---|---|
name | String | The name of the user |
roles | Array of: String | The roles corresponding to the user |
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/users/v1/show", true);
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/users/show");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "name": "DataReader", "roles": [ "DataReader" ] }, { "name": "ItemSenseUser", "roles": [ "DataReader" ] }, { "name": "JobRunner", "roles": [ "JobRunner" ] }, { "name": "SuperAdmin", "roles": [ "Admin" ] } ]
Get the Current User
Show the user corresponding to the API call
Authorized Roles
Admin, ConfigManager, DataReader, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/users/currentUser
Response
Parameter | Type | Description |
---|---|---|
name | String | The name of the user |
roles | Array of: String | The roles corresponding to the user |
Show the User Roles
Display the list of roles that can be assigned to users
Authorized Roles
Admin
HTTP Request
GET http://BASE_URL/configuration/v1/users/roles/show
Response
Array of:
Parameter | Type | Description |
---|---|---|
role | String | A role that the user can be assigned |
Authenticate the current user
Authenticate
Authorized Roles
Admin, ConfigManager, DataReader, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/users/authenticate
Response
Parameter | Type | Description |
---|---|---|
name | String | The name of the user |
roles | Array of: String | The roles corresponding to the user |
Response Codes
Code | Description |
---|---|
200 | The user was successfully authenticated |
401 | No user provided; or the provided user credentials were not authorized |
Authentication
Itemsense users have two options for authenticating:
- HTTP Basic Authentication with the user's Itemsense credentials
- Token-based authentication, using our Authentication API.
To use token-based authentication for authorizing API calls, you must set the Authorization request header with the token value. For example:
Headers['Authorization'] = 'Token {"token": "128faacd-e4bb-4687-90e0-af2836b2c098"}'
If you do not have basic credentials, a user with administrative privileges must generate a token for you.
Get a Token
In order to begin using the token-based authentication mechanism, you must first get a token. This call requires you (or an administrator) to supply Basic Auth credentials.
Authorized Roles
Admin
HTTP Request
PUT http://BASE_URL/authentication/v1/token/{username}
Parameters
Parameter | Type | Description |
---|---|---|
username | String | Name of user for which to create token |
Response
Parameter | Type | Description |
---|---|---|
token | String | The value of the token in UUID format |
Sample Response
{ "token": "128faacd-e4bb-4687-90e0-af2836b2c098" }
Get a Token for the Current User
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/authentication/v1/token
Response
Parameter | Type | Description |
---|---|---|
token | String | The value of the token in UUID format |
List Tokens
List all tokens for a specific user.
Authorized Roles
Admin
HTTP Request
GET http://BASE_URL/authentication/v1/listTokens/{username}
Parameters
Parameter | Type | Description |
---|---|---|
username | String | Name of user for which to list tokens |
Response
An array of:
Parameter | Type | Description |
---|---|---|
authenticationToken | AuthenticationToken | The token |
issued | String | Date of issue of the token in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
username | String | Username associated with token |
lastUsed | String | When the token was last used in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
valid | Boolean | Whether the token is valid |
Revoke Token
Revoke a specific authentication.
Authorized Roles
Admin
HTTP Request
PUT http://BASE_URL/authentication/v1/revokeToken
Request Body
Parameter | Type | Description |
---|---|---|
token | String | The value of the token in UUID format |
Response
This endpoint returns an empty response
Revoke Tokens
This method is used to revoke all tokens for a specific user
Authorized Roles
Admin
HTTP Request
PUT http://BASE_URL/authentication/v1/revokeTokens/{username}
Parameters
Parameter | Type | Description |
---|---|---|
username | String | Name of user for which to revoke tokens |
Response
This endpoint returns an empty response
Validate Token
Validate the provided token
Authorized Roles
Admin
HTTP Request
POST http://BASE_URL/authentication/v1/validateToken
Request Body
Parameter | Type | Description |
---|---|---|
token | String | The value of the token in UUID format |
Response
Parameter | Type | Description |
---|---|---|
name | String | The name of the user |
roles | Array of: String | The roles corresponding to the user |
Response Codes
Code | Description |
---|---|
200 | The token was successfully authenticated |
422 | No token provided |
401 | The provided token is invalid |
AuthenticationToken
Parameters
Parameter | Type | Description |
---|---|---|
token | String | The value of the token in UUID format |
Facilities
Impinj ItemSense is capable of managing multiple physical locations. Each physical location is called a "Facility," which is is independently able to run jobs, build zone maps, specify different reader definitions, and query items. It is also possible to query items across all facilities.
Recipes, reader configurations, and users are shared across all facilities supported by the ItemSense installation.
If ItemSense is only using one facility, no additional configuration is necessary, and the facility name will not be required for other API endpoints. For multiple facilities, the following API endpoints require a facility to be specified as part of the request body:
-
Jobs
- Start
-
Zone Maps
- Create
- Create or Replace
-
Reader Definitions
- Create
- Create or Replace
ItemSense comes pre-loaded with one facility, called 'DEFAULT'.
Create
Create a new facility (but do not replace an existing one)
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/facilities/create
Request Body
Property | Type | Description |
---|---|---|
name (required) |
String | The name associated with the facility. This name is used as the identifier for retrieving, updating, and deleting a facility. It is also used as the primary identifier for a facility in other API calls, where required. |
Sample Code
var facility = { "name": "Warehouse-123" };
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/facilities/create", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(facility));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/facilities/create");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
name = "Warehouse-123"
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "Warehouse-123" }
Create or Replace
Replace an existing facility, or create a new one.
Authorized Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/facilities/createOrReplace
Request Body
Property | Type | Description |
---|---|---|
name (required) |
String | The name associated with the facility. This name is used as the identifier for retrieving, updating, and deleting a facility. It is also used as the primary identifier for a facility in other API calls, where required. |
Sample Code
var facility = { "name": "Warehouse-123" };
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/facilities/createOrReplace", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(facility));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/facilities/createOrReplace");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
name = "Warehouse-123"
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "Warehouse-123" }
Delete
Delete a specific facility.
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/facilities/destroy/{facilityName}
Parameters
Parameter | Type | Description |
---|---|---|
facilityName | String | The name of the facility to delete |
Sample Code
var facilityName = "Warehouse-123";
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/facilities/destroy/" + facilityName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string facilityName = "Warehouse-123";
Uri uri = new Uri("http://BASE_URL/configuration/v1/facilities/destroy/" + facilityName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get
Retrieve a specific facility.
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/facilities/show/{facilityName}
Parameters
Parameter | Type | Description |
---|---|---|
facilityName | String | The name of the facility to retrieve |
Sample Code
const facilityName = "Warehouse-123";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/facilities/show/" + facilityName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string facilityName = "Warehouse-123";
Uri uri = new Uri("http://BASE_URL/configuration/v1/facilities/show/" + facilityName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "Warehouse-123" }
Get All
Retrieve all of the facilities
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/facilities/show
Response
Array of:
Parameter | Type | Description |
---|---|---|
name | String | The name of the facility |
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/facilties/show", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/facilities/show/");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "name": "DEFAULT" }, { "name": "Warehouse-123" } ]
Zone Maps
Zone Maps are used to divide the facility that is being monitored by ItemSense into spatial regions.
A Zone Map consists of a facility, and a set of named Zones. A Zone allocates the space within a facility in a way that is meaningful to the application (e.g. Men’s, Women’s and Shoe departments in a retail store).
Zone names do not have to be unique. If more than one zone definition has the same name as another, then the spaces of the two (or more) physical zones are combined into one logical zone (e.g. Women’s Shoes might be on the 1st floor and Women’s dresses on the 3rd floor; these could be combined into a “Women’s Clothing” zone).
It is not necessary to define zones for the entire space of a facility. ItemSense assigns tags to the zone name “FACILITY” if they are present and outside of any user-defined zones (or “ABSENT” if the tag is detected with LOW presenceConfidence).
If zones are defined, they cannot overlap in space.
When combined with a reader definition’s spatial coordinates, ItemSense provides powerful location data, such as which zone an item is in, and when an item transitions from one zone to another.
Zone Map Example
{ "name": "Contoso_Fashion", "facility": "DEFAULT", "zones": [ { "name": "Womens", "floor": "1", "points": [ { "x": 7.0, "y": 0.0, "z": 0.0 }, { "x": 0.0, "y": 6.0, "z": 0.0 }, { "x": 7.0, "y": 20.0, "z": 0.0 }, { "x": 22.0, "y": 18.0, "z": 0.0 }, { "x": 23.0, "y": 10.0, "z": 0.0 }, { "x": 12.0, "y": 11.0, "z": 0.0 } ] }, { "name": "Mens", "floor": "1", "points": [ { "x": 22.0, "y": 18.0, "z": 0.0 }, { "x": 28.0, "y": 26.0, "z": 0.0 }, { "x": 31.0, "y": 18.0, "z": 0.0 }, { "x": 23.0, "y": 10.0, "z": 0.0 } ] } ] }
Zones
A Zone consists of a name, an optional floor, and a shape in space. The shape is defined by an array of points in two-dimensional* space, using the Cartesian coordinate system, measured in meters. Each point represents a vertex of the shape. They can be triangular (requiring three points), rectangular (requiring four points), or more more complex polygonal shapes (requiring the same number of points as the number of sides in the polygon). When defining a polygon, the vertex points must be specified in an order that describes the outside of the polygon (i.e. points next to each other in the list must share an edge of the polygon).
The z-dimension of point property is currently set to 0 in all cases.
Property | Type | Description |
---|---|---|
name (required) |
String | The name given to the specific zone |
floor (optional) |
String | The name of the floor where the zone exists |
points (required) |
Array of Point | An array of points that define the zone's boundaries |
Points
Property | Type | Description |
---|---|---|
x | Number | The x coordinate of the zone point, in meters from the 0.0,0.0 location in the monitored space. |
y | Number | The y coordinate of the zone point, in meters from the 0.0,0.0 location in the monitored space. |
z | Number | The z coordinate of the zone point. Z is not currently used, and defaults to 0.0 if not specified. While the z property may be omitted, it may not be specified with a null value. |
Non-contiguous Zone Example
{ "name": "Contoso_Fashion", "facility": "DEFAULT", "zones": [ { "name": "Womens", "floor": "1", "points": [ { "x": 7.0, "y": 0.0, "z": 0.0 }, { "x": 0.0, "y": 6.0, "z": 0.0 }, { "x": 7.0, "y": 20.0, "z": 0.0 } }, { "name": "Womens", "floor": "2", "points": [ { "x": 7.0, "y": 0.0, "z": 0.0 }, { "x": 0.0, "y": 6.0, "z": 0.0 }, { "x": 7.0, "y": 20.0, "z": 0.0 } }
Create
Create a new zone map (but do not replace an existing one)
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/zoneMaps/create
Request Body
Property | Type | Description |
---|---|---|
name (required) |
String | The name associated with a specific zone map. This name will be used as the identifier for retrieving, updating, and deleting a zone map. It will also be used for setting the Current zone map. |
facility (optional, except if using multiple facilities) |
String | The name of the facility which the zone map will be associated with. |
zones (required) |
Array of Zone | A collection of zones that define the geographic coordinates for each zone in the monitored space. Zone definitions cannot overlap. |
Response
Parameter | Type | Description |
---|---|---|
name | String | The name associated with the zone map |
facility | String | The facility with which the zonemap is associated |
zones | Array of: Zone | The collection of zones within the zone map |
Sample Code
var zoneMap = {
"name": "Contoso_Fashion",
"facility": "DEFAULT",
"zones": [
{
"name": "Womens",
"floor": "1",
"points": [
{
"x": 7.0,
"y": 0.0,
"z": 0.0
},
{
"x": 0.0,
"y": 6.0,
"z": 0.0
},
{
"x": 7.0,
"y": 20.0,
"z": 0.0
},
{
"x": 22.0,
"y": 18.0,
"z": 0.0
},
{
"x": 23.0,
"y": 10.0,
"z": 0.0
},
{
"x": 12.0,
"y": 11.0,
"z": 0.0
}
]
},
{
"name": "Mens",
"floor": "1",
"points": [
{
"x": 22.0,
"y": 18.0,
"z": 0.0
},
{
"x": 28.0,
"y": 26.0,
"z": 0.0
},
{
"x": 31.0,
"y": 18.0,
"z": 0.0
},
{
"x": 23.0,
"y": 10.0,
"z": 0.0
}
]
}
]
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/zoneMaps/create", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(zoneMap));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/zoneMaps/create"");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
name = "Contoso_Fashion",
facility = "DEFAULT",
zones =
{
new
{
name = "MENS",
floor = "0",
points = {
{
x = 28.0,
y = 18.0,
z = 0.0
},
{
x = 28.0,
y = 26.0,
z = 0.0
},
{
x = 31.0,
y = 18.0,
z = 0.0
},
{
x = 23.0,
y = 10.0,
z = 0.0
}
}
},
new
{
name = "WOMENS",
floor = "0",
points = {
{
x = 7.0,
y = 0.0,
z = 0.0
},
{
x = 0.0,
y = 6.0,
z = 0.0
},
{
x = 7.0,
y = 20.0,
z = 0.0
},
{
x = 22.0,
y = 18.0,
z = 0.0
},
{
x = 23.0,
y = 10.0,
z = 0.0
},
{
x = 12.0,
y = 11.0,
z = 0.0
}
}
}
}
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "Contoso_Fashion", "facility": "DEFAULT", "zones": [ { "name": "Womens", "floor": "1", "points": [ { "x": 7.0, "y": 0.0, "z": 0.0 }, { "x": 0.0, "y": 6.0, "z": 0.0 }, { "x": 7.0, "y": 20.0, "z": 0.0 }, { "x": 22.0, "y": 18.0, "z": 0.0 }, { "x": 23.0, "y": 10.0, "z": 0.0 }, { "x": 12.0, "y": 11.0, "z": 0.0 } ] }, { "name": "Mens", "floor": "1", "points": [ { "x": 22.0, "y": 18.0, "z": 0.0 }, { "x": 28.0, "y": 26.0, "z": 0.0 }, { "x": 31.0, "y": 18.0, "z": 0.0 }, { "x": 23.0, "y": 10.0, "z": 0.0 } ] } ] }
Create or Replace
Replace an existing zone map, or create a new one
Authorized Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/zoneMaps/createOrReplace
Request Body
The same as the Create Request Body
Response
The same as Create Request Body
Sample Code
var zoneMap = {
"name": "Contoso_Fashion",
"facility": "DEFAULT",
"zones": [
{
"name": "Womens",
"floor": "1",
"points": [
{
"x": 7.0,
"y": 0.0,
"z": 0.0
},
{
"x": 0.0,
"y": 6.0,
"z": 0.0
},
{
"x": 7.0,
"y": 20.0,
"z": 0.0
},
{
"x": 22.0,
"y": 18.0,
"z": 0.0
},
{
"x": 23.0,
"y": 10.0,
"z": 0.0
},
{
"x": 12.0,
"y": 11.0,
"z": 0.0
}
]
},
{
"name": "Mens",
"floor": "1",
"points": [
{
"x": 22.0,
"y": 18.0,
"z": 0.0
},
{
"x": 28.0,
"y": 26.0,
"z": 0.0
},
{
"x": 31.0,
"y": 18.0,
"z": 0.0
},
{
"x": 23.0,
"y": 10.0,
"z": 0.0
}
]
}
]
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/zoneMaps/createOrReplace", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(zoneMap));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/zoneMaps/create"");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
name = "Contoso_Fashion",
facility = "DEFAULT",
zones =
{
new
{
name = "MENS",
floor = "0",
points = {
{
x = 28.0,
y = 18.0,
z = 0.0
},
{
x = 28.0,
y = 26.0,
z = 0.0
},
{
x = 31.0,
y = 18.0,
z = 0.0
},
{
x = 23.0,
y = 10.0,
z = 0.0
}
}
},
new
{
name = "WOMENS",
floor = "0",
points = {
{
x = 7.0,
y = 0.0,
z = 0.0
},
{
x = 0.0,
y = 6.0,
z = 0.0
},
{
x = 7.0,
y = 20.0,
z = 0.0
},
{
x = 22.0,
y = 18.0,
z = 0.0
},
{
x = 23.0,
y = 10.0,
z = 0.0
},
{
x = 12.0,
y = 11.0,
z = 0.0
}
}
}
}
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
The same as the Create Request Body
Delete
Delete a zone map.
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/zoneMaps/destroy/{zoneMapName}
Parameters
Parameter | Type | Description |
---|---|---|
zoneMapName | String | The name of the zone map to delete |
Sample Code
var zoneMapName = "Contoso_Fashion";
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/zoneMaps/destroy/" + zoneMapName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string zoneMapName = "Contoso_Fashion";
Uri uri = new Uri("http://BASE_URL/configuration/v1/zoneMaps/destroy/" + zoneMapName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get
Retrieve a specific zone map.
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/zoneMaps/show/{zoneMapName}
Parameters
Parameter | Type | Description |
---|---|---|
zoneMapName | String | The name of the zone map to retrieve |
Response
Parameter | Type | Description |
---|---|---|
name | String | The name associated with the zone map |
facility | String | The facility with which the zonemap is associated |
zones | Array of: Zone | The collection of zones within the zone map |
Sample Code
var zoneMapName = "Contoso_Fashion";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/zoneMaps/show/" + zoneMapName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string zoneMapName = "Contoso_Fashion";
Uri uri = new Uri("http://BASE_URL/configuration/v1/zoneMaps/show/" + zoneMapName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "Contoso_Fashion", "facility": "DEFAULT", "zones": [ { "name": "Womens", "floor": "1", "points": [ { "x": 7.0, "y": 0.0, "z": 0.0 }, { "x": 0.0, "y": 6.0, "z": 0.0 }, { "x": 7.0, "y": 20.0, "z": 0.0 }, { "x": 22.0, "y": 18.0, "z": 0.0 }, { "x": 23.0, "y": 10.0, "z": 0.0 }, { "x": 12.0, "y": 11.0, "z": 0.0 } ] }, { "name": "Mens", "floor": "1", "points": [ { "x": 22.0, "y": 18.0, "z": 0.0 }, { "x": 28.0, "y": 26.0, "z": 0.0 }, { "x": 31.0, "y": 18.0, "z": 0.0 }, { "x": 23.0, "y": 10.0, "z": 0.0 } ] } ] }
Get All
Show all of the configured zone maps
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/zoneMaps/show
Response
Array of:
Parameter | Type | Description |
---|---|---|
name | String | The name associated with the zone map |
facility | String | The facility with which the zonemap is associated |
zones | Array of: Zone | The collection of zones within the zone map |
Sample Code
var zoneMapName = "Contoso_Fashion";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/zoneMaps/show", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/zoneMaps/show");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[{ "name": "Contoso_Fashion", "facility": "DEFAULT", "zones": [ { "name": "Womens", "floor": "1", "points": [ { "x": 7.0, "y": 0.0, "z": 0.0 }, { "x": 0.0, "y": 6.0, "z": 0.0 }, { "x": 7.0, "y": 20.0, "z": 0.0 }, { "x": 22.0, "y": 18.0, "z": 0.0 }, { "x": 23.0, "y": 10.0, "z": 0.0 }, { "x": 12.0, "y": 11.0, "z": 0.0 } ] }, { "name": "Mens", "floor": "1", "points": [ { "x": 22.0, "y": 18.0, "z": 0.0 }, { "x": 28.0, "y": 26.0, "z": 0.0 }, { "x": 31.0, "y": 18.0, "z": 0.0 }, { "x": 23.0, "y": 10.0, "z": 0.0 } ] } ] }]
Get Current
Show the current zone map for the given facility
AuthorizedRoles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/control/v1/currentZoneMap/show/{facilityName}
Parameter | Type | Description |
---|---|---|
facilityName (optional, except if using multiple facilities) |
String | The name of the facility for which to retrieve the current zone map. |
Response
Parameter | Type | Description |
---|---|---|
status | One of: WAITING_FOR_ZONE_MAP, RUNNING, FAILED, COMPLETE |
The status of the zone map |
name | String | The name of the zone map |
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/control/v1/currentZoneMap/show", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/control/v1/currentZoneMap/show");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Responses
Without a value currently set:
{ "name": null, "status": "WAITING_FOR_ZONE_MAP" }
With a value currently set:
{ "name": "Contoso_Fashion", "status": "COMPLETE" }
Update Current
Select a specific zone map to apply.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/control/v1/currentZoneMap/select/{zoneMapName}
Parameter | Type | Description |
---|---|---|
zoneMapName | String | The name of the zone map to apply |
Response
Parameter | Type | Description |
---|---|---|
name | String | The name associated with the zone map |
facility | String | The facility with which the zonemap is associated |
zones | Array of: Zone | The collection of zones within the zone map |
Sample Code
var zoneMapName = "Contoso_Fashion";
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/control/v1/currentZoneMap/select" + zoneMapName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string zoneMapName = "Contoso_Fashion";
Uri uri = new Uri("http://BASE_URL/control/v1/currentZoneMap/select" + zoneMapName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Responses
{ "name": "Contoso_Fashion", "status": "COMPLETE" }
Clear Current
Reset the current zone map for the given facility.
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/control/v1/currentZoneMap/clear/{facilityName}
Parameters
Parameter | Type | Description |
---|---|---|
facilityName (optional, except if using multiple facilities) |
String | The name of the facility for which to clear the current zone map. |
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/control/v1/currentZoneMap/clear", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/control/v1/currentZoneMap/clear");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Reader Definitions
Reader Definitions are used to define a reader for use with ItemSense. Each reader definition specifies a single reader.
Create
Create a new reader definition (but do not replace an existing one)
Note that groups are created implicitly as a property of the reader definition. For example, if you specify the name "storeroom" as a group on three readers, those three readers are now part of one "storeroom" group.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/readerDefinitions/create
Request Body
Parameter | Type | Description |
---|---|---|
name | String | The name associated with the reader definition. If not provided, will default to the address. |
address | String | The IP address or the hostname of the reader |
groups | Array of: String | The groups with which this reader is associated |
type | One of: XARRAY, XSPAN, XPORTAL, SPEEDWAY, UNKNOWN |
The type of reader |
readerZone | String | The spot zone with which to associate this reader |
antennaZones | Map[int,string] | A map of antenna-to-spot-zone associations. If not specified, antenna is allocated to the readers spot zone |
facility | String | The facility with which the reader is associated |
placement | PlacementConfig | The placement of the reader |
labels | Array of: String | A list of configurable strings associated with the reader |
agentIdentifier | String | Internal use only. This value is set by the ItemSense Management Console, during reader provisioning. |
Response
Parameter | Type | Description |
---|---|---|
name | String | The name that identifies the reader definition |
serialNumber | String | The serial number of the reader |
address | String | The IP address or the hostname of the reader |
groups | Array of: String | The groups with which this reader is associated |
type | One of: XARRAY, XSPAN, XPORTAL, SPEEDWAY, UNKNOWN |
The type of reader |
readerZone | String | The spot zone with which to associated this reader |
antennaZones | Map[int,string] | A list of antenna-to-spot-zone associations. If not specified, antenna is allocated to the readers spot zone |
facility | String | The facility with which the reader is associated |
placement | PlacementConfig | The placement of the reader |
labels | Array of: String | A list of string tags associated with the reader |
features | Map[Feature, ReaderFeatureStatus] | See Configure Feature |
agentIdentifier | String | Internal use only |
Sample Code
var readerDefinition = {
name: "xarray-11-30-0D",
address: "xarray-11-30-0D.impinj.com",
groups: [ "ceiling", "closet" ],
type: "XARRAY",
placement: {
x: 4.3,
y: 6.65,
z: 2.68,
yaw: 30,
pitch: 0,
roll: 90,
floor: 1
}
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/readerDefinitions/create", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(readerDefinition));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/create");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
name = "xarray-11-32-34",
address = "xarray-11-32-34.impinj.com",
groups = new string[] { "ceiling", "closet" },
type = "XARRAY",
placement = new
{
x = 4.3,
y = 6.65,
z = 2.68,
yaw = 30,
pitch = 0,
roll = 90,
floor = 1
},
labels = null,
readerZone = "xarray-11-32-34.impinj.com",
antennaZones = null
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "xarray-10-D9-41", "agentIdentifier": "xarray-10-D9-41", "address": "xarray-10-D9-41.impinj.com", "groups": [ "ceiling", "closet" ], "type": "XARRAY", "placement": { "x": 4.3, "y": 6.65, "z": 2.68, "yaw": 30, "pitch": 0, "roll": 90, "floor": 1 }, "features": {}, "labels": null, "readerZone": "xarray-10-D9-41", "antennaZones": null }
Create or Replace
Replace an existing reader definition, or create a new one.
Authorized Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/readerDefinitions/createOrReplace
Request Body
The same as the Create Request Body
Response
The same as the Create Response
Sample Code
var readerDefinition = {
name: "xarray-11-30-0D",
address: "xarray-11-30-0D.impinj.com",
groups: [ "ceiling", "closet" ],
type: "XARRAY",
placement: {
x: 4.1,
y: 3.65,
z: 1.68,
yaw: 30,
pitch: 0,
roll: 90,
floor: 1
}
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/readerDefinitions/createOrReplace", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(readerDefinition));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/create");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
name = "xarray-11-32-34",
address = "xarray-11-32-34.impinj.com",
groups = new string[] { "ceiling", "closet" },
type = "XARRAY",
placement = new
{
x = 4.1,
y = 3.65,
z = 1.68,
yaw = 30,
pitch = 0,
roll = 90,
floor = 1
},
labels = null,
readerZone = "xarray-11-32-34.impinj.com",
antennaZones = null
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
The same as the Create Sample Response
Replace
This API is equivalent to createOrReplace in functionality.
Authorized Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/readerDefinitions/replace/{Name}
Request Body
The same as the Create Request Body
Response
The same as the Create Response
Query Parameter
Parameter | Type | Description |
---|---|---|
name | string | Name of reader definition to update. Must match name in request body. |
Sample Code
var currentName = "";
var params = {
name: "",
agentIdentifier: "",
address: "",
groups: [],
type: "",
placement: {
x: 4.1,
y: 3.65,
z: 1.68,
yaw: 30,
pitch: 0,
roll: 90,
floor: 1
},
facility: "",
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http:///itemsense/configuration/v1/readerDefinitions/replace/" + currentName, true)
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic " + btoa(":"));
xhr.send(JSON.stringify(params));
string username = "";
string password = "";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string json;
string currentName = "";
Uri uri = new Uri("http:///itemsense/configuration/v1/readerDefinitions/replace/" + currentName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
var data = new
{
name = "",
agentIdentifier = "",
address = "",
//groups = [],
type = "",
placement = new {
x = 4.1,
y = 3.65,
z = 1.68,
yaw = 30,
pitch = 0,
roll = 90,
floor = 1
},
facility = ""
};
json = JsonConvert.SerializeObject(data);
sw.Write(json);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
The same as the Create Sample Response
Delete
Delete a specific reader definition
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/readerDefinitions/destroy/{readerDefinitionName}
Parameters
Parameter | Type | Description |
---|---|---|
readerDefinitionName | String | Name of the reader definition to be deleted |
Sample Code
var readerName = "xarray-11-30-0D";
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/readerDefinitions/destroy/" + readerName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string readerName = "xarray-11-30-0D";
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/destroy/" + readerName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get
Get a specific reader definition
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/readerDefinitions/show/{readerDefinitionName}
Parameters
Parameter | Type | Description |
---|---|---|
readerDefinitionName | String | The name of the reader definition to retrieve |
Response
The parameters returned in the response are the same as those specified in the Create Response Body
Sample Code
var readerName = "xarray-11-30-0D";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/readerDefinitions/show/" + readerName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string readerName = "xarray-11-30-0D";
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/show/" + readerName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
The same as the Create Sample Response
Get All
This method is used to retrieve all of the reader definitions
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/readerDefinitions/show
Response
Array of objects whose properties are defined by the Create Response Body
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/readerDefinitions/show", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/show");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "name": "xarray-10-D9-41", "agentIdentifier": "xarray-10-D9-41", "address": "xarray-10-D9-41.impinj.com", "groups": [ "ceiling", "closet" ], "type": "XARRAY", "placement": { "x": 4.3, "y": 6.65, "z": 2.2, "yaw": 30, "pitch": 0, "roll": 90, "floor": 1 }, "labels": null, "features": null, "readerZone": "xarray-10-D9-41", "antennaZones": null }, { "name": "xarray-11-30-0D", "agentIdentifier": "xarray-11-30-0D", "address": "xarray-11-30-0D.impinj.com", "groups": [ "ceiling", "closet" ], "type": "XARRAY", "placement": { "x": 8.1, "y": 5.65, "z": 2.68, "yaw": 30, "pitch": 0, "roll": 90, "floor": 1 }, "labels": null, "features": {}, "readerZone": "xarray-11-30-0D", "antennaZones": null } ]
Groups
Retrieve the superset of elements (group names) assigned to any reader definition groups property.
For example, given these readers with these defined groups:
readerDefinition1.groups = ['storeroom', 'dressingroom']
readerDefinition2.groups = ['storeroom', 'ceiling']
readerDefinition3.groups = ['ceiling']
A call to this endpoint would return:
['storeroom', 'dressingroom', 'ceiling']
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/readerDefinitions/groups
Response
Array of strings
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/readerDefinitions/groups", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/groups");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ "ceiling", "closet" ]
Configure Feature
Some readers support features that can be configured for specific uses, e.g. to enable an Antenna Hub on a Speedway reader.
A call to this endpoint produces a status of ACCEPTED(202) and a response HTTP header for "Location", which is a URL used to get the status of the new configuration request.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/readerDefinitions/{readerDefinitionName}/featureChanges
Parameters
Parameter | Type | Description |
---|---|---|
readerDefinitionName | String | The name of the reader on which to configure the feature. |
Request Body
Parameter | Type | Description |
---|---|---|
feature | One of: ANTENNA_HUB |
The name of the feature to configure. |
action | One of: ENABLE, DISABLE |
The configuration action to perform. |
Sample Code
var readerName = "xarray-11-dd-ef";
var featureRequest = {
feature: "ANTENNA_HUB",
action: "ENABLE"
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/readerDefinitions/" + readerName + "/featureChanges", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(featureRequest));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string readerName = "xarray-11-dd-ef";
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/" + readerName + "/featureChanges");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
feature: "ANTENNA_HUB",
action: "ENABLE"
});
sw.Write(data);
}
Sample Response
202 Accepted
Get Feature Status
Get the status of a specific feature on a reader.
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/readerDefinitions/{readerDefinitionName}/featureChanges/{feature}
Parameters
Parameter | Type | Description |
---|---|---|
readerDefinitionName | String | The name of the reader whose feature information is to be returned. |
feature | One of: ANTENNA_HUB |
The feature whose status on that reader is to be returned. |
Response
Parameter | Type | Description |
---|---|---|
status | One of: ENABLED, DISABLED |
The last known status of the feature reported by this reader. If the requestStatus is CONFIGURING or ERROR, this field should not be trusted to reflect the current state of the feature. |
statusLastUpdated | String | The last time the reader reported the status of the feature to ItemSense in ISO-8601 format, e.g. "2017-05-02T15:35:01.560Z". |
requestStatus | One of: IDLE, INITIALIZING, CONFIGURING, ERROR |
The status of the most recent request to change the status of the feature. IDLE means that there is no current request, and the last request, if there was one, completed successfully. INITIALIZING indicates that there is a request preparing to configure. CONFIGURING means there is an active request in progress, and ERROR means the last request failed. |
requestStatusLastUpdated | String | The last time a request to change the status of this feature updated the requestStatus or null if there has never been one, in ISO-8601 format, e.g. "2017-05-02T15:35:01.560Z". |
requestTargetStatus | One of: null, ENABLED, DISABLED |
The target status of the current request to change the status of the feature, if the request is CONFIGURING or in ERROR (null if there is no active request) |
message (optional) |
String | A message with more details on the status of the current or most recent request to change the status of the feature. |
Sample Code
var readerName = "xarray-11-30-0D";
var feature = "ANTENNA_HUB";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/readerDefinitions/" + readerName + "/featureChanges/" + feature, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string readerName = "xarray-11-30-0D";
string feature = "ANTENNA_HUB";
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/" + readerName + "/featureChanges/" + feature);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "status": "DISABLED", "statusLastUpdated": "2017-05-02T15:35:01.560Z", "requestStatus": "IDLE", "requestStatusLastUpdated": null }
Get Active Feature Request Status
Get the status of active feature requests on a reader. Active requests are those where the feature status is CONFIGURING or ERROR.
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/readerDefinitions/{readerDefinitionName}/featureChanges
Parameters
Parameter | Type | Description |
---|---|---|
readerDefinitionName | String | The name of the reader definition whose feature information is to be returned. |
Response
A map of feature names to feature status objects, represented as an object where the field names correspond to valid feature names and the value is the same as the response from the feature status request
Sample Code
var readerName = "xarray-11-30-0D";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/readerDefinitions/" + readerName + "/featureChanges", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string readerName = "xarray-11-30-0D";
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/" + readerName + "/featureChanges");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "ANTENNA_HUB": { "status": "DISABLED", "statusLastUpdated": "2017-05-01T10:13:14Z", "requestStatus": "ERROR", "requestStatusLastUpdated": "2017-05-05T16:33:42Z", "message": "Reader failed to execute the configuration request" } }
Data Definitions
Placement Configuration
A Placement Configuration provides ItemSense with the information that it needs to position a reader relative to the space that is being monitored, and to ensure that the tag locations reported by the reader are relative to the same space. It is not required to specify the placement of any reader; if a placement is specified, then certain fields are required, depending on the reader type, as specified in the table below. Specifying a placement for an XARRAY will allow it to fulfill LOCATION use-cases, and for all reader types can be used to enhance output data.
For an XARRAY gateway, the placement includes a precise location in three-dimensional space.
For all readers, the placement may include a floor, which will be applied to all tag reads from the reader.
Placement Configurations are an important component of the reader definition. They allow ItemSense to accurately position RFID tags within the space monitored by the xArray reader(s). There are three sets of parameters: the floor; the x, y, and z parameters that define where an xArray reader center point is located within the monitored space; and the yaw, pitch, and roll parameters that define the orientation of the xArray reader around its center point, as defined in the diagram below:
Parameter | Type | Allowed For Reader Types | Required for Reader Types | Description | Notes |
---|---|---|---|---|---|
x | Number | XARRAY, XSPAN, XPORTAL | XARRAY, XSPAN, XPORTAL | The x-axis offset, in meters, of the reader from the (0,0) location in the monitored space | |
y | Number | XARRAY, XSPAN, XPORTAL | XARRAY, XSPAN, XPORTAL | The y-axis offset, in meters, of the reader from the (0,0) location in the monitored space | |
z | Number | XARRAY, XSPAN, XPORTAL | XARRAY, XSPAN, XPORTAL | The average distance between the height of the xArray and the height of the tags | |
yaw | Number | XARRAY, XSPAN, XPORTAL | XARRAY, XSPAN, XPORTAL | The angle, in degrees, that the xArray is rotated about its Z axis | |
pitch | Number | XARRAY, XSPAN, XPORTAL | None | The angle, in degrees, that the xArray is tilted about its X axis | This parameter is ignored and is not used by ItemSense |
roll | Number | XARRAY, XSPAN, XPORTAL | None | The angle, in degrees, that the xArray is tilted about its Y axis | This parameter is ignored and is not used by ItemSense |
floor | String | All Readers | SPEEDWAY | The number or name of the floor on which the reader is installed | Once this is set on a reader, it cannot be set to null , nor can the placement itself be set to null . |
Reader Configurations
A Reader Configuration defines how a RAIN™ RFID reader will be utilized when a job is running. This configuration includes properties that control what Reader Mode is being executed, and what Session it is using. For a full list and description of configuration properties, please view the section Reader Configuration Details.
Create Reader Configuration
Create a new reader configuration (but do not replace an existing one)
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/readerConfigurations/create
Request Body
Property | Type | Description |
---|---|---|
name (required) |
String | The name identifying the reader configuration |
operation (required) |
One of: INVENTORY, LOCATION, THRESHOLD, DO_NOTHING |
The operation that the reader performs. Reader is disabled if set to DO_NOTHING. |
configuration | ReaderConfigDetails | The details of the reader configuration |
Sample Code
var readerConfiguration = {
name: "LOCATION_WITH_FILTER",
operation: "LOCATION",
configuration: {
readerMode: "MODE_1002",
session: 2,
filter: {
tagMask: 3034
}
}
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/readerConfigurations/create", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(readerConfiguration));
// Encode credentials
string encodedCredentials = ...
var readerConfiguration = new
{
name = "LOCATION_WITH_FILTER",
operation = "LOCATION",
configuration = new
{
readerMode = "MODE_1002",
session = 2,
filter:
{
tagMask: 3034
}
}
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/create");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(readerConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "LOCATION_WITH_FILTER", "configuration": { "readerMode": "MODE_1002", "session": 2, "filter": { "memoryBank": 1, "pointer": 32, "tagMask": "3034" } }, "operation": "LOCATION" }
Update Reader Configuration
Update an existing configuration, or create a new one if it does not already exist
Authorization Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/readerConfigurations/createOrReplace
Request Body
The same as the #reader-configuration-create-request-body"Create Request Body.
Sample Response
var readerConfiguration = {
name: "IMPINJ_InventoryConfig",
operation: "INVENTORY",
configuration: {
readerMode: "MODE_1002",
searchMode: "DUAL_TARGET",
session: 1,
tagPopulationEstimate: 500,
antennas: [
45,
16,
35,
14,
49,
36,
2,
31,
18,
29,
48,
19,
46,
3,
33,
52,
15,
50,
13,
32,
1,
51,
30,
17,
47,
20,
34,
4
]
}
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/readerConfigurations/createOrReplace", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(readerConfiguration));
// Encode credentials
string encodedCredentials = ...
var readerConfiguration = new
{
name = "IMPINJ_InventoryConfig",
operation = "INVENTORY",
configuration = new
{
readerMode = "MODE_1002",
searchMode = "DUAL_TARGET",
session = 1,
tagPopulationEstimate = 500,
antennas = {
45,
16,
35,
14,
49,
36,
2,
31,
18,
29,
48,
19,
46,
3,
33,
52,
15,
50,
13,
32,
1,
51,
30,
17,
47,
20,
34,
4
}
}
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerDefinitions/create");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(readerConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "IMPINJ_InventoryConfig", "operation": "INVENTORY", "configuration": { "readerMode": "MODE_1002", "searchMode": "DUAL_TARGET", "session": 1, "tagPopulationEstimate": 500, "transmitPowerInDbm": null, "antennas": [ 45, 16, 35, 14, 49, 36, 2, 31, 18, 29, 48, 19, 46, 3, 33, 52, 15, 50, 13, 32, 1, 51, 30, 17, 47, 20, 34, 4 ], "filter": null, "channelConfig": null } }
Delete Reader Configuration
Delete a reader configuration
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/readerConfigurations/destroy/{readerConfigurationName}
Parameters
Parameter | Type | Description |
---|---|---|
readerConfigurationName | String | The name of the reader configuration to be deleted |
Sample Code
var readerConfigurationName = "IMPINJ_LocationConfig";
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/readerConfiguration/destroy/" + readerConfigurationName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
string readerConfigurationName = "IMPINJ_LocationConfig";
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerConfigurations/destroy/" + readerConfigurationName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get Reader Configuration
Retrieve a specific reader configuration
AuthorizedRoles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/readerConfigurations/show/{readerConfigurationName}
Parameters
Parameter | Type | Description |
---|---|---|
readerConfigurationName | String | The name of the reader configuration to be retrieved |
Response
The same as the Create Request Body.
Sample Code
var readerConfigurationName = "IMPINJ_LocationConfig";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/readerConfiguration/show/" + readerConfigurationName, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
string readerConfigurationName = "IMPINJ_LocationConfig";
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerConfigurations/show/" + readerConfigurationName);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "MY_LOCATION", "configuration": { "readerMode": "MODE_1002", "session": 2, "filter": null }, "operation": "LOCATION" }
Get All Reader Configurations
Retrieve all of the reader configurations
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/readerConfigurations/show
Response
Array of Create Reader Configuration Request Body.
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/readerConfiguration/show", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri("http://BASE_URL/configuration/v1/readerConfigurations/show");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "name": "IMPINJ_LocationConfig", "configuration": { "readerMode": "MODE_1002", "session": 2, "filter": null }, "operation": "LOCATION" }, { "name": "IMPINJ_GatewayConfig", "configuration": { "readerMode": "MODE_1002", "session": 2, "searchMode": "DUAL_TARGET", "tagPopulationEstimate": null, "transmitPowerInDbm": null, "polarization": null, "antennas": [ 1, 2, 3, 4 ], "filter": null, "channelConfig": null }, "operation": "INVENTORY" }, { "name": "IMPINJ_InventoryConfig", "configuration": { "readerMode": "MODE_1002", "session": 2, "searchMode": "SINGLE_TARGET", "tagPopulationEstimate": null, "transmitPowerInDbm": null, "polarization": null, "antennas": [ 45, 16, 35, 14, 49, 36, 2, 31, 18, 29, 48, 19, 46, 3, 33, 52, 15, 50, 13, 32, 1, 51, 30, 17, 47, 20, 34, 4 ], "filter": null, "channelConfig": null }, "operation": "INVENTORY" } ]
Data Definitions
Reader Configuration Details
Property | Type | Description |
---|---|---|
readerMode (required) |
One of:
|
The RFID reader mode For more information on reader modes, please see this article |
session (required) |
One of: 0, 1, 2, 3 | The RFID session When operation=LOCATION, must be 2 or 3 |
searchMode (required) |
One of:
|
The RFID search mode Only available when the reader operation=INVENTORY For more information on sessions and search modes, please see this article |
filter (optional) |
Filter Configuration | Tag filter definition |
filters (optional) |
Filter Configuration | Array of tag filter definitions. Must always be used in conjunction with filterOperation . Note that filter and filters are mutually exclusive. Using both at the same time will cause an error. Also, more than two filter arrays at a time are not supported. |
filterOperation (optional) |
Boolean | Flag that indicates how the filters are combined, as an AND or an OR operation. This property is necessary if the filters property is used. |
method * (optional) |
One of:
|
Apply a set of built-in algorithmControl parameters based on the selected method When set to CUSTOM then algorithmControl must be supplied. For all other values algorithmControl must not be supplied Only available when the reader operation=LOCATION |
algorithmControl * (optional) |
Array of Integers | Set additional location algorithm configuration parameters May only be supplied when method=CUSTOM Only available when the reader operation=LOCATION |
tagPopulationEstimate (optional) |
Integer | An estimate of the number of tags in the field of view of the readers. This value will be used to set the starting ‘Q’ value in the UHF Gen2 RFID inventory protocol Only available when the reader operation=INVENTORY |
transmitPowerInDbm (optional) |
Number | The transmit power, in dBm to use for each of the selected antenna ports. |
polarization (optional) |
Boolean | This flag tells the reader to use an antenna's ID in polarized format. These IDs will show up in the antennaId field of the tag report data. By default xArrays support antenna numbers 1-52. Both horizontal and vertical polarizations of a beam map to the same antenna ID. With polarization enabled, the tag reads on the horizontal polarization will have an offset of 1000 applied (1001-1052). Tag reads on the vertical polarization will have an offset of 2000 applied (2001-2052). Only available when the reader operation=INVENTORY |
antennas (optional) |
Array of Integers | Array of integers defining which antenna ports that readers will use. If not specified, or array is empty, all antennas will be used. Only available when the reader operation=INVENTORY |
disabledAntennas (optional) |
Array of Integers | Array of integers defining which antennas that the readers will not use. This is helpful in situations when the reader is located very close to an obstruction and location accuracy could be improved by disabling the antenna(s) facing that obstruction. Only available when the reader operation=LOCATION. |
receiveSensitivityInDbm (optional) |
Integer | Used to filter out tag reads that fall below the specified value. Allows the user to reduce sensitivity by limiting range while maintaining power. Values from -70 to -30 are accepted. Defaults to -80 if no value is specified. Only available when the reader operation=INVENTORY. |
channelConfig (optional) |
Channel Configuration | Defines any fixed frequency channel configurations that the readers will use. This option is used only by readers certified for use in a regulatory region that supports the use of fixed frequencies. ItemSense will not block the user from entering an invalid channel configuration for a region, nor will it alert the user that the configuration is invalid until the job runs and reports a failure, as follows: "message": "xArray-11-30-0D reported a failure: [FailedToStartError] ChannelConfig cannot be specified for this reader since it is in a hopping region" |
powerSweep (optional) |
RF Power Sweep Configuration | When present this parameter will enable the Impinj-specific RF Power Sweep operation Available when the reader operation is INVENTORY or THRESHOLD. |
Filter Configuration
Property | Type | Description | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
tagMask (required) |
String | A hexadecimal value on which to filter tags | ||||||||||
memoryBank (optional) |
Integer | The RFID tag memory region to base a tag filter on, based on the following:
Defaults to 1 |
||||||||||
pointer (optional) |
Integer | A pointer to the bit in memory from which to start the filter. For example, bits 0-31 of EPC memory are used to store the tag CRC and PC Word. To filter on the EPC value of a specific tag, it would therefore be necessary to start the filter on bit 32. Defaults to 32 |
Channel Configuration
Property | Type | Description | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
channelIndex (optional) |
Integer | For RFID readers operating in regions with fixed frequency regulatory requirements, channelIndex is used to define a single frequency for the reader to operate in. This is a one-based integer value into the Low Level Reader Protocol (LLRP) frequency table that points to the position of a frequency in the list of available frequencies. You must already know the channels that are available for your region. For example, RAIN RFID readers for the ETSI region have the following list of available channels:
|
||||||||||
txFrequenciesInMhz (optional) |
Array of Numbers | For RAIN RFID readers operating in regions with frequency-hopping regulatory requirements, txFrequenciesInMhz is used to define a custom frequency hop table. The table can only include frequencies that are allowed by the reader’s region, but frequencies can be defined in any order including repeating and/or omitting frequencies. For example, based on the ETSI frequencies above, an ETSI frequency hop table might be defined as [865.7, 866.3, 866.9, 867.5], which will prompt the reader to hop only in these frequencies, in this order. |
RF Power Sweep Configuration
Property | Type | Description |
---|---|---|
minimumPowerLevel (required) |
Number | The minimum power level that the RF Power Sweep will start at before incrementing. It must be specified in 0.25 dB increments and be less than the value of transmitPowerInDbm . |
powerLevelStepSize (required) |
Number | The step size that the power will increment by when applying RF Power Sweep. It must be specified in 0.25 dB increments. |
Events
In addition to its REST query APIs, ItemSense includes a real-time event push system that allows you to configure a message queue that notifies you when a particular event occurs. This system includes a broker, which is an event messaging server, and a publisher, which is a managed connection to an event broker. To create a message queue, you define your event broker, then configure event publishers that will send messages to that broker. Event publishers can be reconfigured even after the job begins running. Note that it can take up to 30 seconds for ItemSense to see the changes.
The preferred mechanism for event messaging is through an external, user-provided AMQP or MQTT message broker (recommended for high-volume tag deployments.), or sending events to a user-specified URL using Webhook invocations. It is also possible to retrieve events from AMQP and MQTT queues that are provided through an ItemSense built-in message broker.
We do not recommend retrieving events through the Items API, which is intended for use during configuration and testing, nor writing to the database after your system enters production; if a large volume of tags is being read, the use of this API will likely result in performance issues.
ItemSense allows you to limit the messages posted to a queue by configuring filters at queue setup. You can filter by three event types:
- Item
- Health
- Threshold
If multiple queues are configured, messages will be sent to all queues with a matching filter, and only those messages in which all the properties match those within the request will be published.
Create Broker
Create a new event broker.
Authorized Roles
ConfigManager, Admin
HTTP Request
http POST http://BASE_URL/configuration/v1/events/brokers/
Request Body
Property | Type | Description |
---|---|---|
id (supplied by ItemSense) |
long | Id of the broker. Supplied by ItemSense at creation. |
name (required) |
string | name of the broker. |
type (required) |
string | One of AMQP, MQTT, or WEBHOOK. |
host (optional) |
string | IP address of broker. |
port (optional) |
integer | Port of the host. |
username (optional) |
string | Name of the user. |
password (optional) |
string | Password for the user. |
internal (optional) |
boolean | Determines if broker is internal. Defaults to false. Creating an internal broker is not allowed. |
secureConnection (optional) |
boolean | Determines if connection is secure. Defaults to false. |
serverCertificate (optional) |
string | Self-signed certificate, uploaded if SSL is used. |
Sample Code
var brokerConfiguration = {
"name": "Broker_Name",
"type": MQTT,
"host": "external_host.company.com",
"port": 1883,
"username": "admin",
"password": "passgoeshere",
"internal": false,
"secureConnection": false,
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/events/brokers", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic" + btoa("admin:passgoeshere"));
xhr.send(JSON.stringify(brokerConfiguration));
// Encode credentials
string encodedCredentials = ...
// Data for new broker
var brokerConfiguration = new
{
name = "Broker_Name",
type = "MQTT",
host = "external_host.company.com",
port = 1883,
username = "admin",
password = "passgoeshere",
secureConnection = false
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/brokers");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(brokerConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 5, "name": "Broker_Name", "type": "MQTT", "host": "external_host.company.com", "port": 1883, "username": "admin", "password": "passgoeshere", "internal": false, "secureConnection": false, "serverCertificate": null }
Replace Broker
Replace an event broker.
Authorized Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/events/brokers{brokerId}
Request Body
Parameter | Type | Description |
---|---|---|
id | long | Id of the broker. |
Property | Type | Description |
---|---|---|
name (required) |
string | name of the broker. |
type (required) |
string | One of AMQP, MQTT, or WEBHOOK. |
host (optional) |
string | IP address of broker. |
port (optional) |
integer | Port of the host. |
username (optional) |
string | Name of the user. |
password (optional) |
string | Password for the user. |
internal (optional) |
boolean | Determines if broker is internal. Defaults to false. Creating an internal broker is not allowed. |
secureConnection (optional) |
boolean | Determines if connection is secure. Defaults to false. |
serverCertificate (optional) |
string | Self-signed certificate, uploaded if SSL is used. |
Sample Code
var updatedBrokerConfiguration = {
"id": 5,
"name": "New_Broker_Name",
"type": "AMQP",
"host": "external_host.company.com",
"port": 5762,
"username": "admin",
"password": "passgoeshere",
"internal": false,
"secureConnection": false,
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/events/brokers{brokerId}", true)
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic" + btoa("admin:passgoeshere"));
xhr.send(JSON.stringify(updatedBrokerConfiguration));
// Encode credentials
string encodedCredentials = ...
// Updated data for existing broker
var updatedBrokerConfiguration = new
{
id = 5,
name = "New_Broker_Name",
type = "AMQP",
host = "external_host.company.com",
port = 5762,
username = "admin",
password = "passgoeshere",
secureConnection = false
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/brokers/" + updatedBrokerConfiguration.id);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(updatedBrokerConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 5, "name": "New_Broker_Name", "type": "AMQP", "host": "external_host.company.com", "port": 5762, "username": "admin", "password": "passgoeshere", "internal": false, "secureConnection": false, "serverCertificate": null }
Delete Broker
Delete the specified event broker.
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/events/brokers/{brokerId}
Request Body
Property | Type | Description |
---|---|---|
id | long | Id of broker to be deleted. If successful, returns Response Code 204. |
Sample Code
var brokerIdToDelete = 5;
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/brokers/{brokerIdToDelete}");
xhr.setRequestHeader("Authorization", "Basic" + btoa("admin:passgoeshere"));
xhr.send();
// Encode credentials
string encodedCredentials = ...
// Must be an existing broker
var brokerIdToDelete = 5;
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/brokers/" + brokerIdToDelete);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get Broker
Get an event broker.
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/configuration/v1/events/brokers/{brokerId}
Request Body
Parameter | Type | Description |
---|---|---|
id | long | id of the broker. Supplied by ItemSense at creation. |
Sample Code
var brokerIdToList = 5;
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/events/brokers/{brokerIdToList}" );
xhr.setRequestHeader("Authorization", "Basic " + btoa("admin:passgoeshere"));
xhr.send();
// Encode credentials
string encodedCredentials = ...
// Must be an existing broker
var brokerIdToList = 5;
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/brokers/" + brokerIdToList);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
The same as the Create Broker Sample Response.
Get All Brokers
Retrieve all of the event brokers.
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1//configuration/v1/events/brokers
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/events/brokers/");
xhr.setRequestHeader("Authorization", "Basic" + btoa("admin:passgoeshere"));
xhr.send();
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/brokers");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "id": 1, "name": "ItemSense internal AMQP", "type": "AMQP", "host": "localhost", "port": 5672, "username": "-", "password": "-", "internal": true, "secureConnection": false, "serverCertificate": null }, { "id": 2, "name": "ItemSense internal MQTT", "type": "MQTT", "host": "localhost", "port": 1883, "username": "-", "password": "-", "internal": true, "secureConnection": false, "serverCertificate": null }, { "id": 3, "name": "REPLACE_BROKER", "type": "MQTT", "host": "localhost", "port": 2, "username": "string", "password": "string", "internal": false, "secureConnection": true, "serverCertificate": "string" }, { "id": 4, "name": "ExternalMQTTOnDev6", "type": "MQTT", "host": "isdev6.i4j.io", "port": 1883, "username": "admin", "password": "admindefault", "internal": false, "secureConnection": false, "serverCertificate": null }, { "id": 5, "name": "ExternalSecureAMQPonDev6", "type": "AMQP", "host": "isdev6.i4j.io", "port": 5671, "username": "admin", "password": "admindefault", "internal": false, "secureConnection": true, "serverCertificate": "-----BEGIN CERTIFICATE-----\nMIIFsDCCA.....-----END CERTIFICATE-----" }, { "id": 6, "name": "ExternalSecureAMQPonSQA53", "type": "AMQP", "host": "FVXENISQA53.i4j.io", "port": 5671, "username": "admin", "password": "admindefault", "internal": false, "secureConnection": true, "serverCertificate": "-----BEGIN CERTIFICATE-----\nMIIFsDCCA.....-----END CERTIFICATE-----" } ]
Test Broker
Test that the specified event broker is enabled by sending a message to it.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/events/brokers/{brokerId}/test
Request Body
Property | Type | Description |
---|---|---|
id | long | Id of broker to be tested. If successful, returns Response Code 204. |
Sample Code
var brokerIdToTest = 5;
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/events/brokers/{brokerIdToTest}/test");
xhr.setRequestHeader("Authorization", "Basic " + btoa("admin:passgoeshere"));
xhr.send();
// Encode credentials
string encodedCredentials = ...
// Must be an existing broker
var brokerIdToTest = 5;
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/brokers/" + brokerIdToTest + "/test");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Create Publisher
Create a new event publisher.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/events/publishers
Request Body
Property | Type | Description |
---|---|---|
id | long | Provided by ItemSense on creation of publisher. |
brokerId (required) |
long | Id of the broker to which the publisher connects. |
name (required) |
string | The name that identifies the publisher. |
messageTypes (required) |
array of strings | One or more of:HEALTH, ITEM, and THRESHOLD |
messageOptions (required) |
string | See AMQP, MQTT, or WEBHOOK. |
Sample Code
var publisherConfiguration = {
"brokerId": 2,
"name": "MY_PUBLISHER",
"messageTypes": [ "HEALTH" ],
"messageOptions": {
"mqtt": {
"topicPrefix": "yourPrefix",
"topicSuffix": "yourSuffix",
"qos": 0
},
},
"filters": {
"health": {
"readerName": "yourSelectedReader",
"type": "THROUGHPUT",
},
}
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/events/publishers", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic " + btoa("admin:passgoeshere"));
xhr.send(JSON.stringify(publisherConfiguration));
// Encode credentials
string encodedCredentials = ...
// Data for new publisher
var publisherConfiguration = new
{
brokerId = 2,
name = "MY_PUBLISHER",
messageTypes = ["HEALTH"],
messageOptions = new
{
mqtt = new
{
topicPrefix = "yourPrefix",
topicSuffix = "yourSuffix",
qos = 0
}
},
filters = new
{
health = new
{
readerName = "yourSelectedReader",
type = "THROUGHPUT"
}
}
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/publishers");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(publisherConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 5, "brokerId": 2, "name": "MY_PUBLISHER", "messageTypes": [ "HEALTH" ], "messageOptions": { "amqp": { "routingKey": null, "routingKeyPrefix": null, "routingKeySuffix": null, "deliveryMode": "PERSISTENT", "exchange": "amq.topic", "vhost": "/" }, "mqtt": { "topic": null, "topicPrefix": "yourPrefix", "topicSuffix": "yourSuffix", "qos": 0 }, "webhook": { "messageTypePlacement": "PATH", "path": null, "pathPrefix": null, "pathSuffix": null, "authenticationType": null, "requestTimeout": 2500 } }, "filters": { "item": null, "health": { "readerName": "", "type": "THROUGHPUT", "code": null }, "threshold": null } }
Replace Publisher
Replace an event publisher.
Authorized Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/events/publishers{publisherId}
Request Body
Parameter | Type | Description |
---|---|---|
id | long | Id of the publisher. |
Property | Type | Description |
---|---|---|
brokerId (required) |
long | Id of the broker to which the publisher connects. |
name (required) |
string | The name that identifies the publisher. |
messageTypes (required) |
string | One of: HEALTH, ITEM, THRESHOLD |
messageOptions (required) |
string | See AMQP, MQTT, or WEBHOOK. |
Sample Code
var updatedPublisherConfiguration = {
"id": 4,
"brokerId": 5,
"name": "REPLACE_PUBLISHER",
"messageTypes": ["HEALTH"],
"messageOptions": {
"mqtt": {
"topicPrefix": "yourPrefix",
"topicSuffix": "yourSuffix",
"qos": 0
}
},
"filters": {
"health": {
"readerName": "yourSelectedReader",
"type": "THROUGHPUT",
}
}
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/events/publishers/{updatedPublisherConfiguration.id}", true)
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic " + btoa("admin:passgoeshere"));
xhr.send(JSON.stringify(updatedPublisherConfiguration));
// Encode credentials
string encodedCredentials = ...
// Updated data for existing publisher
var updatedPublisherConfiguration = new
{
id = 4,
brokerId = 5,
name = "REPLACE_PUBLISHER",
messageTypes = ["HEALTH"],
messageOptions = new
{
mqtt = new
{
topicPrefix = "yourPrefix",
topicSuffix = "yourSuffix",
qos = 0
}
},
filters = new
{
health = new
{
readerName = "yourSelectedReader",
type = "THROUGHPUT"
}
}
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/publishers/" + updatedPublisherConfiguration.id);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(updatedPublisherConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 4, "brokerId": 5, "name": "REPLACE_PUBLISHER", "messageTypes": [ "HEALTH" ], "messageOptions": { "amqp": { "routingKey": null, "routingKeyPrefix": null, "routingKeySuffix": null, "deliveryMode": "NON_PERSISTENT", "exchange": "amq.topic", "vhost": "/" }, "mqtt": { "topic": "string", "topicPrefix": "yourPrefix", "topicSuffix": "yourSuffix", "qos": 0 }, "webhook": { "messageTypePlacement": "PATH", "path": null, "pathPrefix": null, "pathSuffix": null, "authenticationType": null, "requestTimeout": 2500 } }, "filters": { "item": null, "health": { "readerName": "string", "type": "CONNECTION", "code": "string" }, "threshold": null } }
Delete Publisher
Delete the specified event publisher.
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/events/publishers/{publisherId}
Request Body
Property | Type | Description |
---|---|---|
id | long | Id of publisher to be deleted. If successful, returns Response Code 204. |
Sample Code
var publisherIdToDelete = 5;
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/events/publishers" + publisherIdToDelete);
xhr.setRequestHeader("Authorization", "Basic " + btoa("admin:passgoeshere"));
xhr.send();
// Encode credentials
string encodedCredentials = ...
// Must be an existing publisher
var publisherIdToDelete = 5;
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/publishers/" + publisherIdToDelete);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get Publisher
Get an event publisher.
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/configuration/v1/events/publishers/{publisherId}
Request Body
Property | Type | Description |
---|---|---|
publisherId (required) |
long | Id of the publisher. |
Sample Code
var publisherIdToList = 5;
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/events/publishers{publisherIdToList}");
xhr.setRequestHeader("Authorization", "Basic " + btoa("admin:passgoeshere"));
xhr.send();
// Encode credentials
string encodedCredentials = ...
// Must be an existing publisher
var publisherIdToList = 5;
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/publishers/" + publisherIdToList);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
The same as the Create Request Body.
Get All Publishers
Retrieve all of the event publishers.
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/events/Publishers
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/events/publishers");
xhr.setRequestHeader("Authorization", "Basic " + btoa("admin:passgoeshere"));
xhr.send();
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/publishers");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "id": 1, "brokerId": 3, "name": "ExternalSecureAMQPEverything", "messageTypes": [ "HEALTH", "THRESHOLD", "ITEM" ], "messageOptions": { "amqp": { "routingKey": null, "routingKeyPrefix": "external", "routingKeySuffix": "everything", "deliveryMode": "NON_PERSISTENT", "exchange": "amq.topic", "vhost": "/" }, "mqtt": { "topic": null, "topicPrefix": null, "topicSuffix": null, "qos": 0 }, "webhook": { "messageTypePlacement": "PATH", "path": null, "pathPrefix": null, "pathSuffix": null, "authenticationType": null, "requestTimeout": 2500 } }, "filters": null }, { "id": 2, "brokerId": 4, "name": "ExternalMQTTEverything", "messageTypes": [ "HEALTH", "THRESHOLD", "ITEM" ], "messageOptions": { "amqp": { "routingKey": null, "routingKeyPrefix": null, "routingKeySuffix": null, "deliveryMode": "NON_PERSISTENT", "exchange": "amq.topic", "vhost": "/" }, "mqtt": { "topic": null, "topicPrefix": "external", "topicSuffix": "everything", "qos": 0 }, "webhook": { "messageTypePlacement": "PATH", "path": null, "pathPrefix": null, "pathSuffix": null, "authenticationType": null, "requestTimeout": 2500 } }, "filters": null }, { "id": 3, "brokerId": 5, "name": "MY_PUBLISHER", "messageTypes": [ "HEALTH" ], "messageOptions": { "amqp": { "routingKey": null, "routingKeyPrefix": null, "routingKeySuffix": null, "deliveryMode": "NON_PERSISTENT", "exchange": "amq.topic", "vhost": "/" }, "mqtt": { "topic": "string", "topicPrefix": "string", "topicSuffix": "string", "qos": 0 }, "webhook": { "messageTypePlacement": "PATH", "path": null, "pathPrefix": null, "pathSuffix": null, "authenticationType": null, "requestTimeout": 2500 } }, "filters": { "item": null, "health": { "readerName": "string", "type": "CONNECTION", "code": "string" }, "threshold": null } } ]
Test Publisher
Test that the specified event publisher is enabled by sending a message to it.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/events/publishers/{publisherId}/test
Request Body
Property | Type | Description |
---|---|---|
id | long | Id of publisher to be tested. If successful, returns Response Code 204. |
Sample Code
var publisherIdToTest = 3;
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/events/publishers/{publisherIdToTest}/test", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic " + btoa("admin:passgoeshere"));
xhr.send();
// Encode credentials
string encodedCredentials = ...
// Must be an existing publisher
var publisherIdToTest = 3;
Uri uri = new Uri("http://BASE_URL/configuration/v1/events/publishers/" + publisherIdToTest + "/test");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Message Options
AMQP
Property | Type | Description |
---|---|---|
routingKey (optional) |
string | Routing key of the publisher. Every message that ItemSense sends to AMQP will have a routing key, which will consist of the type of message being sent. If used, routingKey overrides both routingKeyPrefix and routingKeySuffix. |
routingKeyPrefix (optional) |
string | If specified, value will be attached to front of message type. |
routingKeyPrefix (optional) |
string | If specified, value will be attached to back of message type. |
deliveryMode (required) |
string | Determines if the delivery mode is persistent or non-persistent. Defaults to non-persistent. |
exchange (optional) |
integer | Type of exchange used by publisher. Defaults to topic. "impinj" as a prefix is not allowed. |
vhost (optional) |
string | Virtual host for the publisher. |
MQTT
Property | Type | Description |
---|---|---|
topic (optional) |
string | Every message that ItemSense sends to AMQP will have a topic,which tells what type of message is sent. If used, topic overrides both topicPrefix and topicSuffix. |
topicPrefix (optional) |
string | If specified, value will be attached to front of message type. |
topicSuffix (optional) |
string | If specified, value will be attached to back of message type. |
qos (required) |
string | Defines guarantee of delivery for specific message (At most once: 0; At least once: 1; Exactly once: 2). Defaults to 0. |
Webhook
Property | Type | Description |
---|---|---|
messageTypePlacement (optional) |
string | One of PATH or QUERY_PARAM. If QUERY_PARAM is selected, the parameter, messageType, will be appended to the HTTP POST Request URL. Ex: "http://HOST_NAME/MY_PATH/messageType=HEALTH". |
path (optional) |
string | Path specified in call. |
pathPrefix (optional) |
string | If specified, value will be attached to front of path. |
pathSuffix (optional) |
string | If specified, value will be attached to back of path. |
authenticationType (optional) |
string | One of BASIC or DIGEST. BASIC communicates credentials using unemcrypted base64 encoding. DIGEST encrypts by applying a hash function. |
requestTimeout (optional) |
long | Converted to milliseconds. Must be 100 or more. Default is 2500. |
Filter Options
Item
Property | Type | Description |
---|---|---|
minimumMovement (optional) |
Float | The minimum distance in meters a tag must move before a queue event (or message) is created. |
jobNamePrefixes (optional) |
String | If specified, value(s) attached to the front of the job name(s). |
fromZone (optional) |
String | The name of the zone from which the tag moved |
toZone (optional) |
String | The name of the zone to which the tag moved |
epcPrefix (optional) |
String | A hexadecimal string representing an EPC prefix of an item. Only items with EPCs that start with this prefix will be returned. |
fromFacility (optional) |
String | The name of the facility from which the tag moved. |
toFacility (optional) |
String | The name of the facility to which the tag moved. |
fromX (optional) |
Float | The x coordinate of the location from which the tag moved. |
toX (optional) |
Float | The x coordinate of the location to which the tag moved. |
fromY (optional) |
Float | The y coordinate of the location from which the tag moved. |
toY (optional) |
Float | The y coordinate of the location to which the tag moved. |
observationTime (optional) |
String | The time at which the event occurred in ISO-8601 format such as "2017-05-02T15:35:01.560Z." |
zoneTransitionsOnly (optional) |
Boolean | Will restrict results to items that have moved from one zone to another. Defaults to true. |
Health
Parameter | Type | Description |
---|---|---|
readerName (optional) |
String | The name of the reader to query. |
type (optional) |
One of: CONNECTION THROUGHPUT CLOCK_SYNC HARDWARE_FAULT SOFTWARE_FAULT LIFECYCLE UNCLASSIFIED |
The type of health event to query. |
code (optional) |
String | The status code to query. See Code Details |
Health Types
ConnectionStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The status of the connection |
code (optional) |
One of: BAD_CERTIFICATE HTTP_FAILURE or NETWORK |
See Code Details |
ThroughputStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The status of reader throughput |
code (optional) |
One of: DROPPED_READ REPORT_BUFFER TAG_POPULATION_OVERFLOW |
See Code Details |
ClockSyncStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The status of network clock (NTP) synchronization |
code (optional) |
One of: NTP CLOCK_SYNC |
See Code Details |
HardwareStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The hardware status |
code (optional) |
One of: READER_COMMAND READER_EXCEPTION READER_RESTART UPGRADE_STATUS |
See Code Details |
SoftwareStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The status of reader throughput |
code (optional) |
One of: CHECKSUM COMMAND_NOT_FOUND CONFIG_SERVICE_SET EXTERNAL_COMMAND FILE_SYSTEM INVALID_SET_VARIABLE UNMARSHAL LLRP PROVISIONING READER_CONNECTION CRASH AGENT_OUTDATED |
See Code Details |
Code Details
Below is a listing of all valid Type and Code combinations as they can appear in Health Events and in Reader Statuses. The same codes are used in both places. Note that not every Health Event type maps to a Reader Status property, and there are no currently known codes that appear in a DeviceStatus.
# | Code | Reader Status Property | Description |
---|---|---|---|
1 | BAD_CERTIFICATE | ConnectionStatus | 1. During provisioning. If invalid certificate is supplied by the IMC when accessing the /provision endpoint. (Note that this process returns a certificate for use on the ItemSense agent channel) 2. After provisioning. If the returned certificate starts failing |
2 | HTTP_FAILURE | ConnectionStatus | Anytime ItemSense returns a non successful HTTP status code. Can also happen during provisioning, when the agent "tests" the ItemSense HTTP connection settings. |
3 | NETWORK | ConnectionStatus | Something else went wrong with the network connection. e.g. network timeout |
4 | RECOVERY | ConnectionStatus | Reader rebooted and returned online after a 30-35 second interval of NO_RESPONSE |
5 | DROPPED_READ | ThroughoutStatus | Agent data buffer overflow error |
6 | REPORT_BUFFER | ThroughputStatus | Internal agent buffer is full or nearly full (conditions are distinguished by a message on the health event) |
7 | TAG_POPULATION_OVERFLOW | ThroughputStatus | Too many tags (in direction or location mode) |
8 | NTP | ClockSyncStatus | The on-reader NTP program failed to synchronize with a time provider, implying that the timestamps on reader are unreliable. (Implies an NTP server is running on the network (internal if no Internet connection)) |
9 | CLOCK_SYNC | ClockSyncStatus | An agent report was received from the reader which showed that the reader's clock is significantly off from the server's clock. The report was dropped by ItemSense in order to prevent issues that occur with determining an endpoint's latest location when readers' clocks differ. |
10 | READER_COMMAND | HardwareStatus | Generated when any LLRP reader command does not return a successful status reply |
11 | READER_EXCEPTION | HardwareStatus | Asynchronous notification from the reader (reported via LLRP) of an uncategorized error condition |
12 | READER_RESTART | HardwareStatus | Reader closed LLRP connection unexpectedly and the agent could not re-open it |
13 | UPGRADE_STATUS | HardwareStatus | When the upgrade (agent or firmware) process encounters any kind of error, or times out |
14 | CHECKSUM | SoftwareStatus | Checksum failure of either CAP or firmware image |
15 | COMMAND_NOT_FOUND | SoftwareStatus | Agent is sent an unknown command by ItemSense |
16 | CONFIG_SERVICE_SET | SoftwareStatus | Surfaced when an error is encountered in the agent config (In practice, this is a software error, or the config file is corrupted) |
17 | EXTERNAL_COMMAND | SoftwareStatus | A program invoked in the octane firmware by the agent returned an error code, or a response that could not be processed |
18 | FILE_SYSTEM | SoftwareStatus | Any file system error within the agent process (usually due to full or corrupted file system) |
19 | INVALID_SET_VARIABLE | SoftwareStatus | Agent is sent an invalid variable set command by ItemSense (type, range etc) |
20 | UNMARSHAL | SoftwareStatus | ItemSense sent invalid or corrupted data |
21 | LLRP | SoftwareStatus | 1. Invalid RF configurations are specified by ItemSense 2. Invalid LLRP packet was sent to the agent by the reader |
22 | PROVISIONING | SoftwareStatus | 1. Invalid provisioning settings 2. Provisioning module failed to start (http server failed to start) |
23 | READER_CONNECTION | SoftwareStatus | Failed to open or close the LLRP connection, or to receive a message over LLRP |
24 | CRASH | SoftwareStatus | The agent crashed and the reader is about to reboot |
25 | AGENT_OUTDATED | SoftwareStatus | An agent report was received from the reader which did not report the reader's time. ItemSense accepted the report, but this is potentially risky because ItemSense will not know if the reader's clock is or becomes out of sync. Upgrading the reader's Agent software is highly recommended. |
26 | REBOOT | None | Communicates the previous reboot reason. (Note: This event does not contribute to bad health status) |
27 | HEALTH_RESET | None | Is a signal used when computing reader status, to indicate ItemSense should disregard all health events older than this one |
28 | KNOWN | None | Any other exception that is expected by the Agent but not by ItemSense, including unknown SNMP events from the reader |
29 | UNKNOWN | None | Anything not previously defined or expected. |
Threshold
Parameter | Type | Description |
---|---|---|
readerName (optional) |
String | The name of the reader to query. |
type (optional) |
One of: CONNECTION THROUGHPUT CLOCK_SYNC HARDWARE_FAULT SOFTWARE_FAULT LIFECYCLE UNCLASSIFIED |
The type of health event to query. |
code (optional) |
String | The status code to query. |
Example Event Messages
Sample Item Event
{ "epc": "E7E92B38AB2C362497818237", "tagId": "", "jobId": "8b2edc53-83a1-4e06-8ebf-5fb6ddbbcfa2", "jobName": "jobName", "from": { "zone": "ABSENT", "floor": null, "facility": null, "x": null, "y": null }, "to": { "zone": "FACILITY", "floor": "1", "facility": "DEFAULT", "x": 0.0, "y": 0.0 }, "observationTime": "2019-03-29T20:16:46Z" }
Sample Health Event
{ "eventTime": "2019-03-29T20:08:10.153211Z", "type": "TYPE", "code": "CODE", "readerName": "xarray-11-00-00.impinj.com", "args": { "reason": "REASON" } }
Sample Threshold Event
{ "epc": "E7E92B38AB2C362497818237", "fromZone": "OUT", "toZone": "IN", "threshold": "MyFavoriteThreshold", "thresholdId": 1, "confidence": 1.0, "jobId": "3e73759c-e419-42b8-9688-4a0e1b6cf457", "jobName": "threshold_job", "observationTime": "2019-03-29T05:31:48.427Z" }
Data Definitions
The following tables provide the semantic meaning of values returned in the fields of event messages:
ItemEvent
Property | Type | Description |
---|---|---|
epc | String | The EPC of the tag for which the event occurred |
tagId | String | The ID of the tag that was read. Note that ItemSense does not currently provide the tagId, and the value of this field is currently set to empty ("") |
jobId | String | The ID of the job that reported the change in the item |
jobName | String | The name of the job that reported the change in the item |
from | JSON Object | The set of location values from which the tag moved, of type Location Details |
to | JSON Object | The set of location values to which the tag moved, of type Location Details |
observationTime | String | The time at which the event occurred in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
HealthEvent
Parameter | Type | Description |
---|---|---|
eventTime | String | The time at which the event occurred in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
readerName | String | The name of the reader that experienced the event |
type | One of: CONNECTION THROUGHPUT CLOCK_SYNC HARDWARE_FAULT SOFTWARE_FAULT LIFECYCLE UNCLASSIFIED |
The type of health event |
code | String | The status code of the event. See Code Details |
LocationReport
Property | Type | Description |
---|---|---|
zone | String | The zone name for the reported location |
floor | String | The floor name for the reported location |
facility | String | The facility name for the reported location |
x | Float | The x coordinate of the reported location |
y | Float | The y coordinate of the reported location |
ThresholdTransitionEvent
Property | Type | Description |
---|---|---|
epc | String | The EPC of the tag for which the event occurred |
observationTime | Integer | The time at which the transition was recorded in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
fromZone | String | The type of transition, being "IN" or "OUT" this will always be the opposite value of toZone |
toZone | String | The type of transition, being "IN" or "OUT" this will always be the opposite value of fromZone |
threshold | String | The name of the threshold where this transition occurred |
thresholdId | Integer | The ID of the threshold where this transition occurred |
jobId | String | The ID of the job that generated the transition record |
jobName | String | The name of the job that generated the transition record |
confidence | Float | The confidence value of the transition event, ranging from 0.0 to 1.0 |
Threshold
A Threshold defines how a collection of readers will be utilized when a threshold job is running.
Create
Create a new threshold configuration (but do not replace an existing one)
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/thresholds
Request Body
Property | Type | Description |
---|---|---|
name (required) |
string | The name of the threshold |
facility (required) |
string | The facility that contains the threshold |
readerArrangement (required) |
One of: SIDE_BY_SIDE, OVERHEAD, OVERHEAD_OFFSET, CUSTOM |
The arrangement of readers around the threshold |
readers (optional) |
Key Value List | A map of reader definiton names and an object with a single property of antennaConfigurationId for specifying what antenna configuration to use |
Sample Code
var threshold = {
"name": "THRESHOLD",
"facility": "DEFAULT",
"readerArrangement": "SIDE_BY_SIDE",
"readers": {
"reader_name_one": {
"antennaConfigurationId": 1
},
"reader_name_two": {
"antennaConfigurationId": 2
}
}
};
;
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/thresholds", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(threshold));
// Encode credentials
string encodedCredentials = ...
var threshold = {
"name": "THRESHOLD",
"facility": "DEFAULT",
"readerArrangement": "SIDE_BY_SIDE",
"readers": {
"reader_name_one": {
"antennaConfigurationId": 1
},
"reader_name_two": {
"antennaConfigurationId": 2
}
}
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(readerConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 1, "name": "THRESHOLD", "facility": "DEFAULT", "readerArrangement": "SIDE_BY_SIDE", "readers": { "reader_name_one": { "antennaConfigurationId": 1 }, "reader_name_two": { "antennaConfigurationId": 2 } } }
Replace
Update an existing threshold
Authorization Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/thresholds/{thresholdID}
Request Body
The same as the Create Request Body, but with an additional ID property
Sample Response
var readerConfiguration = {
"id": 1,
"name": "THRESHOLD",
"facility": "DEFAULT",
"readerArrangement": "SIDE_BY_SIDE",
"readers": {
"reader_name_one": {
"antennaConfigurationId": 1
},
"reader_name_two": {
"antennaConfigurationId": 2
}
}
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/thresholds/1", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(readerConfiguration));
// Encode credentials
string encodedCredentials = ...
var readerConfiguration = {
"id": 1,
"name": "THRESHOLD",
"facility": "DEFAULT",
"readerArrangement": "SIDE_BY_SIDE",
"readers": {
"reader_name_one": {
"antennaConfigurationId": 1
},
"reader_name_two": {
"antennaConfigurationId": 2
}
}
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds/1");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(readerConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 1, "name": "THRESHOLD", "facility": "DEFAULT", "readerArrangement": "SIDE_BY_SIDE", "readers": { "reader_name_one": { "antennaConfigurationId": 1 }, "reader_name_two": { "antennaConfigurationId": 2 } } }
Delete
Delete a threshold configuration
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/threshold/{thresholdID}
Parameters
Parameter | Type | Description |
---|---|---|
thresholdID | Integer | The id of the threshold to be deleted |
Sample Code
var thresholdID = 1;
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/thresholds/" + thresholdID, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
int thresholdID = 1;
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds/" + thresholdID);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get
Retrieve a specific threshold configuration
AuthorizedRoles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/thresholds/{thresholdID}
Parameters
Parameter | Type | Description |
---|---|---|
thresholdID | Integer | The ID of the threshold configuration to be retrieved |
embed (optional) |
The stringantennaConfiguration
|
Entity or entities to embed as whole objects within the response, in addition to just the ID that could be used to reference the object. This functions identically in the Get All and Get APIs. Currently, only one legal value exists for this parameter. For more details, see the Response and Sample Response sections. |
Response
The same as the Create Request Body, but with an
additional ID property. If embed
entities were requested, those will be embedded in the response.
antennaConfiguration
embed
When the antennaConfiguration
embed is requested using the embed
query parameter, the response object will contain the entire antennaConfiguration object adjacent to the antennaConfigurationId. See Sample Response.
Sample Code
var thresholdID = 1;
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/thresholds/" + thresholdID, true);
// To request the antennaConfiguration embed, add the query parameter:
// xhr.open("GET", "http://BASE_URL/configuration/v1/thresholds/" + thresholdID + "?embed=antennaConfiguration", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
int thresholdID = 1;
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds/" + thresholdID);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 1, "name": "THRESHOLD", "facility": "DEFAULT", "readerArrangement": "SIDE_BY_SIDE", "readers": { "reader_name_one": { "antennaConfigurationId": 1 }, "reader_name_two": { "antennaConfigurationId": 2 } } }
With antennaConfiguration
embed
{ "id": 1, "name": "THRESHOLD", "facility": "DEFAULT", "readerArrangement": "SIDE_BY_SIDE", "readers": { "reader_name_one": { "antennaConfigurationId": 1, "antennaConfiguration": { "id": 1, "name": "left_configuration_name", "side": "LEFT", "in": [ {"antennaId": 1}, {"antennaId": 3}], "out": [ {"antennaId": 2}, {"antennaId": 4}] } }, "reader_name_two": { "antennaConfigurationId": 2, "antennaConfiguration": { "id": 2, "name": "right_configuration_name", "side": "RIGHT", "in": [ {"antennaId": 5}, {"antennaId": 7}], "out": [ {"antennaId": 6}, {"antennaId": 8}] } } } }
Get All
Retrieve all of the threshold configurations
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/thresholds
Parameters
Parameter | Type | Description |
---|---|---|
embed (optional) |
The stringantennaConfiguration
|
Entity or entities to embed as whole objects within the response, in addition to just the ID that could be used to reference the object. This functions identically in the Get All and Get APIs. Currently, only one legal value exists for this parameter. For more details, see the Response and Sample Response sections. |
Response
Array of Create Threshold Request bodies with the ID property.
If embed
entities were requested, those will be embedded in the response.
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/thresholds", true);
// To request the antennaConfiguration embed, add the query parameter:
// xhr.open("GET", "http://BASE_URL/configuration/v1/thresholds?embed=antennaConfiguration", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "id": 1, "name": "threshold_one", "facility": "DEFAULT", "readerArrangement": "SIDE_BY_SIDE", "readers": { "reader_name_one": { "antennaConfigurationId": 1 }, "reader_name_two": { "antennaConfigurationId": 2 } } }, { "id": 2, "name": "threshold_two", "facility": "DEFAULT", "readerArrangement": "SIDE_BY_SIDE", "readers": { "reader_name_one": { "antennaConfigurationId": 1 }, "reader_name_two": { "antennaConfigurationId": 2 } } } ]
Threshold Antenna Configuration
An antenna configuration defines how a given reader's antennas should be utilized for a particular threshold
Create
Create a new threshold antenna configuration (but do not replace an existing one)
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/thresholds/antennaConfigurations
Request Body
Property | Type | Description |
---|---|---|
name (required) |
string | The name of the antenna configuration. |
side (optional*) |
One of: LEFT, RIGHT |
The side of the threshold that the antenna is positioned on. *If it is on neither side (e.g. above the threshold) this property should be null or absent. |
readerType (optional) |
One of: XARRAY, XSPAN, XPORTAL |
Threshold antenna configurations can be specific to reader types. If defined, this field can be helpful for assigning configurations to specific reader types. Note that while it is possible to set a readerType of SPEEDWAY, this is not a supported configuration for this feature |
readerArrangement (optional) |
One of: SIDE_BY_SIDE, OVERHEAD, OVERHEAD_OFFSET, CUSTOM |
Threshold antenna configurations can be specific to reader arrangements. If defined, this field can be helpful for assigning configurations to specific threshold arrangements. |
in (optional*) |
array of objects | A collection of antenna objects that point to the inside of the threshold. *At least one of the "in" or "out" antennas must be specified. |
out (optional*) |
array of objects | A collection of antenna objects that point to the outside of the threshold. *At least one of the "in" or "out" antennas must be specified. |
ignored (optional) |
array of objects | A collection of antenna objects where the antennas are enabled on the reader, but their reads will be ignored. This is useful in order to help synchronize cycle durations across readers that may otherwise have differing enabled antenna counts. In a request, providing null , an empty list, or omitting the property are all equivalent ways of specifying no antennas to ignore.In a response, either the property will be absent or the value will be a nonempty list (it will never be null or an empty list). |
Sample Code
var antennaConfiguration = {
"name": "configuration_name",
"side": "LEFT",
"readerType": "XARRAY",
"readerArrangement": "OVERHEAD",
"in": [
{
"antennaId": 1
},
{
"antennaId": 3
}
],
"out": [
{
"antennaId": 2
},
{
"antennaId": 4
}
]
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/configuration/v1/thresholds/antennaConfiguration", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(antennaConfiguration));
// Encode credentials
string encodedCredentials = ...
var antennaConfiguration = {
"name": "configuration_name",
"side": "LEFT",
"readerType": "XARRAY",
"readerArrangement": "OVERHEAD",
"in": [
{
"antennaId": 1
},
{
"antennaId": 3
}
],
"out": [
{
"antennaId": 2
},
{
"antennaId": 4
}
]
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds/antennaConfiguration");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(antennaConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 1, "name": "configuration_name", "side": "LEFT", "readerType": "XARRAY", "readerArrangement": "OVERHEAD", "in": [ { "antennaId": 1 }, { "antennaId": 3 } ], "out": [ { "antennaId": 2 }, { "antennaId": 4 } ] }
Replace
Update an existing threshold antenna configuration
Authorization Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/thresholds/antennaConfiguration/{antennaConfigurationID}
Request Body
The same as the Create Request Body, but with an additional ID property
Sample Response
var antennaConfiguration = {
"id": 1,
"name": "configuration_name",
"side": "LEFT",
"readerType": "XARRAY",
"readerArrangement": "OVERHEAD",
"in": [
{
"antennaId": 1
},
{
"antennaId": 3
}
],
"out": [
{
"antennaId": 2
},
{
"antennaId": 4
}
]
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/configuration/v1/thresholds/antennaConfiguration/1", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(antennaConfiguration));
// Encode credentials
string encodedCredentials = ...
var antennaConfiguration = {
"id": 1,
"name": "configuration_name",
"side": "LEFT",
"readerType": "XARRAY",
"readerArrangement": "OVERHEAD",
"in": [
{
"antennaId": 1
},
{
"antennaId": 3
}
],
"out": [
{
"antennaId": 2
},
{
"antennaId": 4
}
]
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds/antennaConfiguration/1");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(antennaConfiguration);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 1, "name": "configuration_name", "side": "LEFT", "readerType": "XARRAY", "readerArrangement": "OVERHEAD", "in": [ { "antennaId": 1 }, { "antennaId": 3 } ], "out": [ { "antennaId": 2 }, { "antennaId": 4 } ] }
Delete
Delete a threshold antenna configuration
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/threshold/antennaConfiguration/{antennaConfigurationID}?replacementId={replacementId}
Parameters
Parameter | Type | Description |
---|---|---|
antennaConfigurationID | Integer | The id of the antenna configuration to be deleted |
replacementId (optional) |
Integer | The id of an antenna configuration to use as a replacement for the one being deleted, passed as a query parameter |
Sample Code
var antennaConfigurationID = 1;
var replacementId = 2;
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "http://BASE_URL/configuration/v1/thresholds/antennaConfiguration/" + antennaConfigurationID + "?replacementId=" + replacementId, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
int antennaConfigurationID = 1;
int replacementId = 2;
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds/antennaConfiguration/" + antennaConfigurationID + "?replacementId=" + replacementId);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "DELETE";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get
Retrieve a specific threshold antenna configuration
AuthorizedRoles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/thresholds/antennaConfiguration/{antennaConfigurationID}
Parameters
Parameter | Type | Description |
---|---|---|
antennaConfigurationId | Integer | The ID of the antenna configuration to be retrieved |
Response
The same as the Create Request Body, but with an additional ID property
Sample Code
var antennaConfigurationID = 1;
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/thresholds/antennaConfiguration/" + antennaConfigurationID, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
int antennaConfigurationID = 1;
Uri uri = new Uri("http://BASE_URL/configuration/v1/thresholds/antennaConfiguration/" + antennaConfigurationID);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": 1, "name": "configuration_name", "side": "LEFT", "readerType": "XARRAY", "readerArrangement": "OVERHEAD", "in": [ { "antennaId": 1 }, { "antennaId": 3 } ], "out": [ { "antennaId": 2 }, { "antennaId": 4 } ] }
Get All
Retrieve all of the threshold antenna configurations
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/thresholds/antennaConfigurations
Response
Array of Create Antenna configuration request bodies with the ID property.
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/configuration/v1/thresholds/antennaConfigurations", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri("http://BASE_URL/configuration/v1/antennaConfigurations");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "id": 1, "name": "configuration_name", "side": "LEFT", "readerType": "XARRAY", "readerArrangement": "OVERHEAD", "in": [ { "antennaId": 1 }, { "antennaId": 3 } ], "out": [ { "antennaId": 2 }, { "antennaId": 4 } ] }, { "id": 2, "name": "configuration_name_2", "side": "LEFT", "readerType": "XARRAY", "readerArrangement": "OVERHEAD", "in": [ { "antennaId": 5 }, { "antennaId": 8 } ], "out": [ { "antennaId": 6 }, { "antennaId": 9 } ] } ]
Recipes
Recipes map reader configurations onto individual reader definitions, as well as specifying other parameters relating to the type of operation that the recipe specifies.
For a recipe to be valid, it must have its readerConfigurationName field set, and/or a list of of reader hostnames and reader configurations in the readerConfigurations field. If an entry exists in the readerConfigurationName field only, then the reader configuration identified by this field will be applied to every defined reader.
If an entry exists in both fields, then the entry in the readerConfigurations field takes precedence.
Create Recipe
Create a new recipe (but do not replace an existing one)
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/configuration/v1/recipes/create
Request Body
Common properties:
Property | Type | Description |
---|---|---|
name (required) |
String | The name of the recipe |
type (required) |
One of: LOCATION INVENTORY THRESHOLD |
The type of recipe |
readerConfigurationName (required) |
String | The name of the default reader configuration to use. The operation attribute of the referenced reader configuration must either match the type attribute of the recipe or be DO_NOTHING |
readerConfigurations (optional) |
Key Value List | A map of reader definition names to reader configuration names. These override the configuration given in readerConfigurationName for the specified reader definitions. The operation attribute of any referenced reader configurations must either match the type attribute of the recipe or be DO_NOTHING e.g. {"xarray-11-22-33.impinj.com":"Example_ReaderConfiguration", "xarray-44-55-66.impinj.com":"Another_ReaderConfiguration"}
|
Location Recipes:
Property | Type | Description |
---|---|---|
tagHeartbeatDuration (optional) |
String | Controls how frequently the lastModifiedTime of a tag is updated when the tag is read but has not moved. Set with a string-based ISO 8601 duration format, PnDTnHnMn.nS, representing the time interval between heartbeat updates. Example = "PT10M", Minimum = "PT1S" |
tagExpiryDuration (optional) |
String | A string in ISO 8601 duration format, PnDTnHnMn.nS, representing the time interval between the last time ItemSense detected a tag, and the tag being marked ABSENT. If this parameter is not set, ABSENCE detection via tag expiration is disabled. If set, this parameter must be greater than the reportingInterval. This parameter is only available for certain combinations of reader configuration parameters: those that allow ItemSense to receive sufficient data to determine whether a tag has indeed gone absent. Allowable combinations:
|
minimumMovementInMeters (optional) |
Decimal | Minimum distance a tag must move for a change in location to be reported. Only valid when type is set to LOCATION. When set to 0 (the minimum value for this parameter, any location change is reported. Default=1, Minimum=0, Resolution=0.5 |
computeWindow (optional) |
Integer | Amount of time in seconds that an EPC is kept in memory for location calculations. Must be greater than or equal to reportingInterval. Greater values will reduce noise and increase location accuracy, lesser values will increase responsiveness, Default = 10 |
reportingInterval (optional) |
Integer (0 or divisor of 60.) |
Frequency in seconds with which the location calculation is performed. Greater values will reduce system load, while lesser values will report changes more quickly. Zero will effectively result in a reporting interval of 500ms. Default = 5 |
Inventory Recipes:
Property | Type | Description |
---|---|---|
tagHeartbeatDuration (optional) |
String | This is used to control how frequently the lastModifiedTime of a tag is updated when the tag is read but has not moved. Set with a string in ISO 8601 duration format.) representing the time interval between heartbeat updates. Example = "PT10M", Minimum = "PT1S" |
tagExpiryDuration (optional) |
String | A string in ISO 8601 duration format.) representing the time interval between the last time ItemSense detected a tag, and the tag being marked ABSENT. If this parameter is not set, ABSENCE detection via tag expiration is disabled. If set, this parameter must be greater than the reportingInterval. This parameter is only available for certain combinations of reader configuration parameters: those that allow ItemSense to receive sufficient data to determine whether a tag has indeed gone absent. Allowable combinations:
|
computeWindow (optional) |
Integer | Internal use only. |
reportingInterval (optional) |
Integer (Divisor of 60.) |
Frequency in seconds with which the inventory calculation is performed. Greater values will reduce system load, while lesser values will report changes more quickly. Default = 5 |
Threshold Recipes:
Property | Type | Description |
---|---|---|
thresholdIds (optional) |
List | The collection of threshold identifiers to use for this recipe. If omitted, empty, or null , when this recipe is used in a job, all thresholds in the job's facility will be used. example = [1, 4] |
profile (optional) |
String | Custom profile data specifying system behavior. If not specified, defaults will be used. Use only under Impinj guidance. |
iterationDataLogEnabled (optional) |
boolean | Enables or disables the logging of iteration data for use in tuning. Defaults to disabled (false). |
Sample Code
var body = {
"name": "MY_RECIPE",
"type": "LOCATION",
"readerConfigurationName": "READER_CONFIGURATION",
"tagHeartbeatDuration": "PT5M",
"tagExpiryDuration": "PT7M",
"minimumMovementInMeters": "1.5",
"computeWindow": "10",
"reportingInterval": "5",
};
xhr.open("POST", "http://BASE_URL/configuration/v1/recipes/create", true)
// Set authorization headers
xhr.send(body)
var body = {
name = "MY_RECIPE",
readerConfigurationName = "READER_CONFIGURATION",
readerConfigurations = new Dictionary(){
{"xarray-11-22-33.impinj.com", "Example_ReaderConfiguration"},
{"xarray-44-55-66.impinj.com", "Another_ReaderConfiguration"}
},
tagHeartbeatDuration = "PT5M",
tagExpiryDuration = "PT7M",
minimumMovementInMeters = 1.5,
computeWindow = 10,
reportingInterval = 5,
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/recipes/create");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
// Encode credentials and add to request header
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(recipe);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "MY_RECIPE", "type": "LOCATION", "readerConfigurationName": "READER_CONFIGURATION", "tagHeartbeatDuration": "PT5M", "tagExpiryDuration": "PT7M", "minimumMovementInMeters": "1.5", "computeWindow": "10", "reportingInterval": "5", }
Update Recipe
Replace an existing recipe, or create a new one
Authorized Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/configuration/v1/recipes/createOrReplace
Request Body
The same as the Create Recipe Request Body.
Sample Code
var body= {
"name": "InventoryRecipe",
"type": "INVENTORY",
"readerConfigurationName": "INVENTORY_READER_CONFIG",
"tagHeartbeatDuration": "PT5M",
"tagExpiryDuration": "PT7M",
"computeWindow": "2",
"reportingInterval": "1",
};
xhr.open("PUT", "http://BASE_URL/configuration/v1/recipes/createOrReplace", true)
// Set authorization headers
xhr.send(body)
// Encode credentials
string encodedCredentials = ...
var recipe = {
name = "InventoryRecipe",
type = "INVENTORY,
readerConfigurationName = "INVENTORY_READER_CONFIG",
tagHeartbeatDuration = "PT5M",
tagExpiryDuration = "PT3M",
computeWindow = "2",
reportingInterval = "1"
};
Uri uri = new Uri("http://BASE_URL/configuration/v1/recipes/createOrReplace");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "PUT";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response for RecipeInventory
{ "name": "InventoryRecipe", "type": "INVENTORY", "readerConfigurationName": "INVENTORY_READER_CONFIG", "tagHeartbeatDuration": "PT5M", "tagExpiryDuration": "PT3M", "computeWindow": "2", "reportingInterval": "1", }
Delete Recipe
Delete a specific recipe from the store
Authorized Roles
ConfigManager, Admin
HTTP Request
DELETE http://BASE_URL/configuration/v1/recipes/destroy/{recipeName}
Path Parameters
Parameter | Type | Description |
---|---|---|
recipeName | String | The name of the recipe to delete |
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("DELETE", "http://BASE_URL/configuration/v1/recipes/destroy/MY_RECIPENAME", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/configuration/v1/recipes/destroy/MY_RECIPENAME);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "DELETE";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Show Recipe
Show a specific recipe
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/recipes/show/{recipeName}
Path Parameters
Parameter | Type | Description |
---|---|---|
recipeName | String | The name of the recipe to retrieve |
Sample Code
// var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/configuration/v1/recipes/show/MY_RECIPENAME", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/configuration/v1/recipes/show/MY_RECIPENAME);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "name": "NEW_RECIPE_CONFIG", "type": "LOCATION", "readerConfigurationName": "IMPINJ_LocationConfig", "tagHeartbeatDuration": "PT5M", "tagExpiryDuration": "PT20S", "readerConfigurations": {}, "minimumMovementInMeters": null, "computeWindow": 20, "reportingInterval": 5 }
Show Recipes
Show all configured recipes
Authorized Roles
ConfigManager, Admin, JobRunner
HTTP Request
GET http://BASE_URL/configuration/v1/recipes/show
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/configuration/v1/recipes/show", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/configuration/v1/recipes/show);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "name": "INVENTORY_RECIPE", "type": "INVENTORY", "readerConfigurationName": "IMPINJ_InventoryConfig", "tagHeartbeatDuration": "PT5M", "tagExpiryDuration": null, "readerConfigurations": {}, "computeWindow": 20, "reportingInterval": 5 }, { "name": "LOCATION_RECIPE", "type": "LOCATION", "readerConfigurationName": "IMPINJ_LocationConfig", "tagHeartbeatDuration": "PT5M", "tagExpiryDuration": null, "readerConfigurations": {}, "minimumMovementInMeters": 1, "computeWindow": 10, "reportingInterval": 5 } ]
Jobs
An ItemSense job runs a recipe to generate item data.
Start a Job
When a job is started, ItemSense will use all the readers in the specified facility that have been selected in the recipe. If you wish to have a job use a subset of these readers you will need to specify a reader group or groups. Reader groups are defined as part of a reader's definition. When a reader group is specified for the job, only readers that have a matching group will be used.
Authorized Roles
JobRunner, Admin
HTTP Request
POST http://BASE_URL/control/v1/jobs/start
Request Body
Property | Type | Description |
---|---|---|
name (optional) |
String | The optional name of the job |
recipeName (required) |
String | Which recipe to run |
facility (optional, except if using multiple facilities) |
String | The name of the facility in which the job will be run |
durationSeconds (optional) |
Integer | The number of seconds for which ItemSense should execute this job. If zero, null, or absent, then the job runs indefinitely |
startDelay (optional) |
String | An ISO 8601 duration format duration for which to delay the job's start. If not specified, defaults to 3 minutes, "PT3M" |
readerGroups (optional) |
Array of: String | The set of reader groups on which to start the job. Must not be specified when a threshold recipe is used |
reportToDatabaseEnabled (optional) |
Boolean | (deprecated) Flag for determining if the job should relay tag reads into the Items database. Note that if this value is false, then data is not available via the Items API. Defaults to true |
reportToHistoryEnabled (optional) |
Boolean | (deprecated) Flag for determining if the job should relay tag reads into the Item History database. Note that if this value is false, then data is not available via the Item History API. Defaults to true |
reportToMessageQueueEnabled (optional) |
Boolean | Flag for determining if the job should report configured queue events. Note that if this value is false, then data is not available via the Message Queue interface. Defaults to true |
useOtherJobData (optional) |
Boolean | (deprecated) Flag for determining if the job should consider data from previous or other active jobs when calculating item zone changes. Defaults to true |
Response
Parameter | Type | Description |
---|---|---|
id | String | The ID of the job in UUID format |
status | One of: WAITING, INITIALIZING, STARTING, RUNNING, RESTARTING_RDE, STOPPING, STOPPED |
The status of the job |
readerNames | Array of: String | The collection of readers to which the job applies |
failedReaderNames | Array of: String | The collection of readers that did not acknowledge job start |
creationTime | String | The time the job was created in ISO 8601 format such as "2017-05-02T15:35:01.560Z" |
lastActivityTime | String | The time of last activity in ISO 8601 format such as "2017-05-02T15:35:01.560Z" |
activeDuration | String | The duration for which the job has been active, in ISO 8601 duration format such as "P23DT12H30M5.044S" |
errorOccurred | Boolean | True when an error has occurred |
errors | Array of: JobError | A list of errors associated with the job |
maxErrors | Integer | The maximum number of errors kept |
stopReason | One of: JOB_COMPLETED, JOB_FAILED, USER_REQUESTED_GRACEFUL, USER_REQUESTED_ABRUPT |
The reason the job was stopped |
facility | String | The name of the facility in which the job was run |
facilities | Array of: String | The facility associated with this job contained in an array of length 1. |
job | Job | The configuration data associated with the job |
instanceMetadata | JobInstanceMetadata | Internal data used by ItemSense |
lastHeartbeatTime | String | The time of last received heartbeat in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
startAttempts | Integer | The number of times the system has attempted to start the job |
JobError
Parameter | Type | Description |
---|---|---|
time | String | The time that the error occured in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
message | String | The job error message |
Sample Code
var job = {
recipeName: "IMPINJ_BasicLocation",
name: "Basic Location Job",
durationSeconds: 60,
readerGroups: [ "ceiling", "store_room" ]
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/control/v1/jobs/start", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(job));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/control/v1/jobs/start");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
recipeName = "IMPINJ_BasicLocation",
name = "Basic Location Job",
durationSeconds = 60,
readerGroups = new string[] { "ceiling", "store_room" }
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": "ebc86633-599c-4de9-8aa0-b11ffcb8bdc5", "status": "WAITING", "readerNames": [ "READER1", "READER2" ], "creationTime": "2016-06-28T17:27:20.106Z", "lastActivityTime": "2016-06-28T17:27:20.106Z", "activeDuration": "PT0S", "errorOccurred": false, "errors": [], "maxErrors": 5, "stopReason": null, "facilities": [ { "name": "HOME" } ], "job": { "name": "Basic Location Job", "recipeName": "RECIPE1", "durationSeconds": 100, "startDelay": "PT1M", "readerGroups": [ "ceiling", "store_room" ], "reportToDatabaseEnabled": true, "reportToHistoryEnabled": true, "reportToMessageQueueEnabled": true, "useOtherJobData": true, "facility": "HOME" }, "instanceMetadata": null, "lastHeartbeatTime": null, "startAttempts": 0 }
Stop a Running Job
Authorized Roles
JobRunner, Admin
HTTP Request
POST http://BASE_URL/control/v1/jobs/stop/{jobId}
Parameter
Parameter | Type | Description |
---|---|---|
jobId | String | The ID of the job to stop |
Query Parameter
Parameter | Type | Description |
---|---|---|
graceful | Boolean | Whether the job should be stopped gracefully or suddenly (defaults to true) |
Sample Code
var jobId= "9e1b45bb-1453-448a-9467-7540964b8004";
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/control/v1/jobs/stop/" + jobId, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string jobId= "9e1b45bb-1453-448a-9467-7540964b8004";
Uri uri = new Uri("http://BASE_URL/control/v1/jobs/stop/" + jobId);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Get a specific Job
Retrieve a specific job and its status
Authorized Roles
JobRunner, Admin
HTTP Request
GET http://BASE_URL/control/v1/jobs/show/{jobId}
Parameters
Parameter | Type | Description |
---|---|---|
jobId | String | The ID of the job to retrieve |
Response
The same as the Start a Job response.
Sample Code
var jobId= "9e1b45bb-1453-448a-9467-7540964b8004";
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/control/v1/jobs/show/" + jobId, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string jobId= "9e1b45bb-1453-448a-9467-7540964b8004";
Uri uri = new Uri("http://BASE_URL/control/v1/jobs/show/" + jobId);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
request.ContentType = "application/json";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
The same as Jobs Start Sample Response
Get All Jobs
Authorized Roles
JobRunner, Admin
HTTP Request
GET http://BASE_URL/control/v1/jobs/show
Parameters
Parameter | Type | Description |
---|---|---|
startedBefore | String | Filter to jobs that have been started before the given time in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
startedAfter | String | Filter to jobs that have been started after the given time in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
lastActivityBefore | String | Filter to jobs that have the last activity time before the given time in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
lastActivityAfter | String | Filter to ZonedDateTimeParam that have the last activity time after the given time in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
sortBy | One of: name, creationTime, lastActivityTime |
The property by which to sort the returned jobs. Defaults to lastActivityTime |
sortOrder | One of: asc, desc |
Whether to sort the jobs in ascending or descending order. Defaults to descending |
status | Array | Filter to jobs that match the given status, can be supplied multiple times |
latest | Integer | Filter to latest N jobs. Defaults to 1. |
Response
Array of: Jobs Start responses
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/control/v1/jobs/show/", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/control/v1/jobs/show");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
request.ContentType = "application/json";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
An array of: Jobs Start Sample Response
Items
An Item is any object fixed with an RFID tag. This API conducts item-level data queries for subsets matching supplied criteria (such as location).
The API is very simple, with just three endpoints; one to show items, another to show the history of items and the final to show when items transition through monitored thresholds.
Get Items
Query current items.
Authorized Roles
DataReader, Admin
HTTP Request
GET http://BASE_URL/data/v1/items/show
Properties
Property | Type | Description |
---|---|---|
epcPrefix (optional) |
String | A hexadecimal string representing an EPC prefix of an item. Only the items with EPCs that start with this prefix will be returned |
jobId (optional) |
String | A UUID job identifier, such as "ffa29f71-f0f9-426e-9ba4-45398361dc5d". This property identifies the job that last saw the item. Specifying both this property and the jobIds property will result in an error. |
jobIds (optional) |
String | A comma-separated list of job identifiers, such as "ffa29f71-f0f9-426e-9ba4-45398361dc5d, a6ce7f09-deb0-40f5-9ed7-0cf923440850". This parameter identifies items that were reported by any of the given jobs. Specifying both this property and the jobId property will result in an error. |
zoneNames (optional) |
String | A comma-separated list of zone names. Only items in these zones will be returned |
facility (optional) |
String | A string indicating the name of a facility. Only items in this facility will be returned |
presenceConfidence (optional) |
One of: HIGH, LOW |
(deprecated) - passing either value has no effect on the query, producing the same result as not including the property at all. |
fromTime (optional) |
String | Items which were last updated on or after this time in ISO-8601 format such as "2017-05-02T15:35:01.560Z". |
toTime (optional) |
String | Items which were updated before this time in ISO-8601 format such as "2017-05-02T15:35:01.560Z". |
epcFormat (optional) |
One of: PURE_ID TAG RAW UPC12 DEFAULT |
Format of the EPC string. Will return the raw hex strings (e.g. E280-1160-6000-0205-077D-321F) if this property is not specified. All options except DEFAULT and RAW require that the tags have SGTIN-96 encoding. If not correctly encoded, they return no data. The DEFAULT option also requires valid SGTIN-96 encoding to decode the EPC and, if successful, returns data in PURE_ID format, but on failure, will revert to RAW format, which returns all tags, regardless of encoding. Note that ItemSense allows EPCs of various lengths up to 256 bits, but will only decode 96-bit EPCs that follow the SGTIN-96 standard. |
pageMarker (optional) |
String | A string indicating which page of results to return. A new marker is returned after each query and can be used to fetch subsequent pages. When using a page marker, the other query properties must be the same as those used in the previous query. |
pageSize (optional) |
Integer | The number of records to return per query (Max of 1000, defaults to 100) |
Response
Property | Type | Description |
---|---|---|
items | Array of:Item | The list of currently detected items |
Sample Code
var xhr = new XMLHttpRequest();
//return the next page's data
//Note: Libraries such as JQuery.Param({pageMarker: "u9tpuBjMfPdXS9TL5ZQCmbdwfEGKfLNGzBMhJQudSdYHdhjR0/Rd6LH2ReOJ3Mhk"}) will simply handling query properties.
var url = sprintf("http://BASE_URL/data/v1/items/show?pageMarker=%1$s", encodeURIComponent("u9tpuBjMfPdXS9TL5ZQCmbdwfEGKfLNGzBMhJQudSdYHdhjR0/Rd6LH2ReOJ3Mhk") );
xhr.open("GET", url, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string url = String.Format("http://BASE_URL/data/v1/items/show/history?pageMarker={0}", Uri.EscapeDataString("ZmeLu/fWX4e+s1CUxOxeXrrMdV415+LcdzEnZiFeUavMkEKYzZCcwwV8CKFUcUJI") );
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(url);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
request.ContentType = "application/json";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "items":[ { "epc":"111100000000000000000019", "tagId":"000000000000", "jobId":"ffa29f71-f0f9-426e-9ba4-45398361dc5d", "xLocation":6.3, "yLocation":9.2, "zLocation":0, "zone":"ZONE1", "facility":HOME, "presenceConfidence":"HIGH", "lastModifiedTime":"2016-02-23T00:38:42Z" }, { "epc":"300833B2DDD9000500010004", "tagId":"000000000000", "jobId":"ffa29f71-f0f9-426e-9ba4-45398361dc5d", "xLocation":1.9, "yLocation":2.1, "zLocation":0, "zone":"ZONE2", "facility":"HOME", "presenceConfidence":"HIGH", "lastModifiedTime":"2016-02-23T00:37:57Z" } ], "nextPageMarker": "bozBcaT89jaLIuUy+gdkWm8xz8FRimZz8++6HHecp9vNvz4PLFxwZeCWAN666lTE" }
Get Item History
Query the history of items. A historic record for an item is created each time an Item has a significant state change. Examples of a significant state change include zone change, tag movement beyond the minimum threshold, and elapsed heartbeat interval.
Authorized Roles
DataReader, Admin
HTTP Request
GET http://BASE_URL/data/v1/items/show/history
Properties
Property | Type | Description |
---|---|---|
epcPrefix (optional) |
String | A hexadecimal string representing an EPC prefix of an item. Only the items with EPCs that start with this prefix will be returned |
jobId (optional) |
String | A UUID job identifier, such as "ffa29f71-f0f9-426e-9ba4-45398361dc5d". This property identifies the job that reported the change in the item. Specifying both this property and the jobIds property will result in an error." |
jobIds (optional) |
String | A comma-separated list of job identifiers, such as "ffa29f71-f0f9-426e-9ba4-45398361dc5d, a6ce7f09-deb0-40f5-9ed7-0cf923440850". This parameter identifies items that were reported by any of the given jobs. Specifying both this property and the jobId property will result in an error. |
fromZone (optional) |
String | A string zone identifier, such as "Men's Department". This property identifies the zone that the item moved out of. |
toZone (optional) |
String | A string zone identifier, such as "Men's Department". This property identifies the zone that the item moved into. |
fromFacility (optional) |
String | A string facility identifier, such as "Seattle Location". This property identifies the facility that the item moved out of. |
toFacility (optional) |
String | A string facility identifier, such as "Seattle Location". This property identifies the facility that the item moved into. |
fromTime (optional) |
String | Events which occurred on or after this time in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
toTime (optional) |
String | Events which occurred before this time in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
epcFormat (optional) |
One of: PURE_ID TAG RAW UPC12 DEFAULT |
Format of the EPC string. Will return the raw hex strings (e.g. E280-1160-6000-0205-077D-321F) if this property is not specified. All options except DEFAULT and RAW require that the tags have SGTIN-96 encoding. If not correctly encoded, they return no data. The DEFAULT option also requires valid SGTIN-96 encoding to decode the EPC and, if successful, returns data in PURE_ID format, but on failure, will revert to RAW format, which returns all tags, regardless of encoding. Note that ItemSense allows EPCs of various lengths up to 256 bits, but will only decode 96-bit EPCs that follow the SGTIN-96 standard. |
zoneTransitionsOnly (optional) |
Boolean | Will restrict results to items that moved zones, defaults to true |
minDistanceMoved (optional) |
Float | Will restrict results to items that moved more than the minimum distance supplied (in meters). |
pageMarker (optional) |
String | A string indicating which page of results to return. A new marker is returned after each query and can be used to fetch subsequent pages. When using a page marker, the other query properties must be the same as those used in the previous query. When paired with the nextPageMarker field, this flag is beneficial for re-querying the same filtered data set at a later time, and expecting to only see the newest records. |
pageSize (optional) |
Integer | The number of records to return per query. The maximum value of this property is 1000. The default value is 100. |
alwaysIncludePageMarker (optional) |
Boolean | Always include the page marker in the query results. Defaults to true. |
Response
Property | Type | Description |
---|---|---|
history | Array of: ItemEvent | A list of item events filtered according to the submitted query |
nextPageMarker | String | A string representing the place in the history where the next set of records begin |
moreHistoryAvailable | Boolean | Whether there is more history available or this is the last set of records |
Sample Code
var xhr = new XMLHttpRequest();
//return the next page's data
//Note: Libraries such as JQuery.Param({pageMarker: "u9tpuBjMfPdXS9TL5ZQCmbdwfEGKfLNGzBMhJQudSdYHdhjR0/Rd6LH2ReOJ3Mhk"}) simplifies handling query parameters.
var url = sprintf("http://BASE_URL/data/v1/items/show/history?pageMarker=%1$s", encodeURIComponent("u9tpuBjMfPdXS9TL5ZQCmbdwfEGKfLNGzBMhJQudSdYHdhjR0/Rd6LH2ReOJ3Mhk") );
xhr.open("GET", url, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
//return the next page's data
string url = String.Format("http://BASE_URL/data/v1/items/show/history?pageMarker={0}", Uri.EscapeDataString("ZmeLu/fWX4e+s1CUxOxeXrrMdV415+LcdzEnZiFeUavMkEKYzZCcwwV8CKFUcUJI") );
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(url);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
request.ContentType = "application/json";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "history":[ { "epc":"5BBA7E85407C51D8", "tagId":"000000000000", "jobId":"ffa29f71-f0f9-426e-9ba4-45398361dc5d", "jobName": "locationJob", "fromZone":"ZONE1", "toZone":"ZONE2", "fromFacility":DEFAULT, "fromFloor": "1" "toFacility":"DEFAULT", "toFloor": "1" "fromX":12,9, "fromY":10.4, "toX":2.4, "toY":2.7, "observationTime":"2016-02-23T00:37:16Z" }, { "epc":"111100000000000000000019", "tagId":"000000000000", "jobId":"ffa29f71-f0f9-426e-9ba4-45398361dc5d", "jobName": "locationJob", "fromZone":"ZONE2", "toZone":"ZONE1", "fromFacility":null, "fromFloor": "1", "toFacility":"DEFAULT", "toFloor": "1", "fromX":null, "fromY":null, "toX":12.2, "toY":10.7, "observationTime":"2016-02-23T00:37:16Z" } ], "nextPageMarker": "xjR3rD6qFcV+p3yUurz0FIMSYHqxarq6xuvgVSFvU+crHVRshQ789d5TO6UI5m9w", "moreHistoryAvailable": true }
Get Item Threshold Transitions
Query the transitions of items through thresholds. When threshold jobs are running and configured to report to the database, a record of each item transition is stored.
Authorized Roles
DataReader, Admin
HTTP Request
GET http://BASE_URL/data/v1/items/show/transitions
Properties
Property | Type | Description |
---|---|---|
epcPrefix (optional) |
String | A hexadecimal string representing an EPC prefix of an item. Only the items with EPCs that start with this prefix will be returned. |
jobId (optional) |
String | A UUID job identifier, such as "ffa29f71-f0f9-426e-9ba4-45398361dc5d". This property identifies the job that reported the transition of the item. Specifying both this property and the jobIds property will result in an error. |
jobIds (optional) |
String | A comma-separated list of job identifiers, such as "ffa29f71-f0f9-426e-9ba4-45398361dc5d, a6ce7f09-deb0-40f5-9ed7-0cf923440850". This parameter identifies items that were reported by any of the given jobs. Specifying both this property and the jobId property will result in an error. |
thresholdId (optional) |
Integer | A numeric threshold ID. Only items that transitioned through this threshold will be returned. If provided, thresholdName must not be used. |
thresholdName (optional) |
String | A string threshold name. Only items that transitioned through this threshold will be returned. If provided, thresholdId must not be used. |
destination (optional) |
String | A string destination identifier, such as "OUT". This property identifies the destination that the item transitioned to. |
facility (optional) |
String | A facility name. Only transitions that occurred through thresholds in this facility will be returned. Additionally specifying a threshold (by name or by id) is allowed but not useful. |
fromTime (optional) |
String | Events which occurred on or after this time in ISO-8601 format such as "2017-05-02T15:35:01.560Z". |
toTime (optional) |
String | Events which occurred before this time in ISO-8601 format such as "2017-05-02T15:35:01.560Z". |
epcFormat (optional) |
One of: PURE_ID TAG RAW UPC12 DEFAULT |
Format of the EPC string. Will return the raw hex strings (e.g. E280-1160-6000-0205-077D-321F) if this property is not specified. All options except DEFAULT and RAW require that the tags have SGTIN-96 encoding. If not correctly encoded, they return no data. The DEFAULT option also requires valid SGTIN-96 encoding to decode the EPC and, if successful, returns data in PURE_ID format, but on failure, will revert to RAW format, which returns all tags, regardless of encoding. Note that ItemSense allows EPCs of various lengths up to 256 bits, but will only decode 96-bit EPCs that follow the SGTIN-96 standard. |
pageMarker (optional) |
String | A string indicating which page of results to return. A new marker is returned after each query and can be used to fetch subsequent pages. When using a page marker, the other query properties must be the same as those used in the previous query. When paired with the nextPageMarker field, this flag is beneficial for re-querying the same filtered data set at a later time, and expecting to only see the newest records. |
pageSize (optional) |
Integer | The number of records to return per query. The maximum value of this property is 1000. The default value is 100. |
alwaysIncludePageMarker (optional) |
Boolean | Always include the page marker in the query results. Defaults to true. |
Response
Property | Type | Description |
---|---|---|
transitions | Array of: ItemThresholdTransitionEvent | A list of item threshold transition events filtered according to the submitted query |
nextPageMarker | String | A string representing the place in the history where the next set of records begin |
moreTransitionsAvailable | Boolean | Whether there is are more transition records available or this is the last set of records |
Sample Code
var xhr = new XMLHttpRequest();
//return the next page's data
//Note: Libraries such as JQuery.Param({pageMarker: "u9tpuBjMfPdXS9TL5ZQCmbdwfEGKfLNGzBMhJQudSdYHdhjR0/Rd6LH2ReOJ3Mhk"}) will simply handling query properties.
var url = sprintf("http://BASE_URL/data/v1/items/show/transitions?pageMarker=%1$s", encodeURIComponent("u9tpuBjMfPdXS9TL5ZQCmbdwfEGKfLNGzBMhJQudSdYHdhjR0/Rd6LH2ReOJ3Mhk") );
xhr.open("GET", url, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
//return the next page's data
string url = String.Format("http://BASE_URL/data/v1/items/show/transitions?pageMarker={0}", Uri.EscapeDataString("ZmeLu/fWX4e+s1CUxOxeXrrMdV415+LcdzEnZiFeUavMkEKYzZCcwwV8CKFUcUJI") );
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(url);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
request.ContentType = "application/json";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "transitions":[ { "thresholdTransitionId": 1, "epc": "epc1", "jobId": "jobid1", "thresholdId": 1, "destination": "out", "confidence": 1, "creationTime": "2017-03-01T22:46:59Z" }, { "thresholdTransitionId": 2, "epc": "epc2", "jobId": "jobid1", "thresholdId": 1, "destination": "out", "confidence": 1, "creationTime": "2017-03-01T22:48:10Z" }, { "thresholdTransitionId": 3, "epc": "epc3", "jobId": "jobid1", "thresholdId": 1, "destination": "out", "confidence": 1, "creationTime": "2017-03-01T22:48:15Z" } ], "nextPageMarker": "xjR3rD6qFcV+p3yUurz0FIMSYHqxarq6xuvgVSFvU+crHVRshQ789d5TO6UI5m9w", "moreTransitionsAvailable": true }
Item Data Message Queue
ItemSense provides an AMQP-based real-time event push system in addition to its REST query APIs.
A queue is configured with a specific query. Clients can then connect to that queue to receive messages matching the configured query. Each property in the request body acts as a filtered item for that specific queue. If multiple properties are present in the request body, queue messages will only be created if all filtered properties are matched.
Authorized Roles
DataReader, Admin
HTTP Request
PUT http://BASE_URL/data/v1/items/queues
Properties
Property | Type | Description |
---|---|---|
deliveryMode (optional) |
One of: NON_PERSISTENT PERSISTENT |
Defaults to NON_PERSISTENT if this property is not specified. If PERSISTENT is specified, messages will be written to disk to be recovered in the event of an outage. This will utilize more disk space and affect performance. |
Request Body
Property | Type | Description |
---|---|---|
fromFacility (optional) |
String | The name of a facility to monitor for tag exit events |
toFacility (optional) |
String | The name of a facility to monitor for tag entry events |
fromZone (optional) |
String | The name of the zone to monitor for tag exit events |
toZone (optional) |
String | The name of the zone to monitor for tag entry events |
epc (optional) |
String | A hexadecimal string representing an EPC prefix of an item. Only the items with EPCs that start with this prefix will be returned |
jobId (optional) |
String | The ID of the job to monitor for tag events |
distance (optional) |
Float | The minimum distance a tag must move before a queue event (or message) is created |
zoneTransitionsOnly (optional) |
Boolean | Flag to only create queue events for tags that have transitioned between zones. Default value is true. |
Sample Code
// Note: this is nodejs code. AMQP cannot be used directly using browser code
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var amqp = require('amqp');
var messageQueue = {
fromZone: "BACK_OF_STORE",
toZone: "FRONT_OF_STORE"
};
var queueConfig = {
durable: true,
noDeclare: true,
arguments: {
'x-expires': 3600000,
'x-message-ttl': 3600000,
'x-max-length-bytes': 1073741824
}
};
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
console.log("State: " + this.readyState);
if (this.readyState === 4) {
console.log("Complete.\nBody length: " + this.responseText.length);
console.log("Body:\n" + this.responseText);
console.log(this.responseText);
var queueInfo = JSON.parse(this.responseText);
createConnection(queueInfo)
.then((connection) => {
console.log('Connection established');
return createQueue(connection, queueInfo);
})
.then((newQueue) => {
console.log('Queue established');
return createSubscription(newQueue);
});
}
};
xhr.open("PUT", "http://BASE_URL/data/v1/items/queues?deliveryMode=NON_PERSISTENT", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(messageQueue));
function createConnection(queueInfo) {
return new Promise((resolve) => {
const connection = amqp.createConnection({ url: queueInfo.serverUrl, login: "", password: ""}, { reconnect: false });
connection.on('ready', () => resolve(connection));
connection.on('error', (err) => {
console.log(`Error: ${err}`);
});
});
}
function createQueue(connection, queueInfo) {
return new Promise((resolve) => {
console.log(`Connecting to queue with ${queueInfo.queue} and ${JSON.stringify(queueConfig)}`);
connection.queue(queueInfo.queue, queueConfig, queue => resolve(queue));
});
}
function createSubscription(queue) {
queue.subscribe((msg) => {
console.log(`Message: ${msg.data}`);
});
console.log(`Listening`);
}
using System;
using System.Net;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace AMQP
{
// Structure to store the AMQP data returned in the response
class AMQPdata
{
public string serverUrl;
public string queue;
}
// Request properties used to filter items for the message queue
class requestParameters
{
public string fromZone="BACK_OF_STORE";
public string toZone="FRONT_OF_STORE";
}
class Program
{
static int Main(string[] args)
{
string currentUser = "(amqpJSON);
amqp.serverUrl = amqpConvertedFromJSON.serverUrl.Replace("://", string.Format("://{0}:{1}@", currentUser, currentUserPassword));
amqp.queue = amqpConvertedFromJSON.queue;
// Print the reader data returned in the REST response
Console.WriteLine("\nAMQP data returned in JSON format: " + amqpJSON + "\n");
Console.WriteLine("\n -- Parsed data --" +
"\n Server URL: " + amqp.serverUrl +
"\n Queue: " + amqp.queue + "\n");
}
// Open an AMQP connection and set up the queue for receiving messages
ConnectionFactory factory = new ConnectionFactory();
factory.Uri = new Uri(amqp.serverUrl);
factory.AutomaticRecoveryEnabled = true;
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
Console.WriteLine("waiting");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("Message: {0}", message);
};
Console.WriteLine(channel.BasicConsume(queue: amqp.queue, autoAck: true, consumer: consumer));
Console.WriteLine("Waiting for results. Hit Enter to Exit");
Console.ReadLine();
}
return 0;
}
}
}
Sample Response for Queue Configuration
{ "serverUrl": "amqp://localhost:5672/%2F", "queue": "1127b6d0c96f6c55d42e54b390f9a6c50fc4911b956c1a3128a2e26c3f6481cd" }
Sample Response for Message Reception
Message: {"epc":"F7091D9A2B9538B689F53AB8", "fromFacility": "Store51", "fromFloor": "MainFloor", "fromX": -1.57, "fromY": 12.22, "fromZone":"BACK_OF_STORE", "jobId":"de9cfdf2-ac9e-4d14-a5cc-b00430140902", "jobName": "AfternoonLocation", "observationTime":"2018-03-30T22:48:18.886Z", "tagId": "", "toFacility": "Store51", "toFloor": "MainFloor", "toX": 2.21, "toY": 8.71, "toZone":"FRONT_OF_STORE"}
Message: {"epc":"02CBA4FF091338C2A35ADB86", "fromFacility": "Store51", "fromFloor": "MainFloor", "fromX": -2.17, "fromY": 13.41, "fromZone":"BACK_OF_STORE", "jobId":"de9cfdf2-ac9e-4d14-a5cc-b00430140902", "jobName": "AfternoonLocation", "observationTime":"2018-03-30T22:48:18.888Z","tagId": "", "toFacility": "Store51", "toFloor": "MainFloor", "toX": 4.98, "toY": 6.29, "toZone":"FRONT_OF_STORE"}
Message: {"epc":"C38B2994C7BA3AD68961A233", "fromFacility": "Store51", "fromFloor": "MainFloor", "fromX": -2.17, "fromY": 13.41, "fromZone":"BACK_OF_STORE", "jobId":"de9cfdf2-ac9e-4d14-a5cc-b00430140902", "jobName": "AfternoonLocation", "observationTime":"2018-03-30T22:48:18.89Z","tagId": "", "toFacility": "Store51", "toFloor": "MainFloor", "toX": 3.15, "toY": 3.05, "toZone":"FRONT_OF_STORE"}
Message: {"epc":"E7E92B38AB2C362497818237", "fromFacility": "Store51", "fromFloor": "MainFloor", "fromX": 0.41, "fromY": 12.92, "fromZone":"BACK_OF_STORE", "jobId":"de9cfdf2-ac9e-4d14-a5cc-b00430140902", "jobName": "AfternoonLocation", "observationTime":"2018-03-30T22:48:18.893Z","tagId": "", "toFacility": "Store51", "toFloor": "MainFloor", "toX": 7.48, "toY": 4.31, "toZone":"FRONT_OF_STORE"}
Message: {"epc":"02D9D40D17A63E9595EB6890", "fromFacility": "Store51", "fromFloor": "MainFloor", "fromX": 1.27, "fromY": 13.45, "fromZone":"BACK_OF_STORE", "jobId":"de9cfdf2-ac9e-4d14-a5cc-b00430140902", "jobName": "AfternoonLocation", "observationTime":"2018-03-30T22:48:18.895Z","tagId": "", "toFacility": "Store51", "toFloor": "MainFloor", "toX": 4.19, "toY": 6.54, "toZone":"FRONT_OF_STORE"}
Queue Message Data
Once a message queue has been configured, messages that match the filter criteria will be appended to the queue. The structure of each element in the queue is the same as an ItemEvent record in the Item History list. Idle queues (those without messages or a consumer) will be removed after one hour of inactivity. Empty queues with a consumer will remain active provided the connection uses the heartbeat mechanism. For AMQP best practices, see RabbitMQ Tutorials.
Threshold Data Message Queue
ItemSense provides an AMQP-based real-time event push system in addition to its REST query APIs.
A threshold queue is configured with a specific query. Clients can then connect to that queue to receive messages matching the configured query. Each property in the request body acts as a filtered item for that specific queue. If multiple properties are present in the request body, queue messages will only be created if all filtered properties are matched.
Authorized Roles
DataReader, Admin
HTTP Request
PUT http://BASE_URL/data/v1/items/queues/threshold
Properties
Property | Type | Description |
---|---|---|
deliveryMode (optional) |
One of: NON_PERSISTENT PERSISTENT |
Defaults to NON_PERSISTENT if this property is not specified. If PERSISTENT is specified, messages will be written to disk to be recovered in the event of an outage. This will utilize more disk space and affect performance. |
Request Body
Property | Type | Description |
---|---|---|
threshold (optional) |
String | The name of a threshold to monitor for events |
jobId (optional) |
String | The ID of the job to monitor for events |
Sample Code
var messageQueue = {
threshold: "REAR_THRESHOLD"
};
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/data/v1/items/queues/threshold?deliveryMode=NON_PERSISTENT", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(messageQueue));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
var messageQueue = new
{
threshold = "REAR_THRESHOLD"
};
Uri uri = new Uri("http://BASE_URL/data/v1/items/queues/threshold?deliveryMode=NON_PERSISTENT");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
string data = new JavaScriptSerializer().Serialize(messageQueue);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "serverUrl": "amqp://localhost:5672/%2F", "queue": "1127b6d0c96f6c55d42e54b390f9a6c50fc4911b956c1a3128a2e26c3f6481cd" }
Threshold Queue Message Data
Once a message queue has been configured, messages that match the filter criteria will be appended to the queue.
The structure of each element in the queue is an ItemThresholdTransitionEvent.
Data Definitions
Item
Property | Type | Description |
---|---|---|
epc (optional) |
String | The EPC of the item |
tagId (not curently provided) |
String | The ID of the tag that was read. Note that ItemSense does not currently provide the tagId, and the value of this field is always set to "000000000000" |
jobId (optional) |
String | The ID of the job that last saw the item |
xLocation (optional) |
Float | The x coordinate of the item's location |
yLocation (optional) |
Float | The y coordinate of the item's location |
zLocation (optional) |
Float | The z coordinate of the item's location |
zone (optional) |
String | The name of the zone in which the item was read |
floor (optional) |
String | The name of the floor on which the item was read |
facility (optional) |
String | The facility in which the item was read |
presenceConfidence (optional) |
String |
(deprecated) - always returns HIGH . This value should no longer be relied upon as an indication of presence confidence. |
lastModifiedTime (optional) |
String | The time at which the item was read in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
ItemEvent
Property | Type | Description |
---|---|---|
epc (optional) |
String | The EPC of the tag for which the event occurred |
tagId (optional) |
String | The ID of the tag that was read. Note that ItemSense does not currently provide the tagId, and the value of this field is always set to "000000000000" |
jobId (optional) |
String | The ID of the job that reported the change in the item |
jobName (optional) |
String | The name of the job that reported the change in the item |
fromZone (optional) |
String | The name of the zone from which the tag moved |
toZone (optional) |
String | The name of the zone to which the tag moved |
fromFloor (optional) |
String | The name of the floor from which the tag moved |
toFloor (optional) |
String | The name of the floor to which the tag moved |
fromFacility (optional) |
String | The name of the facility from which the tag moved |
toFacility (optional) |
String | The name of the facility to which the tag moved |
fromX (optional) |
Float | The x coordinate of the location from which the tag moved |
toX (optional) |
Float | The x coordinate of the location to which the tag moved |
fromY (optional) |
Float | The y coordinate of the location from which the tag moved |
toY (optional) |
Float | The y coordinate of the location to which the tag moved |
observationTime (optional) |
String | The time at which the event occurred in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
ItemThresholdTransitionEvent
Property | Type | Description |
---|---|---|
epc (optional) |
String | The EPC of the tag for which the event occurred |
thresholdTransitionId (optional) |
Integer | The ID of the specific transition record |
jobId (optional) |
String | The ID of the job that generated the transition record |
thresholdId (optional) |
Integer | The ID of the threshold where this transition occurred |
destination (optional) |
String | The name of the destination that the item transitioned to |
confidence (optional) |
Float | The confidence value of the transition event |
creationTime (optional) |
String | The time at which the transition was recorded in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
QueuedThresholdTransitionEvent
Property | Type | Description |
---|---|---|
epc (optional) |
String | The EPC of the tag for which the event occurred |
observationTime (optional) |
Integer | The time at which the transition was recorded in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
fromZone (optional) |
String | The type of transition, being "IN" or "OUT" this will always be the opposite value of toZone |
toZone (optional) |
String | The type of transition, being "IN" or "OUT" this will always be the opposite value of fromZone |
threshold (optional) |
String | The name of the threshold where this transition occurred |
jobId (optional) |
String | The ID of the job that generated the transition record |
confidence (optional) |
Float | The confidence value of the transition event |
Health
A read-only interface to query reader health status
Reader
Show the health of a single reader
Authorized Roles
Admin, ConfigManager, DataReader, JobRunner
HTTP Request
GET http://BASE_URL/health/v1/readers/{readerName}
Path Parameters
Parameter | Type | Description |
---|---|---|
readerName | String | The name of the reader |
Response
Parameter | Type | Description |
---|---|---|
readerName | String | The name of the reader |
state | One of: AWAITING_AGENT IDLE RUNNING_JOB UPDATING_FIRMWARE NOT_RESPONDING ERROR |
The state of the reader |
lastCheckin | String | The time at which the reader last contacted itemsense in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
lastReboot | String | The time at which the reader was last re-booted in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
version | object | The version of firmware that the reader is running |
connectionStatus | ConnectionStatus | The status of the health and monitoring connection to the reader |
throughputStatus | ThroughputStatus | The throughput status of the reader |
clockSyncStatus | ClockSyncStatus | The clock sync status of the reader |
hardwareStatus | HardwareStatus | The hardware status of the reader |
softwareStatus | SoftwareStatus | The software status of the reader |
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/health/v1/readers/MY_READERNAME", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/health/v1/readers/MY_READERNAME);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "readerName": "xArray-11-4D-3D", "state": "IDLE", "lastCheckin": "2016-08-23T15:33:59.496Z", "lastReboot": "2016-08-23T14:41:33.378Z", "version": { "App": "0.0.1.15", "Firmware": "5.6.2.240" }, "connectionStatus": { "status": "HEALTHY", "code": null }, "throughputStatus": { "status": "HEALTHY", "code": null }, "clockSyncStatus": { "status": "HEALTHY", "code": null, }, "hardwareStatus": { "status": "HEALTHY", "code": null, "devices": null }, "softwareStatus": { "status": "HEALTHY", "code": null } }
Readers
Show the health of all readers
Authorized Roles
Admin, ConfigManager, DataReader, JobRunner
HTTP Request
GET http://BASE_URL/health/v1/readers
Response
An array of: Reader Health Response
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/health/v1/readers", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/health/v1/readers);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "readerName": "xArray-11-4D-3D", "state": "RUNNING_JOB", "lastCheckin": "2016-08-23T20:08:57.771Z", "lastReboot": "2016-08-23T16:02:24.410Z", "version": { "App": "0.0.1.15", "Firmware": "5.6.2.240" }, "connectionStatus": { "status": "HEALTHY", "code": null }, "throughputStatus": { "status": "HEALTHY", "code": null }, "clockSyncStatus": { "status": "HEALTHY", "code": null, }, "hardwareStatus": { "status": "HEALTHY", "code": null, "devices": null }, "softwareStatus": { "status": "HEALTHY", "code": null } }, { "readerName": "xArray-11-42-2B", "state": "IDLE", "lastCheckin": "2016-08-23T20:08:57.403Z", "lastReboot": "2016-08-23T19:36:19.390Z", "version": { "App": "0.0.1.15", "Firmware": "5.8.0.26" }, "connectionStatus": { "status": "HEALTHY", "code": null }, "throughputStatus": { "status": "HEALTHY", "code": null }, "clockSyncStatus": { "status": "HEALTHY", "code": null }, "hardwareStatus": { "status": "HEALTHY", "code": null, "devices": null }, "softwareStatus": { "status": "HEALTHY", "code": null } } ]
Events
Search health events
Authorized Roles
Admin, ConfigManager, DataReader, JobRunner
HTTP Request
POST http://BASE_URL/health/v1/events
Request Body
Property | Type | Description |
---|---|---|
readerNames (optional) |
Array of: String | The set of reader names for which to query health events |
types (optional) |
Array of: String | The set of status types for which to query health events |
codes (optional) |
Array of: String | The set of status codes for which to query health events (see Code Details below). |
fromTime (optional) |
String | The beginning of the query time period in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
toTime (optional) |
String | The end of the query time period in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
pageSize (optional) |
Integer | The number of events to return per query |
nextPageMarker (optional) |
String | The marker of the next page to return |
Response
Parameter | Type | Description |
---|---|---|
events | Array of: HealthEvent | List of reader health events |
nextPageMarker | String | The value of the marker to supply for the next page of reader health results |
Sample Code
var body = {
"types": ["LIFECYCLE"]
};
var xhr = new XMLHttpRequest()
xhr.open("POST", "http://BASE_URL/health/v1/events", true)
// Set authorization headers
xhr.send(body)
var body = {
"types": ["LIFECYCLE"]
};
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/health/v1/events);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
using (StreamWriter sw = new StreamWriter(request.GetRequestStream())
{
string data = new JavaScriptSerializer().Serialize(body);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "events": [ { "eventTime": "2016-08-23T14:41:33.378Z", "readerName": "xArray-11-4D-3D", "type": "LIFECYCLE", "code": "REBOOT", "args": { "reason": "BootReason='Cold'" } }, { "eventTime": "2016-08-23T14:02:46.316Z", "readerName": "xArray-11-4D-3D", "type": "LIFECYCLE", "code": "REBOOT", "args": { "reason": "BootReason='Cold'" } }, { "eventTime": "2016-08-22T22:57:55.217Z", "readerName": "xArray-11-4D-3D", "type": "LIFECYCLE", "code": "VERSION_UPDATE", "args": { "newVersion": "{\"App\":\"0.0.1.15\",\"Firmware\":\"5.6.2.240\"}" } }, { "eventTime": "2016-08-22T22:57:54.337Z", "readerName": "xArray-11-4D-3D", "type": "LIFECYCLE", "code": "REBOOT", "args": { "reason": "BootReason='Processor / Reboot'" } } ], "nextPageMarker": null }
Event Queue
Configure a queue to receive health event messages with the given filter.
A queue is configured with a specific query. Clients can then connect to that queue to receive messages matching the configured query.
Authorized Roles
Admin, DataReader
HTTP Request
PUT http://BASE_URL/health/v1/events/queues
Query Parameters
Parameter | Type | Description |
---|---|---|
deliveryMode (optional) |
One of: NON_PERSISTENT PERSISTENT |
Defaults to NON_PERSISTENT if this parameter is not specified. If PERSISTENT is specified, messages will be written to disk to be recovered in the event of an outage. This will utilize more disk space. |
Request Body
Parameter | Type | Description |
---|---|---|
readerName (optional) |
String | The name of the reader to query |
type (optional) |
One of: CONNECTION THROUGHPUT CLOCK_SYNC HARDWARE_FAULT SOFTWARE_FAULT LIFECYCLE UNCLASSIFIED |
The type of health event to query |
code (optional) |
String | The status code to query |
Response
Parameter | Type | Description |
---|---|---|
serverUrl | String | The URL of the reader health event queue |
queue | String | The queue identifier |
Sample Code
var body = {
"readerName": "xArray-11-4D-3D",
"type": "CONNECTION",
"code": "NETWORK",
};
var xhr = new XMLHttpRequest()
xhr.open("PUT", "http://BASE_URL/health/v1/events/queues?deliveryMode=NON_PERSISTENT", true)
// Set authorization headers
xhr.send(body)
var body = {
"readerName": "xArray-11-4D-3D",
"type": "CONNECTION",
"code": "NETWORK",
};
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/health/v1/events/queues?deliveryMode=NON_PERSISTENT);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "PUT";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
using (StreamWriter sw = new StreamWriter(request.GetRequestStream())
{
string data = new JavaScriptSerializer().Serialize(body);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "serverUrl": "amqp://localhost:5672/%2F", "queue": "8913429d-d11e-404f-ab1a-9c01da4a9f0a" }
Data Definitions
Each of the Reader Status objects has a status
and a code
property.
When the status
is HEALTHY, the code
will be null.
When the status
is WARNING or FAILED, the code
should be one of several values (see Code Details below).
ConnectionStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The status of the connection |
code (optional) |
One of: BAD_CERTIFICATE HTTP_FAILURE or NETWORK |
See Code Details |
ThroughputStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The status of reader throughput |
code (optional) |
One of: DROPPED_READ REPORT_BUFFER TAG_POPULATION_OVERFLOW |
See Code Details |
ClockSyncStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The status of network clock (NTP) synchronization |
code (optional) |
One of: NTP CLOCK_SYNC |
See Code Details |
HardwareStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The hardware status |
code (optional) |
One of: READER_COMMAND READER_EXCEPTION READER_RESTART UPGRADE_STATUS |
See Code Details |
devices (optional) |
Array of: DeviceStatus | The status of each hardware device (e.g. all of the antennas on a reader) |
DeviceStatus
Property | Type | Description |
---|---|---|
device (optional) |
String | The hardware device e.g. a specific antenna |
code (optional) |
String | An optional string code HealthCode associated with the status |
SoftwareStatus
Property | Type | Description |
---|---|---|
status (optional) |
One of: HEALTHY WARNING FAILED |
The status of reader throughput |
code (optional) |
One of: CHECKSUM COMMAND_NOT_FOUND CONFIG_SERVICE_SET EXTERNAL_COMMAND FILE_SYSTEM INVALID_SET_VARIABLE UNMARSHAL LLRP PROVISIONING READER_CONNECTION CRASH AGENT_OUTDATED |
See Code Details |
HealthEvent
Property | Type | Description |
---|---|---|
eventTime (optional) |
String | The time of the event in ISO 8601 format such as "2017-05-02T15:35:01.560Z" |
readerName (optional) |
String | The name of the reader |
type (optional) |
One of: CONNECTION THROUGHPUT CLOCK_SYNC HARDWARE_FAULT SOFTWARE_FAULT LIFECYCLE UNCLASSIFIED |
The type of event |
code (optional) |
String | See Code Details |
args (optional) |
Object | Additional event-specific properties, often including a helpful message about the cause of the event |
Code Details
Below is a listing of all valid Type and Code combinations as they can appear in Health Events and in Reader Statuses. The same codes are used in both places. Note that not every Health Event type maps to a Reader Status property, and there are no currently known codes that appear in a DeviceStatus.
# | Code | Reader Status Property | Description |
---|---|---|---|
1 | BAD_CERTIFICATE | ConnectionStatus | 1. During provisioning. If invalid certificate is supplied by the IMC when accessing the /provision endpoint. (Note that this process returns a certificate for use on the ItemSense agent channel) 2. After provisioning. If the returned certificate starts failing |
2 | HTTP_FAILURE | ConnectionStatus | Anytime ItemSense returns a non successful HTTP status code. Can also happen during provisioning, when the agent "tests" the ItemSense HTTP connection settings. |
3 | NETWORK | ConnectionStatus | Something else went wrong with the network connection. e.g. network timeout |
4 | RECOVERY | ConnectionStatus | Reader rebooted and returned online after a 30-35 second interval of NO_RESPONSE |
5 | DROPPED_READ | ThroughoutStatus | Agent data buffer overflow error |
6 | REPORT_BUFFER | ThroughputStatus | Internal agent buffer is full or nearly full (conditions are distinguished by a message on the health event) |
7 | TAG_POPULATION_OVERFLOW | ThroughputStatus | Too many tags (in direction or location mode) |
8 | NTP | ClockSyncStatus | The on-reader NTP program failed to synchronize with a time provider, implying that the timestamps on reader are unreliable. (Implies an NTP server is running on the network (internal if no Internet connection)) |
9 | CLOCK_SYNC | ClockSyncStatus | An agent report was received from the reader which showed that the reader's clock is significantly off from the server's clock. The report was dropped by ItemSense in order to prevent issues that occur with determining an endpoint's latest location when readers' clocks differ. |
10 | READER_COMMAND | HardwareStatus | Generated when any LLRP reader command does not return a successful status reply |
11 | READER_EXCEPTION | HardwareStatus | Asynchronous notification from the reader (reported via LLRP) of an uncategorized error condition |
12 | READER_RESTART | HardwareStatus | Reader closed LLRP connection unexpectedly and the agent could not re-open it |
13 | UPGRADE_STATUS | HardwareStatus | When the upgrade (agent or firmware) process encounters any kind of error, or times out |
14 | CHECKSUM | SoftwareStatus | Checksum failure of either CAP or firmware image |
15 | COMMAND_NOT_FOUND | SoftwareStatus | Agent is sent an unknown command by ItemSense |
16 | CONFIG_SERVICE_SET | SoftwareStatus | Surfaced when an error is encountered in the agent config (In practice, this is a software error, or the config file is corrupted) |
17 | EXTERNAL_COMMAND | SoftwareStatus | A program invoked in the octane firmware by the agent returned an error code, or a response that could not be processed |
18 | FILE_SYSTEM | SoftwareStatus | Any file system error within the agent process (usually due to full or corrupted file system) |
19 | INVALID_SET_VARIABLE | SoftwareStatus | Agent is sent an invalid variable set command by ItemSense (type, range etc) |
20 | UNMARSHAL | SoftwareStatus | ItemSense sent invalid or corrupted data |
21 | LLRP | SoftwareStatus | 1. Invalid RF configurations are specified by ItemSense 2. Invalid LLRP packet was sent to the agent by the reader |
22 | PROVISIONING | SoftwareStatus | 1. Invalid provisioning settings 2. Provisioning module failed to start (http server failed to start) |
23 | READER_CONNECTION | SoftwareStatus | Failed to open or close the LLRP connection, or to receive a message over LLRP |
24 | CRASH | SoftwareStatus | The agent crashed and the reader is about to reboot |
25 | AGENT_OUTDATED | SoftwareStatus | An agent report was received from the reader which did not report the reader's time. ItemSense accepted the report, but this is potentially risky because ItemSense will not know if the reader's clock is or becomes out of sync. Upgrading the reader's Agent software is highly recommended. |
26 | REBOOT | None | Communicates the previous reboot reason. (Note: This event does not contribute to bad health status) |
27 | HEALTH_RESET | None | Is a signal used when computing reader status, to indicate ItemSense should disregard all health events older than this one |
28 | KNOWN | None | Any other exception that is expected by the Agent but not by ItemSense, including unknown SNMP events from the reader |
29 | UNKNOWN | None | Anything not previously defined or expected. |
Software
Reader software (firmware) can be queried and upgraded via these endpoints.
List Images
Show all versions of a specific image type
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/configuration/v1/softwareVersions/list/{imageType}
Path Parameters
Parameter | Type | Description |
---|---|---|
imageType | One of: FIRMWARE_SPEEDWAY CAP_ITEMSENSE |
The type of image |
Response
An array of:
Parameter | Type | Description |
---|---|---|
versionInfo | VersionInfo | The version information associated with the image |
description | String | A string describing the version |
created | String | The time at which the image was created in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
updated | String | The time at which the image was updated in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
updateComment | String | A comment associated with the update |
recordVersionNumber | Integer | An integer representing the update revision number |
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/configuration/v1/softwareVersions/list/FIRMWARE_SPEEDWAY", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/configuration/v1/softwareVersions/list/FIRMWARE_SPEEDWAY);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "versionInfo": { "versionIdentifier": { "version": "5.6.2.240", "imageType": "FIRMWARE_SPEEDWAY", }, "imageName": "octane-5.6.2.240.upg", "checksum": "076dae4e1c37037a42e37d012014ad62", }, "description": "Octane v5.6.2.240", "created": "2016-09-06T18:21:08.000Z", "updated": "2016-09-06T18:21:08.000Z", "updateComment": null, "recordVersionNumber": 1 }, ... ]
Show Image
Show a specific software image by type and version
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/configuration/v1/softwareVersions/show/{imageType}/{version}
Path Parameters
Parameter | Type | Description |
---|---|---|
imageType | One of: FIRMWARE_SPEEDWAY CAP_ITEMSENSE |
The type of image |
version | String | The version of the software image |
Response
Parameter | Type | Description |
---|---|---|
versionInfo | VersionInfo | The version information associated with the image |
description | String | A string describing the version |
created | String | The time at which the image was created in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
updated | String | The time at which the image was updated in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
updateComment | String | A comment associated with the update |
recordVersionNumber | Integer | An integer representing the update revision number |
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/configuration/v1/softwareVersions/show/FIRMWARE_SPEEDWAY/MY_VERSION", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/configuration/v1/softwareVersions/show/FIRMWARE_SPEEDWAY/MY_VERSION);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "versionInfo": { "versionIdentifier": { "version": "5.6.2.240", "imageType": "FIRMWARE_SPEEDWAY", }, "imageName": "octane-5.6.2.240.upg", "checksum": "076dae4e1c37037a42e37d012014ad62", }, "description": "Octane v5.6.2.240", "created": "2016-09-06T18:21:08.000Z", "updated": "2016-09-06T18:21:08.000Z", "updateComment": null, "recordVersionNumber": 1 }
VersionInfo
Parameter | Type | Description |
---|---|---|
versionIdentifier | VersionIdentifier | The version of the software image |
imageName | String | The name of the software image |
checksum | String | The checksum of the image |
VersionIdentifier
Parameter | Type | Description |
---|---|---|
version | String | The version of the software image |
imageType | One of: FIRMWARE_SPEEDWAY CAP_ITEMSENSE |
The type of image |
Show Upgrades
List all of the software upgrade jobs
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/control/v1/upgrades/show
Response
An array of:
Parameter | Type | Description |
---|---|---|
id | String | System-generated Universally Unique Identifier (UUID) returned as a string |
upgradeRequest | UpgradeRequest | Details of the upgrade request |
created | String | When the upgrade was created in ISO-8601 format such as '2017-05-02T15:35:56.456Z' |
updated | String | When the upgrade was last updated in ISO-8601 format such as '2017-05-02T15:35:56.456Z' |
numDevices | Integer | The number of devices being upgraded |
isCancelled | boolean | Whether or not the request to upgrade has been cancelled |
numFailures | Integer | The number of devices that have failed to upgrade |
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/control/v1/upgrades/show", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/control/v1/upgrades/show);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
[ { "id": "9b76015b-43e8-4fe1-9af6-599a439883e8", "upgradeRequest": { "target": { "type": "Facility", "values": "[MY_FACILITY]", }, "versionIdentifier": { "version": "5.6.2.240", "imageType": "FIRMWARE_SPEEDWAY", }, "created": "2017-05-02T15:35:56.456Z", "updated": "2017-05-02T16:01:45.345Z", "numDevices": 10, "isCancelled": false, "numFailures": 0 }, ... ]
Show Upgrade
Show the status of a specific upgrade job
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/control/v1/upgrades/show/{upgradeInstanceId}
Path Parameters
Parameter | Type | Description |
---|---|---|
upgradeInstanceId | String | The ID of the upgrade instance to retrieve |
Response
Parameter | Type | Description |
---|---|---|
id | String | System-generated Univerally Unique Identifier (UUID) returned as a string |
version | VersionIdentifier | The software version to which to upgrade the readers |
status | One of: WAITING IN_PROGRESS COMPLETED FAILED |
The status of the upgrade |
target | UpgradeRequestTarget | The criteria for specifying the set of readers to upgrade |
details | UpgradeStatusDetails | The upgrade status details |
elapsedTimeSeconds | Integer | The elapsed time of the upgrade |
lastUpdatedTime | String | The time that the reader was last updated |
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/control/v1/upgrades/show/7df1a27b-64d2-485c-9140-215c1e5b55cc", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/control/v1/upgrades/show/7df1a27b-64d2-485c-9140-215c1e5b55cc);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "id": "9b76015b-43e8-4fe1-9af6-599a439883e8", "version": { "version": "5.6.2.240", "imageType": "FIRMWARE_SPEEDWAY", }, "status": "IN_PROGRESS", "target": { "type": "Facility", "values": ["MY_FACILITY"], }, "details": { "readers": [ { "name": "SpeedwayR-11-79-9D", "previousVersion": { "version": "5.6.2.240", "imageType": "FIRMWARE_SPEEDWAY" }, "status": "WAITING", "elapsedTimeSeconds": 0, "lastUpdatedTime": "2016-09-06T22:27:31Z" }, { "name": "xArray-11-3F-5F", "previousVersion": { "version": "0.0.0.0", "imageType": "FIRMWARE_SPEEDWAY" }, "status": "IN_PROGRESS", "elapsedTimeSeconds": 0, "lastUpdatedTime": "2016-09-06T22:27:37.428Z" }, { "name": "SpeedwayR-11-1E-13", "previousVersion": { "version": "0.0.0.0", "imageType": "FIRMWARE_SPEEDWAY" }, "status": "WAITING", "elapsedTimeSeconds": 0, "lastUpdatedTime": "2016-09-06T22:27:31Z" } ] }, "elapsedTimeSeconds": 5, "lastUpdatedTime": "2016-09-06T22:27:36.185Z" }
A Note About Software Versions
In the Sample Response above, note each reader's previousVersion
property.
SpeedwayR-11-79-9D shows a previous version of 5.6.2.240
(coincidentally, this is equal to the version being upgraded to in the example), while xArray-11-3F-5F and SpeedwayR-11-1E-13 show a previous version of 0.0.0.0
.
This is because the version of the software running on the latter two readers had not been previously registered with ItemSense.
The readers had properly reported in to ItemSense with their versions of the software, but during the process of initializing the software upgrade request, the readers' software versions were not recognized.
For the purposes of this upgrade request, they were replaced by the fallback version 0.0.0.0
.
This has no negative impact on the upgrade process.
Start Upgrade
Start a software upgrade
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/control/v1/upgrades/start
Request Body
Property | Type | Description |
---|---|---|
target (required) |
UpgradeRequestTarget | The criteria for specifying the set of readers to upgrade |
versionIdentifier (required) |
VersionIdentifier | The software version to which to upgrade the readers |
policy (optional) |
UpgradePolicy | The upgrade policy to employ |
Response
Parameter | Type | Description |
---|---|---|
upgradeInstanceId | String | Instance identifier of the upgrade |
Sample Code
var body = {
"target": {
"type": "Facility",
"values": ["FAC"],
},
"versionIdentifier": {
"version": "5.6.2.240",
"imageType": "FIRMWARE_SPEEDWAY",
}
};
var xhr = new XMLHttpRequest()
xhr.open("POST", "http://BASE_URL/control/v1/upgrades/start", true)
// Set authorization headers
xhr.send(body)
var body = {
"target": {
"type": "Facility",
"values": ["FAC"],
},
"versionIdentifier": {
"version": "5.6.2.240",
"imageType": "FIRMWARE_SPEEDWAY",
}
};
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/control/v1/upgrades/start);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
using (StreamWriter sw = new StreamWriter(request.GetRequestStream())
{
string data = new JavaScriptSerializer().Serialize(body);
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "upgradeInstanceId": "7df1a27b-64d2-485c-9140-215c1e5b55cc", }
Cancel Upgrade
Cancel a specific upgrade job
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/control/v1/upgrades/stop/{upgradeInstanceId}
Path Parameters
Parameter | Type | Description |
---|---|---|
upgradeInstanceId | String | The ID of the upgrade instance to cancel |
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("POST", "http://BASE_URL/control/v1/upgrades/stop/7df1a27b-64d2-485c-9140-215c1e5b55cc", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/control/v1/upgrades/stop/7df1a27b-64d2-485c-9140-215c1e5b55cc);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
204 No Content
Data Definitions
UpgradeRequest
Property | Type | Description |
---|---|---|
target (required) |
UpgradeRequestTarget | The criteria for specifying the set of readers to upgrade |
versionIdentifier (required) |
VersionIdentifier | The software version to which to upgrade the readers |
policy (optional) |
UpgradePolicy | The upgrade policy to employ |
VersionIdentifier
Property | Type | Description |
---|---|---|
version (required) |
String | The version of the software image |
imageType (required) |
One of: FIRMWARE_SPEEDWAY CAP_ITEMSENSE |
The type of image |
UpgradeRequestTarget
Property | Type | Description |
---|---|---|
type (required) |
One of: DEVICE FACILITY |
The criteria for selecting the set of readers to upgrade |
values (required) |
Array of: String | The values of the criteria for selecting the set of readers to upgrade (i.e. if type = FACILITY, then a list of facility names, and if type = DEVICE, then a list of reader names) |
UpgradeStatusDetails
Property | Type | Description |
---|---|---|
readers (required) |
Array of: UpgradeDeviceStatus | The upgrade status for each reader |
UpgradePolicy
Property | Type | Description |
---|---|---|
maxParallelReaders (optional) |
integer | The maximum number of readers upgrading at any given moment. As readers finish, ItemSense will stay at maxParallelReaders by starting the upgrade process on the next in line. Default: 10 |
allowedReaderTypes (optional) |
Array of: String | The types of readers that are allowed to be upgraded. Default: [SPEEDWAY, XARRAY, XSPAN, XPORTAL] |
UpgradeDeviceStatus
Parameter | Type | Description |
---|---|---|
name | String | The name of the reader |
previousVersion | VersionIdentifier | The previous version of the reader software |
status | One of: WAITING IN_PROGRESS COMPLETED FAILED SKIPPED |
The status of the upgrade |
elapsedTimeSeconds | Integer | The elapsed time of the upgrade in seconds |
lastUpdatedTime | String | The time that the reader software was last updated |
Support
Factory Reset
Reset ItemSense to the default configuration. All item data and configuration data will be removed and put back to the starting state.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/support/v1/configuration/factoryReset
Response
None
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("POST", "http://BASE_URL/support/v1/configuration/factoryReset", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/support/v1/configuration/factoryReset);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
Download Iteration Data Log
Retrieves iteration data.
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/support/v1/logs/iterationData/{jobId}
Request Body
Parameter | Type | Description |
---|---|---|
jobId | String | A UUID job identifier, such as "cbfa1f54-c3b0-40d4-9597-e4fec9b9e623" Identifies the job for which the iteration data log should be returned. |
Response
Response | Description 200 | Iteration data log returned 404 | Iteration data log not present
Sample Code
var userName = "Admin"
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/support/v1/logs/iterationData/" + jobID);
xhr.setRequestHeader("Authorization", "Basic " + btoa("Admin:admindefault"));
//xhr.setRequestHeader("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send();
string username = "Admin";
string password = "admindefault";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string specificUser = "Admin";
Uri uri = new Uri("http://BASE_URL/support/v1/logs/iterationData/" + jobID);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic " + encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Configure ItemSense Time Sync
Configures the setting for enabling itemsenseTimeSync.
Authorized Roles
ConfigManager, Admin
HTTP Request
PUT http://BASE_URL/support/v1/readers/itemsenseTimeSync
Request Body
Parameter | Type | Description |
---|---|---|
enabled | boolean | Enables or disables itemsenseTimeSync settings. Defaults to enabled, true. |
Response Body
204 Request was successful but there is no response body.
Sample Code
var params = {};
params.enabled = BOOLEAN;
var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://BASE_URL/itemsense/support/v1/readers/itemsenseTimeSync", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic " + btoa("USER:PASSWORD"));
xhr.send(JSON.stringify(params));
string username = "USER";
string password = "PASSWORD";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string json;
Uri uri = new Uri("http://BASE_URL/itemsense/support/v1/readers/itemsenseTimeSync");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "PUT";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
var data = new
{
enabled = false
};
json = JsonConvert.SerializeObject(data);
sw.Write(json);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
No content
Get ItemSense Time Sync
Retrieve setting that dictates if ItemSense configures readers and gateways to use ItemSense Server for time synchronization.
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/support/v1/readers/itemsenseTimeSync
Response
Parameter | Type | Description |
---|---|---|
enabled | boolean | Returns the setting that dictates if ItemSense is configuring readers and gateways to use ItemSense Server for time synchronization. |
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://BASE_URL/itemsense/support/v1/readers/itemsenseTimeSync");
xhr.setRequestHeader("Authorization", "Basic " + btoa("USER:PASSWORD"));
xhr.send();
string username = "USER";
string password = "PASSWORD";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http:///itemsense/support/v1/readers/itemsenseTimeSync");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "enabled": true }
Item Reset
Remove all ItemSense item data. All item, item history and transition data will be removed from the system.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/support/v1/items/reset
Response
None
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("POST", "http://BASE_URL/support/v1/items/reset", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/support/v1/items/reset);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
Reader Reboot
Reboots a particular reader.
If the reader was participating in a job, it will reboot and then rejoin the job. If the reader was busy performing some other task, e.g., a firmware upgrade, that task may be interrupted, which is likely to have unpredictable and undesired consequences.
ItemSense does not expose a mechanism for tracking the progress of the reader's reboot. Determining whether a reader has completed its reboot should be done manually by observing the reader's status LEDs, or by attempting to reach the reader over the network.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/itemsense/support/v1/readers/{readerName}/reboot
Path Parameters
Parameter | Type | Description |
---|---|---|
readerName | string | Identifier of the reader to be rebooted |
Response
None
Sample Code
var readerName = "";
var url = "http:///itemsense/support/v1/readers/" + readerName + "/reboot";
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic " + btoa(":"));
xhr.send();
string username = "";
string password = "";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string readerName = "";
Uri uri = new Uri("http:///itemsense/support/v1/readers/" + readerName + "/reboot");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Export ItemSense Logs
Download an export of the ItemSense internal logs for use by Impinj customer support. By default the file downloaded will include 7 days worth of logs starting from now going backwards.
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/support/v1/logs
Query Parameters
Parameter | Type | Description |
---|---|---|
from | String | Filter for logs after the given time in ISO-8601 format such as "2017-03-02T15:35:01.560Z" |
to | String | Filter for logs before the given time in ISO-8601 format such as "2017-05-02T15:35:01.560Z" |
extended | boolean | Include extended logged data; will include logs not filtered by the 'from' and 'to' parameters |
Response
A compressed tar.gz file
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/support/v1/logs?from=2014-01-07T22%3A46%3A00%2B01%3A00", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/support/v1/logs?fromTime=2014-01-07T22%3A46%3A00%2B01%3A00);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
Create Reader Logs Request
Instruct ItemSense to gather logs from readers. Can designate specific readers or include all readers in the request. When complete, logs are downloaded via Get Reader Logs API.
Authorized Roles
ConfigManager, Admin
HTTP Request
POST http://BASE_URL/support/v1/readers/logs/requests
Request Body
Property | Type | Description |
---|---|---|
readerNames (optional) |
Array of: String | Names of the readers from which to download logs; if empty, all readers are included in the request |
Response Body
Parameter | Type | Description |
---|---|---|
requestId | String | The ID of the log export request |
state | String | The state of the newly created log export request; this is always "RUNNING" for the initial request |
message | String | Details of the newly created log export request |
requestTime | String | The request creation time in ISO 8601 format, such as "2017-05-02T15:35:01.560Z" |
completeTime | String | The request completion time in ISO 8601 format, such as "2017-05-02T15:35:01.560Z;" always null on creation |
readerNames | Array of: String | The names of the readers from which logs are exported |
readersStates | Key Value List | A list of readers' states, grouped by state; on creation, all readers or all readers specified as part of the request are listed under "RUNNING" |
downloadUrl | String | The URL to which results of this request are downloaded when complete |
Sample Code
var readers = {
"readerNames": [
"READER_NAME_1",
"READER_NAME_2"
]
};
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://BASE_URL/support/v1/readers/logs/requests", true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send(JSON.stringify(readers));
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/support/v1/readers/logs/requests");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
//JavaScriptSerializer.Serialize method produces an equivalent to JSON.stringify()
string data = new JavaScriptSerializer().Serialize(new
{
"readerNames": [
"READER_NAME_1",
"READER_NAME_2"
]
});
sw.Write(data);
}
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Sample Response
{ "requestId": "750b8a3e-08b2-4f34-8dcf-81c9041e00b3", "state": "RUNNING", "message": "", "requestTime": "2018-09-11T18:13:20.776Z", "completeTime": null, "readerNames": [ "xArray-11-30-0D" ], "readersStates": { "RUNNING": [ "xArray-11-30-0D" ], "ERROR": [], "DONE": [] }, "downloadUrl": "/support/v1/readers/logs/download" }
Get Reader Logs Status
ItemSense gathers logs in an asynchronous manner. Poll this endpoint until the process is complete before attempting to download the gathered reader logs.
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/support/v1/readers/logs/requests
Response Body
Parameter | Type | Description |
---|---|---|
requestId | String | Identifier for log latest export request |
state | String | State of the log export request. Valid values are: RUNNING, DONE, ERROR |
message | String | Details about the log export request, usually blank |
requestTime | String | The request creation time in ISO 8601 format, such as "2017-05-02T15:35:01.560Z" |
completeTime | String | The request completion time in ISO 8601 format, such as "2017-05-02T15:35:01.560Z" |
readerNames | Array of: String | The names of the readers |
readersStates | Key Value List | A map of states to lists of reader names; key values are: RUNNING, DONE, ERROR |
downloadUrl | String | The URL to download the results of this request when it completes |
Sample Code
var xhr = new XMLHttpRequest();
xhr.open("GET", `http://BASE_URL/support/v1/readers/logs/requests`, true);
xhr.requestHeaders("Content-Type", "application/json");
xhr.requestHeaders("Authorization", "Basic ENCODED_USERNAME_PASSWORD");
xhr.send();
string username = "CurrentUser";
string password = "CurrentPassword";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
Uri uri = new Uri("http://BASE_URL/support/v1/readers/logs/requests");
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Headers.Add("Authorization", "Basic "+ encodedCredentials);
request.Method = "GET";
request.ContentType = "application/json";
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Get Reader Logs
Download the last export of the reader logs for use by Impinj customer support. Reader log exports are kept for 4 days.
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/support/v1/readers/logs/download
Response
A compressed tar.gz file
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/support/v1/readers/logs/download", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/support/v1/readers/logs/download);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
Export ItemSense Configuration
Download an export of the ItemSense internal configuration for use by Impinj customer support.
Authorized Roles
ConfigManager, Admin
HTTP Request
GET http://BASE_URL/support/v1/configuration
Response
A compressed tar.gz file
Sample Code
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://BASE_URL/support/v1/configuration", true)
// Set authorization headers
xhr.send()
// Encode credentials
string encodedCredentials = ...
Uri uri = new Uri(http://BASE_URL/support/v1/configuration);
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(uri);
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Basic "+ encodedCredentials;
HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
HTTP Return Codes
ItemSense API returns the following HTTP codes:
Code | Meaning |
---|---|
200 | Request was successful |
202 | Request was successful. Use the "Location" header to obtain status on the request. |
204 | Request was successful but there is no response body. Returned in response to delete requests. |
400 | Bad Request |
401 | Unauthorized |
403 | Forbidden |
404 | Not Found |
405 | Method Not Allowed |
406 | Not Acceptable -- the requested format was not JSON |
500 | Internal Server Error -- there was a problem with the server. Please try again later. |
503 | Service Unavailable -- server offline for maintenance. Please try again later. |
User Guide
Introduction
Impinj® ItemSense™ is a software platform that simplifies management and monitoring of RAIN RFID infrastructure by providing a graphical user interface (GUI) and simple-to-use APIs.
The functionality of Impinj ItemSense can fulfill many use cases. For example, ItemSense can discover an item’s identity and location, which can then be used to manage a retail store inventory or to locate items within a medical facility.
Impinj ItemSense has the ability to:
- Define RAIN RFID readers and organize them into logical groups
- Monitor the health of the readers
- Discover the identify and location of tagged items and track them
- Capture configuration into storable units
- Apply a predefined configuration to the readers during the execution of jobs
- Collect tag data and make it available for use by upstream applications
These capabilities and how to use them are discussed in this document along with some concepts.
RAIN RFID
RAIN RFID is a global alliance promoting the universal adoption of UHF RFID technology, comparable to other wireless technology organizations such as the Wi-Fi Alliance and Bluetooth SIG. RAIN uses the GS1 UHF Gen2 protocol which ISO/IEC has standardized as 18000-63. The word RAIN, which is an acronym derived from RAdio frequency IdentificatioN, is intended to emphasize the link between UHF RFID and cloud computing, as RFID-based data can be stored, managed and shared via the Internet.
Tags, Readers and Gateways
An RFID tag is the device that allows an item to be tracked once it is attached to an item. A tag is made up of two parts:
- An integrated circuit (IC), which stores information about the tag and processes the RF signals it receives
- An antenna, which receives and transmits RF signals
A reader, when paired with one or more antennas, can send and receive information to and from RAIN-compliant tags.
A gateway comprises a reader and one or more antennas integrated together into a single device. The Impinj xArray® gateway can perform extra functions like the calculation of tag locations, which ItemSense is able to utilize and augment with data from adjacent xArray gateways deployed within the same RFID infrastructure.
Throughout this User Guide the terms reader and gateway shall sometimes be used interchangeably. Nevertheless, the distinction between the two terms should be understood.
Regulatory Regions
Regulations in different countries apply restrictions on the UHF frequencies that can be used, the power at which they are transmitted, and the durations of the allowable signals. Impinj manufactures and certifies readers specific to each supported regulatory region.
Impinj ItemSense can manage the following regulatory regions:
- United States (FCC)
- Europe (ETSI)
- Japan
- China
- Singapore
Capabilities
ItemSense supports the primary capabilities of RFID including inventory, real-time presence detection, and location.
Inventory
In RFID, an inventory is the act of performing a read of all the tags within the field of view of all the gateways or readers used by ItemSense. During this read, the details about the tags in the field of view are discovered. These details typically include the Electronic Product Code (EPC) which is conventionally a unique product code encoded into the EPC memory of the tag IC.
An inventory is performed by using a special Search Mode which tells the tag to stop communicating with the reader once the tag has been read. One by one, each tag is read and silenced until all readable tags have been read. Silencing tags once they are read reduces signal interference. Less interference enables the reader to communicate more effectively thereby allowing a higher percentage of tags in an area to be read.
Reading tags in an area is probabilistic rather than deterministic. This means that performing two inventories on the same set of tags within the same area using the same Inventory settings, might yield different results. This is due to RF communication being influenced by many transient factors. Describing these goes beyond the scope of this guide. However, some of the primary factors which determine reader quality and consistency are:
- Number of tags being read simultaneously
- Distance the tag is from the reader
- Strength of the RF signal from the reader
- Interference from other RF signals
This could be from other RF equipment in or near the reader. This is especially so if those devices are operating on the same or similar frequencies and channels as RAIN RFID readers. - RF reflections
Some surfaces (like metal) in a room can cause RF signals to bounce off them. - Material (or substrate) to which the tag is applied
Some materials can absorb RF which weakens a tag's ability to both receive and transmit RF. - Angle of the tag to the reader
This is rotation of the tag around the X or Y axis (also known as roll and pitch). - Orientation of the tag
This is the position of the tag rotated around the Z axis. Also known as the Yaw. This is important depending on the type of antenna used. Circularly polarized antennas are not affected by the orientation of the tag. - Predefined mode of the reader
This is specified by the Reader Mode property of the reader configuration. Slower reader modes can tolerate more RF interference. - Length of time spent inventorying
A reader or gateway is more likely to find hard-to-read tags when more time is spent inventorying.
ItemSense can control the configuration of each reader it manages. As such, the Reader Configuration used by a reader when performing an Inventory of tags can be tailored to the reader's environment. ItemSense provides full control of a reader. For example, it can set Gen-2 parameters such as Session, Search Mode, transmit power, antenna sequence, tag population, and enable/disable antennas.
Each of these parameters can be used to ensure that a reader picks up only tags that are of interest. To ensure that only tags of interest are read, the following 3 steps can be considered:
- Adjust the transmit power of the reader or gateway. This lowers the field of view of the gateway so that its read area is more constrained.
- Disable antennas completely. If the above step doesn't constrain the field of view enough or the gateway is positioned near a RF reflective surface, it may be necessary to disable all antennas near that reflective surface, thus minimizing the amount and effect of reflections.
- Use a Gen-2 EPC filter. Within RAIN RFID it is possible to configure the readers to only select tags whose EPC (or indeed values in other memory banks) conform to a specific prefix. This is useful when the tags of interest within the field of view of the reader all share common values within the tag memory banks.
Once a tag has been read, ItemSense will enrich the tag report with other information it knows about the tag before (optionally) storing the tag report in its internal database ready for querying at some later point.
For more information about performing an inventory of tags, please refer to the Gateway Deployment guide which can be found on the support website.
Real-Time Presence Detection
The real-time presence detection function within ItemSense is very similar to the inventory function except that a different searchMode
is used so that the tags are never silenced. They are continuously read, thus allowing an application to have real-time knowledge about a whether a tag is in a particular area. Since no tags are silenced in this mode, fewer tags can be monitored in real-time than can be inventoried.
Location
Another primary use case supported by ItemSense is determining tag location.
Initial XY position of a tag is calculated by the Impinj xArray gateway. Multiple xArray readers can calculate XY positions for the same tag. ItemSense can combine this data to enhance the location accuracy of the tag. ItemSense will then use the calculated locations of tags to generate configurable custom events based on movements of the tag.
These events could be:
- When a tag has moved a specific distance
- When it has crossed a geographic threshold known as a zone boundary
The location of a tag cannot be calculated with 100% accuracy; there will be some error between a tag's calculated position and its actual position so the tag’s estimated location will vary with each calculation. This is known as jitter, because it causes a tag's location to apparently pop around. The greater the error, the greater the jitter.
Location accuracy and the amount of jitter depend on many factors. These are typically:
- Number of xArray readers
When multiple xArray readers calculate XY positions for the same tag, ItemSense can increase the number of readings for that tag and use this data to provide a more accurate location estimate (i.e. reducing jitter). - Distance of tag from the center of an xArray
An xArray can provide a better determination of a tag's position if the tag is close to the antenna. (However, the tag must be at least one meter from the xArray.) The xArray determines a tag's position based on the number of times a tag's RF signal is received by each antenna. The further away from the xArray a tag is, the greater the error margin in the calculated position of the tag. In other words, the further the tag is from the center of an xArray, the greater the jitter. - Reflections in an environment
Certain materials (or substrates) can reflect a tag's backscatter, which affects the transmission of the tag's response to a reader. - Absorption of RF
Similar to the above point, certain substrates can absorb backscatters from tags causing them to be read by an xArray less frequently than what is optimum for calculating its position. - Predefined mode of the reader
This is specified by the Reader Mode property of the reader configuration. Calculating the position of a tag requires as many reads possible of that tag. The reader mode affects the [data rate] Reader Mode of the communication between the antenna and the tag. The faster the reader mode, the better. However, fast reader modes are more affected by the RF environment. - Speed of the tag as it moves
If the tag is moving, then the count of reads by each antenna will be reduced. The faster the movement of the tag, the fewer the reads, making it more difficult to calculate an accurate XY position and resulting in higher jitter. The more static a tag, the better the final calculation of its location. The jitter caused by a moving tag can be mitigated by increasing thecomputeWindow
in ItemSense set in a recipe. ThecomputeWindow
is the time span over which the xArray and ItemSense aggregates tag reads used for a location calculation. A tag's location is only calculated at the end of thecomputeWindow
. LongercomputeWindow
periods produce more accurate tag positions, but the longer thecomputeWindow
the longer it will take to calculate the position of a tag.
To correctly position a tag on a floor, ItemSense needs the XY coordinates (in meters) of each xArray on the floor, relative to a chosen origin point (0,0). For more information on how to do this, please refer to the Gateway Deployment guide which may be found on the support website.
Threshold Monitoring
Threshold monitoring detects when an item has crossed a point, or threshold, and the direction in which the item was moving when it crossed. The threshold is typically a border between areas of a facility. Threshold monitoring allows items to be tracked as they move through the supply chain. In a typical scenario, a loading dock in a warehouse can be monitored to track items going into or out of the warehouse.
When an item crosses a threshold, the item's tag is read, and a transition event is generated to record the item's transition from one area to another. These events can be collected via the API or put in a queue to be consumed by a client. An event includes the following information.
- Name of the threshold that is crossed
- Unique identifier of the threshold
- Time of day that the transition occurs
- Direction, in or out, the item is moving as it crosses the threshold
- Electronic product code (EPC) of the item's tag
- Calculated confidence level that the item made the transition
Setting up a threshold to be monitored requires a reader and some configuration in ItemSense. Some parameters such as threshold name, IN and OUT directions, and other necessary details are defined by the user in ItemSense. In a usual scenario, many tagged items simultaneously cross a threshold; however, only a limited number of tags can be read at a time. To limit the number of tags read, an EPC filter is set to distinguish between the tags of different types of items thereby allowing the undesired tag readings to be filtered out. For example, if a tagged pallet is loaded with tagged cartons and each carton contains individually tagged items, an EPC filter can filter out all tags except the pallet tags. See the threshold setup section for instructions.
Readers must be positioned near a threshold in one of three arrangements:
- Overhead: A reader is centered directly above the threshold
- Side*by-side: A reader is placed on each side of the threshold facing inwards
- Overhead offset: A reader is placed above the threshold at each edge
For threshold monitoring, the reader must be either an xSpan gateway or an xArray gateway, depending on the reader arrangement. Either type of gateway can be used in the overhead or side-by-side arrangements, but the overhead offset arrangement requires an xArray gateway.
When choosing a reader arrangement, two factors to consider are the dimensions of the threshold and the number of adjacent thresholds. A single overhead reader can cover a ten-foot-wide threshold. An additional overhead reader can be added if a threshold is wider than ten feet. A side-by-side reader can be double-stacked on either side of the threshold to increase coverage. An overhead offset reader can cover two adjacent thresholds; see Overhead Offset Arrangement for more details. The following figure shows the three reader arrangements for threshold monitoring.
Another factor to consider is the position of the tag on an item. When tags are positioned on top of an item, the overhead arrangement must be used. Either the side-by-side or overhead offset arrangement can be used when tags are positioned on the side of an item.
Additional factors to consider when choosing a reader arrangement for threshold monitoring are the number of tagged items simultaneously crossing a threshold, the speed of the items as they move across a threshold, and the cost of the reader arrangement.
Overhead Offset Arrangement
An overhead offset arrangement is typically used with multiple, adjacent thresholds, as the most efficient way to maximize coverage. In this arrangement, each reader is positioned between two thresholds and each threshold is configured to use two readers.
Each reader is configured with two of four possible configurations.
- xArray Offset Left and xArray Offset Left End cover the left side of the threshold.
- xArray Offset Right and xArray Offset Right End cover the right side of the threshold.
Each tag in the overhead offset arrangement is read by two xArray readers as it moves through a threshold. However, unlike readers placed in a side-by-side arrangement, readers placed in an overhead offset arrangement can fill two roles, as shown in the image below. In that image, Reader B is used twice, both to cover Threshold 1 from the right and to cover Threshold 2 from the left.
The exception is that a reader positioned at the end of a line of thresholds/readers is used only once, configured either as xArray Offset Right End or as xArray Offset Left End. Again, this is illustrated in the image below.
Laying out infrastructure
ItemSense simplifies the management of an RFID infrastructure. There is a small set of terms which are used to help group together related readers, such as a set of xArray readers, for example, into a given physical area. It also allows for the enrichment of tag reports based on knowledge ItemSense has about the reader which reads the tag. For example, if a reader in facility "Building 1" and on floor "12" read the tag, then this information can be added to the tag report and used by an application to perform business logic based on that information. The terms used to map a physical infrastructure include facility, floor, and zone.
Facility
A facility currently represents the largest area concept, and single or multiple facilities may be defined within ItemSense. Although analogous to a physical building, the user has final determination of what constitutes a facility in their deployment, and must specify a name when defining a facility, either via the HTTP API or through the ItemSense Management Console. This is the facility's primary (and only) identifier.
ItemSense comes with a single, pre-defined facility, named DEFAULT. Readers added to an instance of ItemSense must be defined with a valid facility, either DEFAULT or a name assigned by the user.
Floor
One facility can have many floors associated with it, each floor representing a level within the facility. Note that floors are not defined as distinct entities within ItemSense, nor are they directly associated with a facility. Instead, floors are tied to facilities via a reader's placement
value which is part of the readerDefinition
profile for the reader.
If a floor name is not specified, or if the placement configuration within the reader definition is not specified, the floor name defaults to the facility name. If, however, the floor name is specified, the reader definition exists on that floor within the given facility. In either case, readers are given a floor
name as part of their placement and are part of a facility.
The reader's floor or facility definition can be updated via the createOrReplace
API.
Zone
ItemSense supports the concept of a zone, which is a named area of a facility. For example, a retail store floor plan may be divided into constituent departments. When ItemSense is configured with zones, tag data is presented with an additional “zone” field that identifies the specific zone on a specific floor in which ItemSense read a tag. Zones are tied to a floor in facility via zone configuration i.e. a zone can be part of a facility and a floor.
A zone should break up the space in a facility in a way that is meaningful way (e.g. Men’s, Women’s and Shoe departments in a retail store). Zone names do not have to be unique. If more than one zone definition has the same name, then the spaces of the two (or more) physical areas in a facility are combined into one logical zone (e.g. Women’s Shoes might be on the 1st floor and Women’s dresses on the 3rd floor; these could be combined into a “Women’s Clothing” zone). However, Zones cannot be layered such that the same physical space could be given more than one Zone name.
It is not necessary to define zones for the entire space in a facility. When ItemSense reads a tag, it gives the tag the zone name "FACILITY" if the tag is outside of any defined zones. The zone name "ABSENT" is given to a tag that has not been read for a defined period.
There are two types of zones; antenna zones and geographic zones.
-
Antenna Zone: An antenna zone is defined by the field of view of an antenna attached to a reader or a gateway. Anything read by that antenna is determined to be in an antenna zone. An antenna zone can have a string name associated with it. This string name augments the ItemSense tag report to reflect the antenna zone in which the tag was read. If the antenna is not assigned a zone name, its zone name defaults to the reader zone name.
The primary advantage of an antenna zone is that it can be defined on any type of reader. However, the zone size depends on RF environment and reader power. The size of the zone becomes smaller with a decrease in the power of the reader. As a result, antenna zones can be somewhat non-deterministic. To mitigate the variability, test the targeted space thoroughly to determine the correct power for the use case.
Antenna zones are defined within the reader definition.
-
Geographic Zones: A geographic zone represents a fixed area of physical space. A geographic zone consists of a name, a facility, an optional floor name, and a set of Cartesian coordinates to define its shape. Each coordinate specifies a vertex of the shape. The vertices must be in an order that describes the polygon’s borders (i.e. points next to each other in the list must share an edge of the polygon). Each XY increment represents 1 meter of physical space. Zones are defined in meters but can be specified down to the centimeter (0.01m).
Geographic zone sizes are fixed. They are not affected by the RF environment or by the reader's RF signal power. They can span multiple readers or be within the field of view of single reader. ItemSense requires a tag's estimated XY coordinates to determine whether it's in a particular geographic zone. Currently, only the Impinj xArray gateway can utilize geographic zones using Location Mode.
Geographic zones within ItemSense are created within a zone map. A Zone Map is used to group together one or more geographic zones. Many Zone Maps may be defined but only one at a time may be applied to a facility.
Zone Usage Practices
Antenna Zones Vs. Geographic Zones
Generally, if accurate control of the shape and size of a zone is a priority, it is better to use Geographic Zones over Antenna Zones. This is because Geographic Zones:
- Allow for zones to be drawn which accurately reflect a physical space such as "Men's Department".
- Utilize multiple readers in an RFID infrastructure. Geographic Zones are agnostic of the readers. This means if one reader isn't available, the zone still persists.
- Use Location mode, which means an XY location of an item can be provided along with zone information.
However, there are cases where using an Antenna zone is more appropriate. These could be:
- When xArray gateways are not available. Geographic zones require XY locations to be calculated, which is a capability currently limited to the xArray gateway, and without which Geographic zones cannot be used.
- When an xArray cannot be placed where you want to place it. There are some cases where an xArray cannot be placed where it is required for complete coverage of a certain area. This could be, for example, because the building in which the xArray would otherwise be placed already has other infrastructure (such as venting or piping) there.
- When there are too many tags for Location mode. This is typically when ItemSense receives over 10,000 tag reports per second. More tag reports are generated when there is an "active" tag population i.e. when tags are actively moving. These limits put an implicit restriction on the amount of tags which can be accurately tracked simultaneously. This is because calculating a location requires many readings of each tag. If a larger amount of tags requires tracking than is possible by a single gateway, an antenna zone may be used.
- When a contained space such as a set of shelves or a cabinet needs to be monitored.
- When xArray readers and non-xArray readers are part of the same job. As the xArray reader supports Inventory mode but a non-xArray reader, such as the Speedway reader, doesn't support location mode, it is only possible to use Inventory mode when non-xArray readers are part of a job. Only Antenna Zones are supported in inventory mode.
- When an xArray can’t be used due to the shape of the room. Thin rooms or rooms with low ceiling heights are not ideal environments for xArray readers. It is often possible to get better item positioning with a well-placed antenna attached to a Speedway reader combined with an Antenna Zone.
Geographic Zone Best Practices
It is possible for jitter to occur when monitoring the XY position of a tag. As the Geographic Zone feature uses the XY position of a tag to determine which zone a tag is in, it may be affected by jitter. If a tag is on a zone border, the tag can be seen to flip flop between one zone and an adjacent zone. Querying the Items table will reveal this is happening as it will show a tag changing zones quickly. This will also cause many zone change events to be generated in the Item History table or on a message queue. There are a few ways that this can be mitigated:
- Ensure a tag doesn't rest closer than the average jitter distance to a zone boundary. A rule of thumb for this is about 1.5 meters.
- If a tag is moving across a zone boundary, when it is near the boundary the zone flip-flopping between zones can occur but will stop again when it moves away from the zone boundary. In an upstream system which consumes tag events, a time-based buffer can be implemented to store several tag events before determining whether a tag has transitioned or is just sitting on a zone boundary.
- Between two adjacent zones, a transition zone can be introduced. This is a new zone which represents a border between the zones on either side of it. For example, between a zone named "Zone A" and a zone named "Zone B," a third zone is introduced, called "Zone A or B". If tag jitter is around 1.5 meters, then this zone should be at least 3 meters wide. The benefit of this extra zone is that when a tag flips between "Zone A" and "Zone A or B", it is definitely in Zone A and not in Zone B. However, the logic to determine this must be implemented in the upstream system that gathers the zone change data.
- Adjust the
minimumMovementInMeters
parameter in a location recipe. This parameter prevents location changes being report if they are below a certain distance. If possible, always set this value to just above the average jitter amount. For example, if the average jitter of tags is 1.5 meters then this value can be set to 1.7 meters. This would almost eliminate jitter. However, doing this also reduces fine grain location tracking so using the attribute is a balance between how detailed the tracking of tag is required versus how stable the tag reports should be.
Antenna Zone Best Practices
When Antenna zones overlap each other, ItemSense can perform zone disambiguation to determine which Antenna zone contains a tag. To help ensure the accuracy of this, antenna zones should overlap as little as possible. Use a combination of antenna type, antenna position, and reader RF signal power to confine the antenna's field of view to the exact area needing to be monitored.
A drawback of using Antenna Zones is that they don't provide an XY position of a tag. In addition to this, if the Antenna zone is associated with a Speedway reader, there will not be floor information for the tag as it is not possible to set the placement
attribute on a Speedway reader. The reason for this is, unlike gateway readers, that the antennas attached to a Speedway could be on different floors or in different locations thus the placement information of the reader provides no insight to where a tag was read. However, it is possible to add this information to a tag report by employing a strong Antenna zone naming convention. The name of the Antenna zone is defined per antenna so antenna specific information can be embedded into the Antenna zone name. A suggested format could be:
LOCATIONNAME-FLOOR-XY_POSITION
Where:
- LOCATIONNAME: a meaningful name describing the area being monitored
- FLOOR: the name of the floor on which the antenna is situated
- XY_POSITION: the position at the center of the space being monitored
Example: cabinet1-12-2.1_3.5
This information is then provided in a tag report in the zone
field and made available to upstream consumers of the data. Upstream systems can then parse the zone name to extract the position information.
Security
The following security measures are used for the Impinj platform, which comprises RFID readers, ItemSense software, and other hardware components.
- It is expected that the Impinj platform is deployed on the premises behind a firewall so that the system is not exposed to an external network.
- Each reader has a one-to-one connection with a single instance of ItemSense and communication between the reader and ItemSense is over HTTPS. See the Reader Agent section for details.
- Each reader is password-protected. The default password of a reader can be changed by using the RShell command, config, as described in the RShell Reference Manual (can be downloaded from the Impinj Support Portal).
- A user is authenticated in API calls, AMQP registration, and communication with the IMC, as described in the Authentication section of the Reference Guide.
- User roles are used to control access to various parts of the system, as described in the Users and Roles section of the Reference Guide.
Configuration Model
Reader Definitions
Reader Definitions hold ItemSense's knowledge about all the readers it manages in an RFID infrastructure. Each definition is a profile of a single reader. This includes:
- IP address of the reader
- eleven-digit serial number (xxx-xx-xx-xxxx) of the reader
- name assigned by Impinj to the reader. For example: xArray-11-41-D9
- reader type, which ItemSense uses to provide reader-specific functionality and to validate reader configurations
- reader placement, specified by X-Y coordinates and angle
- reader zone, which ItemSense uses as the default zone for a tag that isn't part of an antenna zone
- antenna zones, which specify the mapping between a zone and an antenna of the reader
- features, such as Antenna Hub, that are enabled on the reader
Reader Configuration Profiles
Reader configuration profiles allow a user to capture a set of configuration parameters. This provides the ability to define the ideal configuration for a reader and save it for subsequent use. This profile can be given a meaningful name which typically describes the intended use of the configuration e.g. "Warehouse1-deepscan-inventory". ItemSense provides default configurations out of the box. These defaults provide the typical settings for performing location or inventory jobs.
Recipes
The term "recipe" associates the reader definitions with the appropriate reader configurations for a given use case. It is comparable to a cooking recipe, which provides both ingredients and instructions for creating a food item.
Recipes should be created when:
- the kind of operations ItemSense is needed to perform are understood
- the necessary reader configurations to run that operation has been defined
- the reader definitions for the readers, on which the operation will be run, have been created
In ItemSense, Recipes map reader configurations onto individual reader definitions, and specify other parameters relating to the intended operation. A default reader configuration may be applied to all readers within the facility unless overridden by a specific reader configuration.
Jobs
Once a recipe has been defined it must be run. This is done as part of a job. A job can be scheduled to start after a set delay. This is particularly useful when performing inventories of tags as it gives the tags a chance to failover to their previous state. The duration of a job must also be set.
When a job is run, many actions take place within ItemSense. The following are the steps of a typical successful job run:
- ItemSense is told to start a job.
- ItemSense waits for the duration specified in the
startDelay
. - Once the job start duration has passed, ItemSense passes each reader their configuration as specified in the Recipe.
- If the configuration passed to this reader is correct for the reader, the job will now be in the "RUNNING" state which means each reader is performing its requested task.
- Tag data is received by ItemSense from each reader.
- Depending on the type of job being run, ItemSense will then:
- aggregate location data from multiple readers
- add zone information to the tag data
- add facility and floor information to the tag data
- begin tag presence expiry timers
- ItemSense will calculate any events (like a zone transition) based on the new information about the tag.
- ItemSense will make the tag data available in the Items table. This is optional and can be set before starting the job.
- ItemSense will make the tag data available in the Item History table. This is optional and can be set before starting the job.
- ItemSense will publish events on any configured event queue. This is optional and can be set before starting the job.
The state of a job can be queried via the HTTP API or seen in the IMC. The information shown includes metadata about the job (e.g. start time, duration), any errors which have occurred during the job and the current status
of the job.
It is often necessary for an application to perform different actions based on the current job status
. This field represents the state of the job. A job, throughout its lifecycle, goes through several states. The following diagram shows how a job transitions between each state:
The jobs states are:
- WAITING: Once a job has been requested to start, the job waits for the period specified in the job start delay. If the start delay is 0 then the job will instantly transition to the INITIALIZING state.
- INITIALIZING: The job manager initializes within ItemSense and waits for the RDE to start. ItemSense sets an initialization timer to 1 minute. If there is some problem starting the tag data manager (called the Reader Data Engine or RDE), ItemSense will reset the initialization timer and retry. It will do this up to 4 times. If the RDE still hasn't started, an error is raised, and the job goes to the STOPPING state. Otherwise, ItemSense will send each reader its configuration and wait for an acknowledgment.
- STARTING: The job is in this state until either each reader has acknowledged the job start or a reader hasn't responded to the job start. If all readers don't acknowledge the job start, then the job moves to the STOPPING state. Otherwise, the job duration timer is now started, and the job moves to the RUNNING state.
- RUNNING: ItemSense will stay in this state until the job has run for the requested duration, at which point the job moves to the STOPPING state. If the RDE fails while in the RUNNING state, the job moves to the RESTARTING_RDE state.
- RESTARTING_RDE: ItemSense will attempt to restart the RDE up to four times. If the RDE still hasn't started, an error is raised, and the job goes to the STOPPING state. Otherwise, the job goes back to the RUNNING state.
- STOPPING: When entering this state ItemSense will attempt to stop any running readers and shut down the RDE. Once all readers have responded, the job moves to the STOPPED state.
- STOPPED: The job is complete.
If connectivity cannot be established with one or more readers during the job starting phase, ItemSense retries for a period of 4-5 minutes (depending on RDE initialization time) before giving up and failing the job.
If connectivity is established with all readers within that period, then ItemSense connects to the reader and the job starts.
Job Best Practices
There are some behaviors and best practices which are useful to know, and should be considered, when using ItemSense's job feature:
- When querying for data, it is good practice to check if a job is running: If no job is running, the data can be stale which can impact data quality for a use case. Also, when starting a job, ensure that the job makes it all the way to a running state without errors.
- Always ensure a job has completely stopped: This can be done either via the IMC or by querying the job status API for a job status of "STOPPED".
- Always monitor a job for errors: As it is possible for various types of errors to occur during a job, a job must be monitored for errors.
- To implement constant real-time monitoring, jobs with infinite duration are preferred: However, there are some caveats to this. When a reader, which is part of a job, drops from the job (due to it either going down or losing network connectivity etc.), it will be not automatically re-added to the job when it comes back up. To successfully use the infinite job run feature of ItemSense, a job monitor is required to detect when a reader has dropped, determine when it's available again and restart the job when it is.
- If constant jobs aren't required, implement a job scheduler: This scheduler should start and stop jobs. It should also handle starting one-off jobs at a scheduled time as well as repeat jobs which need to be started at the same time every hour, day, week, etc. This allows for jobs to be configured to solve multiple use cases over a 24-hour period. In retail, this could be a deep scan inventory outside of store hours and real time location during store hours.
-
If starting multiple single-target session 2 or 3 inventory jobs back to back, remember to allow time for the tags to de-energize: When using single target session 2 or 3, tags are put in their "B" state which means they aren't able to be inventoried. They don't revert to their "A" state until after a certain amount of time. For more information about this refer to the Reference Guide. The job start interface has a
startDelay
which allows for a job to be started after a certain wait time. This delay should be greater than the tag persistence time of the tags being used. - Readers need to be instructed to stop by ItemSense: If a job has been started by ItemSense but then ItemSense or its host goes down, the reader shall continue to run the job until it is either rebooted or ItemSense comes back up and issues a stop command. Stopping the ItemSense Docker container will not stop a reader from running a job. When ItemSense comes back up it will continue the job from the time it went down. For example, if a 120 second job was started and after 30 seconds ItemSense goes down for a period of time, when ItemSense is restarted, the job will continue for another 90 seconds.
If an ItemSense restart occurs during a job, an error message is be displayed in the IMC and in the response to a job status request. This error message indicates that the RDE will need to be restarted. This is just an informational message as ItemSense does this automatically. There also may be HTTP_FAILURE health events which the readers will generate when ItemSense goes down and forward to ItemSense when the connection is restored. If all the readers are communicating with ItemSense and the job is in the RUNNING state, the job is working correctly, and no action needs to be taken. Otherwise, the connection errors need to be diagnosed and the job should be restarted. Please see the Health Monitoring section for more information about how health events work.
Items Table
This is the table within ItemSense that holds the known details of an individual tag at the time it is read. There is one entry in this table per EPC read by ItemSense. The table also holds the facility name and the observation time (which in the API is called lastModifiedTime
). If the tag is continuously being read (i.e. a job is running and the tag is present), the lastModifiedTime
is updated on an interval specified by tagHeartbeatDuration
. If a job is not running, the lastModifiedTime
shall be updated next time a job is run.
In addition to the parameters mentioned above, if running an inventory recipe:
- The
zone
field will be updated with the antenna zone name. If no antenna zones have been defined, this will be thereaderZone
parameter from within thereaderDefinition
of the reader which read the tag.
If running a location recipe on an xArray:
- The
xLocation
andyLocation
fields will be updated. - The
zone
information will be updated with geographic zone name. If no geographic zones have been defined, then this field shall be set to the literal string 'FACILITY'.
Each tag report has a presenceConfidence
parameter. This has been deprecated; it is still present in the table for backwards compatibility but is always set to the literal string 'HIGH'.
Item Table Size
The Items table can have up to three days' worth of item data, depending on the size of the hard drive attached to the server on which ItemSense is run. The following table describes when each table size will be available:
Percentage full | Days of Records |
---|---|
0% | 3 days |
90% | 2 days |
99% | 1 day |
As an example, the top line in this table can be read as: If the hard disk is between 0% and 90% full, ItemSense will store up to three days' worth of Item data. Data older than 3 days will be removed.
ItemSense will check the size of the table on three-hour intervals. All table pruning is performed silently.
Item History Table
The Item History Table effectively captures movement events for tags. By default, the table captures changes to the following fields:
- Zone
- Facility
- Floor
- X Location
- Y Location
The Item History table record captures the "from" and "to" value for each of these parameters. For example, there are a fromX
and toX
parameters or fromZone
and toZone
. Note that location information will not be populated for Inventory jobs.
In addition to the above fields, this table also captures the EPC and the observation time of the tag. It is typically used to track the history of tag movements within a monitored facility.
Item History Table Size
The Items History table can have up to 180 days' worth of item data. This is dependent on the size of the hard drive on which ItemSense is run. The following table describes when each table size will be available.
Percentage full | Days of Records |
---|---|
0% | 180 days |
25% | 150 days |
50% | 120 days |
75% | 90 days |
85% | 60 days |
90% | 30 days |
95% | 14 days |
99% | 7 days |
As an example, this table can be read as: If the hard drive is between 25% and 50% full, ItemSense will store up to 150 days' worth of Item History data. Between 50% and 75%, ItemSense will store up to 120 days' worth of data, and so on.
ItemSense will check the size of the table on three-hour intervals. All table pruning is performed silently.
Interacting with ItemSense
A user can interact with ItemSense as follows:
- Directly through the ItemSense API.
- Through the ItemSense Management Console (IMC) graphical user interface (GUI).
- Using event message queues.
ItemSense API
The ItemSense API is a REST-like API used both to configure ItemSense and attached readers, and to configure mechanisms for retrieving collected item data. The API is divided into the following sections:
Endpoint | Description |
---|---|
authentication | Used to manage access tokens to ItemSense. |
configuration | Used to configure various parts of ItemSense including, reader definitions, recipes, zone maps, and facilities. |
control | Used to manage jobs including start a job, stopping a job and querying for running jobs. It is also used to control software updates on the readers. |
data | Used for querying tag data including the current status of a tag as well as the history of events around a tag. |
health | Used to for querying the current status of a reader as well as the history of health status change events. |
For more specific information, please see the ItemSense API Guide.
ItemSense Management Console (IMC)
The IMC is a web-based GUI application that provides a clean graphical interface to almost all of ItemSense's functionality, including but not limited to:
- Reader management
- User management
- Job control
- Tag item history
- Reader health
- Event queues
For more detailed information on the IMC, please refer to the ItemSense Management Console Guide.
Event Message Queues
Rather than send a request for data at specified intervals, you can configure a message queue to notify you when a particular event occurs. To create a message queue, you define your event broker, then configure event publishers that will send messages to that broker. Event publishers can be reconfigured even after the job begins running. It can take up to 30 seconds for ItemSense to see the changes.
A message queue is useful when:
- You want to be notified of changes to tags in real-time.
- The network traffic of a short polling interval isn't acceptable.
- You prefer to get notification of changes to tags rather than calculate deltas for each poll.
Event Message Queues can be implemented using the ItemSense Event API, which can be accessed directly or through the IMC. To access message queues through the IMC, from the top navigation bar, click More | Event Configuration. This will take you to the Publishers page. From there you can configure your publishers, or click the Brokers tab to configure your broker.
ItemSense provides support for event messaging through a variety of mechanisms:
Preferred:
- Sending events to an external, user-provided AMQP or MQTT message broker. (This is recommended for high-volume tag deployments.)
- Sending events to a user-specified URL using Webhook invocations.
- The retrieval of events, by the user application, from AMQP and MQTT queues that are provided through an ItemSense built-in message broker.
Not Recommended: Retrieving events through the ItemSense Items API
, which has been deprecated as of 2.1.0.
Protocols
Following is a brief overview of how ItemSense interacts with the protocols to create message queues. It is expected that you will have a working knowledge of these protocols, as an in-depth exploration of their functionality is beyond the scope of this documentation. We have, however, included links to outside resources for your convenience.
AMQP
- ItemSense supports AMQP version 0.9.1.
- Every message sent by ItemSense to the AMQP broker will have a routing key.
- If you specify a prefix or suffix, the values will be combined with the type of message.
- If you specify a full routing key, the full routing key will take precedence. All messages sent to the broker by the publisher will contain the full routing key rather than the prefix, suffix, or event type.
- If using the internal AMQP broker, you cannot specify an exchange with an "impinj" prefix.
- If connecting to an external broker, it is assumed you have already created the exchange.
- The connection to an external exchange will be passive.
- In order to connect to the ItemSense built-in broker, users must have either the DataReader or Admin role and supply their credentials from an account created within ItemSense.
Other resources:
MQTT
- ItemSense supports MQTT version 3.1.1.
- Every message that ItemSense sends to MQTT will have a topic, which the broker uses to filter messages for each connected client.
- If you specify a prefix or suffix, the values will be combined with the type of message.
- If you specify a full topic, the full topic will take precedence. All messages sent to the broker by the publisher will contain the full topic rather than the prefix, suffix, or event type.
- The internal MQTT broker supports QoS levels 0 and 1 only.
- In order to connect to the ItemSense built-in broker, users must have either the DataReader or Admin role and supply their credentials from an account created within ItemSense.
Other resources:
Webhook
- Webhooks should not be used for configurations that produce more than 500 tag reports a second. MQTT and AMQP are more scalable.
- It is important to factor in network latency and HTTP response time when using a webhook. If the receiving webhook is slow, the ItemSense message buffer will overflow and data may be lost.
- Every message sent by ItemSense to the WEBHOOK broker will specify a path.
- If you specify a prefix or suffix, these values will be combined with the type of message as the path.
- If you specify a full path, that path will take precedence. All messages sent to the broker by the publisher will contain the full path rather than a prefix, suffix, or event type.
- The authentication type can be Digest or Basic .
- If "QUERY_PARAM" is specified when messages are sent to the web server, a query parameter named "messageType" will be appended to the HTTP POST Request URL. For example: "http://hostname.foo.com/my_specified_path?messageType=HEALTH"
- We will attempt to utilize an HTTP persistent connection. https://en.wikipedia.org/wiki/HTTP_persistent_connection
- Every post will be JSON, containing a collection of messages.
- Each post will contain messages of one "type" only.
Other resources: https://en.wikipedia.org/wiki/Webhook
Filters
You can set filters either through the Event Configuration section of the IMC or through the Events API within the body of an HTTP POST request message. Once received and parsed, ItemSense will set up the queue based on the parameters in the request message and reply with details about the queue:
- Request URL
- Queue ID
The client will use these parameters in the reply to connect to the queue and begin waiting for ItemSense to post messages onto the queue. Only those messages that meet the filters specified in the queue setup request are posted.
ItemSense allows you to limit the messages posted to a queue by configuring filters at queue setup. You can filter by three event types:
- Item
- Health
- Threshold
Following are brief summaries of each type. For more specific detail, please refer to the ItemSense API Guide.
Item Events
When configured for Item Events, ItemSense will post a message to the queue for each of the following Item types:
- Item
- Job Name Prefixes
- From Zone
- To Zone
- EPC Prefix
- From Facility
- To Facility
- Zone Transitions
Health Events
When configured for Health Events, ItemSense will post a message to the queue for each of the following Health types:
- CLOCK_SYNC
- HARDWARE_FAULT
- SOFTWARE_FAULT
- LIFECYCLE
- UNCLASSIFIED
- ITEM
- THRESHOLD
Threshold Events
When configured for Threshold Events, ItemSense will post a message to the queue for each of the following parameters:
- EPC Prefix
- Threshold
- Job Name Prefixes
- Direction
Internal Queues
The message queues provided by ItemSense have the following behavioral properties:
- Once a client has requested that a queue be created, ItemSense will create it immediately. It will be marked as durable with a timer of 60 minutes. While a client is connected, no timer is set. The queue will be deleted if no client has been connected for 60 minutes. When a client disconnects, the timer starts from zero again. Messages will be held in memory until a client connects or a queue is deleted.
- A queue can be given a
deliveryMode
parameter that will persist messages to disk. In the case of an outage, this guarantees that no messages will be lost. This will affect system performance due to messages being written to disk. - Messages are persisted inside the docker container. These messages will persist if the container is stopped and started but not if the composition is brought up and down.
- If multiple clients each need to receive the same event messages, a separate queue for each client must be created.
- If multiple clients connect to the same queue, each client will receive messages in 'round-robin' fashion beginning with the client that connected first.
Building Configuration
No matter which method is used to configure ItemSense, it is helpful to first think about the RFID infrastructure that ItemSense is going to manage and how it should be broken up into the physical sections described above. Once that has been done, it's possible to define an actual configuration within ItemSense.
To configure a new ItemSense, follow these steps:
- Configure users with the appropriate roles.
- Add the required facilities.
- Divide the facilities into zones (if applicable). If a geographic zone is required, then create a Zone Map for the zones and give the Zone Map a floor to which it should be applied.
- Add a reader definition for each deployed RAIN RFID gateway. This can be done manually or via the network scanner within the IMC.
- Establish and understand what tag data needs to be collected based on the use case being fulfilled.
- Add the appropriate reader configurations and recipes to collect the tag data established in the step above.
- Configure and start jobs to perform these operations.
- Query tag data via event-based message queues.
- Monitor health of the readers via event-based message queues.
- Update firmware on the readers when necessary using the software management API.
Each configurable resource (i.e. recipes, reader configurations, etc.), the operations that can be performed on that resource, and the returned parameters associated with each operation, are fully defined in the API documentation.
The sections below give configuration guidelines for the most common use cases fulfilled by ItemSense. These values may require tuning for a particular installation.
ItemSense does ship with several default reader and recipe configurations, which may be used for many applications.
For more information on how to set each parameter, refer to the Reference Guide.
Inventory
Goal: to perform an inventory data on a set of static items
Reader Configuration Parameters
- Set
operation
toINVENTORY
- In the
configuration
sub-section:- Set
readerMode
toMODE_1002
if the readers are well spaced, and toMODE_1004
if the readers are densely spaced. Both reader modes will automatically adapt the actual reader mode used to the environment. See the Reader Mode section in the Reference Guide for more information. - Set
searchMode
toSINGLE_TARGET
- Set
session
to 2 or 3. Adjacent readers can use different session values to improve inventory accuracy - Set
antennas
according to the type of reader - Set
receiveSensitivityInDbm
to filter out tag reads. This allows rejection of unwanted reports from distant tags when higher transmit power levels are in use. Values from -70 dBm to -30 dBm are accepted. If no value is specified, it defaults to -80 dBm, which disables the filtering. - If in a fixed frequency regulatory region (such as ETSI), set
channelConfig
to desired frequencies of operation. Adjacent readers can use alternating ETSI channels to avoid interference and improve inventory accuracy
- Set
- If inventorying a large number of tags, set
tagPopulationEstimate
to32
- If inventorying a small number of tags, set
tagPopulationEstimate
to4
Recipe Parameters
- Set
type
to INVENTORY - If all readers have the same configuration, then set
readerConfigurationName
to this configuration. - If different readers require different settings, create a map of reader names to reader configuration names in the
readerConfigurations
parameter - Leave the
reportingInterval
at its default of 5 seconds - Leave the
computeWindow
at its default of 20 seconds
Job Parameters
- Set the
recipeName
to the recipe defined in the above step - If there is more than one facility defined, set the
facility
to the one in which this job will run - Set the
durationSeconds
to the required length of the inventory job. The longer the duration of the job, the more tags are likely to be inventoried.
Location
Goal: to track dynamic items within a facility
Reader Configuration Parameters
- Set
operation
toLOCATION
- In the
configuration
sub-section:- Set
readerMode
toMODE_1002
if the readers are well spaced, and toMODE_1004
if the readers are densely spaced. Both of these reader modes will automatically adapt the actual reader mode used to the environment. - Set
session
to 2 or 3. Adjacent readers can use different session values to improve inventory accuracy
- Set
Recipe Parameters
- Set
type
toLOCATION
- If all readers have the same configuration, then set
readerConfigurationName
to this configuration. - If different readers require different settings, create a map of reader to readerConfiguration in the
readerConfigurations
parameter - Set
reportingInterval
- Set
computeWindow
to a value that is larger thanreportingInterval
. However, a longer computeWindow will also slow down the response time to location changes. - Set
minimumMovementInMeters
to equal the amount of movement above which needs to be reported. The lower this value, the more precision there is in the location data, but this comes at the expense of system load and possibly extra jitter.
Job Parameters
- Set the
recipeName
to the above recipe - If there is more than one facility, set the
facility
to the one in which this job will run - Set the
durationSeconds
to the required length of the location job. If you want this job to run indefinitely, set thedurationSeconds
to 0
Threshold
Goal: to track items moving across a threshold
Reader Configuration Parameters
- Set
operation
toTHRESHOLD
. - Set
configuration.readerMode
toMAX_THROUGHPUT
. - Set
configuration.session
to 2 or 3. Adjacent readers should use different session values to improve accuracy.
Antenna Configuration Parameters
- Set
name
of the new antenna configuration - Each antenna configuration has an optional side of LEFT or RIGHT. This should be empty if is not applicable
- Each antenna configuration has two sets of antennas. These are called in and out and represent the side of the threshold that the individual antenna is facing. All antennas which need to monitor the "in" side of the threshold need to be assigned to the "in" set and likewise for the "out" set.
The following diagram shows the configuration of xArray antennas.
The following diagram shows the configuration of xSpan antennas.
Threshold Configuration Parameters
- Set the
name
of the threshold - Set the
facility
of the threshold, this must be the same as the facility defined for the reader - Set the
readerArrangement
property reflecting the physical arrangement of the readers and threshold:- SIDE_BY_SIDE, OVERHEAD, OVERHEAD_OFFSET, CUSTOM (Impinj internal R&D uses only)
- Set the map of readers to the antenna configuration(s) already defined as part of the antenna configuration
Recipe Parameters
- Set
type
toTHRESHOLD
- Set the threshold IDs of the thresholds you have created that you wish to use for this configuration. If none are specified, all thresholds will be used
- If all readers have the same configuration, then set
readerConfigurationName
to this configuration. - If there are multiple reader configurations with different settings, then create a map of these in
readerConfigurations
- Set custom profile data specifying system behavior. If not specified, defaults will be used.
- If desired, enable iteration data logging, used in tuning. It is disabled by default.
Job Parameters
- Set the
recipeName
to the above recipe - If you have more than one facility, set the
facility
to the one in which this job will run - Set the
durationSeconds
to the required length of the location job. You might want this job to run indefinitely, in which case, set thedurationSeconds
to 0
Multizone per Reader
Goal: to use one reader with multiple antennas to locate items within different zones
Reader Definition
- Map each antenna of the reader to a zone name using the
antennaZones
parameter
Reader Configuration Parameters
- Set
operation
toINVENTORY
- Set
configuration.readerMode
toMODE_1002
, which will automatically adapt the communication frequencies to the environment - Set
configuration.searchMode
toDUAL_TARGET
- Set
configuration.session
to 2 or 3 - Set
configuration.antennas
according to the type of reader - If in a fixed frequency regulatory region (such as ETSI), set
configuration.channelConfig
to desired frequencies of operation - If inventorying a large number of tags, set
tagPopulationEstimate
to32
- If inventorying a small number of tags, set
tagPopulationEstimate
to4
Recipe Parameters
- Set
type
toINVENTORY
- Assuming there is just one reader, then set
readerConfigurationName
to the reader configuration above - Assuming there are a limited number of tags, set
reportingInterval
to a low value. e.g. 1 (second) - Set
computeWindow
to a value that is larger thanreportingInterval
. This is the window over which reads from different antennas will be disambiguated
Job Parameters
- Set the
recipeName
to the above recipe - If you have more than one facility, set the
facility
to the one in which this job will run - Set the
durationSeconds
to the required length of the location job. You might want this job to run indefinitely, in which case, set thedurationSeconds
to 0
Filter for specific EPCs
Goal: to improve RFID performance by filtering on only known EPCs
This configuration can be used for any operation type.
Reader Configuration Parameters
- Set the
tagMask
of thefilter
parameter to the hex value of the EPC prefix that you want to filter on e.g.3034
. By default, this will filter on EPCs that have this prefix. You can make this filtering more general by setting a differentmemoryBank
and/or bitpointer
into memory.
Tag Heartbeat Duration
A change event is defined as either a zone change or a location change over the minimum movement threshold. Heartbeat Duration determines how often ItemSense publishes to the message brokers, or the item and history tables, if the tag is observed but its zone or location has not changed since the last published event. The purpose of Heartbeat Duration is to suppress the amount of unnecessary published records returned during a job run.
Instead of publishing every time the tag is observed, ItemSense publishes only if an event has taken place or if no change has taken place but the Heartbeat Duration has been reached. It can be set via the Recipes API or on the Recipes tab in the IMC. If not set, it defaults to five minutes.
The diagram below illustrates how Tag Heartbeat Duration works. To fully understand what is happening, keep in mind that “reporting interval” means how frequently, in seconds, the reader sends a tag report to ItemSense Core. The illustration can be described as follows:
- The job begins and the tag is reported.
- Every 60 seconds, while the tag is in the field of view, the reader reports on the tag status.
- At 5 minutes, no change events have triggered ItemSense to publish a report, but because the Tag Heartbeat Duration has been set to five minutes, ItemSense publishes that record and the Tag Heartbeat Duration resets.
- At 12 minutes, a change event occurs and ItemSense publishes it.
- At 17 minutes, five more minutes have passed since the last report but no change events have occurred, so the Tag Heartbeat Duration triggers ItemSense to publish a report. This happens again five minutes later, at 22 minutes.
In summary, a report is published only if a tag was observed by the reader and either a change event has occurred (zone change or movement beyond the minimum threshold) since the last published event, or the heartbeat interval has elapsed since the last published event.
Tag Expiration Duration
The Tag Expiration Duration is optional. If set, it determines the time interval between the last time a tag has been observed and the time that ItemSense publishes it as Absent. Its goal is to eliminate, or greatly reduce, false publications of missing tags.
To understand Tag Expiration Duration, you must first understand Tag Heartbeat Duration. Like Tag Heartbeat duration, Tag Expiration Duration is only valid when performing a location operation or a dual-target inventory operation. Unlike Target Heartbeat Duration, it is optional. If not set, tag absence detection is disabled.
The following two examples demonstrate how Tag Expiration Duration works with Tag Heartbeat Duration. These examples are meant only to provide an overview and are relatively basic, involving one tag and one reader. The first example illustrates a straightforward situation, in which no records are published until the tag is recognized as Absent. The second is slightly more complicated, demonstrating more interplay between Tag Heartbeat Duration and Tag Expiration Duration. Both examples use the following parameters:
- Reporting interval: 60 seconds
- Tag Heartbeat Duration: five minutes
- Tag Expiration Duration ten minutes
Tag Expiration Duration Example #1
- The job starts at 0.
- Every 60 seconds, while the tag is in the field of view, the reader records the tag status.
- No event occurs, so at five minutes and again at ten minutes, Tag Heartbeat Duration triggers ItemSense to publish a report.
- At 12 minutes, the tag disappears from the field of view. (This is not considered an event so is recorded but not published).
- For the next ten minutes, the tag is no longer observed, so ItemSense is never triggered to publish.
- At 22 minutes, Tag Expiration Duration recognizes that the tag has been missing for the duration set by the user (in this example, ten minutes).
- At 22 minutes, ItemSense publishes the tag as moving to Absent. It is reported absent as of 12 minutes, because this is when it was first recorded as missing from the field of view.
Tag Expiration Duration Example #2
This example and the illustration that accompanies it illustrate a somewhat more complex scenario.
- The job starts at 0.
- Every 60 seconds, while the tag is in the field of view, the reader records the tag status.
- At three minutes, the tag disappears. (This is not considered an event so is recorded but not published).
- At five minutes, the tag is not observed, so ItemSense doesn’t publish. It is well within the expiration duration, so is not yet considered Absent.
- At six minutes, the tag reappears. Its reappearance is not counted as a change because it falls within the Tag Expiration Duration, but does trigger ItemSense to publish a Tag Heartbeat Duration report because more than five minutes have passed without an event since the last published report.
- At 11 minutes, because no change event has taken place, the Tag Heartbeat Duration triggers a published report again.
- An event occurs at 12 minutes, triggering a ItemSense to publish. This also resets the Heartbeat Duration timer.
- The tag disappears from the field of view again at 14 minutes.
- For the next ten minutes, the tag is no longer observed, so no report is triggered.
- At 24 minutes Tag Expiration Duration recognizes that the tag has been missing for the Tag Expiration Duration (in this example, ten minutes).
- At 24 minutes, ItemSense publishes a report of the tag moving to Absent. It is reported Absent as of 14 minutes, because this is when it was first recorded as missing from the field of view.
Summary
Again, these are fairly simple examples of Tag Heartbeat and Tag Expiration durations and how they interact. A few takeaways:
- The Tag Heartbeat Duration determines when a record is published only if no event occurs.
- By itself, the disappearance of a tag is not considered a change event and ItemSense does not publish it as such. It does not become a change event and published as Absent until/unless it remains outside the field of view for the entire Time Expiration Duration.
- The tag is reported Absent at the end of the expiration duration, but the time reported is the time it first disappeared. So, as in the case of our examples, if a tag disappears at 12 minutes and the expiration duration is ten minutes, at 22 minutes ItemSense publishes that it disappeared at 12 minutes.
Recipe Parameters
- Set the
tagExpiryDuration
to a value greater than thereportingInterval
. The smaller the value the quicker the response time, but the larger the load on the system.
Note that absence detection via tag expiration only generates ABSENT events after the antennas of the reader have completed one cycle time. This value is dependent on the number of tags in the field of view. For large numbers of tags, the reader must "warm up" in this way before it can perform absence detection.
Running Jobs Simultaneously in the Same Facility
When running multiple simultaneous jobs, it is important to ensure that each reader is used by only one job. Attempting to use a reader in more than one job will result in a job failing to start. For a threshold recipe, the readers to use are specified on each threshold configuration.
To use only a subset of readers in a job running a non-threshold recipe, it may be helpful to use reader groups.
This can be done by giving readers a group
as part of the reader definition, then telling a job to use one or more readerGroup
s when starting it.
Initial Setup
When ItemSense has been installed started for the first time it will not be usable from any interface until some initial setup has been performed by the user. This initial set must be done via the IMC. Once logged in, the user is taken through a 6-step wizard:
- Change the default admin password.
- Define a new facility. ItemSense comes with the facility "default" but the user is required to make another.
- Set up a network. This requires entering a name for the network and either a Class C IP address or CIDR subnet. This class address can either be of a reader on the intended network or just an IP address which on same the class c network as the readers. It is possible to create multiple networks. -> Each Class C network that has readers will need to be defined separately.
- Scan the networks defined in step 3 for Impinj readers and gateways. This can take a little while. The more networks defined in step 3, the longer this scan will take. This will produce a list of reader which can be selected. The selected readers will be registered during the next step. Click on the "Register Readers" when right readers have been selected.
- Reader are now being provisioned, that is, the Reader Agent is being installed on to the selected readers and they are being associated with this instance of ItemSense
- Ready to go. After this step, ItemSense will be ready to use via all interfaces.
Reader Agent
ItemSense is made up of three different components. There is the IMC, the ItemSense Core and the Reader Agent. The ItemSense Core is the central piece of ItemSense. It coordinates all of ItemSense's functions. From communicating with the readers and monitoring health, to managing jobs, storing tag reports and exposing tag data via the HTTP REST API. ItemSense Core doesn't connect directly to the reader's LLRP (Low Level Reader Protocol) port, it communicates with the third component of ItemSense, the Reader Agent.
The Reader Agent is installed onto the reader itself into the Customer Access Partition (CAP), the space reserved on all Impinj Readers and Gateways for third party application to be installed on the reader. This means that no other CAP application can be used on a reader managed by ItemSense.
Apart from registration, ItemSense Core doesn't ever initiate communication with the reader. All communication with the reader is done through the Reader Agent. Reader Agent to ItemSense Core communication is done using a tailored purpose-built protocol called ISAP (ItemSense Agent Protocol). The protocol itself is implemented within the body of HTTPS POST request messages which are sent from the Reader Agent to ItemSense Core. These messages will contain the tag data read by the reader as well as health information on the reader itself. ItemSense Core controls the reader by issuing commands in the response to the POST requests. These commands typically include setting reader configuration or starting and stopping jobs.
Reader Agent Registration
Readers can only be associated to one instance of ItemSense Core at a time. Installing the Reader Agent onto the reader and associating the Reader to ItemSense Core is referred to as registering the reader. This function is performed by the IMC.
The first step within the IMC is to define a class-C subnet by specifying an IP address on that subnet. Once this is defined, a scan for Impinj RAIN RFID readers can be performed. When the scan is complete, you can select the readers that need to be managed by ItemSense, and the installation and registration of the Reader Agent can be performed. To do this, click on the DISCOVER READERS button at the bottom of the Readers Scanner page in the IMC. If a reader definition already exists for a discovered reader, the IMC will mark this reader with a small exclamation point(!).
Click on the REGISTER SELECTED READERS button and the installation and registration of the Reader Agent will begin.
This is a two-step process. The Reader Agent file is uploaded to the reader and then the reader is rebooted begin the installation of the Reader Agent. Once the reboot is complete and the Reader Agent is installed and running, it is in a state where it hasn’t been assigned to any ItemSense Core instance. At this point the IMC will send the Reader Agent information about how to communicate with the ItemSense core including:
- ItemSense Core IP address: this is the IP address used to navigate to the IMC used when registering.
- API Key: this is effectively the same as an authentication token except that during registration the token is generated by the IMC.
- IS Core Certificate: This is a self-sign certificate used for the HTTPS communication from the Reader Agent to the ItemSense Core.
- Reader ID : This is a moniker which is used by the Reader Agent to identify itself when it sends updates to ItemSense Core.
Note: A reader has a one to one connection with a single ItemSense Core. This means that the reader will need to be re-registered if it needs to be associated with a different ItemSense Core. This is done by creating a reader definition in the new ItemSense IMC, either manually or using the network scan tool, and then following the process outlined in the previous slide to register the reader with that new ItemSense instance.
All this needs to be done via the IMC. For this reason, to allow registration of the reader, the IMC requires the following ports to be open in any firewall which sits between the ItemSense Core and the reader:
- Outbound HTTPS port 443 from the reader: for ISAP, as mentioned earlier
- Inbound HTTP port 80 to the reader: for reader discovery
- SSH port 22: for managing the CAP through RShell (for tasks like re-register the Reader Agent)
- Port 51505: used by Reader Agent for listening when it has been installed but not assigned to any ItemSense instance.
The IMC will send the registration information to this port via HTTPS. Once the Reader Agent has been assigned to an ItemSense Core instance, the Reader Agent will stop listening on this port.
To provide a little more clarity, the following sequence diagram shows the four main sections of what happens when a reader is registered with an ItemSense Core instance. It shows the messages sent between ItemSense and the reader within each section; the four sections are reader discovery, Reader Agent install, reader registration, and reader check in. This flow is really managed by the IMC as the Reader Agent installation can only be done via the IMC.
- During network scanning, the IMC sends out HTTP GET messages to the network. When it receives an HTTP response, which is usually a 401 UNAUTHORIZED, this tells the IMC that there is a web service listening,
- This time IMC sends out the HTTP GET message with the reader credentials which allows the reader to authorize the request and respond with its webpage. This contains a lot of details about the reader which the IMC uses to create a reader definition.
- Now the IMC has the reader details it will upload the ItemSense Reader Agent to the reader.
- The reader is rebooted which causes the Reader Agent to be installed.
- The IMC will then poll the reader to see if has finished rebooting. It does this by sending HTTP GET messages to the reader. When the reader is available again the Reader registration can happen.
- When the Reader Agent has started, but hasn’t been associated to any ItemSense instance, it will start listening on port 51505. This is the Reader Agent registration port. First, the IMC double checks that this port listening.
- Once the IMC has confirmed this, it will send the details which the Reader Agent will need to speak to ItemSense Core. Things like the ItemSense IP it should use, the HTTPS certificate, the ID of the Reader.
- At this point the Reader Agent stops listening on port 51505 and is now able to send updates to ItemSense about its health status and tag data.
Reader Health Events
The Reader Agent checks in with ItemSense once per second by sending an HTTP POST message to ItemSense. The body of this message contains the health events that have occurred since the last check-in. The body also includes tag data if a job is being performed. The response from ItemSense contains commands to the reader.
Examples of health events are errors from the LLRP interface, the reader clock going unsynchronized, and software faults. Each individual health event has the following properties:
-
eventTime
: The time the event occurred -
readerName
: the name of the reader from which the event occurred -
type
: type of event. All events are one of seven types. -
code
: a code generated by the Reader Agent which represents the health event, e.g.,ReaderException
orReaderRestartError
. -
args
: a space in the health event message where additional details about the event can be specified. For example, if the eventtype
is LIFECYLCLE and itscode
is REBOOT, thenargs
might contain information such as "user initiated" to indicate why the reboot occurred. However, some of the messages seen in this section might not be immediately informative for an end user but would be great information to provide to ItemSense support if necessary.
Health Status Monitoring
Once a reader has been registered, ItemSense is able to provide health updates about that reader to a client. The health of the reader is determined when ItemSense processes the health events generated by the reader. Once determined, the reader's health is reflected by several reader properties in the ItemSense reader definition. When a reader's health status changes, ItemSense itself generates an event.
The following diagram depicts the general communications involved in monitoring reader health.
A reader's health information is available from ItemSense via the following interfaces:
- HTTP REST API: allows the reader health and the history of health events to be queried.
- Message queue: allows connected clients to be notified of health events via a message queue. It is possible to set up queues with various filters so that only specific events are put onto the queue.
- ItemSense Management Console (IMC): allows the reader health to be monitored in a GUI. However, the history of health events cannot be searched within the IMC.
Reader Health Properties
The health of a reader is reflected by the value of eight reader properties. These properties are displayed in the reader definition in the IMC and correspond to similarly named fields returned by the Reader endpoint of the Health API.
The Health Status property in the IMC or the state field in the API specifies the general operational state of the reader. It has the following possible values:
- AWAITING_AGENT: The reader is known to ItemSense, but ItemSense has not received any health updates from the reader, possibly because the Reader Agent has not been installed yet.
- IDLE: The reader is fully configured but performing no operations, such as running jobs or updating software.
- RUNNING_JOB: A job is currently active on the reader.
- UPDATING_FIRMWARE: The reader firmware or the reader agent is in the process of being updated.
- NOT_RESPONDING: The reader not checked in with ItemSense recently. This could be due to network latency or reader disconnection from the network.
The following seven properties provide status or information related to specific operations and are displayed in the reader definition in the IMC by clicking the View details link:
-
Last check-in: The last time ItemSense received a message from the reader
- Last reboot: The last time the reader rebooted
- Connection status: The status of ItemSense’s ability to communicate with the Reader Agent
- Throughput status: The status of throughput in the health and data buffers inside the Reader Agent
- Clock sync status: The status of the reader's clock synchronization with its configured NTP server(s)
- Hardware status: The status of communication between the reader agent and the reader firmware
- Software status: The status of the reader's software layer
Five of these properties specify the status of a specific reader function: connection, throughput, clock synchronization, hardware, and software. The possible status values are HEALTHY, WARNING, and FAILED. ItemSense sets the value of the properties when it processes the health events received from a reader. This processing is discussed below.
ItemSense Health-event Processing
ItemSense processes health events received from a reader by counting all of the health events received from the reader for the particular event type within a rolling one-minute window. Each reader function, which includes connection, throughput, clock synchronization, hardware, and software, is associated with an event type.
ItemSense determines the status of each reader function based on the following criteria:
- If there have been zero events in the last 1 minute, the status is HEALTHY.
- If there has been between 1 and 3 events in the last 1 minute, the status is WARNING.
- If there have been 3 or more events in the last 1 minute, the status is FAILED.
When the status is WARNING or FAILED, an error code is provided. When the status is HEALTHY, the error code is null. Each of the five properties corresponding to reader functions has different error codes, as described in the Code Details section of the API documentation.
Health Message Queue
It is possible to monitor changes in health status. A queue can be created via the API interface to receive messages when a health event occurs. The health messages can be filtered based on:
- A specific name of a reader
- A type of health event
- A queue can be given a
deliveryMode
parameter that will persist messages to disk. In the case of an outage, this guarantees that no messages will be lost.
The reader agent sends a health event only when the state of an event type changes. For example, if the state of the CONNECTION type health event changes from HEALTHY to FAILED, the reader agent sends the event; if the state of the CONNECTION type health event changes from FAILED to WARNING or back to HEALTHY, the reader agent sends the event. No health event is sent as long as the CONNECTION type health event remains in the same state.
Log Rotation
For most ItemSense logs, they are rotated every hour, stored for 7 days and have a maximum total size allowed (See Table Below). The oldest logs will start being deleted when the maximum total size has been surpassed.
There are a number of logs generated by ItemSense. The following is a list of the most common logs used for debugging and troubleshooting.
Service | Log | Rotation | History | Maximum Total Size | Description | Location |
---|---|---|---|---|---|---|
Coordinator | app | Hourly | 168 hours | 500mb | General Coordinator Log: Internal state and error message information | $HOME/containers/itemsense/home/itemsense/Coordinator/var/output/logs |
Coordinator | request | Hourly | 168 hours | 500mb | HTTP Request Log: Detailed Web Service Communication from reader agents and IMC | $HOME/containers/itemsense/home/itemsense/Coordinator/var/output/logs |
ItemSenseReaderDataEngine | app | Hourly | 168 hours | 200mb | General Application Job Log: job related activity (e.g. Starting and Stopping) | $HOME/containers/itemsense/home/itemsense/var/output/logs |
ItemSenseAPIService | app | Hourly | 168 hours | 100mb | General Item Query Log: Internal Data Web Service state and error message information | $HOME/containers/itemsense/home/itemsense/ItemSenseAPIService/var/output/logs |
ItemSenseAPIService | request | Hourly | 168 hours | 100mb | HTTP Request Log: Detailed Item Data Web Service Communication | $HOME/containers/itemsense/home/itemsense/ItemSenseAPIService/var/output/logs |
In addition to the logs for the services above, there are also logs for RabbitMQ, NGINX and the IMC.
Service | Location |
---|---|
RabbitMQ | $HOME/containers/is-rabbit/var/log/rabbitmq/ |
NGINX | $HOME/containers/nginx/var/log/nginx/ |
IMC | $HOME/containers/itemsense/var/log/impinj/ |
Managed Software Upgrades
ItemSense provides the ability to manage software upgrades on the readers. As many as 30 readers can be updated in a single update request. Both the Reader Agent software or the Impinj Octane™ firmware can be updated via the IMC or the API. However, the API provides more options to give the user finer control over the updates.
A user can control the upgrade by specifying:
- Readers on which to update the Reader Agent software.
- The types of readers on which to update the Reader Agent software.
- The maximum number of readers to update in parallel.
- Facilities where Reader Agent software will be updated on readers.
Once an upgrade has been started, ItemSense provides the ability to monitor the progress. This can be done programmatically via the API or via the IMC. If an upgrade fails, an update job can be queried for error messages associated with the job. An error message might look like:
"message": "There was an error processing your request. It has been logged (ID 9e0315498ce3383b)."
The message includes an error ID that is entered in the ItemSense application logs along with additional information about the error.
Glossary
Acronym | Name |
---|---|
CRC | Cyclic Redundancy Check |
DHCP | Dynamic Host Configuration Protocol |
EPC | Electronic Product Code |
FHSS | Frequency Hopping Spread Spectrum |
IMC | ItemSense Management Console |
LLRP | Low Level Reader Protocol |
MAC | Media Access Control |
PC | Protocol Control |
TID | Tag IDentifier |
ItemSense Management Console
Introduction
The ItemSense Management Console (IMC) is a graphical user interface (GUI) for Impinj ItemSense. The IMC runs on the ItemSense server and is accessed with a web browser.
The IMC allows you to define and configure the RAIN RFID readers; define zone maps, recipes, and jobs, which are required for an ItemSense data collection session; view the data results from a data collection session; monitor the health of the readers.
After ItemSense is installed, the user must complete an initial setup via the IMC. ItemSense is not usable from any interface until the initial setup has been completed.
Provision ItemSense for the First Time
When you run the IMC for the first time, a wizard walks you through the necessary steps to configure and confirm an ItemSense installation. After the wizard completes, ItemSense is ready to use.
Check Prerequisites
The following browsers are currently supported:
- Google Chrome Latest
- Mozilla Firefox Latest
- Apple Safari Latest
The following steps must be completed before provisioning ItemSense:
- Install an ItemSense server
- Deploy RAIN RFID gateways
- Configure the network
Connect to ItemSense
To connect to ItemSense:
Type
http://<server IP>:3010
into the address line of a web browser and press Enter.
The following dialog appears.Enter either your ItemSense UUID or your ItemSense ID.
If you do not know any of these values, please contact support@impinj.comSelect your Regulatory Region from the drop-down menu.
Click the SUBMIT button to continue.
Log In to ItemSense
It will take a few seconds for your ItemSense instance to register itself. Once this is complete, you can log in to ItemSense. Enter the username and password of the ItemSense server administrator. By default, the ItemSense server administrator has a username of admin with the password of admindefault. Click the LOG IN button.
Configure ItemSense
Once the user is logged in, the IMC Wizard takes the user through a six-step process to set up ItemSense. The IMC wizard executes only on the first login.
Step 1: Change the administrator password
The first step is to change the administrator password. This step is optional, but recommended.
Enter the new administrator password into the New Password and the Confirm New Password fields. Click the NEXT STEP button to continue to the next step.
Step 2: Create one or more facilities
The Facilities page appears. ItemSense comes with one facility, DEFAULT, already created. You may continue with this as your facility or create your own. To create one or more of your own facilities:
- Click the CREATE A FACILITY button.
- Enter a facility name in the New facility name field.
- If you want this facility to be the default, put a check mark in the Set as current facility check box.
- Click the CREATE NEW FACILITY button. A spinner page may briefly appear with the text Creating new facility.
After the facility has been created within ItemSense, the Facilities page will reappear with the text, You have 1 valid facility defined. If you want to create more facilities, click the CREATE MORE button and follow the prompts.
When you have created all of the facilities that you currently want, click the NEXT STEP button.
Step 3: Define network subnets
The network subnet of the RAIN RFID readers is usually different from the network subnet of the ItemSense server. On the Configure Networking page, you must define any subnets on which RAIN RFID readers reside so that the IMC can discover which readers are connected when it scans the networks.
To define a new subnet, click the ADD SUBNET button; enter a name for the subnet in the Name field (the name aenSubnet01 is used in this example); in the IP Address/Range field, enter either the IP address of a target reader or an IP address range in CIDR format (an IP address range of 10.200.35.0/27 is used in this example).
Click the ADD RANGE button to add the subnet. To add more subnets, click the ADD SUBNET button again and repeat the process. When you've finished adding subnets, click the NEXT STEP button.
Step 4: Scan the networks for readers
On the Scan attached networks for readers page, the subnets that you defined in step 3 are listed. Select the subnets that you want to scan (you should scan all of them for this initial setup) and click the DISCOVER READERS button. This might take some time, depending on the number of networks defined—the more networks defined in step 3, the longer this scan will take.
Alternatively, you can scan for specific reader names or IP addresses, instead of the subnets you have defined. Click the radio button for Manually Enter Hostnames or IP Addresses and then enter the host names of your readers or their IP addresses in the text box, separated by commas or newline characters.
When the scan completes, a list of valid RAIN RFID readers is displayed. If you want to register the readers later, click the SKIP READER REGISTRATION STEPS button to skip the registration process; otherwise, select the readers that you want to register and then click the REGISTER SELECTED READERS button to proceed with the registration process.
After you click the REGISTER SELECTED READERS button, a message box requests confirmation. Click the Proceed button to confirm that you want to start the registration process. Once this process begins, it will take up to ten minutes to complete.
Step 5: Register readers and install the Reader Agent
The readers that you selected in step 4 are now being registered. ItemSense installs the Reader Agent on each reader that it registers.
The status of the installation on each reader is displayed on the Reader Registration page as the process continues. Once the reader registrations and Reader Agent installations have completed, ItemSense displays the message Reader registration completed successfully. Click the GO TO READER DEFINITIONS button to continue.
Step 6: Complete the setup
The Setup complete page displays indicating that ItemSense is now set up and ready to use via either the IMC or the APIs. Click the GO TO DASHBOARD button to view the IMC dashboard.
Monitor Reader Health
The overall health status of the reader is displayed next to the reader either as Healthy or as Unhealthy.
The details of the health of the reader is viewed by clicking on the reader link.
The reader states that indicate the overall health status are described in the following table.
Reader state | Meaning |
---|---|
AWAITING_AGENT | The reader is known to ItemSense but ItemSense has not received any health updates from the reader, possibly because the Reader Agent has not yet been installed. |
IDLE | The reader is fully configured but performing no activities. In other words, no jobs are running and no software updates are being performed. |
RUNNING_JOB | The reader is running a job. |
UPDATING_FIRMWARE | The reader is having its firmware updated. |
NOT_RESPONDING | The reader has stopped checking in to ItemSense. |
Additionally, details include five status categories:
- Connection status: Reported as unhealthy when there is a problem with the health and monitoring channel between the reader and ItemSense
- Throughput status: Reported as unhealthy when the reader is accumulating data faster than it can send data to ItemSense
- Clock synchronization status: Reported as unhealthy when the reader cannot synchronize with its time provider (e.g. its NTP server)
- Software status: Reported as unhealthy when the reader has received invalid input or has encountered either an internal configuration error or a software error
- Hardware status: Reported as unhealthy when a low-level error occurs on the reader
Each of these categories shows HEALTHY if there are no conditions affecting the health of the reader.
A category shows WARNING when a condition that affects reader health has occurred at a low enough frequency that it is not considered an error. A category shows FAILED when a condition that affects reader health has occurred at a higher frequency.
A status returns to healthy in the absence of conditions affecting reader health being reported to ItemSense.
Host Health
The IMC provides a page for tracking and displaying the health of the host machine that is running ItemSense.
To navigate to the ItemSense Host Health page, click More on the navigation bar at the top of the page and select that option from the resulting menu.
The browser will navigate to a page that shows the current health state of the host machine, along with past health history. There are four separate areas of the page that deal with different aspects of host health, as shown in the following annotated page image:
Current host health status badge: Healthy or Error. If the running average of the host system CPU Usage or Memory Available metrics exceed the configured limits, this status badge will display an Error state. The default limits are 95% for CPU usage and 1GB of available memory, over a 5-minute time window, but these values can be customized if needed.
CPU Usage chart: tracks system CPU usage within the last hour, measured as a percentage. The measured metric is system CPU usage, not just process CPU usage, so it is affected by any software running on the host, including ItemSense. The chart is updated every 10 seconds.
Memory Available chart: tracks the amount of host memory available within the last hour, measured in megabytes. This available memory is shared by all software running on the host, including ItemSense. The chart is updated every 10 seconds.
Most Recent Events list: a time-ordered list of significant host health events, with the most recent events at the top of the list. This list is updated whenever a significant event begins or ends. Some events are instantaneous (beginning and ending at the same time), but most have a duration, with different start and end times. Times are listed in UTC format. If an event has a start time but has not ended, the end time will be represented with dashes (“---“). Events are remembered from the time that the system was installed.
Error Events
When one or both of the measured system metrics exceed the prescribed limits over the specified time window (5 minutes by default), the Host Server Health badge will change to an Error state and a new event will be added to the Most Recent Events list, as shown in the following diagram:
The event will be listed with a start time, but the end time will be displayed as dashes (“---“) to indicate that the event is still in effect.
As metric values are continually sampled and added to the running average, the average may fall below the prescribed limit. If this happens, the error state is terminated, and a new event will be added to indicate both the start and end times for the error state. If there are no other error states in progress, the Host Server Health badge will return to the Healthy indication.
Customizing Error State Limits
The default error state limits are 95% system CPU Usage and 1GB of Memory Available, measured over a default time window of 5 minutes for both. These values should be effective for installations that are running on the recommended server hardware configurations, but they can be customized if needed.
The configuration file that sets the host health limits is stored on disk under the installation directory:
[installation directory]/impinj/itemsense/[version]/containers/is-health/config/config.yml
The file is text-based and provides several settings to the service that monitors system health on the host. There are four fields involved in setting the error limits:
To update the health warning limits on the host:
- Stop any currently running jobs
- Navigate to the configuration file location,
[installation directory]/impinj/itemsense/[version]/containers/is-health/config/config.yml
- Make the file writable:
sudo chmod 666 config.yml
- Open the file in your editor of choice
- Optionally change the value for
cpu:max:
, using integer values from 1-100 - Optionally change the value for
cpu:duration:max
, using ISO 8601 duration format - Optionally change the value for
memory:free:min
, using integer values for megabytes - Optionally change the value for
memory:free:duration:max
, using ISO 8601 duration format - Save the file changes
- Navigate to the base ItemSense installation directory
- Bring down and then bring up all ItemSense services:
sudo docker-compose -f itemsense-prod-3.yml down sudo docker-compose -f itemsense-prod-3.yml up -d
Re-register Readers
Sometimes it may be necessary to re-register a reader if the reader loses contact with ItemSense. Re-registering a reader can also be done as a troubleshooting step if the reader in question is displaying a bad health status that has not resolved for some time.
To re-register a reader:
From the landing page, click the Scanner tab.
Select if you will Scan by Networks or Manually Enter Hostnames or IP Addresses.
-
Click the DISCOVER READERS button.
A highlighted message is displayed for any reader that is unhealthy. To continue with re-registration, just select the desired readers and click the REGISTER SELECTED READERS button. Readers that have an unhealthy status appear towards the top of the reader list.
After the reader is re-registered, it may take up to ten minutes for the reader to show up as healthy on the IMC and health API endpoints. This is because ItemSense must see the reader in a healthy state for a certain period of time before the reader can be considered fully healthy again.
Administration
To perform administration tasks, click More on the navigation bar at the top of the page, then click Admin Panel.
A panel will be displayed with options for resetting ItemSense, network scanner configuration, and software management.
Update Reader Firmware
On the Admin Home page, click the Software Management icon or tab. Start a new update operation by clicking on the Start New Update button.
In the Image Type field, select FIRMWARE_SPEEDWAY. Select the version and (optionally) the maximum number of readers to update in parallel.
Under Select Readers To Update, click the arrow to the right side of a facility name to view a list of all readers within a particular facility. For each facility, check the box to the left of each reader that you want to update.
Click the Submit button to start the update process.
Reset Configuration and Data
On the Admin Home page, click on the Reset ItemSense icon or tab. On that tab there are buttons to Clear Item Data and Factory Reset.
After the factory reset completes, the browser window returns to the ItemSense provisioning flow. The ItemSense Instance ID and Regulatory region are required at that point.
Restarting Readers
To restart a reader, navigate to the "Reader | Definitions" tab and click the Restart button for each reader you want restarted. The Restart button is also visible on the individual Reader Definition Summary page.
Regulatory Regions
ItemSense supports the following regulatory regions:
*United States (FCC) *Europe (ETSI) *Japan *China *Singapore
The region is configured at installation time.
When a new reader configuration is added, the management console validates that the configuration is valid for the configured region.
The following configuration reader configuration elements vary by region:
Configurable Channel Frequencies
In EU1 and EU2 regions only, individual channel frequencies can be configured. The following channels can be enabled, as well as their hopping sequence.
Channel | EU1 | EU2 |
---|---|---|
1 | 865.7MHz | 916.3 MHz |
2 | 866.3MHz | 917.5 MHz |
3 | 866.9MHz | 918.7 MHz |
4 | 867.5MHz | NA |
Reader Modes
In FCC regions, AUTOSET_DENSEREADER_TWO
mode is not available.
In EU1, Japan and China regions, MAX_MILLER
mode is not available.
Maximum Antenna Power
*In China, the maximum antenna power is 32.5dBm. *In EU1, the maximum antenna power is 31.5dBm. *In EU2, the maximum antenna power is 33.5dBm. *In FCC, the maximum antenna power is 32.5dBm. *In Japan, the maximum antenna power is 30dBm. *In Singapore, the maximum antenna power is 32.5dBm.
Visualization
Threshold Monitoring
Threshold monitoring visualization can be used to configure and tune threshold transition configuration.
You can view live item transitions, and tune the configuration to verify that the correct data is being produced by ItemSense.
This data can be filtered by EPC prefix, observation start and end time, and the transition direction.
There are two different levels of aggregation of this data:
*Transitions from all thresholds associated with a specific running job *Transitions from a single threshold
Transitions From All Thresholds Associated With a Specific Running Job
- Navigate to the Jobs` tab in the top navigation bar
- Locate the specific job of interest under Active Jobs
- Click on the icon circled below to navigate to live transitions for that job
Transitions From a Single Threshold
- Navigate to the Thresholds tab.
- Locate the threshold of interest
- If the threshold is running a job, click on the icon circled below to navigate to the live transition for that threshold
Resource Requirements
Supported Operating Systems / Distributions
- Ubuntu Linux 16.04
- Ubuntu Linux 18.04
- CentOS 7
Minimum Server Hardware Requirements
Determining the specific hardware requirements for your environment requires you to evaluate a number of factors. The following table describes the minimum requirements necessary to run a basic ItemSense configuration, and is intended as a starting point. Please refer to Appendix A: ItemSense Hardware Sizing Guidelines or contact your Impinj account representative for assistance.
Server Resource | Standard (Unless using the deprecated built-in data storage feature. See note.) |
---|---|
CPU core count | 2 physical cores with hyperthreading/SMT (4 logical cores) |
CPU speed | ≥2.4 GHz |
Memory | ≥6 GB |
Disk space | ≥64 GB |
Network interface | Must support 1 Gbps Ethernet |
General Network Requirements
The network for an Impinj ItemSense installation consists of the components that reside within a private Customer Operated Network.
Hardware Requirements:
- 1000 Mbps Ethernet Network (For small deployments, a 100 Mbps network may be sufficient)
- 802.3af PoE Switches
Port Requirements:
Direction | Port | Purpose |
---|---|---|
ItemSense to reader | 80 | Gateway discovery |
51505 | Reader Agent provisioning | |
22 | SSH commands during reader registration | |
Reader to ItemSense | 443 | ItemSense Agent Protocol (ISAP) for configuration and data/health reporting |
End user to ItemSense | 80 | REST API access |
443 | REST API access via TLS | |
5672 | AMQP access | |
3010 | IMC access | |
Reader and ItemSense to NTP server | 123 | Network Time Protocol (NTP) for clock synchronization |
The bulk of the traffic within the customer-operated network consists of the communication between the ItemSense instance and the RAIN RFID gateways, as shown in the following diagram. Note that the IMC and ItemSense core are shown as architecturally separate components but are currently co-located on the same host.
Supported Readers
Impinj ItemSense supports the Turbo version of these readers: Speedway R120, Speedway R220, Speedway R420, xPortal, xSpan, and xArray.
The following table summarizes the reader modes and the readers that support each mode.
Mode ID | Mode Name | Readers |
---|---|---|
2 | Dense Reader M4 | All models support these modes |
3 | Dense Reader M8 | |
5 | Dense Reader Two M4 | |
1000 | AutoSet | |
0 | Max Throughput | All models except Speedway R120 and Speedway R220 support these modes |
1 | Hybrid | |
4 | Max Miller | |
1002 | AutoSet Static | |
1003 | AutoSet Static Fast | |
1004 | AutoSet Static DRM |
Reader Power Requirements
Readers operate at the 802.11af Class 3 limit for POE power, and require that the maximum resistance of the Ethernet cable is 10 Ohms or less (for 100 meter length cable). For more information refer to the Gateway Installation and Operation Guides on the Impinj ItemSense Support website.
Supported Firmware Versions
ItemSense is shipped with the latest Octane Reader firmware. All readers should be upgraded to this firmware version after ItemSense has been installed. Readers without the latest firmware show an alert in the ItemSense Management Console, with instructions to upgrade.
Regulatory Regions
The regulatory requirements of a region must be considered when setting a reader's RF power level, mode, and channel frequency. See Reader Configuration, in the ItemSense Reference Guide for more details.
Appendix A: ItemSense Hardware Sizing Guidelines
Choosing the correct server hardware configuration is key to the stable and reliable operation of ItemSense. This guide will help you identify the right hardware for your specific deployment and reader configuration.
Note that the sizes listed below are estimates, and are provided only as guidelines. To get a more accurate sizing that is specific to your environment, conduct benchmarks based on your physical facility, reader layout, and tag environment.
Preparation
Before proceeding, gather the following information about the new deployment:
- Reader model and count (e.g. 4 R420, 4 XArray, 1 xSpan)
- Approximate physical layout (location and placement of readers e.g. Overhead, Side-by-Side)
- Tag count, in total and per reader (e.g. 230 total / 50 per reader)
- For Inventory and Location jobs, tag turnover rate (e.g. 100 tags leaving the field per hour)
- For Threshold jobs, tag movement rate per minute (e.g. 6 pallets with 24 tags each per minute)
- ItemSense parameters and operating mode (e.g. Inventory with reportingInterval = 60 seconds, tagHeartbeatDuration = 5 minutes)
- Concurrent job count and type (e.g. 5 Threshold, 3 inventory)
- How data will be consumed from ItemSense (e.g. internal broker using AMQP or MQTT, external broker, Item API, etc.)
- Hardware requirements for any additional software running on the server/VM, e.g. monitoring software, etc. Note that we recommend minimizing the amount of additional software running on the ItemSense server.(e.g. VMWare needs an additional 4 GB and 10 GB of disk space)
Processor Sizing
Processor requirements can vary considerably depending on the job type (inventory, location, or threshold), reader count, and tags in view for each reader.
The tables below define an estimated maximum count of supported readers (totaled across all concurrent running jobs) for various processor core counts and speeds, and can be used to approximate the processor configuration needed to support your deployment.
If hosting ItemSense in a virtual machine environment, the logical core count should be treated as the number of vCPU to allocate. Be aware that the number of readers that your VM can support may not be constant, as the loads generated by other VMs on the same server will affect the performance of your VM (the so-called "noisy neighbor" effect).
The maximum number of readers that ItemSense is capable of supporting is limited only by the available hardware resources.
Inventory
Core Count | Est. reader count (1k tags in view) | Est. reader count (4k tags in view) |
---|---|---|
2 physical / 4 logical | 75 | 50 |
4 physical / 8 logical | 125 | 100 |
Inventory job settings: reportingInterval = 60 seconds / tagHearbeatDuration = 5 minutes
Location
Core Count | Est. reader count (250 tags in view) | Est. reader count (1k tags in view) |
---|---|---|
2 physical / 4 logical | 100 | 75 |
4 physical / 8 logical | 125 | 100 |
Location job settings: reporting interval = 60 seconds / tagHearbeatDuration = 5 minutes
Threshold
Because of the nature of the algorithms and processing involved, threshold jobs generate a higher continuous processor load than the inventory and location modes.
Note that the estimated count below are per reader, not per threshold. If using multiple readers per threshold, each reader in the threshold should be counted separately.
Core Count | Est. reader count (one 6-tag group/transition/reader) | Est. reader count (one 24 tag group/transition/reader) |
---|---|---|
2 physical / 4 logical | 40 | 25 |
4 physical / 8 logical | 80 | 50 |
Threshold job settings: default; one group of tags passes through each reader's view every 6 seconds.
Memory
Memory usage depends on the number of concurrent jobs running and, to a lesser extent, on the number of readers and tags being processed.
The minimum physical RAM required for a basic installation of ItemSense running one job is approximately 6GB.
For each additional concurrent job, up to ~700 MB of additional RAM is required. A table that can be used for estimating RAM requirements is provided below.
If using the internal broker for data egress, an additional 1.5 GB of RAM is recommended. Roughly the same amount must remain free at all times. In the event of a network outage preventing data from being retrieved from the broker, this memory will be used to buffer tag events until network connectivity is restored.
Job count | Est. RAM (ext. broker) | Est. RAM (int. broker) |
---|---|---|
1 | 6.0 GB | 7.5 GB |
2 | 6.7 GB | 8.2 GB |
4 | 8.1 GB | 9.6 GB |
8 | 10.9 GB | 12.4 GB |
16 | 16.5 GB | 18.0 GB |
32 | 27.7 GB | 29.2 GB |
35 (max) | 29.8 GB | 31.3 GB |
Storage
A minimum of 64 GB of total disk space is recommended to accommodate ItemSense's internal data and log files. Use of a SSD is suggested, particularly for large deployments, but not required.
Of that 64 GB, maintaining a minimum of 15 GB free disk space at all times is necessary to allow working space for the ItemSense log retrieval system as well as working space for ItemSense version upgrades.
Network
Determining the necessary amount of network bandwidth depends on the the number of readers, the total number of tags being monitored, and, for inventory or location modes, the reporting interval chosen. The table below assumes a reporting interval >= 30 seconds if using inventory or location mode.
Reader count | Network |
---|---|
< 25 | 100 Mbps network or 1 Gbps network recommended |
≥ 25 | 1 Gbps network recommended |
(Deprecated) Using ItemSense's Built-in Data Storage Feature
For existing customers using the now-deprecated internal data storage feature through the Item API, the minimum recommended hardware configuration remains the same as for previous releases.
- Processor: Supported reader counts are half that shown in the tables above. Systems with a logical processor count / vCPU count of less than 4 are not supported
- Memory: Increase the required memory by a minimum of 2GB
- Storage: A SSD is required if running more than 10 readers, 256 GB or larger, 96k IOPS or greater
If necessary, please contact support@impinj.com for additional assistance.
Appendix B: Evaluation System Reference Table
Core Count | Processor | Base frequency | Memory | Storage |
---|---|---|---|---|
2 physical / 4 logical | Intel i3-4130T | 2.9 GHz | 8 GB | 500 GB HDD |
4 physical / 8 logical | Intel i7-6700T | 2.8 GHz | 16 GB | 256 GB SSD |
6 physical / 12 logical | Intel i7-8700T | 2.4 GHz | 16 GB | 256 GB SSD |
Reference Guide
Introduction
This guide serves as reference manual for configuring the features of ItemSense, once all of its concepts and components are understood. It describes each configurable parameter and element and provides guidance on how and when to use them.
It should be used in conjunction with the API Documentation. When configuring a section of ItemSense, the work flow is:
- Navigate to the appropriate section in the API Guide.
- Read the description of the parameters which need to be set including what values they can be set to.
- Navigate to the appropriate section in the this document to provide guidance an when certain values should be used.
The ItemSense API is currently the most comprehensive method of getting access to the underlying configurable parameters of ItemSense. At the beginning of each configuration section, there is a table which specifies whether the configurable parameter can be accessed via the API, the IMC, or both.
Users and Roles
In ItemSense, users are assigned roles that control the user's access to the system. Users can be added and managed through both the IMC and the API. Only users in the Admin role can administer other users. ItemSense is initially provisioned with one user in the Admin role:
Username: admin
Password: admindefault
Once ItemSense has been logged into for the first time (via the IMC or the API), this password should be changed to something more secure. ItemSense does not force a password change, but it is strongly recommended.
The roles that ItemSense provides are described in the following table.
Role | Description |
---|---|
Admin | User has complete access to the system including administering other users. |
DataReader | User has access to the items and the message queues API endpoints. |
JobRunner | User has access to the jobs API endpoints. |
ConfigManager | User has access to the configuration API endpoints. This includes reader definitions, reader configurations, and recipe configurations. |
It is possible to assign a single user more than one role, but assigning a user all individual roles is not the same as assigning the Admin role. Some actions within ItemSense are allowed only by the Admin role. For information about what parts of ItemSense a user can access, see the API Documentation.
Authentication
Authentication confirms the identity of a user. It answers the question, who is this user. The IMC and the API use different authentication methods.
To authenticate a user, the IMC requires a user to enter a valid username and password before being granted access to the rest of the management console.
To authenticate a user via the API, there are two methods that can be used:
-
HTTP basic authentication - This can be used with a previously set up username and password. HTTP basic authentication is inherently insecure as the username and the password are passed over the wire as plain text that is base64-encoded. As such, HTTP basic authentication should be used only when communicating with ItemSense from within a secured network. Otherwise, HTTPS is preferred. HTTP basic authentication is specified in HTTP Authentication: Basic and Digest Access Authentication.
In HTTP basic authentication, the username and password are passed in the Authorization HTTP header field. Its value is constructed by specifying the authorization method followed by a space which in this case would look like "Basic ". This is then put before the base64 encoded string of the username and password combined with a colon. For Example, if the default administrator username and password are used, the final HTTP header field would look like:
Authorization: Basic YWRtaW46YWRtaW5kZWZhdWx0
-
Token-based authentication - ItemSense provides the ability to associate a token to a user. A token is a universally unique identifier (UUID), which is associated with the user to represent both the username and the password when authenticating. Token-based authentication is done in a similar way to basic authentication except that the value of the Authorization header field is the string "Token " followed by a JSON key value pair with string "token" as the key and the token as the value. For example:
Authorization: Token {"token": "8fa61016-7531-4f07-a2ab-9b7046a1bbc9"}
Generate a Token
Tokens can be generated either via the API or via the IMC. Using these methods it is possible to generate tokens for any user if the correct username and password are specified.
Via the IMC, token generation is done as follows:
- Click on the three vertical dots in the upper right corner of the IMC.
- Navigate to admin -> API Keys. The IMC name for a token is "API Key".
- Select the username from the drop-down list.
- If necessary, enter the password for that user.
- Click on the Generate API Key button.
The generation of API keys is the only token-related task that can be done via the IMC.
Via the API, it is possible to:
- Generate tokens for a user.
- Revoke token(s) for a user.
- List all tokens for a user.
- Find out which user a token is associated to.
A user is authenticated in an AMQP registration via HTTP basic authentication. The AMQP interface does not support token-based authentication.
Authorization
Authorization verifies the permissions that a user is granted. It answers the question, what is the user allowed to do. ItemSense uses roles to set the user's permissions.
Zones and Zone Maps
A zone is a two-dimensional area of space within a facility. A zone map is a grouping of the zones within a facility. Only one zone map can be applied to a facility at any given time. To apply a zone map to a facility, it has to be made the current zone map on the facility. Once current, the zones in a zone map are reported during location jobs.
Having multiple zones in a single facility allows different zones to be active (or current) at different times. For example, if a new zone map needs to be applied to the facility, the new zone map can be created independently of the current one and made current at a prescribed time to test its effectiveness. If the preference is for the original zone map, the original can just be made the current zone map on the facility again.
A zone map has the following properties:
Property | Set via IMC | Set via API |
---|---|---|
name | Yes | Yes |
facility | Yes | Yes |
zones | Yes | Yes |
name
A name for the zone map. This should be set to something describing what the collection of zones is for.
facility
This is the name of an existing facility the zone map should be associated with. Therefore, the target facility must be created before a zone can be created.
zones
This is the collection of zones that are in the zone map. Each zone is defined by a name, the floor, and a set of points.
A zone has the following properties:
Property | Set via IMC | Set via API |
---|---|---|
name | Yes | Yes |
floor | Yes | Yes |
points | Yes | Yes |
name - This is the name applied to the zone. It is the string that is added to a tag report when ItemSense detects that a tag is in this zone. A name that is meaningful to a downstream system should be used. Zone names can contain:
- Any character in the range a-z, uppercase or lowercase
- Any digit 0-9
- One or more of the following characters: * _ : -
floor - As a facility can have multiple floors, it is necessary to specify which floor a zone is on. This name should aligned with the floor name applied to the reader definitions on the same floor.
points - This is a collection of X-Y coordinates which define the points of a the polygon which represents the zone. On each floor an origin point is selected and the xArray gateway placement values (in the readerDefinition) are specified based on the xArray's relative position to that origin point. The same consideration must be given to the points of the zone. In a zone, the X and Y values must be specified. The Z value is not used by ItemSense. All points are in meters.
A zone is defined by three or more points, which must be specified in a circular way. In other words, the points must be specified either in a clockwise order or in a counterclockwise order. For example, to define a square:
Valid definition: (3,0), (3,4), (11,4), (11,0)
Invalid definition: (3,0), (3,4), (11,0), (11,4)
The following diagram shows how ItemSense interprets these definitions. Interpretation of the valid definition is shown on the left.
With the invalid definition, ItemSense uses the first three points to create a triangle and sees the last point as an outlier. It then raises an error stating that this isn't a valid polygon.
Zone definitions cannot overlap unless they are on different floors.
Reader Definition
The reader definition provides details about a reader that is connected to ItemSense. There is one reader definition for each reader. One facility can have many readers defined within it but a single reader can be defined in only one facility. In the typical ItemSense usage, a reader definition is created automatically by the reader discovery process initiated by the IMC; however, a reader definition can be added manually.
A reader definition has the following properties:
Property | Set via IMC | Set via API |
---|---|---|
Name | Yes | Yes |
Address | Yes | Yes |
Type | Yes | Yes |
Reader Zone | Yes | Yes |
Antenna Zone | Yes | Yes |
facility | Yes | Yes |
Placement - X position | Yes | Yes |
Placement - Y position | Yes | Yes |
Placement - Z position | Yes | Yes |
Placement - Yaw position | Yes | Yes |
Placement - Pitch position | No | Yes |
Placement - Roll position | No | Yes |
Placement - Floor | Yes | Yes |
Name
This is the name of the reader definition and is used to identify a single reader definition entity. The name of the reader can be anything meaningful but it is common just to name the definition the same as the reader itself. For example, "Speedwayr-11-A2-AB" or "Xarray-11-42-DD".
Address
This is the IPV4 IP address of the reader. This is set via DHCP and so is only known when the reader is attached to the network. To find the IP address of the reader, connect to the reader network or connect to a network with active routes defined to the reader network. Once connected, run the ping command with the reader's name.
The reader's name can be intuited by taking the reader model followed by the 4th, 5th, and 6th octets of the reader's MAC address, each octet separated by dashes ('-'): readername-4th-5th-6th. The MAC address of the reader is found on the reader itself. It looks similar to the following:
00:16:25:11:34:AF
The 4th, 5th and 6th octets have been highlighted.
Examples of names: speedwayr-11-a2-ab and xarray-11-42-dd
An example of the ping command for the speedwayr reader:
$ ping speedwayr-11-a2-ab
PING speedwayr-11-a2-ab.impinj.com (10.200.25.34): 56 data bytes
64 bytes from 10.200.25.34: icmp_seq=0 ttl=63 time=0.358 ms
64 bytes from 10.200.25.34: icmp_seq=1 ttl=63 time=0.424 ms
The ping response from this reader specifies the reader's IP address as 10.200.25.34.
Type
ItemSense allows the type of reader to by defined. There are four types: XARRAY, XPORTAL, SPEEDWAY, XSPAN, and UNKNOWN. The UNKNOWN type can be set only via the API interface. In the IMC, not selecting any type is equivalent to specifying the UNKNOWN type.
The type property is only used to help qualify data. For example, antenna zones can only be defined on SPEEDWAY or XPORTAL reader types. Similarly, ItemSense calculates only X-Y coordinates of tags when XARRAY is selected as the reader type.
Reader Zone
This parameter is optional. When not specified, ItemSense sets this value to be the same as the name property of the reader definition. The value of this property is used during an Inventory job as the zone name in a tag report. It is reported when a tag was read by a reader's antenna on which no antenna zones have been defined.
Antenna Zone
This is the name reported by the reader in tag report whenever a particular antenna reads a tag. Each antenna can be given a different name and names can be shared across antennas.
Antenna zones are defined by specifying an antenna number and the zone name to attach to it. The antenna number is an integer while the antenna name is a string.
The following is an example tag report which is received either when querying for the item history via the API or when listening to a queue. In this example, ItemSense has a reader defined with two antennas attached to it:
{
"epc": "200011606000020573A2749E",
"tagId": "000000000000",
"fromZone": *[READER_NAME]*,
"fromFloor": null,
"toZone": "antennaRight",
"toFloor": null,
"fromFacility": "DEFAULT",
"toFacility": "DEFAULT",
"fromX": 0,
"fromY": 0,
"toX": null,
"toY": null,
"observationTime": "2016-09-07T00:00:02.148Z[Etc/UTC]"
}
This event shows that a tag has moved from the antenna which didn't have a zone name assigned to it, which means the fromZone
field is listed as readerZoneName
, and then moved to be read by the antenna which has the name antennaRight
assigned to it.
Facility
This parameter specifies an existing facility for the reader. In the IMC, the facility that is selected at the top of the reader definition page applies to all definitions on that page.
Placement
The parameters for placement are:
- x - distance in meters from the origin point along the x axis.
- y - the distance in meters from the origin point along the y axis.
- z - the difference, in meters, between the height of the reader and the average height of the tags from the floor.
- yaw - The angle, in degrees, that the xArray is rotated about its Z axis.
- pitch - The angle, in degrees, that the xArray is tilted about its X axis.
- roll - The angle, in degrees, that the xArray is tilted about the Y axis.
- floor - The name of the floor on which the reader is placed. This name could be just numeric characters.
These seven parameters can be logically split into four subsets.
The X
and Y
parameters indicate to ItemSense where an xArray is positioned on a floor relative to an origin point. All xArrays on a floor must be positioned relative to the same origin point, otherwise location accuracy will be severely hampered. The Z
parameter specifies the average height of the tags to be read by the xArray. The manner in which the tag is used must be considered when specifying the average height. For example, if a retail shop floor is being monitored, the height of the tag as it is hanging on a rack should be measured. If the use case is to track patient movements around a hospital, the height of the tag should be the distance from an average height patient's wrist to the floor. It is possible for different xArrays to have different Z values but only one may be specified per xArray.
The third set (pitch
, roll
, and yaw
) concerns the rotation of the xArray about the X, Y, and Z axes. It is possible that not all xArrays in a facility face the same direction. Therefore, it is necessary to pick one xArray to set the direction of the positive Y axis. This direction corresponds to the side of the xArray on which the lights are placed. From here all the other xArrays should be oriented. If a second xArray is a quarter turn counterclockwise, this should be set as -90 (when looking down from above) and so on. The pitch and roll are used when the xArray is not parallel to a floor.
The following picture gives a few more examples on how to position the X
, Y
and Yaw
values. These yaw value examples are from the perspective of looking down at the floor from above.
The fourth subset contains only one parameter; the floor name. This name is used in a few places:
- It is used in the tag report as the name of floor on which the tag was read.
- The name here should match the name specified in a Zone Map when the reader is on the same floor to which the Zone Map applies.
- During tag data aggregation for location calculations. If an xArray is on a different floor to a tag, the reads from that xArray are not used in the tag location calculation.
This placement information is critical for allowing ItemSense to calculate the location relative to the same origin point as tags read by other xArrays in a facility.
Restrictions on reader definition parameter updates
When changing the reader's facility
as part of a reader definition update,
an internal consistency issue within ItemSense requires the name of the readerZone
to change, as well as the names of any antennaZones
.
When changing the reader's placement's floor
as part of a reader definition update,
the names of the readerZone
and antennaZones
must change. Furthermore, once a reader has a
floor assigned to it, the floor cannot be removed (which occurs when the
floor
property is set to null, or the placement
itself is set to null).
It is permissible to change the floor to a different, non-null value.
ItemSense enforces the restrictions above. Calls to the associated API endpoint fail and the IMC prohibits (and displays an informative warning) when such configuration changes are attempted.
Facilities Management
A facility is analogous to a physical building. A facility must be defined in ItemSense before any readers can be defined. If the user chooses not to create a facility, ItemSense uses the facility name "DEFAULT" for all readers.
Readers cannot be moved directly from one facility to another. If a reader needs to be moved to another facility, it first must be deleted from its initial facility and then re-added to the new facility.
In the IMC, facilities are managed under the "facilities" tab.
Reader Configuration
A reader configuration defines how a reader is utilized when running a job. Reader configurations are independent from reader definitions, which are managed and stored separately. A reader configuration is applied to a reader via a recipe. A reader configuration has common properties and operation-specific properties.
A reader configuration has the following common properties:
Property | Set via IMC | Set via API |
---|---|---|
Name | Yes | Yes |
Operation | Yes | Yes |
Reader mode | Yes | Yes |
Transmit power | Yes | Yes |
Filter | Yes | Yes |
Session | Yes | Yes |
The following properties apply to the INVENTORY operational mode:
Property | Set via IMC | Set via API |
---|---|---|
Search mode | Yes | Yes |
Tag population estimate | Yes | Yes |
Polarization | Yes | Yes |
Antennas | Yes | Yes |
Channel Configuration | Yes | Yes |
RF Power Sweep Configuration | Yes | Yes |
The following properties apply to the LOCATION operational mode:
Property | Set via IMC | Set via API |
---|---|---|
Disabled Antennas | Yes | Yes |
The following properties that apply to the THRESHOLD operational mode:
Property | Set via IMC | Set via API |
---|---|---|
Search mode | Yes | Yes |
Tag population estimate | Yes | Yes |
Polarization | Yes | Yes |
RF Power Sweep Configuration | Yes | Yes |
Name
This is the name of the reader configuration. It is a good practice to specify the intent of the particular configuration definition. For example, "Inventory-Dense-Speedway". This conveys that the configuration is for an inventory job that uses a Speedway reader in a dense reader environment.
Operation
This is the operational mode of the reader. It has the following options:
- INVENTORY - Use the reader to perform an inventory of tags. The inventory can be standard or real-time presence detection.
- LOCATION - Use the reader to determine the location of tags.
- THRESHOLD - Use the reader to detect movement of tags across a threshold.
- DO_NOTHING - Disable the reader.
Reader Mode
There are many parameters which can be set in an RAIN compliant reader in order to optimize throughput; these can include: data rates, modulation type (both reader-to-tag and tag-to-reader), bit encoding, pulse widths and other air protocol particulars. There are over 128 combinations of settings on a typical RAIN RFID reader. Several reader modes have been predefined to cover almost all reading scenarios.
Reader Mode | Data Rate | Positive | Negative |
---|---|---|---|
MAX_THROUGHPUT | 640 kbps (FCC), 436kbps (ETSI), using FM0 encoding | Highest data rate. | Prone to collisions. Lowest sensitivity. |
HYBRID | 320kbps (FCC), 218kpbs (ETSI), using Miller subcarrier=2 | ||
DENSE_READER_M4 | 68.5kbps (FCC), 80kpbs (ETSI), using Miller subcarrier=4 | Good for when there are a large number of readers in an environment. | |
DENSE_READER_M8 | 21.33kbps (FCC), 80kpbs (ETSI), using Miller subcarrier=8 | Most immune to interference (from other readers or elsewhere). Best sensitivity. | Lowest data rate. |
MAX_MILLER | Data rates: 160kbps (FCC), using Miller subcarrier=4 | Good compromise of speed and sensitivity. Usually the default setting on most readers. | |
DENSE_READER_M4_TWO | Faster forward link than Mode 2 (only ETSI, China, India, Japan, Korea, and So. Africa) | ||
AUTOSET_DENSE_READER (aka AutoPilot) | Dynamically optimizes tag read and data rates based in the RF environment. Suited to a dense reader environments. | Tags might be transient due to outlying tags being read in some modes over others. | |
MODE_1002 (aka AutoPilot Static) | Dynamically optimizes tag read and data rates based in the RF environment. Good for finding the weakest tags. | Tag population has to be relatively static. | |
MODE_1003 (aka AutoPilot Static Fast) | Same as MODE_1002 except that it performs at a higher data rate. | Tag population also has to be relatively static except that this mode is better suited to an RF environment which is known to be good. | |
MODE_1004 | Same as MODE_1002 except that it favors reading weaker tags. Hence, this mode is better for more difficult RF environments. | Slower than read rate than MODE_1002. |
A couple of points are important to note regarding reader mode settings:
- Not all modes are available on all models or in all regions.
- There is an inverse relationship between data rate and sensitivity to interference. Higher data rates are more susceptible to interference whereas lower data rates are more tolerant of it.
- A dense reader area is defined as an area in which more than half the available channels are predominantly occupied.
- Some regions allow only dense reader modes because of the limited number of available channels in certain regions (ETSI, for example).
The AutoPilot modes automatically change the reader settings based on the number of readers in the environment. When the number of readers increases beyond a certain limit, the reader switches from a non-dense reader mode to a dense reader mode.
For more information on how to set this parameter, see the Performance Expectations chapter in the Gateway Deployment Guide on the support website.
Transmit Power
This is the power, in dBm, that radiates from the reader's antenna when performing an operation. Some common factors to consider when selecting the transmit power are:
- Regulatory restrictions of the region in which the reader is operating
- The gain of the antennas being used with the reader
- The cable loss between the reader and the antenna
- The area the reader needs to cover. For example, if the field of view of the reader has to be tightly controlled so that the reader doesn't read certain tags, the transmit power can be reduced.
The regulatory restrictions, antenna gain, and cable loss are further explained below.
Maximum Output Radiated Power
Throughout the world there are different standards which regulate the use of RFID. The two most prominent regulations are FCC and ETSI. The selected value for transmit power must be within the range allowed by the regulatory commission of the operating area. Regulations usually state the maximum output radiated power in watts (W). To convert this to dBm, the following formula is used:
dBm = 10 log(power in milliwatts)
For example, FCC specifies 4W as maximum allowed radiated power. To convert this to dBm:
4W = 4000mW = 10 log(4000) = 36 dBm
Antenna Gain
The gain refers to how much the antenna focuses the RF beam emitted from the antenna and thus increasing the radiated power. The gain is normally given in dBi on an antenna data sheet which is the gain in reference to an isotropic antenna. If the regulatory maximum output radiated power is specified as effective isotropic radiated power (EIRP), the dBi value is used when calculating the maximum reader output power. However, if the regulatory maximum output radiated power is specified as effective radiated power (ERP), which references a dipole antenna, the dBi value must be converted to dBd. To convert dBi to dBd, the following formula is used:
dBd = dBi - 2.15
Cable Loss
This is usually specified on the cable data sheet as loss in dB per meter.
Calculation of Maximum Allowed Reader Output Power
The following formula is used to calculate the maximum reader output power allowed by a region's regulatory agency:
maximum allowed reader output power (dBm) =
cable loss (dB) - antenna gain (dBi or dBd)
+ maximum radiated output power (dBm EIP or dBm EIRP)
The following example shows the calculation of the maximum reader output power for the ETSI region. |Attribute|Unit|Value| |--------|----|-----| |Maximum radiated output power| dBm ERP |33| |Cable loss for 4 meters of cable| dB | 4m x 0.5 dB/m = 2 | |Antenna gain|dBd| 8 dBi - 2.15 = 6dBm (rounded)| |Maximum allowed reader output power|dBm|29dBm|
Transmit Power for xArrays
The above calculations are not necessary when using ItemSense with an xArray as the maximum power limits within each region are known to ItemSense. This allows ItemSense to prevent the selection of an incorrect power level for that region.
Disabled Antennas
A comma-separated list of integers representing antenna IDs of a reader. The antennas identified in this list are disabled.
Filter
This field allows for specify a filter the reader should apply to the tags it inventories. A filter can be be placed on any value in any memory bank within the tag. To create a reader based filter three values need to be selected. These are the memory bank, pointer, and the tag mask. Only one filter can be set per reader configuration.
Memory Bank
A tag usually has four memory banks, although the user memory bank is specified as optional in RAIN RFID standard. The following table shows how to reference a particular memory bank: |Memory Bank Number| Memory Region Name| |------------------|--------------------| |0|Reserved| |1|EPC| |2|TID| |3|User|
Pointer
This is a bit offset to the exact place in memory where the filter mask should start. For example, it is common to filter on an EPC but the EPC doesn't start at bit zero in the EPC memory bank. Before the EPC itself is the 16-bit CRC and the 16-bit PC. This means that the actual EPC starts on bit 32 so to filter on the EPC a pointer value of 32 (to skip bits 0-31) would be required.
Tag Mask
This is a hexadecimal string of characters which is matched against the specified position in TAG memory.
Session
The RAIN standard allows for up to four sessions, each with its own 'A' or 'B' state flag; these sessions serve two purposes:
- They determine how often a tag responds to a "select 'A' state tag" query from the reader.
- They allow for multiple readers to conduct independent inventories.
The RAIN RFID reader selects which session is to be used within the tag. The inventory flags in each tag session can be independently set to 'A' or 'B'. Each session has different tag persistence properties. Depending on the use case, one session type might be more applicable than the other.
The four session options are:
- 0 - The inventoried flag is set to 'B' state but once it has left the field of view it immediately reverts back to the A state.
- 1 - In Single Target mode with Session set to '1' the tag is read and then moved to the 'B' state. After some period of time, which is known as persistence, the tag reverts back to the 'A' state and be read again. This is done even when the tag remains in the field of view of the reader. This persistence value is defined in the RAIN standard as being between 500ms and 5 seconds; again it cannot be expressly set, only approximated. The persistence value will vary depending on the tag IC (Integrated Circuit) manufacturer and even specific tag IC model. For example, the Impinj Monza S1 persistence is approximately 1 second. So, if we set the reader for Single Target Session 1, we will see a Monza tag being read around every second; if the tag uses a different IC it may be some other value between 500ms and 5 seconds.
- 2 - The tag will be read once then switch to the 'B' state and remain quiet the entire time it is in the read field. This is because the reader, when in SINGLE_TARGET mode, will only select 'A' state tags. Once the tag leaves the read field, a RAIN RFID compliant tag will have a persistence time of a minimum of 2 seconds with no maximum defined. In reality, tags revert back to the 'A' state about 45 seconds to a minute after leaving the read field. However, as with session 1, this can vary across both IC manufacturer and model, and can't be user defined.
- 3 - Same behavior as session 2.
Search Mode
This parameter specifies the type of RFID search mode the reader should use. To understand search modes it is important to understand the concepts of "states", "sessions" and "persistence". While this guide is not intended to be the definitive resource on how these work (as the EPC GEN 2 specification itself is best for that) it is important that these concepts are framed.
State
Each RAIN compliant tag has two states: 'A' and 'B'. The 'A' state is default when the tag powers up (or after the 'B' state times out). These states are essentially flags which when raised (i.e. when in 'B' state) indicates the tag has already been inventoried.
Persistence
Persistence pertains to how long a tag remains in the 'B' state. Once the RFID reader inventories a tag, the flag state in the tag is changed from 'A' to 'B' - how long the tag stays in the 'B' state before reverting back to the 'A' state is called "persistence". It is important to realize that exact persistence times cannot be set by the user; they can only be approximated according to the Search Mode and Session. Different sessions have a different persistence time. Please see the section on setting the "session" configuration parameter for more information.
Knowing the above key search mode concepts provides some context around the different search modes which can be selected. These are:
- READER_SELECTED - This allows the reader to select the Search Mode depending on the session selected.
- SINGLE_TARGET - The reader only selects all 'A' state tags then moves them all into the 'B' state (unless session 0 is selected). This allows tags to stay quiet once they are inventoried. This mode is good for high population, dynamic environments and high-throughput applications where a reduction in repeated tag observations is preferred. Persistence (and by extension, the session) is an important factor to consider when selecting SINGLE_TARGET. Used when performing deep stock inventory counts, where as many tags as possible need to be counted.
- DUAL_TARGET - The reader selects all 'A' tags then moves all 'A' tags into 'B'. Reader then selects all 'B' tags then moves them all back into the 'A' state. The process is then repeated. In other words, no tags are actually silenced because they are selected by the reader no matter what state they are in. Persistence, and so session type, is not a factor when using DUAL_TARGET mode. This mode is good for low to medium tag counts or low-throughput applications where repeated tag observation is preferred i.e. readers behaving as gateways or when determining the location of tags. This mode is used for location use cases and for real-time tag presence detection. These modes require as many tag reads as possible to work so tags should never be silenced like there are when using SINGLE_TARGET.
- TAG_FOCUS - This is also known as "single target with suppression" or "S1 boost". This is like SINGLE_TARGET with session 2 in that the tag will stay in the 'B' state while within the read field but once the tag has left the read field, it will have a persistence time like session 1. An example of a good use case for this mode would be when a population of tags is moved through a portal/dock door and then a short time later (less than 30 seconds) the same population of tags goes through another dock door and needs to be inventoried both times.
- SINGLE_TARGET_BTOA - The reader selects tags in the 'A' state. This search mode is also known as "single target reset inventory". This mode is used when a set of tags is in the 'B' state, perhaps because of a previous inventory.
- DUAL_TARGET_WITH_BTOASELECT - This search mode is an optimized version of the DUAL_TARGET search mode. This mode is faster and, therefore, preferable over the DUAL_TARGET search mode. This mode is used for real-time presence detection.
Tag Population Estimate
This property is not used for normal operation and should not be set by the user.
Polarization
This property is not used for normal operation and should not be set by the user.
Antennas
This parameter is only available for Inventory reader configurations. It is a comma-separated list of integers representing antenna IDs of a reader. The order of the antenna IDs in the list determines the order in which the antennas are used during a job.
For example:
38, 52, 46, 48
Under normal operation, all antennas of a reader or gateway should be enabled to ensure maximum coverage of a given area. However, in some scenarios it is necessary to disable certain antenna beams. This is normally done when:
- The gateway is placed near a reflective surface which is causing interference.
- There is an over-deployment of xArrays in a given area such that they cause interference with one another.
To find the optimal set of antennas that should be used in a given area requires experimentation and reasonable knowledge of RF and the factors that affect it.
A little bit of care has to be taken when setting this value. Most of the other values in the configuration profile are common across reader types (particularly for an Inventory reader configuration profile) so when setting them, little consideration has to be given to the reader the configuration is intended for. This is not the case for the antenna
parameter. The listed antenna IDs cannot be greater than the number of antennas available on the reader.
For example, the following antenna configuration causes an error when it is applied to a standard Speedway reader (without an antenna hub attached):
1, 2, 3, 4, 5
This is because the Speedway reader doesn't support more than 4 antennas by default.
Channel Configuration
In some regions specific frequencies should be used by a reader. Other regions a frequency hopping spread spectrum (FHSS) is used to rapidly switch among frequency channels using a pseudorandom sequence every 200 milliseconds. This Channel Configuration section is never used in FHSS regions but provides control of the channels used in regions where channel management has to be considered.
Using the ETSI region as an example, there are a small amount of channels, less power and less bandwidth per channel when compared to the FCC region. If there are more than two active readers in close proximity careful consideration must be given to the design of the system. Which channels to use, separation of antennas, angle of antennas and how operation of the reader is triggered are all variables that can affect the effectiveness of the RAID RFID solution. To get the most out of the available channels some best practices can be applied:
It is always best to use all four channels when possible. However, due to reader proximity, this is not always possible. In this situation, try to have readers which are in close proximity to each other all operate on different channels. See point 2. The ETSI regulations permit transmitting on a single channel for a defined period of time; 4 seconds if tags are being read and only one second if no tags are being read. If these limits are breached then the reader must stop transmitting for a period of 100ms. The reader ensures it complies with the regulations automatically, therefore it is important, where possible, to ensure more than one channel is selected.
If there is more than one reader in close proximity that is operating at the same time, use alternate output channels. This is often necessary when two readers are used to create a portal (i.e. two readers facing each other to monitor the space in between), when two dock door portals are in close proximity or when multiple xArrays are monitoring an overlapping floorspace.
An example of an alternate channel strategy would be having reader A use channels 1 and 3 (865.7 and 866.9 MHz), and reader B using channels 2 and 4 (866.3 and 867.5 MHz).
If this separation of channels is not designed into the system, there is a 25% chance that each reader will be transmitting at the same time on the same channel thereby increasing the chance of interference. Any interference affects a reader's ability to accurately read tags.
There are two parameters which help control the channels that a reader uses; Channel Index and Tx Frequency in Mhz. Note that the parameters are mutually exclusive and both can not be set simultaneously.
Channel Index
For RFID readers operating in regions with fixed frequency regulatory requirements, the Channel Index is used to define a single frequency channel for the reader to operate in.
Low Level Reader Protocol (LLRP) has a frequency table that maps a channel number to list of available frequencies. The channel to frequency mapping for a region must be known to be able to correctly select the intended channel frequency.
For example, RAIN RFID readers for the ETSI region has the following list of available channels:
Channel | Frequency |
---|---|
1 | 865.70 Mhz |
2 | 866.30 Mhz |
3 | 866.90 Mhz |
4 | 867.40 Mhz |
Using this parameter, only one channel may be selected for a reader.
Tx Frequencies in Mhz
To allow more than one frequency channel to be used, the txFrequenciesInMhz (reader as "Transmit Frequencies in MegaHertz") allows for the definition of a custom frequency hop table. The table can only include frequencies that are allowed by the reader’s region, but frequencies can be defined in any order including repeating and/or omitting frequencies. For example, based on the ETSI frequencies above, an ETSI frequency hop table might be defined as [865.7, 866.3, 866.9, 867.5], which will prompt the reader to hop only to these frequencies, in this order.
Or, to define the alternate channel strategy mentioned above:
- Reader A: [865.7, 866.9]
- Reader B: [866.3, 867.5]
RF Power Sweep
Use this parameter to configure Impinj-specific RF Power Sweep operation.
When this parameter is present in a either the INVENTORY or the THRESHOLD Reader Configuration, the reader performs each inventory operation - transitioning tags from one state to another (A to B or B to A) - at multiple power levels starting at or above the minimumPowerLevel
, in increments of powerLevelStepSize
, ending with the maximum power level specified by transmitPowerInDbm
.
For example, if the minimumPowerLevel
is specified as 25.5 dBm and the transmitPowerInDbm
is 30 dBm, with powerLevelStepSize
set to 2 dBm, each inventory operation will be performed at power levels 26 dBm, 28 dBm, and 30 dBm, in that order.
Note: This custom parameter requires expert knowledge and is intended for Impinj internal use only.
Minimum Power Level
The minimum power level that the RF Power Sweep will start at before incrementing. It must be specified in 0.25 dB increments and be less than the value of transmitPowerInDbm
.
Power Level Step Size
The step size that the power will increment by when applying RF Power Sweep. It must be specified in 0.25 dB increments.
Recipe Configuration
Recipes allow for the pairing of readers to previously defined reader configurations. That is, it allows the user to specify which reader configuration should to be mapped to an individual reader for a job. This means if a job is running which involves a number of readers, each requiring a different set of configuration (perhaps because there is a mix of Speedway, xPortal and xArrays), then all of the configuration to reader mappings can be specified and saved under one recipe. It is also possible to specify some of the ItemSense data aggregation settings via the recipe configuration. Once all the recipe has been set up it can be saved under a meaningful name.
A recipe configuration has the following common properties:
Property | Set via IMC | Set via API |
---|---|---|
Name | Yes | Yes |
Type | Yes | Yes |
Reader Configuration Name | Yes | Yes |
Reader Configurations | Yes | Yes |
The following properties apply to the INVENTORY operational mode:
Property | Set via IMC | Set via API |
---|---|---|
Reporting Interval | Yes | Yes |
Compute Window | Yes | Yes |
Tag Expiry | Yes | Yes |
Tag Heartbeat Duration | Yes | Yes |
The following properties apply to the LOCATION operational mode:
Property | Set via IMC | Set via API |
---|---|---|
Minimum Movement In Meters | Yes | Yes |
Reporting Interval | Yes | Yes |
Compute Window | Yes | Yes |
Tag Expiry | Yes | Yes |
Tag Heartbeat Duration | Yes | Yes |
The following properties that apply to the THRESHOLD operational mode:
Property | Set via IMC | Set via API |
---|---|---|
Thresholds | Yes | Yes |
Iteration data logging | Thresholds | Yes |
Profile | Yes | Yes |
Name
This is the name of the recipe which can be selected when running a job.
Type
This is the type of connection to the reader that ItemSense will use.
- LOCATION - For use with reader configurations which have
operation
set to LOCATION. - INVENTORY - For use with reader configurations which have
operation
set to INVENTORY. - THRESHOLD - For use with reader configurations which have
operation
set to THRESHOLD.
Reader Configuration Name (Default Configuration)
In the IMC this field is actually called "Default Configuration" due to this configuration being used if no other configuration is specified in via the "Reader Configurations" property.
If no default reader configuration should be applied to the readers then this value can be set to a "DO_NOTHING" reader configuration i.e. set to a reader configuration with the operation
type set to "DO_NOTHING". If this is done, the Reader Configurations property must be used.
Reader Configurations (Configuration Mappings)
This is a list of reader definition to reader configuration mappings. Multiple mappings can be specified. In the IMC, there are drop-down lists which allow the user to select from the existing reader definitions and configurations. Via the API, a mapping is just a key value pair in JSON. The following is an example of the format:
"readerConfigurations": {
"xArray-11-41-d9": "IMPINJ_Deep_Scan_Inventory",
"SpeedwayR-11-A2-AB": "IMPINJ_Deep_Scan_Inventory_Spwy"
},
When specifying reader configuration mappings via the API, the key can either be the specific reader 'name' or a reader 'type'. This makes it possible, for example, to map a configuration to all readers of the same type.
"readerConfigurations": {
"XARRAY": "IMPINJ_Deep_Scan_Inventory"
}
Reporting Interval
This parameter specifies the frequency, in seconds, with which the reader agent sends its tag reports to ItemSense Core.
When the recipe type
is set to INVENTORY, the reportingInterval
has an added function. ItemSense uses all tag data sent by the reader agents in a report to count the number of tag reads per antenna on the reader. ItemSense use tag counts per antenna to determine which antenna zone a tag is in. This means that the larger this value is set to, the great number of tag reads in a report and the better ItemSense is at determining which antenna zone a tag is in. The trade off is that the bigger the window, the longer it takes for antenna zone transitions to occur.
Compute window
This parameter is specifies the time, in seconds, over which tag reports should be aggregated.
When the recipe type
is set to INVENTORY, the compute window isn't used.
When the recipe type
is set to LOCATION, the compute window
is the window over which the tag location data is averaged. If the compute window is larger, the tag's reported location is more accurate. However, the reporting of a tag's location is delayed by a larger compute window. The more movement the tags are likely to do, the smaller the compute window should be. More movement produces more frequent XY position updates for each tag. If the tags are likely to be still, a larger compute window can produce more accurately reported tag locations, although the locations are updated less frequently.
For more information about how the compute window works, please refer to the Gateway Deployment guide which can be found on the support website.
Minimum Movement in Meters
This parameter is only available when the recipe type
is LOCATION.
ItemSense is able to calculate the difference in meters between each report XY tag location. The value of this parameter is the minimum distance a tag should move before it is reported.
Depending on the environment, the reported tag raw tag locations can change frequently. Even if the tag is static. This is known as jitter. The minimumMovementInMeters
can be used to tell ItemSense to ignore jitter within a certain radius. This means only "significant", defined as any movement greater than this parameter value, movements are reported.
What value this parameter should be set to is based on the following considerations:
- How "clean" the RF environment is. Environments with little RF noise can produce less tag location jitter. The smaller the jitter, the smaller this parameter can be set to.
- The required location accuracy. If small movements need to be tracked and the RF environment allows for it, this parameter should be set to a smaller value.
- When tags do move, by how much do they move? This parameter should always be less than that amount.
This parameter can be set to 0 which means that all calculated XY locations are stored and processed which can produce a large amount of tag data. Setting this parameter to 0 significantly reduces the number of tags which can be tracked simultaneously by an ItemSense instance. It is generally better practice to set minimumMovementInMeters
to as large a value as the use case requirements can tolerate.
Tag Expiry
A string representing the interval between the time that the tag was last detected and the time that the tag was marked absent.
Tag Heartbeat Duration
A string representing the interval between heartbeat updates. This value controls how frequently the lastModifiedTime of a tag is updated when the tag is read but has not moved.
Thresholds
A list of integers, each of which identifies a threshold to be used in the recipe. If this value is omitted, empty, or null, all thresholds in the facility are used.
Iteration Data Logging
Boolean value that enables or disables the logging of iteration data for use in tuning. The default is disabled (false).
Profile
Encrypted data specifying system behavior. This property must not be set without guidance from Impinj. When a recipe is created, ItemSense uses a default value.
Troubleshooting Guide
Introduction
This troubleshooting guide catalogs common issues, organized by symptom, within three categories: setup, jobs, and data collection. For each symptom, the likely causes and the resolutions to each of those causes are described.
If you are already aware of the cause of an issue and are just looking for the steps for fixing it, see the Common Procedures section.
This guide assumes familiarity with Linux commands. See the manual pages for details about individual Linux commands.
Issues
Setup
Installation fails to complete
During the Impinj ItemSense installation, the script displays "cannot start service itemsense" or "encountered errors while bringing up the project". The script may continue to run, but it eventually exits with a status 1. The most likely cause is a conflict on one of the ports that ItemSense requires, as specified by the port requirements in the Resource Requirements guide. For example, if an Apache web server is running, it is consuming port 80.
Resolution:
- Use the following command to see which port is being consumed:
sudo netstat -tlnp | grep ':80\W\|:3010\W\|:443\W\|:5672\W'
2. Stop the process that is consuming the port and uninstall the package.
3. Go to the directory where you extracted the ItemSense archive file. Rerun the ItemSense installation script in the tarfile directory. For specific instructions, follow the steps beginning at step 5 of the Install Instructions in the Installation Guide.
Error Code 400 Received During Provisioning
A 400 error code received while provisioning could indicate that the request has timed out. This could have a number of possible causes.
Resolution:
- Check for a firewall blocking the port between ItemSense and the reader agent.
- Check for typos or other errors in the host name.
- Check for a reader with a custom password
- Make sure the provided host name or IP address is correct.
- Ensure that the reader is able to resolve hostname of ItemSense server using DNS.
Unable to modify reader NTP settings
With Octane Firmware 5.10 and greater, Network Time Protocol (NTP) settings cannot be modified without first disabling the NTP service.
Resolution:
Use the following command to disable the NTP service:
config network ntp disable
Reader provisioning fails
Networking issues may cause reader provisioning failures. Although ItemSense may be able to communicate with the readers, the readers may not be able to communicate with ItemSense.
Resolution:
- Verify connectivity between the readers and ItemSense.
- If no networking issues were found, attempt to re-provision the reader.
- If you are still unable to provision the reader, contact Impinj support.
ItemSense operates slowly when reporting tags
When the readers are provisioned, the IP address or hostname used to access the ItemSense Management Console (IMC) is written to the reader as the ItemSense address. If this is an IP address or hostname that the reader has trouble connecting to, then the reader will have connectivity issues as it tries to communicate back to the IMC.
Resolution:
- When provisioning the readers, be sure to access the IMC using the same IP Address that the readers will be expected to use. This would be the IP address the readers use to communicate back to the IMC.
- If the wrong address was used, you may have to re-provision a reader using the correct address.
- If the issue persists, contact Impinj support.
Lost administrator password
If the ItemSense administrator password has been lost, it is possible to reset it back to its default value "admindefault".
Resolution:
- Call the factory reset API endpoint as specified in the API Documentation
OR
- Connect to ItemSense server using the Secure Shell (SSH) protocol.
- Use the following command to edit the admin.json file:
sudo vi ~/containers/itemsense/home/itemsense/data/configstore/users/admin.json
- Replace the contents of the file with the following text:
{"name":"Admin","roles":["Admin"],"visible":true,"passwordHash":"$2a$10$INiYM7LUIq1SDh90qSn6T.tEA1NpIs1/fXhUoOKrQaXGMbKvwlHnu"}
- Reboot the ItemSense server, and log in to the IMC using "admindefault" as the password.
Stopping ItemSense produces errors
When ItemSense is stopped, one or more error messages are displayed. For example, you may see a message such as driver "overlay" failed to remove root filesystem. You must not restart ItemSense without addressing the issues.
Resolution:
- Address the issues that were indicated by the error messages. If you are unsure how to proceed, contact Impinj Support.
- Verify that no containers are running:
sudo docker ps
Data is lost when restarting ItemSense
When ItemSense is stopped and then restarted, all configuration data is lost.
Resolution:
Contact Impinj Support.
Access to ItemSense is denied when hostname changed
If the ItemSense hostname changes, you will get an "invalid user/password combination" when attempting to access the IMC.
Resolution:
Recreate the docker containers:
sudo docker-compose -f itemsense-prod-3.yml down
sudo docker volume prune
sudo docker-compose -f itemsense-prod-3.yml up -d
Files config.yml and logback.xml are not editable
To make the files config.yml and logback.xml editable, you must first escalate the permissions using either chmod, chmod +x config.yml
or sudo, sudo gedit config.yml
Reader Health
Reader is in questionable state of health
The overall health status of a reader is either NOT_RESPONDING or IDLE with last check-in reporting null, as shown in the following screenshot. A reader should check in with ItemSense at 15-second intervals. The most likely cause is that the reader is no longer paired with this instance of ItemSense or the reader is disconnected from the network.
Resolution:
- Determine reader and ItemSense pairing. If the reader is indeed paired to this instance of ItemSense, verify connectivity between the reader and ItemSense; otherwise, proceed to step 2.
- Note the IP address of the reader in the reader definition. You will need the reader's IP address to re-pair it to your instance of ItemSense.
- Delete the reader by clicking on EDIT at the bottom of the reader definition.
- Click on the SCANNER tab on the Readers page.
- Select the subnet that includes the IP address of the reader that you deleted.
- Click the DISCOVER READERS button. After ItemSense discovers the readers, the reader that you deleted should be listed under Available for registration.
- Select the reader and click the REGISTER SELECTED READERS button.
Tag Data Collection
Wrong facility is reported on tag reads
There may be several causes of this issue.
Resolution:
Contact Impinj Support.
Some EPC values do not get reported in PURE_ID, TAG, and UPC12 formats
PURE_ID, TAG, and UPC12 require that the tags have SGTIN-96 encoding. If not correctly encoded, they return no data.
Resolution:
- Make sure the tags have SGTIN-96 encoding, or
- Use the RAW format when running queries.
For more information about EPC formats, see Get Items, Get Item History, or Get Item Threshold Transitions under Items in the ItemSense API documentation.
No tags show up in the Items screen
NTP time-synchronization issues are the most common cause of tag-read issues. Readers must be synchronized with each other and with the ItemSense server. The following situations may prevent this synchronization from happening:
- Option 42 (DHCP option to use NTP servers) is not enabled in the DHCP client configuration file
- The DHCP server used by the ItemSense server is different from the DHCP server used by the readers
- An internet-based NTP server is not accessible and no NTP server is configured on the local network
Network issues or a lack of sufficient disk space may also cause tag-read issues.
Resolution:
- Check the job configuration and verify that no filters are preventing tags in the field of view from being read.
- Visually inspect the LED lights of the readers to verify that the jobs are running and that they have not been rebooted since the start of the job.
- Verify that NTP is working properly:
ntpq -pn
This command displays information about the peer servers specified in the NTP configuration file. Sample output is shown below. A *
or +
symbol at the beginning of the line indicates that the peer can be used for synchronization. If no peer is marked by a *
or a +
, NTP is not operating properly.
If NTP is working properly, proceed to the next step; otherwise, set up the ItemSense server as an NTP server and configure the readers to use the ItemSense server as their NTP server, as described in the ItemSense Installation document. 4. Verify connectivity between the readers and ItemSense. 5. Confirm that there is enough disk space on the ItemSense server. See the Server Recommendations section in the ItemSense documentation for resource requirements. 6. Prune the ItemSense logs to reclaim disk space. 7. If problems persist, contact Impinj support.
No tags show up in the Item or Threshold event message output
If jobs are running that should be producing Item or Threshold events but no output is seen on properly configured event brokers, there are several potential causes that warrant investigation:
The job does not have the option set for sending tag events to message queues. Resolution: enable the Data Handling option to "Send tag events to message queues", if using the IMC, or pass a true value for the "reportToMessageQueueEnabled" parameter to the ...control/v1/jobs/start URL if using the API.
The filters on the publisher or message queue are too restrictive and are eliminating all events. Resolution: adjust the filters to be less restrictive, double-check spelling on any EPC prefix or Job Name prefix filter fields.
Parsing on the client side is failing due to an added or changed field (compared to the 2018r2 release of ItemSense). This applies to message queues configured using the ...data/v1/items/queues and ...data/v1/items/queues/threshold URL endpoints. Starting with ItemSense version 2.0.3, Item and Threshold events are published with an additional "jobName" field, and Threshold events have a field that was changed from "dockDoor" to "thresholdId". These changes, particularly for the changed field, are not likely to be handled by client code written to work with the 2018r2 release. Resolution: Update the client code to handle the changed and added fields, or better yet, switch to using the newer publisher and broker APIs to configure the data sources (the APIs under ...configuration/v1/events), as these provide more options and control.
RabbitMQ message queue silently dies after one hour
The RabbitMQ broker will quit after an hour of inactivity (no tag reads), and the connected app will not receive any notification that the connection is broken.
Resolution:
No resolution is necessary — this behavior is by design.
Jobs
Job prematurely stops running or fails to start
If a job stops running before it completes or if a job is unable to start and the IMC displays the following message, the problem may be that there is not enough disk space on the ItemSense server.
Resolution:
- Confirm that there is enough disk space on the ItemSense server. See the Server Requirements section in the ItemSense documentation for resource requirements.
- Prune the ItemSense logs to reclaim disk space.
- If jobs still do not start, contact Impinj Support.
ItemSense is stopped during a Job
If ItemSense is stopped while a job is running, it should be able to continue to receive data from the reader once it restarts. Data may be lost if reader’s buffer fills before ItemSense is started.
Resolution:
- Restart ItemSense to reconnect to the job.
- If ItemSense is unable to reconnect, it may be necessary to re-provision the reader.
A reader is stopped, or loses its network connection, during a Job
If the network is temporarily disconnected from a reader while the reader is running a job, ItemSense does not display an error message to indicate that it has lost contact with the reader.
Resolution:
- Reconnect the reader and the reads will successfully continue.
- If the reader buffer did not overflow, no data was lost.
Common Procedures
Verify connectivity between the readers and ItemSense
Although ItemSense may be able to communicate with the readers, the readers may not be able to communicate with ItemSense. Use the following steps to verify that the readers can communicate with ItemSense.
- Log on to the ItemSense server.
- Use the
ifconfig
command to see which network interface is being utilized for connectivity between ItemSense and the readers. -
Use the
tcpdump
command to test for reader-to-ItemSense connectivity issues. For example, if eth1 is the network interface, use thetcpdump
command as follows:- To test for basic reader-to-ItemSense connectivity, specify port 443:
tcpdump -i eth1 port 443 -w tcpdumpfile.443.pcap
- To test reader-agent provisioning, specify port 51505:
tcpdump -i eth1 port 51505 -w tcpdumpfile.51505.pcap
- To test SSH commands sent to the reader, specify port 22:
tcpdump -i eth1 port 22 -w tcpdumpfile.22.pcap
- To test NTP communication from the reader to ItemSense, specify port 123:
tcpdump -i eth1 port 123 -w tcpdumpfile.123.pcap
When the
tcpdump
command fails or completes, closetcpdump
and load the resulting .pcap file into your preferred network traffic analyzer.
Prune the ItemSense logs
ItemSense logs are contained within the home directory of the user who installed it. Each ItemSense service will have its own directory within the ItemSense parent directory. Generally, log files are only created when ItemSense is being used. In other words, no logs are created if ItemSense isn't being used. 1. Log into the ItemSense server using the ItemSense installer’s login with an SSH or FTP client. 2. Delete the largest logs from the general ItemSense logs directory.
File path: ~/containers/itemsense/home/itemsense/var/output/logs
- Delete the largest logs from the API service ItemSense logs directory.
File path: ~/containers/itemsense/home/itemsense/ItemSenseAPIService/var/output/logs
- Delete the largest logs from the coordinator ItemSense logs directory.
File path: ~/containers/itemsense/home/itemsense/Coordinator/var/output/logs
Re-provision a reader
Perform the following steps when a reader needs to be provisioned: 1. Delete the reader configuration from the IMC if it exists. 2. Connect to the reader using SSH. 3. Remove the reader’s CAP file:
config image removecap
- Close the SSH client, and use the IMC to re-add the reader.
Determine reader and ItemSense pairing
You can determine the instance of ItemSense with which a reader is paired by examining the reader's config.json file. Use the following steps to retrieve this file from a reader.
- Connect to the reader via secure shell:
ssh root@
- Once connected, use the config network RShell command to enable FTP on the reader:
config network ftp enable
- Exit out of RShell and connect to the reader via an FTP client:
ftp
- Change to the reader's cust directory, download the config.json file, and exit out of your FTP client. The commands may vary slightly, depending on the FTP client that you use. The following commands are an example:
cd /
cd cust
get config.json
quit
- Display the contents of the reader's config.json file by using the cat command:
cat config.json
Example output:
{"agentid":"xArray-11-3F-5F","apikey":"94a6546f-7e61-4860-b22a-3cf762e7cf10","baseurl":"https://10.200.10.23:443/itemsense/","tlscertfile":"/cust/cert.pem"}
The contents of the baseurl field in the .json file specify the instance of ItemSense that the reader is paired with.