📓
Enginique Docs
HomeHow-to
  • Documentation Home
  • Single Board Computers
    • Engage
  • Industrial Devices
    • Evolve
      • Calibration
      • Reprogramming
    • Evolve 'R
    • Energy Analyzer
    • R'IO: Mini PLC
  • Sensor Modules
    • Bioacoustics Module
    • CO2 RHT Module
    • Environmental Module
    • Hall Effect Module
    • I2C Adapter Module
    • IMU Module
    • Irradiance Module
    • Positioning Module
    • Presence Module
    • RTD Module
  • Extension Boards
    • NFC Broker
  • Connectivity Modules
    • M.2 BLE 802.15.4 Module
    • M.2 CAT-M NB-IoT Module
    • M.2 Developer Module
    • M.2 LEO Satellite Module
    • M.2 LoRa Module
    • M.2 WiFi Module
  • Robotics
    • Wheeled Robot Controller
  • Environmental Monitoring
    • Air Quality Sensor
      • Modbus Protocol
    • Environmental Sensor
      • Modbus Protocol
    • Depth Sensor
      • Modbus Protocol
    • Irradiance Sensor
      • Modbus Protocol
    • Mechanical Wind Sensor
      • Modbus Protocol
    • Rain Gauge
      • Modbus Protocol
    • Soil Sensor
      • Modbus Protocol
    • Ultrasonic Wind Sensor
      • Modbus Protocol
  • Value-Line Devices
    • Sensor Carrier BLE
    • Sensor Carrier LoRa
  • Communication Protocols
    • CoAP
    • LoRaWAN
    • Matter
    • Modbus
    • MQTT
  • Libraries
    • ACS71240 Current Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • Adrastea-I Cellular Module
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • BME280 Env Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • BME688 Env Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • BGT60TR13C Radar Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • DS18B20 Temp Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • EEPROM Memory
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • Elara-I Positioning Module
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • Irradiance Meter
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • LIS3DH IMU
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • MAX31865 RTD Converter
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • MCP23 Series Expander
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • SCD4x CO2 Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • SEN5x Air Quality Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • ST25R3916 NFC Device
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • SX1262 LoRa Transceiver
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • TMAG5273 Hall Effect Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • TSL2540 Light Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • WL-ICLED
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • WSEN-HIDS Humidity Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • WSEN-PADS Pressure Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
    • WSEN-TIDS Temperature Sensor
      • Arduino / ESP32
        • Arduino (C/C++)
        • MicroPython
      • Raspberry Pi OS
        • Go
        • Python
      • STM32
        • C
        • MicroPython
  • Important Notice
Powered by GitBook

Copyright (c) 2024 Enginique.

On this page
  • Protocol Specifications
  • Payload Format
  • Uplink Frame Ports
  • Uplink Payload Structure
  • Uplink Payload Formatter
Export as PDF
  1. Communication Protocols

LoRaWAN

LoRaWAN, which stands for Long Range Wide Area Network, is a wireless communication protocol designed for low-power IoT devices. It enables secure and scalable data transmission over long distances while consuming minimal power. This makes it well-suited for widespread use in smart cities, industrial IoT, and agricultural applications.

This document describes LoRaWAN protocol support and payload structure for data transmission.

Protocol Specifications

The latest firmware complies with the following LoRaWAN specifications.

Property
Value

LoRaWAN Version

1.0.4

Regional Parameters Version

RP002 Regional Parameters 1.0.4

Available Frequency Plans

EU868 (Europe) US902-928 (USA, Canada, and South America)

Payload Format

Uplink Frame Ports

The frame port is a data frame field specifying the application-specific commands or data payload type. For instance, Device firmware uses the frame port field to tell the payload formatter how to decode the transmitted message.

Frame Port
Event
Description

1

System

Device state

2

Telemetry

Periodic sensor readouts

3

Telemetry Alert

Alarm state

4

Telemetry Log

Periodic historical sensor readouts

Uplink Payload Structure

The firmware may dynamically change the telemetry payload according to its sensor configuration. Each sensor reading data, e.g., vibration, contains 4 bytes. This structure includes sensor type, statistics mode, and 24-bit sensor reading.

For example, the firmware encodes an average of 100 Hz vibration on the x-axis as 00111001 00000001 10000110 10100000 where; - Bits [31:26] indicate the sensor data type (x-axis vibration), - Bits [25:24] indicate the statistics type (average), - And bits [23:0] indicate sensor reading (100,000 Hz).

When the device reads more than one sensor data, it adds another 4-byte structure with the same logic for each reading. The illustrated sensor data structure is as follows.

Sensor Data

Bits
Data
Description

[31:26]

Data Type

Sensor readout type, e.g., temperature or light intensity

[25:24]

Statistics Type

Statistical type of the readout, e.g., actual, average, min, or max

[23:0]

Value

Sensor readout

Data Types

Position: Bits [31:26]

Index
Data Type
Signed
Fraction
Unit
Description

0

Null / Terminator

N/A

N/A

N/A

Indicates no reading

1

Temperature

Yes

4

C

Ambient temperature

2

Relative Humidity

No

4

%

Ambient relative humidity

3

Pressure

No

4

hPa

Air pressure

4

Gas Estimation

No

4

%

Classified gas estimation

5

IAQ

No

4

AQI

Indoor air quality index

6

VOC

No

4

ppm

Volatile organic compounds

7

NOx

No

2

ppb

Nitrogen oxides index

8

CO2

No

2

ppm

CO2

9

Particulate Matter

No

2

μm

Particles in the air

10

Dew Point

Yes

4

C

Dew Point

11

VPD

No

4

kPa

Vapor Pressure Deficit

12

Visible Light

No

0

Human visible light

13

IR Light

No

0

Infrared light

14

UV Index

No

4

UV Index

Ultraviolet index

15

Light Custom

No

0

N/A

Application specific data

16

Angle

Yes

4

deg

Device angle

17

Vibration

No

4

Hz

Vibration of the device

18

RPM

No

2

Ticks

Revolutions per minute

19

Speed

No

4

Km/h

Current speed

20

Latitude

Yes

4

deg

Current latitude

21

Longitude

Yes

4

deg

Current longitude

22

Altitude

Yes

2

m

Current altitude

23

Heading

Yes

4

deg

Current heading

24

Weight

No

0

g

Measured weight

25

Distance

No

0

mm

Distance to an object

26

Contact

No

0

bits

Contact sensor state

27

Movement Detect

No

0

bits

PIR sensor state

28

Wind Speed

No

4

Km/h

Current wind speed

29

Wind Direction

Yes

4

deg

Current wind degree

30

Precipitation

No

2

mm

Current rainfall

31

Soil Moisture

No

4

%

Soil moisture level

32

Water Flow

No

0

Ticks

Amount of water flow

33

Water Conductivity

No

0

µmhos/cm

Water EC

34

pH

No

4

pH

Water pH

35

Salinity

No

4

ppt

Concentration of salt in water

36

TDS

No

4

ppm

Total dissolved solids

37

Water Custom 1

No

0

N/A

Application specific data

38

Water Custom 2

No

0

N/A

Application specific data

39

Water Custom 3

No

0

N/A

Application specific data

40

Voltage

No

4

V

Voltage reading

41

Current

No

2

A

Current passing

42

Frequency

No

4

Hz

Mains frequency

43

Real Power

No

2

W

Energy consumption

44

Apparent Power

No

2

VA

Voltage Current

45

Reactive Power

No

2

VAR

Voltage-Current phase shift

46

Power Factor

No

4

%

Real power ratio

47

Phase Angle

No

4

deg

Angular time-shift

48

Custom 1

No

0

N/A

Application specific data

49

Custom 2

No

0

N/A

Application specific data

50

Custom 3

No

0

N/A

Application specific data

51

Custom 4

No

0

N/A

Application specific data

52

Sound Pressure

Yes

4

dB

Sound pressure

53

Solar Radiation

No

2

W/m²

Solar power to panel area ratio

54

Probe Temperature

Yes

3

C

Probe temperature

55

Probe Pressure

No

2

hPa

Probe pressure input

56

UID

No

0

Bytes

Unique Id

57

Time

No

0

N/A

Event timestamp

58

Battery Voltage

No

4

V

Battery input Voltage

59

Solar Voltage

No

4

V

Solar panel input Voltage

60

Counter

No

0

Ticks

Digital input change counter

61

Duty Cycle

No

4

%

Digital input duty cycle

62

Analog Input

No

4

V

Analog input reading

63

Digital Input

No

0

Bits

Digital input port state

Statistics Types

Position: Bits [25:24]

Index
Statistics Type
Description

0

Actual

Latest sensor reading

1

Average

Average of the historical data

2

Minimum

Minimum of the historical data

3

Maximum

Maximum of the historical data

Value

Position: Bits [23:0]

The value field carries the actual sensor readout. The payload formatter encodes the value according to the "signed" and "fraction" specifications of the data type.

Uplink Payload Formatter

Use the following Javascript code as the custom payload formatter script.

Uplink Payload Formatter
// Enginique Uplink Payload Formatter Version 1.3.4
function decodeUplink(input) {
    let addFraction = (n, d) => n / (10 ** d);
    let decodeReadingId = (d) => d >> 2;
    let decodeStatisticsId = (d) => d & 0x03;

    let data = {};

    // Events
    const events = {
        2: "telemetry",
        3: "telemetry alert",
        4: "telemetry log"
    };

    // Reading structures (type, signed, fraction)
    const readingStructures = {
        0: ["null", false, 0],
        1: ["temperature", true, 4],
        2: ["relative_humidity", false, 4],
        3: ["pressure", false, 4],
        4: ["gas_estimation", false, 4],
        5: ["iaq_index", false, 4],
        6: ["voc", false, 4],
        7: ["nox_index", false, 2],
        8: ["co2_concentration", false, 2],
        9: ["particulate_matter", false, 2],
        10: ["dew_point", true, 4],
        11: ["vpd", false, 4],
        12: ["visible_light", false, 0],
        13: ["ir_light", false, 0],
        14: ["uv_index", false, 4],
        15: ["light_custom", false, 0],
        16: ["angle", true, 4],
        17: ["vibration", false, 4],
        18: ["rpm", false, 2],
        19: ["speed", false, 4],
        20: ["latitude", true, 4],
        21: ["longitude", true, 4],
        22: ["altitude", true, 2],
        23: ["heading", true, 4],
        24: ["weight", false, 0],
        25: ["distance", false, 0],
        26: ["contact", false, 0],
        27: ["movement_detection", false, 0],
        28: ["wind_speed", false, 4],
        29: ["wind_direction", true, 4],
        30: ["precipitation", false, 2],
        31: ["soil_moisture", false, 4],
        32: ["water_flow", false, 0],
        33: ["water_conductivity", false, 0],
        34: ["ph", false, 4],
        35: ["salinity", false, 4],
        36: ["tds", false, 4],
        37: ["water_custom_1", false, 0],
        38: ["water_custom_2", false, 0],
        39: ["water_custom_3", false, 0],
        40: ["voltage", false, 4],
        41: ["current", false, 2],
        42: ["frequency", false, 4],
        43: ["real_power", false, 2],
        44: ["apparent_power", false, 2],
        45: ["reactive_power", false, 2],
        46: ["power_factor", false, 4],
        47: ["phase_angle", true, 4],
        48: ["custom_1", false, 0],
        49: ["custom_2", false, 0],
        50: ["custom_3", false, 0],
        51: ["custom_4", false, 0],
        52: ["sound_pressure", true, 4],
        53: ["solar_radiation", false, 2],
        54: ["probe_temperature", true, 3],
        55: ["probe_pressure", false, 2],
        56: ["uid", false, 0],
        57: ["time", false, 0],
        58: ["battery_voltage", false, 4],
        59: ["solar_voltage", false, 4],
        60: ["counter", false, 0],
        61: ["duty_cycle", false, 4],
        62: ["analog_input", false, 4],
        63: ["digital_input", false, 0]
    };

    // Three-letter statistics type abbreviations
    const statistics = {
        0: "",
        1: "_avr",
        2: "_min",
        3: "_max"
    };

    // Decode frame port
    data.event = events[input.fPort];

    // Sensor data decoding for "telemetry" and "telemetry alert" frame ports
    if (input.fPort == 2 || input.fPort == 3) {
        for (let i = 0; i < input.bytes.length; i += 4) {
            const readingId = decodeReadingId(input.bytes[i]);

            // Stop decoding if data type is null
            if (readingId == 0)
                break;

            // Decode digital input channels
            else if (readingId == 63) {
                for (let j = 0; j < 8; j++) {
                    const prop = (input.bytes[i + 3] >> j) & 1;
                    data[`di${j + 1}`] = prop == 1 ? true : false;
                }
            }

            // Decode other data types
            else {
                // Decode data type
                let prop;
                // If multiple-read data type, e.g., vlt_1, vlt_2
                if ([4,9,16,17,18,40,41,42,43,44,45,46,47,54,55,60,61,62].includes(readingId))
                {
                    for (let j = 1; j <= 64; j++) {
                        let tempProp = `${readingStructures[readingId][0]}_${j}${statistics[decodeStatisticsId(input.bytes[i])]}`;
                        if (data[tempProp] == null) {
                            prop = tempProp;
                            break;
                        }
                    }
                }
                // If single-read data type, e.g., tmp, pre
                else {
                    prop = `${readingStructures[readingId][0]}${statistics[decodeStatisticsId(input.bytes[i])]}`;
                }

                // Decode value
                const value = (input.bytes[i + 1] << 16) + (input.bytes[i + 2] << 8) + (input.bytes[i + 3]);

                // Get the fraction
                const fraction = readingStructures[readingId][2];

                // Check if the data type is signed
                if (readingStructures[readingId][1]) {
                    // Decode signed data
                    const negative = ((value >> 23) & 1) == 1 ? true : false;
                    data[prop] = addFraction(negative ? -((~(value - 1)) & 0xFFFFFF) : value, fraction);
                }
                else {
                    // Decode unsigned data
                    data[prop] = addFraction(value, fraction);
                }
            }
        }
    }

    return {
        data: data
    };
}

Last updated 9 days ago

Uplink Payload Structure