Skip to main content
Version: 8.3

Usage

Device Lifecycle

OTAA Join Process

  1. Registration: Register device with DevEUI and AppKey
  2. Device Power On: Device sends JoinRequest
  3. Server Validation: Module verifies the MIC and checks DevNonce (replay protection)
  4. Session Creation: Server derives session keys and assigns a DevAddr
  5. JoinAccept: Server sends the encrypted JoinAccept via a gateway
  6. Ready: Device is joined and can send data

ABP Activation

  1. Registration: Register device with DevEUI, DevAddr, NwkSKey, AppSKey
  2. Device Power On: Device immediately sends data frames
  3. Ready: No join procedure needed

When a device sends an uplink:

  1. Gateway receives the LoRa transmission
  2. Gateway forwards it to Ignition via UDP
  3. Module processes the frame (MIC verification, frame-counter validation, decryption, and payload decoding if a decoder is assigned)
  4. Tags are updated in real time under Uplink/ and, for decoded fields, at the device root
  5. Device state is persisted

Multi-Gateway Deduplication

When multiple gateways receive the same uplink (keyed by DevAddr:FCnt within a 5-second window):

  • The frame is processed once
  • The best gateway is selected for downlink routing by RSSI (with a 3 dB advantage threshold), then SNR as a tiebreaker
  • Duplicate receptions are otherwise dropped

Downlinks can be enqueued three ways: via the REST API, via tags, or internally by the module. The per-device queue holds up to 10 messages. Confirmed downlinks are retried, and the module falls back to RX2 when RX1 cannot be used.

Queue via Tags

Set the writable downlink tags on the device, then trigger the send:

  1. Write [LoRaWAN]/Devices/{Name}/Downlink/Payload (hex)
  2. Write [LoRaWAN]/Devices/{Name}/Downlink/Port
  3. Optionally write [LoRaWAN]/Devices/{Name}/Downlink/Confirmed
  4. Write true to [LoRaWAN]/Devices/{Name}/Downlink/Send (edge trigger)

The current queue is visible as a dataset at [LoRaWAN]/Devices/{Name}/Downlink/Queue.

Queue via REST API

Endpoint: POST /data/lorawan/devices/:devEui/downlink

curl -X POST "http://localhost:8088/data/lorawan/devices/A358C4B192543F75/downlink" \
-H "Content-Type: application/json" \
-d '{
"fPort": 10,
"payload": "48656C6C6F",
"confirmed": false
}'
FieldTypeRequiredDescription
fPortintegerYesLoRaWAN port
payloadstringYesHex-encoded payload
confirmedbooleanNoRequest device acknowledgment

Returns HTTP 503 when the module trial has expired.

curl "http://localhost:8088/data/lorawan/devices/A358C4B192543F75/downlinks"
curl -X DELETE "http://localhost:8088/data/lorawan/devices/A358C4B192543F75/downlinks/{id}"

Transmission Timing

Device ClassTiming
Class ARX1 window after uplink, with RX2 fallback
Class CScheduled by the Class C scheduler; a prior uplink is required so the module knows how to route the frame
Class C Requires a Prior Uplink

Class C downlinks are routed through the last gateway that heard the device, so the device must have sent at least one uplink before a downlink can be scheduled.

RX2 Fallback

When RX1 cannot be used, the module falls back to the region's RX2 default frequency and data rate. Confirmed downlinks are retried up to 8 times before the entry is marked failed and leaves the queue.


Device Status

Automatic Status Requests

The module issues a DevStatusReq periodically. The interval is configurable and defaults to every 100 uplinks.

On-Demand Status Request

Via API:

curl -X POST "http://localhost:8088/data/lorawan/devices/A358C4B192543F75/status-request"

Via Tag: Write true to [LoRaWAN]/Devices/{Name}/Status/Request

Status Information

FieldDescription
BatteryBattery level reported in DevStatusAns
MarginSNR margin in dB
TimestampWhen the status was received

Adaptive Data Rate (ADR)

The module implements ADR to optimize device transmission parameters by sending LinkADRReq MAC commands, adjusting the device's spreading factor and TX power based on observed link margin.


REST API Reference

Two route families are exposed:

  • OpenAPI resource routes at /data/api/v1/resources/{moduleId}/... for managing device, gateway, and decoder resources. POST/PUT bodies are arrays; updates and deletes require a signature.
  • Custom routes at /data/lorawan/... for runtime status, downlinks, status requests, and CSV bulk operations.

Custom Routes

MethodPathDescription
GET/data/lorawan/gateways/statusStatus of all gateways
GET/data/lorawan/devices/statusStatus of all devices
POST/data/lorawan/devices/:devEui/status-requestTrigger DevStatusReq
POST/data/lorawan/devices/:devEui/downlinkEnqueue a downlink (503 if trial expired)
GET/data/lorawan/devices/:devEui/downlinksList queued downlinks
DELETE/data/lorawan/devices/:devEui/downlinks/:idCancel a queued downlink
POST/data/lorawan/gateways/:eui/blockBlock a gateway (stop accepting its traffic)
POST/data/lorawan/gateways/:eui/unblockUnblock a previously blocked gateway
GET/data/lorawan/editionReport the running edition (used to apply the Edge device cap)
GET/data/lorawan/devices/exportDownload all devices as CSV
POST/data/lorawan/devices/importUpsert devices from a CSV body
GET/data/lorawan/devices/templateDownload an empty device CSV template
GET/data/lorawan/gateways/exportDownload all gateways as CSV
POST/data/lorawan/gateways/importUpsert gateways from a CSV body
GET/data/lorawan/gateways/templateDownload an empty gateway CSV template

Device Status Example

curl "http://localhost:8088/data/lorawan/devices/status"

Gateway Status Example

curl "http://localhost:8088/data/lorawan/gateways/status"

Device Registration Example

# Register an OTAA device
curl -X POST "http://localhost:8088/data/api/v1/resources/com.operametrix.ignition.lorawan/device" \
-H "Content-Type: application/json" \
-d '[{
"name": "TempSensor_01",
"config": {
"name": "TempSensor_01",
"devEui": "A358C4B192543F75",
"appKey": "925742558798bfb46e938d7a5a1b161f",
"mode": "OTAA",
"deviceClass": "A"
}
}]'

Scripting API

The system.lorawan.* namespace provides 13 functions (all accept keyword arguments). Writes and mutations are scripted; reads, listings, and downlink queueing are intentionally not scripted — use the [LoRaWAN] tag provider for those.

FunctionReturnsDescription
system.lorawan.addDevice(devEui, appKey, name, mode, deviceClass, decoder, devAddr, nwkSKey, appSKey, fCntUp, fCntDown)DevEUIRegister a device
system.lorawan.updateDevice(devEui, name, appKey, deviceClass, decoder)Update a device
system.lorawan.removeDevice(devEui)Remove a device
system.lorawan.addGateway(eui, name, description, location)EUIRegister a gateway
system.lorawan.updateGateway(eui, name, description, location)Update a gateway
system.lorawan.removeGateway(eui)Remove a gateway
system.lorawan.addDecoder(name, file)Add a decoder from a JS file
system.lorawan.updateDecoder(name, file)Update a decoder from a JS file
system.lorawan.removeDecoder(name)Remove a decoder
system.lorawan.exportDevices(file)row countExport devices to CSV
system.lorawan.exportGateways(file)row countExport gateways to CSV
system.lorawan.importDevices(file)JSON reportImport devices from CSV
system.lorawan.importGateways(file)JSON reportImport gateways from CSV
File Arguments

For decoder, import, and export functions, file is a path on the machine running the script.

# Register an OTAA device
system.lorawan.addDevice(
devEui="A358C4B192543F75",
appKey="925742558798bfb46e938d7a5a1b161f",
name="TempSensor_01",
mode="OTAA",
deviceClass="A",
decoder="EnvSensor")

Ignition Integration

Tag Bindings

Bind device data to components using the [LoRaWAN] tag provider:

[LoRaWAN]/Devices/TempSensor_01/Temperature
[LoRaWAN]/Devices/TempSensor_01/Uplink/RSSI
[LoRaWAN]/Devices/TempSensor_01/Status/Battery

Historian

Enable history on LoRaWAN tags to store time-series data:

  1. Right-click a device tag and select Edit Tag
  2. Enable History
  3. Configure the sample mode (typically "On Change")

Alarming

Create alarms on LoRaWAN device data:

[LoRaWAN]/Devices/TempSensor_01/Temperature > 80
[LoRaWAN]/Devices/TempSensor_01/Status/Battery < 50

Scripting with Tags

# Read a decoded value
temp = system.tag.readBlocking(["[LoRaWAN]/Devices/TempSensor_01/Temperature"])[0].value

# Request device status
system.tag.writeBlocking(["[LoRaWAN]/Devices/TempSensor_01/Status/Request"], [True])

# Enqueue a downlink via tags
system.tag.writeBlocking([
"[LoRaWAN]/Devices/TempSensor_01/Downlink/Payload",
"[LoRaWAN]/Devices/TempSensor_01/Downlink/Port",
"[LoRaWAN]/Devices/TempSensor_01/Downlink/Send",
], ["48656C6C6F", 10, True])

Troubleshooting

IssuePossible CauseSolution
Gateway not connectingUDP blockedCheck firewall for the configured port (default 1700)
Gateway not connectingWrong server addressVerify gateway configuration
Uplinks ignoredGateway not registeredRegister the gateway; only registered gateways are accepted
Device not joiningWrong AppKeyVerify the 32-character hex key
Device not joiningDevNonce replayDevice may need a reset
Downlinks not receivedClass A timingDevice must uplink first
Class C downlink not sentNo prior uplinkClass C needs a prior uplink to establish routing
Tags report Bad_TrialExpiredTrial expiredApply a license to restart the network layer
Downlink returns 503Trial expiredApply a license
"Class B is not supported" on CSV import or a scripting callClass B is not implementedSet the device to Class A or Class C (the web UI only offers these two)

Best Practices

  1. Register gateways first - Only registered gateways are accepted; unregistered gateways are rejected
  2. Use OTAA - Provides better security than ABP
  3. Assign decoders - Convert raw payloads into meaningful tags
  4. Enable historian - Store time-series data for analysis
  5. Monitor battery - Set up alarms on device status
  6. Use Class A - Unless minimal-latency downlinks are required
  7. Check signal quality - Low RSSI/SNR indicates poor coverage
  8. Back up device keys - Store AppKeys securely outside Ignition
  9. Keep a license current - Trial expiry disables the network layer