Skip to content

Application API

Data Types

Applications generally interact with TrackCentral via websockets or REST APIs of TrackCentral IO (data path) and TrackCentral Terminal (device and router management) using messages or parameters encoded in JSON. For expressiveness, generic JSON values (e.g., integers, float, strings) are further differentiated into data types to express specific data elements.

Type Description
EUI64 string of the form HH-HH-HH-HH-HH-HH-HH-HH whereby HH represents two uppercase hex digits
HEX32 string of the form HH..HH with exactly 32 uppercase hexdigits
HEX* string with sequence of pairs of hex digits; can be empty
BOOL boolean value, true or false
INT4 decimal integer in the range –231.. 231 –1
INT8 decimal integer in the range –263.. 263 –1
UINT4 decimal integer in the range 0 .. 232 –1
UINT8 decimal integer in the range 0 .. 264 –1
TIMESPAN string representation of a timespan \d+(.\d+)?)(ms
ISODATE string of the form YYYY-MM-DD (UTC time)
MACADDR a string of 6 octets denoting a 48-bit MAC address such as 00:A3:C9:14:C8:F1
ID6 string representaion of a 64-bit number in the same way as a IPv6 address (e.g.“1::”, “::0”, “abc::12a”)
URI string forming a URI
WSURI string forming a websocket URI (ws://.. or wss://..)
UPID INT8 and unique message number per service end point

NOTE: JSON messages may contain not documented fields, which should be ignored

TrackCentral IO (TCIO)

Data exchanges with devices are performed via websockets, whereby a websocket streams messages (text records) containing JSON data structures containing, for example, data frames and context information. Historic messages can be retrieved via REST interfaces.

Connection Establishment

Applications establish a websocket connection to a specified initial URI by sending an initial request to obtain the service URIs that resolve to the current set of TCIO instances for a given owner. The initial URI hereby is installation-specific and serves as the common entry point for all owners requesting message exchanges with devices via their respective TCIO instances. Note that after the websocket connection is established, the first request must be sent immediately. Otherwise, the websocket connection will be closed after a short timeout.

An application must connect to all its TCIO instances to retrieve all messages from all devices. For small device populations a single TCIO instance may do, for larger populations multiple TCIO instances may be in use.

Only one connection per TCIO maybe open at any time. Creating a second connection will make the older connection being closed.

Depending on the type and amount of data processing performed on the application side, forwarded messages again may be handled by a single application server or multiple application servers. This scaling issue is to be tackled by the application owner.

After a connection to a TCIO instance has been established all messages from devices arriving from this point on will be forwarded via the connection. If the connection is closed messages arriving during this time are saved in the retention backlog. In addition, applications can append to the URI a query like ?upid=N to restart message transmission at a specific point. If N–1 is the last upid the application has processed then it will obtain all the messages from where the previous connection stopped. Note that this cannot retrieve messages that have been deleted because their retention time expired. If N=0 is used then an application can retrieve all messages stored on an TCIO.

With the connection, a client can also request a certain API version. If not available or not supported, the response will contain a corresponding error message. If no version is requested, the latest version is used. The response will contain the used protocol version number.

Request:

{
   "owner":       ID6
   "version":     UINT4 // requeted API version (optional)
}

Response:

{
   "error":       STRING    // only in case of an error
   "owner":       ID6
   "appx_list":   [ EP0, .., EPn ]
   "version":     UINT4 // used API version
}
EP = {
   "appxid":      ID6       // unique ID of the TCIO instance
   "uri":         WSURI     // corresponding websocket URI
}

Data Exchanges

TrackCentral saves all messages from all devices and all control messages into a database. Messages are retained for a certain amount of time and once the retention time of a message is exceeded it will be deleted irrespectively of whether or not it has been retrieved by the application.

Applications must retrieve upstream messages from devices by connecting to their respective TCIO instances obtained during the initial protocol phase. The device population of an owner may be distributed over k TCIO instances, whereby each of the TCIO instances then maintains only a subset of the overall device population. Upstream messages received from a particular device are forwarded over a single TCIO instance only, while downstream messages sent to a device from the application can be submitted via any TCIO instance. If possible, the TCIO instance through which upstream messages of the same device are received shall be preferred.

TrackCentral buffers only up to a single downstream message per device internally and it is up to the application to manage further pending messages. A buffered downstream message can be updated or deleted at any time, yet deleting a buffered message does not mean the message has not been delivered to the device. Due to the asynchronous nature of the LoRaWAN protocol it may have been transmitted before the delete request has been executed.

For buffered downstream messages requesting a confirmed down data frame TrackCentral automatically retransmits the down data frame until acknowledged by the device, or the buffered downstream message has been deleted or replaced by the application. It is the responsibility of the application to revoke buffered downstream messages after a some maximum number of unsuccessful attempts as this decision is inherently application-specific and depending on the nature of the device and the kind information to be conveyed.

All upstream messages have a message identifier (upid) unique per TCIO instance, which is strictly increasing over time. Note that upids are not necessarily contiguous nor unique across TCIO instances, though. Each TCIO instance further maintains a transient read pointer. If an application connects to a TCIO instance for the first time, it will be forwarded all upstream messages stored in the database beginning with the oldest one. Once all stored messages have been processed, new message will be forwarded to the application as received without further delay. Each message forwarded increases the read pointer accordingly.

All messages exchanged in either direction further have a msgtype field of type string that identifies the message type.

Downstream Messages

msgtype ‘dndf’

Submits a downstream message for transmission within the next downlink window for a given device. Each downstream message must be identified by a globally unique application-specific integer tag MsgId. TrackCentral uses this tag as internal reference and when reporting back to the application.

For confirmed down data frames the confirm field has to be set to true. TrackCentral automatically retransmits confirmed down data frames until acknowledged by the device, or the buffered downstream message has been deleted or replaced by the application.

As mentioned before, only up to a single downstream message is buffered per device. A new downstream message replaces any previously buffered downstream message.

{
   "msgtype":     "dndf"
   "MsgId":       INT8
   "FPort":       UINT1     // port number on the device
      "FRMPayload":  HEX*      // down data frame payload (may be empty)
   "DevEui":      EUI64     // identity of the device
   "confirm":     bool      // confirmed down data frame? 
}

To delete a buffered downstream message only the identity of the device shall be provided.

{
   "msgtype":     "dndf"
   "DevEui":      EUI64     // identity of the device
}

Upstream Messages

msgtype ‘updf’

Reports an upstream message with its up data frame payload as transmitted by a given device and additional context information. This message is forwarded without delay and, if a given up data frame is received by multiple gateways, only the first copy received is forwarded.

{
   "msgtype":     "updf"
   "DevEui":      EUI64     // device identifier
   "upid":        INT8      // unique message identifier
   "SessID":      INT4      // session identifier (0=ABP, >0 OTAA join sessions)
   "FCntUp":      UINT4     // frame counter used by the device
   "FPort":       UINT1     // port number
   "FRMPayload":  HEX*      // up data frame payload (may be empty)
   "DR"           int       // data rate the message was sent with
   "Freq"         int       // frequency the message was sent with
   "region"       str       // region specifier
}

msgtype ‘upinfo’

Reports additional context information about an up data frame as received from a given device. This information usually arrives a short time after a corresponding updf message because forwarding is delayed to take into account context information from potentially multiple routers for the same up data frame.

An upinfo can be linked to its corresponding updf message via the SessID and FCntUp fields.

Note: The value of upid is unique for each updf and upinfo messages and therefore does NOT link the upinfo message to a updf message.

{
   "msgtype":     "upinfo"
   "DevEui":      EUI64     // device identifier
   "upid":        INT8      // unique message identifier
   "SessID":      INT4      // session identifier
   "FCntUp":      UINT4     // frame counter used by the device
   "FPort":       UINT1     // port number
   "FRMPayload":  HEX*      // up data frame payload (may be empty)
   "DR"           int       // data rate the message was sent with
   "Freq"         int       // frequency the message was sent with
   "region"       str       // region specifier
   "upinfo":     [ UOBJ, .. ]
}

UOBJ = {
   "routerid":   INT8       // identifier of the router having received the frame
   "muxid":      INT8       // internal routing information
   "rssi":       float      // signal strength
   "snr":        float      // signal to noise ratio
   "ArrTime":    float      // arrival time stamp in the de-mux fabric
}

msgtype ‘dntxed’

Reports successful transmission of a down data frame. The MsgId field links the dntxed message to the corresponding dndf message.

Note that for confirmed down data frames every retransmission is reported separately until eventually acknowledged by the device, or until the buffered downstream message is deleted or replaced by the application.

{
   "msgtype":     "dntxed"
   "MsgId":       INT8
   "upinfo": {
     "routerid":  INT8      // identifier of the router which sent the down frame
   }
   "confirm":     bool      // confirmed down data frame?
   "DevEUI":      EUI64     // device EUI-64
}

msgtype ‘dnacked’

Reports acknowledgement of reception of a given down data frame by the device. The downstream message must have requested a confirmed down data frame.

Note that for confirmed down data frames every retransmission is reported separately until eventually acknowledged by the device, or until the buffered downstream message is deleted or replaced by the application.

{
   "msgtype":     "dnacked"
   "MsgId":       INT8
}

msgtype ‘joining’

A joining message signals that a device, identified by the DevEui, initiated an over-the-air activation (OTAA) to the network.

{
   "msgtype":     "joining"
   "SessID":      UINT4        // unique session identifier per device
   "NetID":       UINT4        // LoRaWAN network identifier
   "DevEui":      EUI64        // device identifier
   "DR"           int          // data rate the message was sent with
   "Freq"         int          // frequency the message was sent with
   "region"       str          // region specifier
   "upinfo":     [ UOBJ, .. ]  // see `updf` for details
}

msgtype ‘joined’

A joined message signals that a device completed an over-the-air activation (OTAA) to the network. The device establised a new session with the network.

{
   "msgtype":     "joined"
   "SessID":      UINT4     // unique session identifier per device
   "NetID":       UINT4     // LoRaWAN network identifier
   "DevEui":      EUI64     // device identifier
}

TrackCentral Terminal (TCT)

For device and router management TrackCentral provides the TrackCentral Terminal REST API. In addition, the TCT offers access to historical data, which is saved for a certain retention period, configured out of scope of the API.

Authentication

  • REST API calls are authenticated by an API token included in each request.
  • The HTTP header field ‘Authorization’ is expected to carry a valid, base64 encoded token.
  • If the token is absent or invalid, an HTTP status code 401 is returned.
  • A token is associated with an owner account and capabilities.
  • A token always allows to list the devices and routers associated with an account and retrieve status information.
  • Adding/removing devices/routers/tokens/owners requires the token to be provisioned with the correct set of capabilities.
  • If a token allows to manage owners, all API requests accept a HTTP query parameter ‘owner’ (ID6) which specifies the owner account on which behalf the request is executed.

URI prefix

The prefix for all HTTP REST API requests is ‘http://host:port/api/’.

Connection Establishment

A POST request on ‘/api/’ can request or verify the API version.

POST /api/

Request:

{
   "version":     UINT4 // requested API version (optional)
}

Response:

{
   "error":       STRING    // only in case of an error
   "uri-prefix":  URI       // '/api/'
   "version":     UINT4     // used API version
}

Historical Messages

TrackCentral stores a certain amount of historical upstream messages per application owner. These messages can be read via REST invocations.

POST /API/HIST/DATA

Retrieves historical upstream messages. The caller may request any subrange from the range returned by the range command. TrackCentral will respond with upstream messages starting from begupid but, depending on the number of upstream messages requested, may deliver only a limited number of upstream messages in response to a single invocation. In that case the application may receive all messages in chunks by repeating the invocation, each time adjusting the begupid field to upid +1 of the last received upstream message.

Request:

{
   "begdate":     ISODATE
   "enddate":     ISODATE
   "continue":    OBJECT // optional, used for pagination (TBD)
}
Response:

{
   "data": [
      UPREC1, .., UPRECn.      // array of updf and upinfo messages
   ]
   "next": OBJECT,  // optional, used for pagination (TBD)
   "error":  STRING // only in case of an error
}

Device Provisioning

POST /API/DEVICE/ADD

Adds a set of devices. Messages from devices that have not yet been added are dropped. In case of an error the request may have been partially executed and therefore exactly the same request shall be repeated to enforce completion of the request (forward recovery).

Request:

[
   DEF1, .., DEFn 
]

Response:

{
   "error":       STRING    // only in case of an error
}

DEF is a JSON object with the following fields:

{
   "deveui":       EUI64    // A/O/0/1   unique device identifier
   "joineui":      EUI64    // A/O/0/1   unique join or application identifier, also known as AppEui
   "devkey":       HEX32    // -/O/0/-   device integrity key
   "nwkkey":       HEX32    // -/O/-/1   network-level secret device key
   "appkey":       HEX32    // -/O/-/1   application-level secret device key
   "devaddr":      INT4     // A/-/0/1   device short address
   "nwkskey":      HEX32    // A/-/0/-   network-level session (up)
   "nwkskeyup":    HEX32    // A/-/-/1   network-level session (up)
   "nwkskeydn":    HEX32    // A/-/-/1   network-level session (down)
   "appskey":      HEX32    // A/-/0/1   application-level session key
   "activation":   STRING   // ABP or OTAA
   "version":      STRING   // 1.0 or 1.1
   "insecureFCnt": BOOLEAN  // OPTIONAL, NOT RECOMMENDED, to be used only for ABP devices which do not correctly maintain a FCnt
   "RFparams":     ..       // firmware specific (TBD)
}

Which fields are required depends on the LoRaWAN version supported by the respective device and whether it has been activated during personalisation (ABP) or will be activated over-the air (OTAA): 0=1.0, 1=1.1, A=ABP, O=OTAA.

POST /API/DEVICE/REMOVE

Removes a set of devices.

Request:

[
   EUI64, .., EUI64 
]

Response:

{
   "error":       STRING    // only in case of an error
}

Router Provisioning

POST /API/ROUTER/ADD

Adds a router. TrackCentral will reject connections of routers which are not provisioned.

Request:

{
   "macaddr":    STRING     // unique router MAC address
   "type":       STRING     // hardware type, currently IDU, DropAP
   "numcon":    INTEGER     // number of SX1301 concentrators (optional, default 1)
   "name":       STRING     // optional name used for tagging a router
   "gpsloc":    [ LAT,LON ] // GPS location of the router (optional)
}

LAT and LON are floating point values in the ranges -90.0..90.0 and -180.0 .. 180.0, respectively.

Response:

{
   "macaddr":     STRING       // unique router MAC address
   "routerids":   [INT8, ...]  // unique router identifier(s), for single concetrator a mac address maps to a routerid
   "error":       STRING       // only in case of an error
}

POST /API/ROUTER/REMOVE

Removes a router.

Request:

{
    "routerid":  INT8      // unique router identifier
}

Response:

{
   "error":       STRING    // only in case of an error
}

POST /API/ROUTER/STATUS

Queries status and statistics information for a set of routers, specified by the routerid RID as INT8 .

Request:

[
    RID1, ..., RIDn    // unique router identifiers
]

Response:

{
   "routers":     [ RSTATUS1, ...  RSTATUSn ] // router status objects
   "next":        OBJECT,  // optional, used for pagination (TBD)
   "error":       STRING    // only in case of an error
}

RSTATUS = {
   "connected":   BOOLEAN 
   "managed":     BOOLEAN   // optional
   "name":        STRING
   "routerid":    INT8
   "macaddr":     STRING
   "cnt_up":      INT8     // number of exchanges JSON messages from router to server
   "cnt_down":    INT8     // number of exchanges JSON messages from server to router
   "firmware":    STRING
   "last_uptime": INT8
   "gpsloc":      [ LAT,LON ] // GPS location of the router (optional)
}

GET /API/ROUTER/LIST

List the routerids of all provisioned routers.

Response

[
   INT8, .., INT8
]

Device Transmission

POST /API/DEVICE/TRANSMIT

Enqueue data with the server for downlink transfer.

Request:

{
        "deveuis":    [ STRING ]     // Target device EUIs
        "port":       INT8           // Port
        "payload":    STRING         // Payload, HEX-encoded
}

Response:

{
   "error":       STRING    // only in case of an error
}

Device Inquiry

GET /API/DEVICE/LIST

Return list of devices.

Response:

{
   "deveuis":     [ STRING ]         // Array of device EUIs
   "next":        OBJECT,            // optional, used for pagination (TBD)
   "error":       STRING             // only in case of an error
}

POST /API/DEVICE/INFO

Return session and persistent device information for a list of devices specified by EUI.

Request:

{
    "deveuis": [ DEVEUI1, ..., DEVEUIn ]    // unique device EUIs
}

Response:

{
   "devinfos":     [ DINFO1, ...  DINFOn ] // router status objects
   "error":       STRING    // only in case of an error
}

DINFO = {
   "DevEui":      STRING
   "SessID":      INT4        // -1 no session yet
   "FCntUp":      INT4        // Frame Counter Up, >= -1
   "AFCntDown":   INT4        // Application Frame Counter Down, >= -1
   "DevAddr":     INT4        // Device Address 
   "prevDevAddr": INT4        // Previous Device Address 
   "AppKey":      STRING
   "NwkKey":      STRING
   "JoinEui":     STRING
}