Skip to main content
Version: Next

LoRaWAN

LoRaWAN Functions

This category contains functions specific to LoRaWAN devices.

API NameBrief Description
api.loraSend(ack, timeout, msg, port)Sends and receives LoRaWAN frames.
api.loraJoin(int, dr)Sends a join request.
api.loraSetup()Configures LoRaWAN parameters. Multiple variants. See below.
api.loraListenClassBC(timeout, class)Listens for messages until timeout in class B or C.
api.loraSetCredential()Sets one LoRa credential. Multiple variants. See below.
api.loraSetCredentials(devADDR, devEUI, nwsKey, appsKey, appEUI)Sets LoRa credentials.
api.loraGetDevEui(format)Retrieves the devEUI.
api.getDeviceAddress()Retrieves the device address.

api.loraSend(ack, timeout, msg, port)


api.loraSend(1, 20000, "HELLO")

Sends and receives LoRaWAN frames.

Arguments

  • ack (integer):
    • 1 for acknowledged mode.
    • 0 for unacknowledged mode.
  • timeout (integer): Maximum execution time in milliseconds (used in acknowledged mode).
  • msg (string): Message sent to LoRaWAN.

Optional

  • port (integer, optional): Port number.

Return

  • status (integer): Positive or zero for success, negative for failure.
    • Positive: Number of bytes received.
    • 0: "No data received".
    • -1: "Not acknowledged" ("NACK").
    • -2: "Cannot send, LoRaMAC keeps busy!".
    • -3: "Failed sending!".
    • -4: "Failed sending LoRaWAN frame! (sent count = %d)".
    • -5: "Cannot send - too long payload for current SF!".
  • port (integer): nil or port on which the answer was received.
  • answer (string): nil or non-zero length string containing gateway answer.

Example

-- Sends 0xCCBBAA35 to LoRa with 20s timeout and acknowledged mode
msg = pack.pack('<b4', 0xCC, 0xBB, 0xAA, 0x35)
status, port, answer = api.loraSend(1, 20000, msg)

--------------------------------

if status >= 1 then -- Checks if device received more than one byte
api.dumpArray(answer) -- If true, print the data
end

for i = 1, 5 do
status, _, answer = api.loraSend(1, timeout, bootMsg, port)
if status >= 0 then break
elseif i == 5 and status < 0 then
print("Failed to send boot message to LoRaWAN, restarting ...")
ex("_reset")
end
timeout = timeout + 2000
end
print("BOOT UP DONE! " .. msgPrint)

-- dividing the LoRaWAN messages to limit it to 50 bytes in size
function loraSendBig(raw, filterId)
ret, port, cfg = api.loraSend(ack, 5000, string.char(1)..string.sub(raw,1,50), filterId)
processConfig(ret, port, cfg)
if #raw > 50 then
ret, port, cfg = api.loraSend(ack, 5000, string.char(2)..string.sub(raw,51,100), filterId)
processConfig(ret, port, cfg)
if #raw > 100 then -- and so on

api.loraJoin(int, dr)


api.loraJoin()

Sends a join request.

Info: Rejoining occurs automatically every 7 days by default. This interval can be modified using api.loraSetup().

Arguments

Optional

  • int (integer, optional):
    • 0 for security context check (sends join request if none).
    • 1 for forced join request.
  • dr (integer, optional): Sets join Data Rate (0 to 5).

Return

  • status (integer): 0 for success, negative for failure.
    • 0: Success.
    • -3: "Timeout, busy!".
    • -4: "General error!".
    • -5: "No answer!".
    • -6: "Error joining!".

Example

-- Check if joined, if not join
api.loraJoin()

--------------------------------

-- Force join
api.loraJoin(1)

--------------------------------

-- Join request send only if ATAA is used
if joinMethod == "OTAA" then api.loraJoin() end

api.loraSetup()

Configures LoRaWAN parameters.

API NameBrief Description
api.loraSetup("ACTIVATION", method)Sets the activation type ("OTAA" or "ABP"). Resets previous activation settings and sends a join request each time.
api.loraSetup("ADR", state)Enables or disables Adaptive Data Rate (1 for on, 0 for off).
api.loraSetup("DR", value)Sets the Data Rate (0-5). If ADR is off and a join request is performed, it assigns a different DR during the join.
api.loraSetup("DC", state)Sets or gets the Duty Cycle state ("ON", "OFF", "DCTIME", "GET").
api.loraSetup("RUN_FSM", timeout)Runs the internal LoRaWAN FSM for the specified milliseconds.
api.loraSetup("CLASS", class)Sets or gets the current LoRaWAN class ("A", "B", or "C"). Verify network server support before setting.
api.loraSetup("OTAA-REJOIN-CONFIRMED-FAILED-COUNTER", value)Sets the number of confirmed messages that must fail before forcing a new join.
api.loraSetup("OTAA-MINIMAL-CONFIRMED-PERIOD", value)Sets the period (in milliseconds) to send a join request (default 7 days).
api.loraSetup("OTAA-REJOIN-CONFIRMED-COUNTER", number)Sets the maximum number of unconfirmed messages in a row (default/minimal 5), forcing every Nth message as confirmed.
api.loraSetup("POWER", power)Sets the power to a defined value in dBm (0, 2, 4, 6, 8, 10, 12, 14).
api.loraSetup("TIME_SYNC", force, zone)Schedules a time synchronization request (requires network server support, compatible with LoRaWAN 1.0.3+).

api.loraSetup("ACTIVATION", method)


api.loraSetup("ACTIVATION", "ABP")

Sets the activation type.

Warning: Resets previous activation settings and sends a join request each time.

Arguments

  • "ACTIVATION" (string, command)

    ❗command - the argument needs to have this exact form❗

  • method (string):

    • "OTAA" - use OTAA as activation type.
    • "ABP" - ABP as activation type.

Example

-- Set activation type as ABP
api.loraSetup("ACTIVATION", "ABP")

--------------------------------

local joinMethod = "OTAA"
api.loraSetup("ACTIVATION", joinMethod)

api.loraSetup("ADR", state)


api.loraSetup("ADR", 1)

Enables or disables Adaptive Data Rate.

Warning: If ABP activation and ADR is on, setting DR always assigns DR = 0.

Arguments

  • "ADR" (string, command)

    ❗command - the argument needs to have this exact form❗

  • state (integer):

    • 1 for on.
    • 0 for off.

Example

-- Enable ADR
api.loraSetup("ADR", 1)

api.loraSetup("DR", value)


api.loraSetup("DR", 0)

Sets the Data Rate.

Warning: If ADR is off and a join request is performed, it assigns a different DR during the join.

Arguments

  • "DR" (string, command)

    ❗command - the argument needs to have this exact form❗

  • value (integer): Data Rate (0-5).

Example

-- Set data rate to 0
api.loraSetup("DR", 0)

--------------------------------

-- Set a scan size limit based on the data rate
if iface == "lorawan" then
dataRate = api.loraSetup("DR")
scanLimitSize = drToMaxLength[dataRate]-2
else
scanLimitSize = 500
end

api.loraSetup("DC", state)


api.loraSetup("DC", "ON")

Sets or gets the Duty Cycle state.

Arguments

  • "DC" (string, command)

    ❗command - the argument needs to have this exact form❗

  • state (string):

    • "ON" - turns it on.
    • "OFF"- turns it off.
    • "DCTIME"
    • "GET"

Example

-- Set duty cycle on
api.loraSetup("DC", "ON")

api.loraSetup("RUN_FSM", timeout)


api.loraSetup("RUN_FSM", 1000)

Runs the internal LoRaWAN FSM for the specified milliseconds.

Arguments

  • "RUN_FSM" (string, command)

    ❗command - the argument needs to have this exact form❗

  • timeout (integer): Milliseconds to run FSM.

Example

-- Run FSM for 1000 ms
api.loraSetup("RUN_FSM", 1000)

api.loraSetup("CLASS", class)


api.loraSetup("CLASS", "C")

Sets or gets the current LoRaWAN class.

Info: Verify network server support before setting to B or C.

Arguments

  • "CLASS" (string, command)

    ❗command - the argument needs to have this exact form❗

  • class (string):

    • "A" - LoRaWAN class A.
    • "B" - LoRaWAN class B.
    • "C" - LoRaWAN class C.

Example

-- Set class to C
api.loraSetup("CLASS", "C")

--------------------------------

-- LoRa setup as part of the bootMessage function
api.loraSetup("ACTIVATION", joinMethod)
api.loraSetup("CLASS", "A")
if joinMethod == "OTAA" then api.loraJoin() end

api.loraSetup("OTAA-REJOIN-CONFIRMED-FAILED-COUNTER", value)


api.loraSetup("OTAA-REJOIN-CONFIRMED-FAILED-COUNTER", 10)

Sets the number of confirmed messages that must fail before forcing a new join.

Arguments

  • "OTAA-REJOIN-CONFIRMED-FAILED-COUNTER" (string, command)

    ❗command - the argument needs to have this exact form❗

  • value (integer): Number of failed confirmed messages.

Example

-- Set failed counter to 10
api.loraSetup("OTAA-REJOIN-CONFIRMED-FAILED-COUNTER", 10)

api.loraSetup("OTAA-MINIMAL-CONFIRMED-PERIOD", value)


api.loraSetup("OTAA-MINIMAL-CONFIRMED-PERIOD", 86400000)

Sets the period (in milliseconds) to send a join request.

Arguments

  • "OTAA-MINIMAL-CONFIRMED-PERIOD" (string, command)

    ❗command - the argument needs to have this exact form❗

  • value (integer): Period in milliseconds (default 7 days).

Example

-- Set period to 1 day
api.loraSetup("OTAA-MINIMAL-CONFIRMED-PERIOD", 86400000)

api.loraSetup("OTAA-REJOIN-CONFIRMED-COUNTER", number)


api.loraSetup("OTAA-REJOIN-CONFIRMED-COUNTER", 10)

Sets the maximum number of unconfirmed messages in a row, forcing every Nth as confirmed.

Arguments

  • "OTAA-REJOIN-CONFIRMED-COUNTER" (string, command)

    ❗command - the argument needs to have this exact form❗

  • number (integer): Max unconfirmed messages (default/minimal 5).

Example

-- Set counter to 10
api.loraSetup("OTAA-REJOIN-CONFIRMED-COUNTER", 10)

api.loraSetup("POWER", power)


api.loraSetup("POWER", 14)

Sets the power to a defined value in dBm.

Arguments

  • "POWER" (string, command)

    ❗command - the argument needs to have this exact form❗

  • power (integer): Power value (0, 2, 4, 6, 8, 10, 12, 14).

Example

-- Set power to 14 dBm
api.loraSetup("POWER", 14)

api.loraSetup("TIME_SYNC", force, zone)


api.loraSetup("TIME_SYNC")

Schedules a time synchronization request.

Info: Requires network server support, compatible with LoRaWAN 1.0.3+.

Arguments

  • "TIME_SYNC" (string, command)

    ❗command - the argument needs to have this exact form❗

Optional

  • force (integer, optional):
    • 1 for force time sync.
    • 0 for not forcing time sync.
  • zone (string, optional): Time zone:
    • "UTC" for UTC time zone.
    • "LOCAL" for local time zone.

Example

-- Schedule time sync
api.loraSetup("TIME_SYNC", 1)

api.loraListenClassBC(timeout, class)


status, port, buffer = api.loraListenClassBC(10000)

Listens for messages until timeout in class B or C.

Warning: Device must be set to Class B or C and supported by the Network Server.

Arguments

  • timeout (integer): Timeout in milliseconds.

Optional

  • class (string, optional):
    • "B" - class B.
    • "C" - class C (default so not needed to be explicit).

Return

  • status (integer): Positive or zero for success, negative for failure.
  • port (integer): nil or port on which the message was received.
  • buffer (string): Message received from LoRa.

Example

-- Listen on LoRa for a message with timeout of 10 seconds
api.loraSetup("CLASS", "C")
status, port, buffer = api.loraListenClassBC(10000)

api.loraSetCredential()

Sets one LoRa credential.

API NameBrief Description
api.loraSetCredential("devADDR", address)Sets the device address (32-bit). Sends a join request automatically.
api.loraSetCredential("devEUI", eui)Sets the device EUI (64-bit). Sends a join request automatically.
api.loraSetCredential("nwkSKey", key)Sets the network session key (128-bit). Sends a join request automatically.
api.loraSetCredential("appSKey", key)Sets the application session key (128-bit). Sends a join request automatically.
api.loraSetCredential("appEUI", eui)Sets the application EUI (64-bit). Sends a join request automatically.

api.loraSetCredential("devADDR", address)


api.loraSetCredential("devADDR", "22011221")

Sets the device address.

Info: Automatically sends a join request.

Arguments

  • "devADDR" (string, command)

    ❗command - the argument needs to have this exact form❗

  • address (string): 32-bit address.

Example

-- Set devADDR
api.loraSetCredential("devADDR", "22011221")

api.loraSetCredential("devEUI", eui)


api.loraSetCredential("devEUI", "3333333333333333")

Sets the device EUI.

Info: Automatically sends a join request.

Arguments

  • "devADDR" (string, command)

    ❗command - the argument needs to have this exact form❗

  • eui (string): 64-bit end-device identifier.

Example

-- Set devEUI
api.loraSetCredential("devEUI", "3333333333333333")

api.loraSetCredential("nwkSKey", key)


api.loraSetCredential("nwkSKey", "44444444444444444444444444444444")

Sets the network session key.

Info: Automatically sends a join request.

Arguments

  • "nwkSKey" (string, command)

    ❗command - the argument needs to have this exact form❗

  • key (string): 128-bit network session key.

Example

-- Set nwkSKey
api.loraSetCredential("nwkSKey", "44444444444444444444444444444444")

api.loraSetCredential("appSKey", key)


api.loraSetCredential("appSKey", "55555555555555555555555555555555")

Sets the application session key.

Info: Automatically sends a join request.

Arguments

  • "appSKey" (string, command)

    ❗command - the argument needs to have this exact form❗

  • key (string): 128-bit application session key.

Example

-- Set appSKey
api.loraSetCredential("appSKey", "55555555555555555555555555555555")

api.loraSetCredential("appEUI", eui)


api.loraSetCredential("appEUI", "70B344440013333")

Sets the application EUI.

Info: Automatically sends a join request.

Arguments

  • "appEUI" (string, command)

    ❗command - the argument needs to have this exact form❗

  • eui (string): 64-bit application identifier.

Example

-- Set appEUI
api.loraSetCredential("appEUI", "70B344440013333")

api.loraSetCredentials(devADDR, devEUI, nwsKey, appsKey, appEUI)


api.loraSetCredentials("22011221", "3333333333333333", "44444444444444444444444444444444", "55555555555555555555555555555555", "70B344440013333")

Sets LoRa credentials.

Info: Automatically sends a join request.

Arguments

  • devADDR (string): 32-bit address.
  • devEUI (string): 64-bit end-device identifier.
  • nwsKey (string): 128-bit network session key.
  • appsKey (string): 128-bit application session key.

Optional

  • appEUI (string, optional): 64-bit application identifier.

Example

-- Set LoRa credentials
api.loraSetCredentials("22011221", "3333333333333333", "44444444444444444444444444444444", "55555555555555555555555555555555", "70B344440013333")

--------------------------------

if usedInterfaces == "both" or usedInterfaces == "lorawan" then
-- use SIM card number as IMSI
-- ensures join
api.loraSetCredentials("00000000", "0"..imsi, "00"..imsi..imsi, "00"..imsi..imsi, "00"..imsi..imsi)
end

api.loraGetDevEui(format)


api.loraGetDevEui("bin")

Retrieves the devEUI.

Arguments

  • format (string): Output format:
    • "bin" - output is in binary.
    • "hex" - output is in hexagonal.

Return

  • eui (string): 64-bit end-device identifier.

Example

-- Get LoRa devEUI
eui = api.loraGetDevEui("bin")
api.dumpArray(eui)

print(api.loraGetDevEui("hex"))

if tonumber(fwma) >= 2 and tonumber(fwmi) >= 14 then
local eui = api.loraGetDevEui("bin")
bootMsg = eui .. bootMsg
local euiHEX = api.loraGetDevEui("hex")
msgPrint = "devEUI: " .. euiHEX .. ", " .. msgPrint
end

api.getDeviceAddress()


api.getDeviceAddress()

Retrieves the device address.

Return

  • device address (hex): 64-bit end-device identifier.

Example

-- Get LoRa device address and print it
wmbusID, _, _ = api.getDeviceAddress()
print("wMBus identification: ", string.format("0x%08X", wmbusID))