Skip to main content

Modbus ASCII / RTU Bridge (LoRaWAN)

LoRaWAN Modbus Bridge with 230 V power supply

Lobaro Modbus LoRaWAN Bridge

The Lobaro Modbus LoRaWAN Bridge connects Modbus ASCII or Modbus RTU devices on an RS-485 bus to a LoRaWAN network.

Key Features

  • LoRaWAN 1.0.x network-server support
  • Experimental LoRaWAN 1.1 support
  • LoRaWAN Class A and Class C operation
  • LoRaWAN time synchronization
  • Modbus ASCII and Modbus RTU support
  • Reading of coils, discrete inputs, input registers, and holding registers
  • Writing of coils and holding registers
  • Scheduled Modbus readouts
  • Modbus commands through LoRaWAN downlinks
  • Configuration through USB or LoRaWAN remote configuration
  • Interactive Modbus dialog mode through USB
  • Listen-before-talk operation alongside another Modbus master
  • Managed power-supply output for attached sensors
  • Compact payload formats for installations with many registers

Purpose

The Bridge operates as a Modbus master/client on an RS-485 bus. It can regularly execute configured Modbus commands and upload the responses through LoRaWAN.

It can also receive Modbus commands through LoRaWAN downlinks, forward them to the connected Modbus device, and return the response through an uplink.

The Bridge supports:

  • Class A for power-efficient battery operation
  • Class C for faster downlink response times

Modbus LoRaWAN system overview

Typical applications include:

  • Electricity meters
  • Water meters
  • Heat controllers
  • Temperature and humidity sensors
  • Industrial machines
  • Solar installations
  • Building-management equipment
info

Modbus TCP

This product supports Modbus ASCII and Modbus RTU over RS-485.

Modbus TCP is not supported.

Supported Devices

The Bridge can communicate with Modbus RTU or ASCII slave/server devices that use compatible serial settings.

Devices previously tested with the Bridge include:

DeviceTypeManufacturer
Octave Ultrasonic MeterWater meterArad Group
ECL ControllerHeating and hot-water controllerDanfoss
UMD 97Smart-grid power meterPQ Plus
DRS458DEPower meterB+G E-Tech
PCE-P18Humidity and temperature transmitterPCE Instruments

Product Variants

Externally Powered Variant

Type: LOB-GW-MODBUS-LW-PWR

ItemOrder number
Modbus LoRaWAN Bridge with external 230 V supply and internal antenna8000137
Modbus LoRaWAN Bridge for DIN rail, without housing8000043
DR-15-5 DIN-rail power supply, 5 V3000006
RK 4/12-L DIN-rail housing3000005

Externally powered Modbus LoRaWAN Bridge

Battery-Powered Variant

Type: LOB-GW-MODBUS-LW

ItemOrder number
Modbus LoRaWAN Bridge with battery connector, external-power input, and IP67 housing8000041
ER34615 3.6 V D-cell battery with XH connector3000169

Battery-powered Modbus LoRaWAN Bridge

The product image may not show the M8 cable gland.

Custom Variants

Custom variants were available with options such as:

  • External antenna
  • AA batteries
  • Alternative housings
  • Alternative power supplies
  • NB-IoT instead of LoRaWAN

Quick Start

This example reads three consecutive holding registers from a single Modbus device.

  1. Connect the RS-485 lines:

    • Bridge A to device A
    • Bridge B to device B
    • Bridge GND to device GND, when available
  2. Connect the Bridge to a computer using the Lobaro USB Configuration Adapter.

  3. Open the Lobaro Maintenance Tool.

  4. Configure the LoRaWAN credentials for your network.

  5. Confirm that the Bridge is within range of a LoRaWAN gateway.

  6. Configure the serial settings according to the connected Modbus device.

  7. Set MbCmd to the required Modbus command.

  8. Save the configuration.

  9. Open the log view and verify the test readout and subsequent uplink.

Example:

MbCmd = 010300000003

The command consists of:

BytesMeaning
01Modbus slave address 1
03Read Holding Registers
0000Start at register 0
0003Read three consecutive registers

Checksums must not be included in MbCmd. The Bridge adds the required RTU CRC or ASCII LRC automatically.

Work Cycle

Modbus Bridge work cycle

Init

After power-up or a reboot, the Bridge performs a self-test and validates its configuration.

A successful self-test is indicated by a slow green LED flash. Invalid configuration values can cause repeated LED flashes followed by a reboot.

Test Reading

After configuration validation, the Bridge executes every configured Modbus command once.

The results are written to the device log but are not uploaded. This allows the installer to verify that the connected Modbus devices can be reached.

LoRaWAN Join

The Bridge connects to the configured LoRaWAN network.

With OTAA, it remains in the join state until joining succeeds. Join requests are repeated with progressively longer intervals.

Data Collection

The Bridge executes the commands configured in MbCmd and collects the responses.

Data Transfer

The responses are transmitted through LoRaWAN. Several uplinks may be required when a large amount of data is read.

A device status message is transmitted at most once per day.

Sleep

After completing the upload, the Bridge enters a low-power state until the next activation defined by MbCron.

Configuration

The initial configuration is normally performed using:

  • Lobaro Maintenance Tool
  • Lobaro USB Configuration Adapter

When enabled, configuration values can also be read or changed remotely using LoRaWAN downlinks.

LoRaWAN Configuration

The LoRaWAN parameters must match the selected network-server configuration.

NameDescriptionTypeValues
OTAASelects OTAA or ABP activationbooltrue or false
DevEUIUnique device identifierbyte[8]For example 0123456789abcdef
JoinEUIJoin identifier for OTAA, formerly called AppEUIbyte[8]For example 0123456789abcdef
AppKeyApplication key for OTAAbyte[16]LoRaWAN 1.0 and 1.1
NwkKeyNetwork key for OTAAbyte[16]LoRaWAN 1.1
SFInitial or maximum spreading factorint712
ADREnables Adaptive Data Ratebooltrue or false
OpModeLoRaWAN operating classstringA or C
TimeSyncTime-synchronization intervalintDays; 0 disables synchronization
RndDelayMaximum random delay before sendingintSeconds
RemoteConfEnables remote configurationbooltrue or false
LostRebootReboot interval when no downlink is receivedintDays; 0 disables the feature

For more information, see the LoRaWAN configuration article.

Modbus and UART Configuration

The serial parameters must match the connected Modbus devices.

NameDescriptionValues
MbProtModbus protocolRTU or ASCII
MbBaudUART baud rateFor example 9600, 19200, 38400
MbDataLenUART data length7, 8, or 9
MbStopBitsUART stop bits0.5, 1, 1.5, or 2
MbParUART parityNONE, EVEN, or ODD
MbCronSchedule for automatic readoutFor example 0 0/15 * * * *
MbCmdComma-separated Modbus commandsFor example 010300010003
PlFmtUplink payload format1, 4, or 5
PlMaxMaximum compact-payload message size10241, subject to LoRaWAN limits
PlIdCompact-format identifier0127
PowerDelaySensor power-supply warm-up time03600 seconds; -1 means always on
EnDLEnables Modbus commands by downlinktrue or false
DialogModeEnables interactive USB dialog modetrue or false
LbtDurationMaximum listen-before-talk duration0 disables; otherwise seconds
LbtSilenceRequired quiet period before transmitting0 disables; otherwise seconds

PlMax, PlId, and PowerDelay are available in firmware version 1.3.0 or newer.

Modbus Commands

Commands in MbCmd are entered as hexadecimal bytes without spaces or checksums.

Multiple commands are separated by commas:

090300640003,0a0300640003

This example reads holding registers 100–102 from devices 9 and 10.

Writing registers

Any valid byte sequence can be configured, including write commands.

Configured commands are also executed during the startup test reading. Avoid configuring write operations unless this behavior is explicitly intended.

Large Modbus responses may exceed the maximum LoRaWAN payload size. In that case, the response is split into several uplinks.

Listen Before Talk

A standard Modbus installation normally has only one master. The Bridge can optionally share a bus with another master using the listen-before-talk feature.

When enabled, the Bridge:

  1. Waits for the existing master to communicate.
  2. Detects when the communication ends.
  3. Waits for a configured quiet period.
  4. Sends its own Modbus requests.

LbtDuration defines how long the Bridge waits for activity from the other master.

LbtSilence defines how long the bus must remain quiet before the Bridge starts transmitting.

Example:

LbtDuration = 130
LbtSilence = 15

This could be used when another master operates approximately every two minutes and communicates for about 30 seconds.

Setting either value to 0 disables listen-before-talk.

Payload Formats

Port Overview

DirectionPortPlFmtPurpose
Uplink1AnyStatus message
Uplink31Scheduled Modbus responses in verbose format
Uplink4AnyResponses to Modbus downlink commands
Uplink5AnyContinuation of a split response
Uplink62Deprecated compact format with timestamp
Uplink73Deprecated compact format without timestamp
Uplink20594 or 5Current compact payload format
Uplink128AnyRemote-configuration response
Uplink129131AnySplit remote-configuration response
Downlink4AnyModbus commands
Downlink128AnyRemote configuration

Status Message - Port 1

Status messages report information about the Bridge itself. They are transmitted at most once per day and have a length of 16 bytes.

FieldPositionLengthTypeDescription
version03uint8[3]Firmware version
flags31uint8Internal status flags
temperature42int16 BEInternal temperature in 0.1 °C
voltage62uint16 BESupply voltage in mV
timestamp85uint40 BEUNIX timestamp
plFmt131uint8Configured payload format
resetReason141uint8Latest reset reason
finalWords151uint8Additional reset information

resetReason and finalWords are available in firmware version 1.3.0 or newer.

Reset Reasons

HexDecimalNameMeaning
0x011LOW_POWER_RESETSupply voltage became critically low
0x022WINDOW_WATCHDOG_RESETWindow watchdog triggered
0x033INDEPENDENT_WATCHDOG_RESETIndependent watchdog triggered
0x044SOFTWARE_RESETFirmware initiated the reboot
0x055POWER_ON_RESETDevice power was switched on
0x066EXTERNAL_RESET_PIN_RESETReset pin or configuration adapter triggered the reset
0x077OBL_RESETOption-byte loader reset
0xff255UNKNOWNUnknown reset reason

Final Words

HexDecimalNameMeaning
0x000NONENo additional information
0x011RESETIntentional firmware reset
0x022ASSERTFirmware assertion failed
0x033STACK_OVERFLOWStack overflow
0x044HARD_FAULTProcessor hard fault
0x055OUT_OF_MEMORYCritical memory allocation failed
0x1016INVALID_CONFIGInvalid configuration detected
0x1117REMOTE_RESETReboot requested remotely
0x1218NETWORK_LOSTLoRaWAN connection was considered lost
0x1319NETWORK_FAILNetwork join failed after a remote configuration change

Verbose Payload Format - Port 3, PlFmt=1

The verbose format contains the complete Modbus response together with information from the command.

Each uplink begins with a five-byte UNIX timestamp followed by one or more response blocks.

Bytes | 0 1 2 3 4 | 5 ... | ... |
Part | timestamp | response 1 | response 2 |

Each response block has this structure:

Bytes | 0 | 1 ... len-3 | len-2..len-1 | len |
Field | len | Modbus response | start address | count |
FieldDescription
lenNumber of bytes in the response block
Modbus responseRaw bytes returned by the Modbus device
start addressFirst requested register or coil
countNumber of requested registers or coils

The additional address and count values allow the backend to identify which part of the Modbus device was queried.

For functions that do not contain a start address or count, these additional values are undefined.

Responses to Modbus commands received through downlink port 4 use the same verbose format as scheduled responses on port 3.

The timestamp represents the time at which the downlink was received.

Split Responses - Port 5

If a Modbus response does not fit into one LoRaWAN uplink:

  • The first part is sent on port 3 or port 4.
  • Remaining bytes are sent on port 5.
  • The backend must append the port 5 payload to the previous response.
  • LoRaWAN frame counters should be checked to detect missing parts.

A split response can require several uplinks when a high spreading factor is used.

To avoid splitting:

  • Read fewer registers per command.
  • Use a lower spreading factor where appropriate.
  • Use a compact payload format.

Deprecated Compact Format - Ports 6 and 7

Payload formats 2 and 3 were used before firmware version 1.3.0.

They have been replaced by the compact format on ports 20-59. Existing installations should migrate to the newer format or remain on a compatible legacy firmware.

Compact Payload Format - Ports 20-59

The compact format transmits only the data portion of successful Modbus responses. It reduces LoRaWAN overhead but requires a parser that already knows the device configuration.

The relevant parameters are:

  • PlFmt
  • PlMax
  • PlId
  • MbCmd

PlFmt=5

The message header is one byte:

bit 7 = error indicator
bits 0–6 = PlId

PlFmt=4

The message header consists of:

1 byte error indicator and PlId
5 bytes UNIX timestamp, big endian

Error Handling

If a command fails:

  • The error bit in the header is set.
  • The data bytes reserved for the failed command are filled with 0xff.

Message Distribution

Responses are assigned sequentially to ports 20–59.

PlMax defines the maximum size of each uplink, including its header. The allowed value depends on the configured spreading factor and regional LoRaWAN limits.

No individual command response may exceed PlMax after including the message header.

Remote Configuration - Ports 128–131

When remote configuration is enabled:

  • Commands are received through downlink port 128.
  • Short responses are sent through uplink port 128.
  • Long responses are split across ports 129, 130, and 131.

A port 4 downlink can contain one or more Modbus commands.

Each command is prefixed with a one-byte length:

[length][command][length][command]...

The commands are sent as raw bytes without RTU CRC or ASCII LRC.

Example:

06180401000001

Breakdown:

BytesMeaning
06Command length: six bytes
18Slave address 24
04Read Input Registers
0100Start at register 256
0001Read one register

If the addressed device does not respond, the Bridge creates a Modbus exception response with code 11, Gateway Target Device Failed to Respond.

Examples

Read Three Holding Registers

Configuration:

MbCmd = 010300000003

Possible successful uplink on port 3:

005d1698fd0c0103061234567890ab000003

Breakdown:

005d1698fd timestamp
0c response length: 12 bytes
01 slave address 1
03 Read Holding Registers
06 six data bytes follow
1234567890ab
0000 start register
03 register count

Possible failed response:

005d1698fd0601830b000003

Here, 83 indicates function 3 with an error flag and 0b indicates that the target device did not respond.

Split Response

Configuration:

MbCmd = 010300010020

The command reads 32 registers and returns 64 data bytes.

The first part is sent on port 3:

005d1698fd46010340000100020003000400050006000700080009000a000b000c000d000e000f001000110012001300140015

The continuation is sent on port 5:

0016001700180019001a001b001c001d001e001f00200120

The application must append the port 5 data to the incomplete response received on port 3.

Compact Format with Timestamp

Configuration:

MbCmd = 010300000003
PlFmt = 4
PlMax = 51
PlId = 0

Successful port 20 uplink:

00005fd8bf08000000010033

Breakdown:

00 no error, PlId 0
005fd8bf08 timestamp
000000010033 data from three registers

Failed port 20 uplink:

80005fd8c7caffffffffffff

The highest header bit indicates an error and the response data is replaced by ff.

Dialog Mode

Dialog Mode provides an interactive Modbus master through the Lobaro Maintenance Tool.

Enable it with:

DialogMode = true

After the device reboots:

  • It does not connect to LoRaWAN.
  • It does not execute scheduled commands.
  • It waits for commands entered through the Maintenance Tool.
  • Commands are sent through the Send via UART input field.
  • Responses are shown in the device log.

Commands must be entered as hexadecimal bytes without checksums.

Example command:

010300100002

This reads holding registers 16 and 17 from device address 1.

Possible responses:

01830b

The target device did not respond.

018302

The addressed registers are not supported.

010304abcd1234

A successful response containing:

Register 16 = abcd
Register 17 = 1234
Battery consumption

Dialog Mode keeps the device active and can quickly discharge the battery.

Do not leave a battery-powered device in Dialog Mode.

Complex Installations

The standard firmware executes all configured commands using one schedule.

Custom firmware may be required when an installation needs:

  • Different schedules for different registers
  • Several measurements followed by averaging
  • Conditional requests based on a status register
  • Custom data transformations
  • More complex error handling
  • Alternative communication such as NB-IoT

Technical Characteristics

Product

PropertyValue
Type, 230 V variantLOB-GW-MODBUS-LW-PWR
Type, battery variantLOB-GW-MODBUS-LW
DescriptionModbus Bridge with LoRaWAN, external 230 V power, and internal antenna

RF Transceiver

PropertyValue
TransceiverSemtech SX1272
Frequency863–870 MHz
Maximum TX power+13 dBm
Typical rangeUp to 2 km
Ideal rangeUp to 10 km with free line of sight

LoRaWAN

PropertyValue
ProtocolLoRaWAN 1.0.2 EU868
Device classesClass A and Class C
LoRaWAN 1.1Experimental
ActivationOTAA or ABP
EncryptionAES-128

Modbus

PropertyValue
Physical busRS-485 twisted pair, optional GND
ProtocolModbus RTU or Modbus ASCII
HBM protectionGreater than ±15 kV
IEC 61000-4-2 contact-discharge protectionGreater than ±12 kV
IEC 61000-4-4 burst protectionGreater than ±4 kV
Tested RS-485 cable lengthUp to 3 m
Longer cablesPossible, but not tested for this product

Environmental Requirements

PropertyValue
Operating temperature-20 °C to +55 °C
Maximum installation height2 m

Standards

CE Disposal

CE Declaration of Conformity

Disposal and WEEE

Dispose of the device and its batteries according to the applicable local requirements for electronic equipment. Please refer to: https://www.lobaro.com/entsorgung-weee-rohs/

Reference Decoder

The following decoder supports the status format, verbose Modbus responses, remote-configuration responses, and exposes compact payloads as raw data.

function readUInt16BE(bytes, offset = 0) {
return (bytes[offset] << 8) | bytes[offset + 1];
}

function readInt16BE(bytes, offset = 0) {
const value = readUInt16BE(bytes, offset);
return value & 0x8000 ? value - 0x10000 : value;
}

function readUInt40BE(bytes, offset = 0) {
return (
bytes[offset] * 0x100000000 +
bytes[offset + 1] * 0x1000000 +
bytes[offset + 2] * 0x10000 +
bytes[offset + 3] * 0x100 +
bytes[offset + 4]
);
}

function bytesToHex(bytes) {
return bytes
.map((value) => value.toString(16).padStart(2, '0'))
.join('');
}

function decodeStatus(bytes) {
if (bytes.length < 14) {
return { error: 'Status payload is too short' };
}

const result = {
port: 1,
version: `v${bytes[0]}.${bytes[1]}.${bytes[2]}`,
flags: bytes[3],
temperature: readInt16BE(bytes, 4) / 10,
voltage: readUInt16BE(bytes, 6) / 1000,
timestamp: readUInt40BE(bytes, 8),
payloadFormat: bytes[13],
noData: Boolean(bytes[3] & 0x01),
};

if (bytes.length >= 16) {
result.resetReason = bytes[14];
result.finalWords = bytes[15];
}

return result;
}

function modbusErrorText(code) {
const errors = {
1: 'Illegal Function',
2: 'Illegal Data Address',
3: 'Illegal Data Value',
4: 'Slave Device Failure',
5: 'Acknowledge',
6: 'Slave Device Busy',
7: 'Negative Acknowledge',
8: 'Memory Parity Error',
10: 'Gateway Path Unavailable',
11: 'Gateway Target Device Failed to Respond',
};

return errors[code] || 'Unknown error code';
}

function decodeVerboseResponse(raw) {
if (raw.length < 6) {
return {
error: 'Response block is too short',
raw: bytesToHex(raw),
};
}

const functionCode = raw[1] & 0x7f;
const isError = Boolean(raw[1] & 0x80);

const result = {
slave: raw[0],
function: functionCode,
error: isError,
rawResponse: bytesToHex(raw.slice(0, -3)),
startAddress: readUInt16BE(raw, raw.length - 3),
count: raw[raw.length - 1],
};

if (isError) {
result.errorCode = raw[2];
result.errorText = modbusErrorText(raw[2]);
}

return result;
}

function decodeVerbose(bytes, port) {
if (bytes.length < 5) {
return { error: 'Verbose payload is too short', port };
}

const timestamp = readUInt40BE(bytes, 0);
const responses = [];
let offset = 5;

while (offset < bytes.length) {
const length = bytes[offset];
offset += 1;

if (offset + length > bytes.length) {
return {
port,
timestamp,
responses,
split: true,
remainingLength: length,
receivedBytes: bytes.length - offset,
};
}

responses.push(
decodeVerboseResponse(bytes.slice(offset, offset + length)),
);

offset += length;
}

return {
port,
timestamp,
responses,
};
}

function decodeTextResponse(bytes) {
const response = String.fromCharCode(...bytes);

return {
response,
error: response.length === 0 || response.startsWith('!'),
};
}

function decodeUplink(input) {
const { fPort, bytes } = input;

if (fPort === 1) {
return { data: decodeStatus(bytes) };
}

if (fPort === 3 || fPort === 4) {
return { data: decodeVerbose(bytes, fPort) };
}

if (fPort === 5) {
return {
data: {
port: fPort,
continuation: true,
raw: bytesToHex(bytes),
},
};
}

if (fPort >= 20 && fPort <= 59) {
return {
data: {
port: fPort,
compact: true,
error: Boolean(bytes[0] & 0x80),
payloadId: bytes[0] & 0x7f,
raw: bytesToHex(bytes),
},
};
}

if (fPort >= 128 && fPort <= 131) {
return {
data: {
port: fPort,
...decodeTextResponse(bytes),
},
};
}

return {
errors: [`Unsupported LoRaWAN port: ${fPort}`],
};
}