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))