lora — LoRa modem driver

The lora module provides a driver for the Murata CMWX1ZZABZ LoRa modem on the Arduino Portenta Vision Shield. It exposes a high-level Lora class that wraps the AT command set used by the modem firmware (including the Arduino MKRWAN ARD-078 firmware) so an application can join a LoRaWAN network and send/receive packets.

Example:

import lora

modem = lora.Lora(band=lora.BAND_EU868, debug=True)
print("Device EUI:", modem.get_device_eui())
if modem.join_OTAA("0000000000000000", "00000000000000000000000000000000"):
    modem.send_data(b"hello", confirmed=True)

Constants

Activation modes

lora.MODE_ABP: int

Activation By Personalization mode.

lora.MODE_OTAA: int

Over-The-Air Activation mode.

RF output modes

lora.RF_MODE_RFO: int

Use the modem’s RFO (low-power) RF output.

lora.RF_MODE_PABOOST: int

Use the modem’s PA_BOOST (high-power) RF output.

Bands

lora.BAND_AS923: int

AS923 (Asia 923 MHz) regional band.

lora.BAND_AU915: int

AU915 (Australia 915 MHz) regional band.

lora.BAND_EU868: int

EU868 (Europe 868 MHz) regional band.

lora.BAND_KR920: int

KR920 (Korea 920 MHz) regional band.

lora.BAND_IN865: int

IN865 (India 865 MHz) regional band.

lora.BAND_US915: int

US915 (United States 915 MHz) regional band.

lora.BAND_US915_HYBRID: int

US915 hybrid (sub-band) regional plan.

Device classes

lora.CLASS_A: str

LoRaWAN end-device Class A.

lora.CLASS_B: str

LoRaWAN end-device Class B.

lora.CLASS_C: str

LoRaWAN end-device Class C.

Exceptions

exception lora.LoraError

Base exception raised for any error returned by the modem or the driver.

exception lora.LoraErrorTimeout

Raised when the modem does not respond within the configured timeout (the receive buffer is empty).

exception lora.LoraErrorParam

Raised on a +ERR_PARAM response when an AT command was issued with an invalid parameter.

exception lora.LoraErrorBusy

Raised on a +ERR_BUSY response when the modem is busy processing a previous command.

exception lora.LoraErrorOverflow

Raised on a +ERR_PARAM_OVERFLOW response when a parameter exceeds the maximum allowed length.

exception lora.LoraErrorNoNetwork

Raised on a +ERR_NO_NETWORK response when the modem has not joined a network.

exception lora.LoraErrorRX

Raised on a +ERR_RX response when an error occurs while receiving a downlink.

exception lora.LoraErrorUnknown

Raised on a +ERR_UNKNOWN response or when the modem reports an undocumented error.

Classes

class lora.Lora(uart: pyb.UART = None, rst_pin: pyb.Pin = None, boot_pin: pyb.Pin = None, band: int = BAND_EU868, poll_ms: int = 300000, debug: bool = False)

Construct a new modem driver. The constructor initializes (or auto-creates) the UART and reset/boot pins, hardware-resets the module, performs autobaud synchronization, reboots the module, queries its firmware version, and configures the requested regional band.

Parameters:
  • uart – Pre-configured pyb.UART instance used to talk to the modem. If None, the driver opens UART(8, 19200) with 8N2 framing (the Portenta Vision Shield default).

  • rst_pinpyb.Pin driving the modem’s reset line. If None, PC6 is configured as a push-pull output.

  • boot_pinpyb.Pin driving the modem’s boot-select line. If None, PG7 is configured as a push-pull output pulled low.

  • band – Regional band to configure. One of the BAND_* constants.

  • poll_ms – Interval in milliseconds between automatic empty uplinks triggered by poll() to keep the downlink window open.

  • debug – When True, all UART traffic is printed via print().

LoraErrors: dict

Mapping from modem error response strings (e.g. "+ERR_BUSY") to the corresponding exception class. Used internally by handle_error().

init_modem() None

Lazy-initialize self.uart, self.rst_pin and self.boot_pin to their Portenta Vision Shield defaults if they are not already set. Called from the constructor; not normally invoked by user code.

debug_print(data: str) None

Print data if debug was enabled at construction time, otherwise do nothing.

is_arduino_firmware() bool

Return True if the modem is running the Arduino MKRWAN ARD-078 firmware (detected from the cached fw_version string).

configure_class(_class: str) None

Configure the LoRaWAN device class.

Parameters:

_class – One of CLASS_A, CLASS_B, CLASS_C.

configure_band(band: int) bool

Configure the regional band and, on Arduino firmware with BAND_EU868, enable the ETSI duty-cycle limiter. Returns True on success.

Parameters:

band – One of the BAND_* constants.

set_baudrate(baudrate: int) None

Change the modem’s UART baud rate (AT+UART).

Parameters:

baudrate – New baud rate, in bits per second.

set_autobaud(timeout: int = 10000) bool

Send empty AT commands until the modem responds with +OK or until timeout milliseconds elapse. Returns True if synchronization succeeded.

Parameters:

timeout – Maximum time to spend trying, in milliseconds.

get_fw_version() str

Query the modem device string (AT+DEV?) and firmware version (AT+VER?) and return them as a single space-separated string.

get_device_eui() str

Return the modem’s 64-bit Device EUI as a hex string.

factory_default() None

Restore factory defaults via AT+FACNEW.

restart() None

Re-synchronize the baud rate, reboot the modem, re-read the firmware version, and re-apply the configured regional band. Raises LoraError on failure.

set_rf_power(mode: int, power: int) None

Configure the modem RF output stage (AT+RFPOWER).

Parameters:
set_port(port: int) None

Configure the LoRaWAN application port (1..223) used by subsequent send_data() calls.

Parameters:

port – LoRaWAN FPort.

set_public_network(enable: bool) None

Enable or disable the public-network sync word.

Parameters:

enableTrue for the public LoRaWAN sync word, False for the private one.

sleep(enable: bool) None

Put the modem into low-power sleep (True) or wake it up (False).

format(hexMode: bool) None

Select the data format used over the UART for payload bytes.

Parameters:

hexModeTrue for ASCII-hex payload format, False for raw binary.

set_datarate(dr: int) None

Set the LoRaWAN data rate index (AT+DR).

Parameters:

dr – Region-specific data rate index.

get_datarate() int

Return the current LoRaWAN data rate index.

set_adr(adr: bool) None

Enable or disable Adaptive Data Rate.

Parameters:

adrTrue to enable ADR, False to disable it.

get_adr() int

Return the current ADR setting (1 if enabled, 0 otherwise).

get_devaddr() str

Return the current 32-bit DevAddr as a hex string.

get_nwk_skey() str

Return the current Network Session Key as a hex string.

get_appskey() str

Return the current Application Session Key as a hex string.

get_rx2dr() int

Return the data rate index used for the RX2 receive window.

set_rx2dr(dr: int) None

Set the data rate index used for the RX2 receive window.

Parameters:

dr – Region-specific data rate index.

get_ex2freq() int

Return the frequency, in Hz, used for the RX2 receive window.

set_rx2freq(freq: int) None

Set the frequency used for the RX2 receive window.

Parameters:

freq – Frequency in Hz.

set_fcu(fcu: int) None

Set the uplink frame counter (AT+FCU).

Parameters:

fcu – New uplink frame counter value.

get_fcu() int

Return the current uplink frame counter.

set_fcd(fcd: int) None

Set the downlink frame counter (AT+FCD).

Parameters:

fcd – New downlink frame counter value.

get_fcd() int

Return the current downlink frame counter.

change_mode(mode: int) None

Switch the activation mode.

Parameters:

mode – One of MODE_ABP, MODE_OTAA.

join(timeout_ms: int) bool

Issue an AT+JOIN and wait for the join-accept event. Returns True if the modem reports +EVENT=1,1 (join succeeded) within timeout_ms.

Parameters:

timeout_ms – Maximum time to wait for both the +ACK and the subsequent join event, in milliseconds.

get_join_status() bool

Return True if the modem is currently joined to a network.

get_max_size() int

Return the maximum LoRaWAN payload size, in bytes, for the current data rate. On Arduino firmware this is fixed at 64.

poll() None

If more than poll_ms milliseconds have passed since the last call, send an empty confirmed uplink to flush pending downlinks. Intended to be called frequently from the application’s main loop.

send_data(buff: bytes, confirmed: bool = True) bool

Transmit a LoRaWAN uplink. Raises LoraError if buff is larger than get_max_size().

Parameters:
  • buff – Payload bytes to transmit.

  • confirmed – When True, send a confirmed uplink (+CTX) and wait for a network-server +ACK. When False, send an unconfirmed uplink (+UTX).

Returns:

True if the modem accepted the packet (and, for confirmed uplinks, the network acknowledged it), False otherwise.

receive_data(timeout: int = 1000) dict | None

Wait for a downlink. Returns None if no +RECV event was received within timeout milliseconds, otherwise a dict {"port": str, "data": str} containing the FPort and the payload bytes.

Parameters:

timeout – Maximum time to wait, in milliseconds.

receive(delimiter: str | list | None = None, max_bytes: int | None = None, timeout: int = 1000) str

Low-level UART read. Reads characters from the modem until a delimiter is matched, max_bytes characters have been read, or timeout milliseconds elapse, then returns the accumulated string with any trailing \r stripped.

Parameters:
  • delimiter – Either a single character to match at the end of the buffer, a multi-character string to match against the full trimmed buffer, or a list of such strings.

  • max_bytes – If set, return as soon as exactly this many bytes have been read.

  • timeout – Overall read timeout, in milliseconds.

available() int

Return the number of bytes currently available in the modem’s UART receive buffer.

join_OTAA(appEui: str, appKey: str, devEui: str = None, timeout: int = 60000) bool

Switch the modem to OTAA mode, program the supplied keys and EUIs, then attempt to join the network. Returns True if the join succeeded.

Parameters:
  • appEui – 64-bit Application/Join EUI as a hex string.

  • appKey – 128-bit Application Key as a hex string.

  • devEui – Optional 64-bit Device EUI as a hex string. If None, the factory-programmed Device EUI is used.

  • timeout – Join timeout, in milliseconds.

join_ABP(nwkId: int, devAddr: str, nwkSKey: str, appSKey: str, timeout: int = 60000) bool

Switch the modem to ABP mode, program the supplied addresses and keys, then attempt to join. Returns the result of get_join_status().

Parameters:
  • nwkId – Network identifier (currently ignored by the firmware).

  • devAddr – 32-bit Device Address as a hex string.

  • nwkSKey – 128-bit Network Session Key as a hex string.

  • appSKey – 128-bit Application Session Key as a hex string.

  • timeout – Join timeout, in milliseconds.

handle_error(command: str, data: str) None

Inspect a modem response and raise the matching LoraError subclass if it represents an error. Does nothing for non-error responses.

Parameters:
  • command – The AT command (without the AT prefix) that produced data.

  • data – The response string returned by the modem.

send_command(cmd: str, *args, delimiter: str = '\\r', data: bytes = None, timeout: int = 1000, raise_error: bool = True) str

Build an AT command from cmd and args, optionally append a raw data payload, transmit it, and return the modem’s response. For query commands ending in ?, only the value portion (the substring after =) is returned.

Parameters:
  • cmd – AT command suffix (e.g. "+JOIN", "+DR="); the "AT" prefix and trailing \r are added automatically.

  • args – Additional arguments concatenated to cmd after string conversion.

  • delimiter – Delimiter forwarded to receive().

  • data – Optional raw bytes written immediately after the AT command (used for binary uplink payloads).

  • timeout – Response timeout, in milliseconds.

  • raise_error – When True, error responses are converted into LoraError exceptions; when False, the raw response is returned to the caller.