Configuration
This build has no web UI. Only the network Settings are edited in the gateway web interface. Devices, gateways, and decoders are managed through the system.lorawan.* scripting API, CSV import/export, and the [LoRaWAN] tag provider. The 8.3 build adds a Connections > LoRaWAN web UI — see the current documentation.
Module Settings
The only configuration page is at Config > LoRaWAN > Settings in the gateway web interface. It is a single form (a Wicket RecordEditForm) backed by a singleton settings record in the gateway's internal localdb, split into Regional and Network categories.
| Setting | Type | Default | Applied | Description |
|---|---|---|---|---|
| Region | Dropdown | EU868 | Requires gateway restart | Regional frequency plan |
| UDP Port | Integer | 1700 | Requires gateway restart | Semtech Packet Forwarder listening port |
| Bind Address | String | 0.0.0.0 | Requires gateway restart | Local address to bind the UDP server to (0.0.0.0 = all interfaces) |
| Gateway Timeout (seconds) | Integer | 120 | Live | Seconds without traffic before a gateway is marked disconnected |
The module also maintains internal state that is not shown on the form: a blocked-gateways list (managed via the block/unblock REST routes) and an OTAA join-nonce counter.
Supported Regions
The Region dropdown offers 11 frequency plans:
EU868 (default), US915, AU915, AS923, AS923-2, AS923-3, AS923-4, CN470, IN865, KR920, RU864
Choose the region that matches your LoRaWAN devices and local regulations. Changing the region requires a gateway restart.
Managing Gateways, Devices, and Decoders
On the 8.1 build there is no dedicated management UI. Use one of the following, all of which are equivalent (they write to the same localdb-backed configuration):
- Scripting — the
system.lorawan.*functions (device / gateway / decoder CRUD plus CSV bulk ops), from Perspective gateway-scope scripts or the Designer script console. - CSV import/export — see Bulk Import / Export.
- Tag provider — browse
[LoRaWAN]/Devices/*and[LoRaWAN]/Gateways/*to list existing resources, and use the writableDownlink/*andStatus/Requesttags for downlinks and status requests (see Per-Device Tags).
Registering a Gateway
Register a gateway with its EUI (16-character hex). A name, description, and location are optional:
eui = system.lorawan.addGateway(
eui="A840411234567890",
name="roof-gw",
description="Building A rooftop",
location="48.85,2.35")
If no name is provided, one is derived from the EUI. EUIs are normalized to uppercase hex.
Gateway Properties
| Property | Description |
|---|---|
| Name | Friendly name for the gateway |
| EUI | 64-bit identifier, 16 hex characters (required) |
| Description | Optional description |
| Location | Optional location information |
Registering a Device
OTAA (default) requires a DevEUI and AppKey. ABP requires session keys. See Device Registration for full examples.
# OTAA device
system.lorawan.addDevice(
devEui="A358C4B192543F75",
appKey="925742558798BFB46E938D7A5A1B161F",
name="TempSensor_01",
deviceClass="A",
decoder="EnvSensor")
Activation Mode
| Mode | Description |
|---|---|
| OTAA | Over-the-Air Activation - device joins dynamically using its AppKey (default) |
| ABP | Activation By Personalization - pre-provisioned session keys (devAddr, nwkSKey, appSKey, optional fCntUp / fCntDown) |
Device Class
| Class | Description |
|---|---|
| Class A | Battery-optimized; receives only after transmitting (RX1/RX2 windows). Default. |
| Class C | Always listening; receives downlinks with minimal delay |
Class B exists as a reserved enum value but is not implemented. Passing deviceClass='B' raises IllegalArgumentException ("Class B is not supported. Use Class A or Class C.").
Device Fields
For OTAA devices:
| Field (kwarg) | Format | Description |
|---|---|---|
devEui | 16 hex chars (required) | Unique device identifier |
appKey | 32 hex chars | Root key for join and session derivation |
name | Text | Friendly name |
deviceClass | A or C | Device class (default A) |
decoder | Text | Name of an assigned payload decoder |
For ABP devices (mode='ABP'), additionally:
| Field (kwarg) | Format | Description |
|---|---|---|
devAddr | 8 hex chars (required) | Pre-assigned network address |
nwkSKey | 32 hex chars (required) | Network session key |
appSKey | 32 hex chars (required) | Application session key |
fCntUp | integer | Starting uplink frame counter (default 0) |
fCntDown | integer | Starting downlink frame counter (default 0) |
Payload Decoders
Payload decoders transform raw LoRaWAN payloads into meaningful Ignition tags. On the 8.1 build a decoder is supplied as a JavaScript file on disk and registered by name via scripting; there is no in-browser editor.
Creating a Decoder
The file path is resolved on the machine running the script — see Usage → File Arguments.
# Register a decoder from a .js file, then assign it to a device
name = system.lorawan.addDecoder(name="EnvSensor", file="/decoders/env.js")
system.lorawan.updateDevice(devEui="A358C4B192543F75", decoder=name)
addDecoder returns the sanitized decoder name.
Decoder Script Format
Decoders follow the ChirpStack/TTN decodeUplink(input) contract and are executed with GraalJS.
function decodeUplink(input) {
var bytes = input.bytes; // number[] - raw payload bytes
var fPort = input.fPort; // number - LoRaWAN port
var temp = bytes[0] | (bytes[1] << 8);
if (temp > 0x7FFF) temp -= 0x10000; // sign-extend int16
return {
data: {
Temperature: temp / 10,
Humidity: bytes[2]
}
};
}
Input Object
The decoder receives a single input object:
{ bytes: [/* number[] */], fPort: /* number */ }
| Property | Type | Description |
|---|---|---|
bytes | number[] | Raw payload as a byte array |
fPort | number | LoRaWAN port |
The decoder runs only for uplinks with fPort > 0 and a non-empty payload.
Return Object
The function returns an object of the form:
{ data: { field: value } }
Each field under data becomes a dynamic tag at the device root ([LoRaWAN]/Devices/{Name}/{field}).
Type Mapping
| JavaScript Type | Ignition Tag Type |
|---|---|
| integer | Int |
| number | Double |
| boolean | Boolean |
| string | String |
Decoders run in a sandboxed GraalJS environment (a fresh Context per invocation) with no file, network, or system access, and are bounded by a watchdog timeout.
Bulk Import / Export
Devices and gateways can be bulk-managed via CSV, using the scripting functions (exportDevices / importDevices / exportGateways / importGateways) or the CSV REST routes.
Device CSV columns: name,devEui,mode,deviceClass,decoder,appKey,devAddr,nwkSKey,appSKey,fCntUp,fCntDown (OTAA rows carry appKey; ABP rows carry the session columns).
Gateway CSV columns: name,eui,description,location.
Import is upsert (matched by DevEUI/EUI — new rows created, existing rows have their config fields updated while runtime session state is preserved) and best-effort: invalid rows are collected in a report rather than aborting the import. Columns are matched by header name (case-insensitive) so order is flexible.
Before any row is applied, the file is rejected if it is empty, larger than 1 MiB, missing the key column (devEui / eui) in the header, or has more than 10,000 data rows. These file-level failures raise an error; per-row problems remain best-effort in the report {created, updated, skipped, failed, errors:[{line, message}]}.
Exported CSV files contain provisioning credentials (AppKey / session keys) in plaintext. Handle exported files accordingly.
Per-Device Tags
When a device is registered, tags are created automatically under [LoRaWAN]/Devices/{DeviceName}/:
[LoRaWAN]/Devices/{DeviceName}/
├── {DecodedField} Dynamic tags produced by the decoder (device root)
├── Config/
│ ├── Name
│ ├── DevEUI
│ ├── DevAddr
│ ├── DeviceClass
│ └── Decoder
├── Uplink/
│ ├── Timestamp
│ ├── Counter
│ ├── Port
│ ├── PayloadHex
│ ├── RSSI (dBm)
│ ├── SNR (dB)
│ ├── Frequency (MHz)
│ ├── DataRate
│ └── GatewayEUI
├── Downlink/
│ ├── Port (writable)
│ ├── Confirmed (writable)
│ ├── Payload (writable, sticky hex)
│ ├── Send (writable, edge-trigger)
│ └── Queue (dataset)
└── Status/
├── Battery (raw byte per TS001-1.0.4 §5.3)
├── Margin (dB)
├── Timestamp
└── Request (writable - write true to queue a DevStatusReq)
Gateway tags are created under [LoRaWAN]/Gateways/{GatewayName}/ with: Name, EUI, Status (Connected/Disconnected), Address, LastSeen, UplinkCount, DownlinkCount.
Summary statistics are exposed under [LoRaWAN]/_Meta/: DeviceCount, ActiveDeviceCount, GatewayCount, ConnectedGatewayCount.