Data Analytics Python Guide

The Data Analytics functionality can be implemented as a Python script using the Python pyziotc (Zebra IOT Connector) module resident on the reader.

The Python pyziotc module is meant to abstract the underlying connections between the IoT Connector components (i.e. Radio Control and Reader Gateway) and allow the script to filter, analyze, and act on the data itself.

The minimal flow of the script is as follows:

  1. Define a new message callback function to operate on the incoming data. This function will be called whenever there is new data to be filtered.

    def new_msg_callback(msg_type, msg_in):
        pass
    

    For more details see New Message Callback

  2. Open the pyziotc module. This will extablish connections between the script and the other IoT Connector components.

    import pyziotc
    ziotcObject = pyziotc.Ziotc()
    
  3. Register the previously defined function from step 1. This notifies the pyziotc module to use the callback funtion when new messages arrive.

    ziotcObject.reg_new_msg_callback(new_msg_callback)
    

Note

The loop.run_forever() method that was required to be called in the legacy python module is not required anymore.

New Message Callback

The user-defined new message callback function is the core of the script. The callback definition must contain 2 parameters, msg_type and msg_in. The function can then process the input message and send out an output message based on the input. All messages shall be Python bytearrays

For example, the following callback function, only sends out a data message if the beginning of the tag’s ID begins with a prefix.

prefix = '38'
def new_msg_callback(msg_type, msg_in):
    if msg_type == pyziotc.MSG_IN_JSON:
        msg_in_json = json.loads(msg_in)
        tag_id_hex = msg_in_json["data"]["idHex"]

        if tag_id_hex.startswith(prefix):
            z.send_next_msg(pyziotc.MSG_OUT_DATA, bytearray("Filtered data " + msg_in, 'utf-8'))

Input Message types

The new message callback will be called each time a new message arrives from the Radio Control. The incoming msg_type is a constant defined in the ziotc.py module. The currently available value for incoming messages is:

MSG_IN_JSON = 0
MSG_IN_GPI = 6

The MSG_IN_JSON type is a JSON tag information message (after decoding from the bytearray). The format is identical to the format of tag messages coming directly from the Radio Control. The MSG_IN_GPI type is a JSON GPI event message (after decoding from the bytearray). The format is identical to the format of GPI messages defined here.

Output Message types

Messages can be sent to the Reader Gateway and off the reader by calling:

ziotcObject.send_next_msg(msg_type, msg_out)

msg_type is a constant defined in the ziotc.py module. The currently available value for outgoing messages are:

MSG_OUT_DATA= 3
MSG_OUT_CTRL= 4
MSG_OUT_GPO = 5

The MSG_OUT_DATA type will send the message to the Reader Gateway to output on the Data Interface. The MSG_OUT_CTRL type will send the message to the Reader Gateway to output on the Management Event Interface. The MSG_OUT_GPO type will send the control the GPO/LED.

Data Analytics Passthru

In addition to processing data from the Radio Control and passing new, or filtered, data through to the Reader Gateway, messages can be passed through the Reader Gateway directly to the Data Analytics script. These messages can be sent to the Reader Gateway via the Management Command/Response interface. In order to process the passed through messages, a pass through callback must be defined and registered with the ZIOTC object.

The pass through callback takes in a single parameter. It is a bytearray of the incoming message.

Important

The function must return a response message that is also a bytearray.

This functionality enables a mechanism to configure the Data Analytics Script. The following code snippet continues the example above and allows for a single command “prefix” to be sent to the script. If only “prefix” is sent, the script returns the current value the script is using to filter tags. If prefix is followed by another string, it will update the “prefix” to the new value.

def passthru_callback(msg_in):
    global prefix
    parts = msg_in.split(" ")
    print(parts)

    if parts[0] == "prefix":
        if len(parts) == 1:
            response = "prefix set to {}".format(prefix)
            response = bytearray(response, 'utf-8')
        else:
            prefix = parts[1]
            response = "prefix set to {}".format(prefix)
            response = bytearray(response, 'utf-8')

    else:
        response = b"unrecognized command"

    return response

ziotcObject.reg_pass_through_callback(passthru_callback)

Management and Control of Reader

DA apps can manage and control the reader using the REST interface described here. Reader bundles the python http module which can be used to call local rest apis.

import http.client
from http.client import HTTPConnection

c=HTTPConnection("127.0.0.1")
c.request('GET', '/cloud/status')
res = c.getresponse()
data = res.read()
print(data)

Notifying GPI events

The process of notifying gpi events can be accomplished through the utilization of the enableGPIEvents function.The following is an example app that is displayed below.

import pyziotc
import json

def new_msg_callback(msg_type, msg_in):
    if msg_type == pyziotc.MSG_IN_GPI:
        print("GPI events : ", msg_in)

z = pyziotc.Ziotc()
z.enableGPIEvents()
z.reg_new_msg_callback(new_msg_callback)

Controlling GPO and LED

DA apps can control the reader GPOs and LEDs using the send_next_msg method. LED can be controlled by sending the below payload in send_next_msg method.

{"type":"LED","color":"RED","LED":3}

Note

Only the App LED (LED 3) can be controlled by the user app.

The sample below changes the color of the LED preiodically.

import pyziotc
import json
import time

led_green_msg = bytearray(json.dumps({"type":"LED","color":"GREEN","led":3}), "utf-8")
led_yellow_msg = bytearray(json.dumps({"type":"LED","color":"AMBER","led":3}), "utf-8")
led_red_msg = bytearray(json.dumps({"type":"LED","color":"RED","led":3}), "utf-8")

z = pyziotc.Ziotc()
while True:
    time.sleep(1)
    z.send_next_msg(pyziotc.MSG_OUT_GPO, led_green_msg)
    time.sleep(1)
    z.send_next_msg(pyziotc.MSG_OUT_GPO, led_red_msg)
    time.sleep(1)
    z.send_next_msg(pyziotc.MSG_OUT_GPO, led_yellow_msg)

Controlling GPO can be achieved by sending the below json object in the payload for send_next_msg method.

{"type":"GPO","state":"HIGH","pin":1}

The sample below toggles the GPO preiodically.

import pyziotc
import json
import time

gpo_high_msg = bytearray(json.dumps({"type":"GPO","state":"HIGH","pin":1}), "utf-8")
gpo_low_msg = bytearray(json.dumps({"type":"GPO","state":"LOW","pin":1}), "utf-8")

z = pyziotc.Ziotc()
while True:
    time.sleep(1)
    z.send_next_msg(pyziotc.MSG_OUT_GPO, gpo_high_msg)
    time.sleep(1)
    z.send_next_msg(pyziotc.MSG_OUT_GPO, gpo_low_msg)

Sending Asynchronous messages from the DA app

DA apps can also send asynchronous messages via the management events endpoint of the IoT Connector. The sample below illustrates sending version message at startup.

import pyziotc
import json
import time

version_msg = bytearray(json.dumps({"version": 1, "time": time.now()}), "utf-8")

z = pyziotc.Ziotc()
z.send_next_msg(pyziotc.MSG_OUT_CTRL,version_msg)

Sample Python DA app

Below is the sample DA app that filters data and controls the LED preiodically. It also sends and asynchronous message via the management events interface whenever the LED changes color.

example 1:

import pyziotc
import json

prefix = "43"
def passthru_callback(msg_in):
    global prefix
    parts = msg_in.split(" ")
    print(parts)

    if parts[0] == "prefix":
        if len(parts) == 1:
            response = "prefix set to {}".format(prefix)
            response = bytearray(response, 'utf-8')
        else:
            prefix = parts[1]
            response = "prefix set to {}".format(prefix)
            response = bytearray(response, 'utf-8')
    else:
        response = b"unrecognized command"

    return response

def new_msg_callback(msg_type, msg_in):
    if msg_type == ziotc.ZIOTC_MSG_TYPE_TAG_INFO_JSON:
        msg_in_json = json.loads(msg_in)
        tag_id_hex = msg_in_json["data"]["idHex"]

        if tag_id_hex.startswith(prefix):
            ziotcObject.send_next_msg(zitoc.ZIOTC_MSG_TYPE_DATA, bytearray(msg_in, 'utf-8'))

ziotcObject = pyziotc.Ziotc()
ziotcObject.reg_new_msg_callback(new_msg_callback)
ziotcObject.reg_pass_through_callback(passthru_callback)

led_green_msg = bytearray(json.dumps({"type":"LED","color":"GREEN","led":3}), "utf-8")
led_yellow_msg = bytearray(json.dumps({"type":"LED","color":"AMBER","led":3}), "utf-8")
led_red_msg = bytearray(json.dumps({"type":"LED","color":"RED","led":3}), "utf-8")

# The below formats for async messages are for illustration only. it can be anything the app wants.
async_msg_red = bytearray(json.dumps({"source":"Sample DA app","message":"LED set to RED"}), "utf-8")
async_msg_green = bytearray(json.dumps({"source":"Sample DA app","message":"LED set to GREEN"}), "utf-8")
async_msg_yellow = bytearray(json.dumps({"source":"Sample DA app","message":"LED set to YELLOW"}), "utf-8")

while True:
    time.sleep(1)
    z.send_next_msg(pyziotc.MSG_OUT_GPO, led_green_msg)
    z.send_next_msg(pyziotc.MSG_OUT_CTRL, async_msg_green)
    time.sleep(1)
    z.send_next_msg(pyziotc.MSG_OUT_GPO, led_red_msg)
    z.send_next_msg(pyziotc.MSG_OUT_CTRL, async_msg_red)
    time.sleep(1)
    z.send_next_msg(pyziotc.MSG_OUT_GPO, led_yellow_msg)
    z.send_next_msg(pyziotc.MSG_OUT_CTRL, async_msg_yellow)