Contents

Introduction

This is the documentation for the 2.1 release of Impinj ItemSense, which was released on July 26, 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
    • Reduced the installation package size by 66%
    • Reduced installation and upgrade time by over 60%
    • Increased minimum docker version requirements for install to 18.09.02 for Docker and 1.23.2 for Docker Compose
    • During in-place upgrade, the user may specify whether to use the recommended DB pruning settings or turn them off
    • During install or upgrade, the user may specify a target install path of their choosing
    • Minimum supported version for in-place upgrade changed to 'ItemSense 2018r2 Build 1139-1'
    • Installer 'remove' command no longer has a --purge flag, since --purge is now the default behavior
    • Added many installer usability improvements, including additional help text, better prompts, and color-coded output
  • Data and Algorithms
    • Database data can now be pruned based on a total number of records to retain as well as age
    • Added the ability to download iteration data logs directly (to help with Threshold tuning)
    • Support for tag expiration cache length configuration in Threshold jobs
    • Added "early reporting" option for faster transition updates from Threshold jobs
    • Added "detection only" calculations to improve Threshold operations
  • RFID Regulatory Region Support
    • Added support for the new EU2 frequencies and higher power output levels on applicable Readers and Gateways
  • Management and Configuration
    • Added support for TLSv1.3 and dropped support for TLSv1.0 (which is less secure)
    • Removed the reportToFileEnabled job property, which previously had no function
    • Removed the tagHeartbeatMinutes property on Location and Inventory Recipes, which has been deprecated since 2017r1
  • ItemSense Management Console (IMC) Improvements
    • Migrated Facility pages to the new IMC platform
    • Migrated User pages to the new IMC platform
    • Migrated Threshold pages to the new IMC platform
    • Completely redesigned the Administration Panel
    • Added help text explaining the detailed behavior of transmit power values
    • Change Job Form defaults, to not store to DB, store to Item History table, or use previous job data by default
    • Removed the "Send to message queues" checkbox on the Job Form, as it is now always enabled
  • Bug Fixes
    • RFTransmitter ChannelIndex from ROSPEC was using the default value instead of the configured one
    • In-place upgrades that could get stuck during DB migration in rare cases
    • It is no longer permitted to specify a non-DUAL_TARGET Search Mode on a THRESHOLD reader configuration
    • Duration input components in the IMC (like Tag Expiry Duration and Tag Heartbeat Duration) were accepting negative values

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 version 18.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:

  1. 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'

  2. 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.

  3. 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

  4. 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

  5. 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.

Installation Instructions

To install ItemSense-2.1.0, you will need to have already downloaded the setup package. This file will be named similar to the following: itemsense-2.1.0+XXX-setup.run

When the setup package file has been obtained:

  1. 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.1.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.

  2. 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.

  3. Make the setup package file executable with the following command:

          chmod +x itemsense-2.1.0+XXX-setup.run

  4. From the same directory as the ItemSense setup package, run the setup package with the argument "install".

          sudo ./itemsense-2.1.0+XXX-setup.run install

    As of ItemSense 2.1.0, Impinj 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_1_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:

    [user@localhost~]$ sudo ./itemsense-2.1.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.1.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_1_0/itemsense-prod.yml
    INFO: Unpacking docker images
    Loaded image: isreg/imc:2.1.0.737
    
    ...
    
    INFO: Unpacking firmware images
    
    ...
    
    Creating 2_1_0_isv2_1      ... done
    
    ...
    
    INFO: Installation action complete using path: /newPath/impinj/itemsense/2_1_0
    INFO: Setting permissions on /newPath/impinj/itemsense/2_1_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://<server IP>: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_1_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.1.0 has been installed according to the Installation instructions, and is up and running on TARGET_SERVER_YYY

Side-by-Side Upgrade Instructions

As of ItemSense 2018r2, the configuration migration is executed through the ItemSense Management Console (IMC).

  1. In a browser on TARGET_SERVER_XXX, navigate to the IMC using the server IP address or host name and port 3010:

  2. From the landing page navigation menu, click More | Configuration Import/Export. This will take you to the Configuration Migration page.

  3. Click the Export Configuration button.

  4. Select and copy the exported configuration, including both the beginning and ending brackets.

  5. Navigate to the IMC Configuration Migration page on TARGET_SERVER_YYY.

  6. Click in the Import Configuration text box and paste the content you copied.

  7. Select Overwrite and click the Import 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).

  1. On the navigation bar, click More | Admin Panel.
  2. Click Software Installation.
  3. For Software to Install, select Reader Agent
  4. For Version to Install, select the latest version of the reader agent.
  5. 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

  1. (Optional) As a precaution, backup your configuration and database.

    1. From the IMC navigation menu, click More | Configuration Import/Export
    2. On the Configuration Import/Export page, click the Export Configuration button.
    3. Select and copy the exported configuration, including both the beginning and ending brackets.
    4. Backup the ItemSense database. The database is stored in: ~/containers/is-db

            sudo cp -r ~/containers/is-db ~/IS_DB_BACKUP

  2. 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.1.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

  3. 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.

  4. Make the setup package file executable:

          chmod +x itemsense-2.1.0+XXX-setup.run

  5. From the same directory as the ItemSense setup package, run the setup package with the argument "upgrade".

ItemSense 2.1.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.1.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.

As of ItemSense 2.1.0, Impinj 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_1_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_1_0/containers
INFO: Generating compose file: /MyDir/impinj/itemsense/2_1_0/itemsense-prod.yml
INFO: Unpacking docker images
Loaded image: isreg/imc:2.1.0.743
Loaded image: isreg/is-mariadb:2.1.1
Loaded image: isreg/is-ntp:0.0.3
Loaded image: isreg/is-proxy:0.2.1
Loaded image: isreg/isv2:0.0.108-a0f0d84b
Loaded image: isreg/itemsense:2.1.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_1_0_itemsense" with driver "bridge"
Creating 2_1_0_isv2_1      ... done
Creating 2_1_0_imc_1       ... done
Creating 2_1_0_itemsense_1 ... done
Creating 2_1_0_is-ntp_1    ... done
Creating 2_1_0_is-db_1     ... done
Creating 2_1_0_is-rabbit_1 ... done
Creating 2_1_0_nginx_1     ... done
INFO: Installation action complete using path: /MyDir/impinj/itemsense/2_1_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_1_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://<server IP>: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_1_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.

  1. Add a network
    1. Find a network to add by looking at the Address field of a reader definition
    2. In the navigation menu, click More | Admin Panel.
    3. Click Scanner Configuration
  2. Register readers
    1. From the Definitions page, click the Scanner tab. This will take you to the SCANNER page.
    2. Click the DISCOVER READERS button.
    3. Select only the readers flagged with the triangle exclamation point
    4. Click the REGISTER SELECTED READERS button
  3. Upgrade reader firmware
    1. Return to the Definitions" page. In the navigation menu, click *More | Admin Panel**.
    2. Click SOFTWARE INSTALL.
    3. Under Software Installation, Software to Install, select Reader Firmware.
    4. Select your set of readers to update
    5. 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:

  1. Go to the directory where you put the ItemSense installer file.

  2. Run the installer with the remove subcommand to remove the ItemSense software:

          sudo ./itemsense-2.1.0+XXX-setup.run remove

    Example output:

    
    [issupport@localhost ~]$ sudo ./itemsense-2.1.0+XXX-setup.run remove
    Verifying archive integrity...  100%   All good.
    
    ItemSense 2.1.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:

  1. 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
    


  2. Remove the containers directory and the itemsense-prod.yml file from the installation directory.

          sudo rm -rf containers/
          sudo rm -f itemsense-prod.yml

  3. 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
    


  1. 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.

  1. Connect to ItemSense via the ItemSense Management Console at: http://TARGET_SERVER:3010.
  2. From the Home Page menu bar, click More|NTP Reader Sync.
  3. 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:

  1. Log in to the reader RShell command prompt using SSH.
  2. Disable NTP:

          config network ntp disable

  3. (Optional) Prevent the reader from dynamically configuring its NTP servers through DHCP:

          config network ntp dynamicservers disable

  4. Delete any configured NTP servers:

          config network ntp delall

  5. Add the external NTP server hostname or IP address:

          config network ntp add <NTP Server hostname or IP>

  6. Re-enable NTP:

          config network ntp enable

  7. 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_1_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_1_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_1_0/itemsense_support/enable_tls.sh disable

Configuration and Logging Files

With ItemSense 2.1.0, 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_1_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.1 release of Impinj ItemSense, which was released on August 15, 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 can be 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:

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
string 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

Zone Map

  {
    "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 = "<CURRENT_READER_NAME>";
var params =  {
   name: "<READER_NAME>",
   agentIdentifier: "<AGENT_ID>",
   address: "<IP_OR_HOSTNAME>",
   groups: [],
   type: "<TYPE_OF_READER>",
   placement: {
      x: 4.1,
      y: 3.65,
      z: 1.68,
      yaw: 30,
      pitch: 0,
      roll: 90,
      floor: 1
   },
   facility: "<FACILITY>",
};

var xhr = new XMLHttpRequest();
xhr.open("PUT", "http://<BASE_URL>/itemsense/configuration/v1/readerDefinitions/replace/" + currentName, true)
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Basic " + btoa("<USERNAME>:<PASSWORD>"));
xhr.send(JSON.stringify(params));
string username = "<USERNAME>";
string password = "<PASSWORD>";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string json;
string currentName = "<CURRENT_READER_NAME>";

Uri uri = new Uri("http://<BASE_URL>/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 =  "<READER_NAME>",
        agentIdentifier = "<AGENT_ID>",
        address = "<IP_OR_HOSTNAME>",
        //groups = [],
        type = "<TYPE_OF_READER>",
        placement = new {
            x = 4.1,
            y = 3.65,
            z = 1.68,
            yaw = 30,
            pitch = 0,
            roll = 90,
            floor = 1
        },
        facility = "<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:

Reader Configuration

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:
  • MAX_THROUGHPUT
  • HYBRID
  • DENSE_READER_M4
  • DENSE_READER_M8
  • MAX_MILLER
  • DENSE_READER_M4_TWO
  • AUTOSET_DENSE_READER
  • MODE_1002
  • MODE_1003
  • MODE_1004
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:
  • READER_SELECTED
  • SINGLE_TARGET
  • DUAL_TARGET
  • TAG_FOCUS
  • SINGLE_TARGET_BTOA
  • DUAL_TARGET_WITH_BTOASELECT
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:
  • CUSTOM
  • LEGACY
  • FAST_CYCLE
  • METHOD_1_18_3
  • METHOD_1_21_3
  • METHOD_2
  • METHOD_3
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:
Memory Bank # Tag Memory Region
0 Reserved
1 EPC
2 TID
3 User

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:
LLRP Channel Index Center Frequency (MHz)
1 865.70 MHz
2 866.30 MHz
3 866.90 MHz
4 867.50 Mhz
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 string
antennaConfiguration
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 string
antennaConfiguration
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:
  • configuration.operation=LOCATION
  • configuration.operation=INVENTORY and configuration.searchMode=DUAL_TARGET
Forbidden combinations:
  • configuration.operation=INVENTORY and configuration.searchMode=SINGLE_TARGET
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:
  • configuration.operation=LOCATION
  • configuration.operation=INVENTORY and configuration.searchMode=DUAL_TARGET
Forbidden combinations:
  • configuration.operation=INVENTORY and configuration.searchMode=SINGLE_TARGET
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<string, string>(){
    {"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: "<USERNAME>", password: "<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 = "<USERNAME";
            string currentUserPassword = "<PASSWORD>";
            string BASE_URL = "...";
            string endpoint = "/data/v1/items/queues";

            HttpWebRequest httpRequest;
            HttpWebResponse httpResponse;
            AMQPdata amqp = new AMQPdata();
            requestParameters reqParams = new requestParameters();

            string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(currentUser + ":" + currentUserPassword));

            // Compose the request
            Uri uri = new Uri(BASE_URL + endpoint);
            httpRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
            httpRequest.Headers.Add("Authorization", "Basic "+ encodedCredentials);
            httpRequest.Method = "PUT";
            httpRequest.ContentType = "application/json";

            // Add the request body
            using (var sw = new StreamWriter(httpRequest.GetRequestStream()))
            {
                // Put the request properties in JSON format for the request body
                string requestBody = JsonConvert.SerializeObject(reqParams);
                Console.WriteLine("Request body in JSON format: " + requestBody);
                sw.Write(requestBody);
            }

            // Send the request and get the response
            httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
            {
                // Save the JSON data returned in the response and then convert it to the AMQPdata structure 
                var amqpJSON = streamReader.ReadToEnd();
                var amqpConvertedFromJSON = JsonConvert.DeserializeObject<AMQPdata>(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://<BASE_URL>/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 = "<READER_NAME>";
var url = "http://<BASE_URL>/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("<USERNAME>:<PASSWORD>"));
xhr.send();
string username = "<USERNAME>";
string password = "<PASSWORD>";
string encodedCredentials = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
string readerName = "<READER_NAME>";

Uri uri = new Uri("http://<BASE_URL>/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 the computeWindow in ItemSense set in a recipe. The computeWindow 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 the computeWindow. Longer computeWindow periods produce more accurate tag positions, but the longer the computeWindow 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.

Threshold IN and OUT

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.

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.

Reader configuration for xArray overhead offset

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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:

  1. ItemSense is told to start a job.
  2. ItemSense waits for the duration specified in the startDelay.
  3. Once the job start duration has passed, ItemSense passes each reader their configuration as specified in the Recipe.
  4. 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.
  5. Tag data is received by ItemSense from each reader.
  6. 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
  7. ItemSense will calculate any events (like a zone transition) based on the new information about the tag.
  8. ItemSense will make the tag data available in the Items table. This is optional and can be set before starting the job.
  9. ItemSense will make the tag data available in the Item History table. This is optional and can be set before starting the job.
  10. 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:

A state diagram showing all the states a job can be in

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 the readerZone parameter from within the readerDefinition of the reader which read the tag.

If running a location recipe on an xArray:

  • The xLocation and yLocation 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:

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:

  1. Configure users with the appropriate roles.
  2. Add the required facilities.
  3. 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.
  4. Add a reader definition for each deployed RAIN RFID gateway. This can be done manually or via the network scanner within the IMC.
  5. Establish and understand what tag data needs to be collected based on the use case being fulfilled.
  6. Add the appropriate reader configurations and recipes to collect the tag data established in the step above.
  7. Configure and start jobs to perform these operations.
  8. Query tag data via event-based message queues.
  9. Monitor health of the readers via event-based message queues.
  10. 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 to INVENTORY
  • In the configuration sub-section:
    • Set readerMode to MODE_1002 if the readers are well spaced, and to MODE_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 to SINGLE_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
    • 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
  • If inventorying a large number of tags, set tagPopulationEstimate to 32
  • If inventorying a small number of tags, set tagPopulationEstimate to 4
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 to LOCATION
  • In the configuration sub-section:
    • Set readerMode to MODE_1002 if the readers are well spaced, and to MODE_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
Recipe Parameters
  • Set type to LOCATION
  • 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 than reportingInterval. 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 the durationSeconds to 0

Threshold

Goal: to track items moving across a threshold

Reader Configuration Parameters
  • Set operation to THRESHOLD.
  • Set configuration.readerMode to MAX_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. Threshold xArray Antenna Configuration

The following diagram shows the configuration of xSpan antennas. Threshold xSpan Antenna Configuration

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 to THRESHOLD
  • 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 the durationSeconds 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 to INVENTORY
  • Set configuration.readerMode to MODE_1002, which will automatically adapt the communication frequencies to the environment
  • Set configuration.searchMode to DUAL_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 to 32
  • If inventorying a small number of tags, set tagPopulationEstimate to 4
Recipe Parameters
  • Set type to INVENTORY
  • 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 than reportingInterval. 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 the durationSeconds 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 the filter 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 different memoryBank and/or bit pointer 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:

  1. The job begins and the tag is reported.
  2. Every 60 seconds, while the tag is in the field of view, the reader reports on the tag status.
  3. 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.
  4. At 12 minutes, a change event occurs and ItemSense publishes it.
  5. 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.

Tag Heartbeat Duration

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

  1. The job starts at 0.
  2. Every 60 seconds, while the tag is in the field of view, the reader records the tag status.
  3. No event occurs, so at five minutes and again at ten minutes, Tag Heartbeat Duration triggers ItemSense to publish a report.
  4. At 12 minutes, the tag disappears from the field of view. (This is not considered an event so is recorded but not published).
  5. For the next ten minutes, the tag is no longer observed, so ItemSense is never triggered to publish.
  6. 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).
  7. 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 Heartbeat Duration Example #1

Tag Expiration Duration Example #2

This example and the illustration that accompanies it illustrate a somewhat more complex scenario.

  1. The job starts at 0.
  2. Every 60 seconds, while the tag is in the field of view, the reader records the tag status.
  3. At three minutes, the tag disappears. (This is not considered an event so is recorded but not published).
  4. 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.
  5. 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.
  6. At 11 minutes, because no change event has taken place, the Tag Heartbeat Duration triggers a published report again.
  7. An event occurs at 12 minutes, triggering a ItemSense to publish. This also resets the Heartbeat Duration timer.
  8. The tag disappears from the field of view again at 14 minutes.
  9. For the next ten minutes, the tag is no longer observed, so no report is triggered.
  10. At 24 minutes Tag Expiration Duration recognizes that the tag has been missing for the Tag Expiration Duration (in this example, ten minutes).
  11. 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.

Tag Heartbeat Duration Example #2

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 the reportingInterval. 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 readerGroups 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:

  1. Change the default admin password.
  2. Define a new facility. ItemSense comes with the facility "default" but the user is required to make another.
  3. 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.
  4. 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.
  5. 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
  6. 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 different components of ItemSense.

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.

A sequence diagram to show how Reader Agent registration works.

  1. 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,
  2. 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.
  3. Now the IMC has the reader details it will upload the ItemSense Reader Agent to the reader.
  4. The reader is rebooted which causes the Reader Agent to be installed.
  5. 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.
  6. 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.
  7. 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.
  8. 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 or ReaderRestartError.
  • args: a space in the health event message where additional details about the event can be specified. For example, if the event type is LIFECYLCLE and its code is REBOOT, then args 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.

Getting reader health information via the API and message queue

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.

After you connect to ItemSense, the following page appears. Enter either your ItemSense UUID or your ItemSense Instance ID and select your regulatory region from the drop-down menu. If you do not know your UUID or your Instance ID, contact support@impinj.com.

Click the SUBMIT button to continue.

Initial page after connecting to server displays Instance ID field and Regulatory Region field.

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.

The log in screen, with Username and Password fields, and a LOG IN button below.

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 1: change password. Text, change administrator password, please update your administrator password. Field, New password. Field, Confirm new password field. Button, Submit. Button, Next Step.

Step 2: Create one or more facilities

The Facilities page appears. ItemSense comes with the facility default, but the user is required to create another. 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.

Step 2: Page, Create facilities. Text, Please create at least one facility before continuing. Button, Create a facility. Field, New facility name. Check box, Set as current facility. Button, cancel. Button, create 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 3: Page, Configure Networking. Text, View, validate, and define networks. Button, Add subnet.

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.

Step 4: Page, Scan attached networks for readers. Text, Select subnet ranges to scan for Impinj readers. Button, Discover readers.

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.

Step 4: Page, Scan for specific readers by name or address. Text, Enter specific reader names or addresses. Button, Discover readers.

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.

Dialog box for entering credentials of a reader.

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. Once begun, the process cannot be canceled.

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.

Reader Registration. Displays status of, Agent installer upload completed, ready for reboot.

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.

Setup complete page. Text, You're good to go. Button, Go to 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.

ItemSense Reader Health

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.

ItemSense Reader Health Categories

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.

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:

  1. From the landing page, click the Scanner tab.

  2. Select if you will Scan by Networks or Manually Enter Hostnames or IP Addresses.

  3. Click the DISCOVER READERS button.

    Reader re-registration

  4. 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.

Selected Readers

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.

Administration

A panel will be displayed with options for resetting ItemSense, network scanner configuration, and software management.

Administration Panel

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.

Software Update Start New

In the Image Type field, select FIRMWARE_SPEEDWAY. Select the version and (optionally) the maximum number of readers to update in parallel.

Sofware Update Select Image Type

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.

Software Update Select Readers In Facilty

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.

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.

Live Transition Data

This data can be filtered by EPC prefix, observation start and end time, and the transition direction.

Live Transition Filtering

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
  1. Navigate to the Jobs` tab in the top navigation bar
  2. Locate the specific job of interest under Active Jobs
  3. Click on the icon circled below to navigate to live transitions for that job

Job Transition Navigation

Transitions From a Single Threshold
  1. Navigate to the Thresholds tab.
  2. Locate the threshold of interest
  3. If the threshold is running a job, click on the icon circled below to navigate to the live transition for that threshold


Threshold Transition Navigation


Resource Requirements

Recommended Server Requirements

Server Resource Size
CPU core count >= 4 physical cores with hyperthreading/SMT (>= 8 logical cores) OR 8 vCPU in VM environments
CPU speed >= 2.5 GHz
Memory >=16 GB, depending on the size and number of concurrent jobs being run.
Hard disk type Enterprise-grade SSD is recommended for prolonged production operation. Consumer-grade SSD is sufficient for short-term proof of concept installations
Hard disk size >= 256 GB
Hard disk speed >= 90,000 IOPS for random access, > 500MBps sequential access
Network interface Must support 1000 Mbps Ethernet
Operating System Ubuntu Linux 16.04, Ubuntu Linux 18.04, or Centos 7

Minimum Server Requirements

Server Resource Size
CPU core count >= 2 physical cores with hyperthreading/SMT (>= 4 logical cores) OR 4 vCPU in VM environments
CPU speed >= 2.5 GHz
Memory >= 8 GB, depending on the size and number of concurrent jobs being run.
Hard disk type Enterprise-grade SSD is recommended for prolonged production operation. Consumer-grade SSD is sufficient for short-term proof of concept installations
Hard disk size >= 64 GB. (256 GB if using the ItemSense Item/Item History API.)
Network interface Must support 1000 Mbps Ethernet
Operating System Ubuntu Linux 16.04, Ubuntu Linux 18.04, or Centos 7

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
  • 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. Although the diagram below shows the IMC and ItemSense core as architecturally separate components, they are currently co-located on the same host.

ItemSense Network Requirements Diagram

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 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 the Reader Configuration section in the ItemSense Reference Guide for more details.


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:

  1. Navigate to the appropriate section in the API Guide.
  2. Read the description of the parameters which need to be set including what values they can be set to.
  3. 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:

  1. Click on the three vertical dots in the upper right corner of the IMC.
  2. Navigate to admin -> API Keys. The IMC name for a token is "API Key".
  3. Select the username from the drop-down list.
  4. If necessary, enter the password for that user.
  5. 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.

A diagram showing how ItemSense interprets valid and invalid zone definitions

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.

A diagram showing how ItemSense interprets valid and invalid zone definitions

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:

  1. They determine how often a tag responds to a "select 'A' state tag" query from the reader.
  2. 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:

  1. 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.

  2. 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:

  1. 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:

  1. Verify connectivity between the readers and ItemSense.
  2. If no networking issues were found, attempt to re-provision the reader.
  3. 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:

  1. 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.
  2. If the wrong address was used, you may have to re-provision a reader using the correct address.
  3. 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:

  1. Call the factory reset API endpoint as specified in the API Documentation

OR

  1. Connect to ItemSense server using the Secure Shell (SSH) protocol.
  2. Use the following command to edit the admin.json file:
   sudo vi ~/containers/itemsense/home/itemsense/data/configstore/users/admin.json
  1. Replace the contents of the file with the following text:
   {"name":"Admin","roles":["Admin"],"visible":true,"passwordHash":"$2a$10$INiYM7LUIq1SDh90qSn6T.tEA1NpIs1/fXhUoOKrQaXGMbKvwlHnu"}
  1. 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:

  1. Address the issues that were indicated by the error messages. If you are unsure how to proceed, contact Impinj Support.
  2. 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-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.

Reader health shows status of NOT_RESPONDING or IDLE with last check-in reporting null"

Resolution:

  1. 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.
  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.
  3. Delete the reader by clicking on EDIT at the bottom of the reader definition.
  4. Click on the SCANNER tab on the Readers page.
  5. Select the subnet that includes the IP address of the reader that you deleted.
  6. Click the DISCOVER READERS button. After ItemSense discovers the readers, the reader that you deleted should be listed under Available for registration.
  7. 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:

  1. Check the job configuration and verify that no filters are preventing tags in the field of view from being read.
  2. 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.
  3. 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.

Information displayed when NTP is working 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:

  1. 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.

  2. 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.

  3. 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.

Message "Error creating job"

Resolution:

  1. Confirm that there is enough disk space on the ItemSense server. See the Server Requirements section in the ItemSense documentation for resource requirements.
  2. Prune the ItemSense logs to reclaim disk space.
  3. 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:

  1. Restart ItemSense to reconnect to the job.
  2. 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:

  1. Reconnect the reader and the reads will successfully continue.
  2. 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.

  1. Log on to the ItemSense server.
  2. Use the ifconfig command to see which network interface is being utilized for connectivity between ItemSense and the readers.
  3. Use the tcpdump command to test for reader-to-ItemSense connectivity issues. For example, if eth1 is the network interface, use the tcpdump 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
    
  4. When the tcpdump command fails or completes, close tcpdump 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

  1. Delete the largest logs from the API service ItemSense logs directory.

File path: ~/containers/itemsense/home/itemsense/ItemSenseAPIService/var/output/logs

  1. 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
  1. 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.

  1. Connect to the reader via secure shell:
   ssh root@<reader hostname>
  1. Once connected, use the config network RShell command to enable FTP on the reader:
   config network ftp enable
  1. Exit out of RShell and connect to the reader via an FTP client:
   ftp <reader hostname or reader IP address>
  1. 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
  1. 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.