This document covers only what is needed by a Modbus master in MODBUSSLV mode:
- usable holding-register map,
- data encoding on the wire,
- read/write rules relevant for polling and configuration.
Register map (holding registers)
| Start address | Size (regs) | Access | Description |
|---|---|---|---|
0x0000 |
2 | R | Serial number (uint32, LSW then MSW) |
0x0002 |
2 | R | Firmware version (uint32, LSW then MSW) |
0x0004 |
1 | R | Storage voltage |
0x0005 |
1 | R | Board temperature |
0x0006 |
1 | R | Base temperature |
0x0007 |
1 | R | TEG voltage |
0x0008 |
2 | R | Measurement counter (uint32, LSW then MSW) |
0x000A |
1 | R | Port 1 configured type (PortType_t, see below) |
0x000B |
1 | R | Port 2 configured type (PortType_t, see below) |
0x000C |
1 | R | Port 3 configured type (PortType_t, see below) |
0x000D |
1 | R | Port 4 configured type (PortType_t, see below) |
0x0020 |
1 | R/W | Delay before standby (seconds) |
0x0021 |
2 | R/W | Measurement period (milliseconds, uint32, LSW then MSW) |
0x0100 |
64 | R (dynamic) | Port 1 measurement data window |
0x0140 |
64 | R (dynamic) | Port 2 measurement data window |
0x0180 |
64 | R (dynamic) | Port 3 measurement data window |
0x01C0 |
64 | R (dynamic) | Port 4 measurement data window |
Encoding and ordering
- Register payload unit is
uint16. - For
uint32/float32, words are ordered LSW first (offset0), then MSW (offset1). - For port windows (
0x0100,0x0140,0x0180,0x01C0), the valid offset range is not fixed at 64 registers: it depends on the active measurement type read from0x000A–0x000D(see Port configured type and dynamic window layout).
Port configured type and dynamic window layout
Each port exposes its active measurement type at 0x000A–0x000D (ports 1–4). The value is a PortType_t code (uint16 in one holding register): the same code used in LoRaWAN uplink metadata (bytes 1–4) and in Toolbox / remote configuration.
Port measurement windows are allocated 64 registers each, but the device exposes only the offsets that match the configured type. Any read beyond that valid range returns illegal address — even inside the 64-register block.
Integrator workflow (dynamic table)
A Modbus master can build its polling map at runtime without hard-coding port wiring:
- Discover — read
0x000A+ (port− 1) for each port (0x000A…0x000D). - Resolve layout — look up the code in the table below and open the matching row in Port measurement windows.
- Poll — read only the valid offsets from that port’s window base (
0x0100,0x0140,0x0180,0x01C0). Global address = window base + offset. - Reconcile on change — if a port is reconfigured (Toolbox or downlink), the type register and valid offsets update; window bases stay fixed.
Example: port 2 reads 0x000B = 0x0F (WEATHER_A) → valid offsets 0–2 → poll holding 0x0140–0x0142 only.
PortType_t lookup
Codes 0x11, 0x15, and 0x17 are reserved and are not used in production configurations.
| Code | Measurement | Valid window offsets | Layout section |
|---|---|---|---|
0x00 |
Port disabled | (none — all reads illegal) | — |
0x01 |
PT1000 | 0 |
Temperature → PT1000 |
0x02–0x09 |
Thermocouple (K, J, T, N, S, E, B, R) | 0–1 |
Temperature → Thermocouple |
0x0A |
Infrared (ref A) | 0 |
Temperature → Infrared |
0x0B |
DC differential voltage | 0 |
Voltage → DC differential voltage |
0x0C |
AC differential voltage (RMS) | 0–1 |
Voltage → AC differential voltage |
0x0D |
DC voltage | 0 |
Voltage → DC voltage |
0x0E |
AC voltage (RMS) | 0–1 |
Voltage → AC voltage |
0x0F |
Temperature and humidity | 0–2 |
Environmental |
0x10 |
Potentiometer | 0–1 |
Industrial analog → Potentiometer |
0x12 |
4–20 mA loop | 0–1 |
Industrial analog → 4–20 mA |
0x13 |
Analog 1-axis vibration | 0–6 |
Vibration |
0x14 |
Dry contact (synchronous) | 0 |
Dry contact → synchronous |
0x16 |
Digital temperature probe (ref A) | 0 |
Temperature → Digital temperature probe |
0x18 |
DC magnetic sensor | 0–1 |
Magnetic field → DC magnetic sensor |
0x19 |
AC magnetic sensor (RMS) | 0–3 |
Magnetic field → AC magnetic sensor |
0x1A |
DC current (voltage difference) | 0–1 |
Current → DC current (voltage difference) |
0x1B |
DC current (magnetic sensor) | 0–1 |
Current → DC current (magnetic sensor) |
0x1C |
AC current (voltage difference, RMS) | 0–3 |
Current → AC current (voltage difference) |
0x1D |
AC current (magnetic sensor, RMS) | 0–3 |
Current → AC current (magnetic sensor) |
0x1E |
DC differential + external amplifier | 0–1 |
Voltage → DC differential + external amplifier |
0x1F |
AC differential + external amplifier (RMS) | 0–3 |
Voltage → AC differential + external amplifier |
0xFF |
Asynchronous dry contact (Alarm mode) | 0 |
Dry contact → asynchronous |
Write behavior
- Writable holding registers:
0x0020(delay before standby — oneuint16, seconds) and0x0021–0x0022(measurement period —uint32in milliseconds). - For the measurement period, write LSW at
0x0021first, then MSW at0x0022, to apply the full value.
Port measurement windows (0x0100 / 0x0140 / 0x0180 / 0x01C0)
Each port has a 64-register window. Offset below is relative to that port’s window base (not the global holding address). Which rows apply is determined by the port’s configured type at 0x000A–0x000D — see Port configured type and dynamic window layout.
| Port | Window base |
|---|---|
| Port 1 | 0x0100 |
| Port 2 | 0x0140 |
| Port 3 | 0x0180 |
| Port 4 | 0x01C0 |
Register encoding in the window
| Wire type | Registers | Decoding |
|---|---|---|
int16 |
1 | Signed value in one uint16 register (two’s complement) |
uint8 |
1 | Low byte valid |
float32 |
2 | IEEE-754, LSW at offset n, MSW at offset n+1 |
Physical scaling matches Harvestree LoRaWAN Payload Decoding where the same quantity is transmitted on LoRaWAN. Reads beyond the valid offset range for the active port type return illegal address.
Temperature
| Measurement | Offsets | Fields | Decoding |
|---|---|---|---|
| PT1000 | 0 |
Temperature | int16, × 0.1 → °C |
| Thermocouple (types K, J, T, N, S, E, B, R) | 0, 1 |
Cold junction, hot junction | int16 each, × 0.1 → °C |
| Digital temperature probe (ref A) | 0 |
Temperature | int16, × 0.1 → °C |
| Infrared (ref A) | 0 |
Object temperature | int16, × 0.1 → °C |
Environmental
| Measurement | Offsets | Fields | Decoding |
|---|---|---|---|
| Temperature and humidity | 0, 1, 2 |
Air temperature, humidity, frost index | int16 × 0.1 → °C; int16 × 0.1 → %RH; uint8 frost byte |
Voltage
| Measurement | Offsets | Fields | Decoding |
|---|---|---|---|
| DC voltage | 0 |
Voltage | int16, × 0.1 → mV |
| AC voltage (RMS) | 0, 1 |
RMS, frequency | int16 × 0.1 → mV RMS; int16 × 0.1 → Hz |
| DC differential voltage | 0 |
Voltage | int16, × 0.1 → mV |
| AC differential voltage (RMS) | 0, 1 |
RMS, frequency | int16 × 0.1 → mV RMS; int16 × 0.1 → Hz |
| DC differential + external amplifier | 0–1 |
Voltage | float32 (project-defined unit) |
| AC differential + external amplifier (RMS) | 0–1, 2–3 |
RMS, frequency | float32 each |
Magnetic field
| Measurement | Offsets | Fields | Decoding |
|---|---|---|---|
| DC magnetic sensor | 0–1 |
Magnetic quantity | float32 (project-defined unit) |
| AC magnetic sensor (RMS) | 0–1, 2–3 |
RMS, frequency | float32 each |
Current
| Measurement | Offsets | Fields | Decoding |
|---|---|---|---|
| DC current (voltage difference) | 0–1 |
Current | float32 (project-defined unit) |
| AC current (voltage difference, RMS) | 0–1, 2–3 |
RMS, frequency | float32 each |
| DC current (magnetic sensor) | 0–1 |
Current | float32 (project-defined unit) |
| AC current (magnetic sensor, RMS) | 0–1, 2–3 |
RMS, frequency | float32 each |
Industrial analog
| Measurement | Offsets | Fields | Decoding |
|---|---|---|---|
| 4–20 mA loop | 0–1 |
Loop quantity | float32 (project-defined unit) |
| Potentiometer | 0–1 |
Position / calibrated quantity | float32 (project-defined unit) |
Vibration
| Measurement | Offsets | Fields | Decoding |
|---|---|---|---|
| Analog 1-axis vibration | 0 |
LF RMS | int16, × 0.01 |
1 |
HF RMS | int16, × 0.01 |
|
2–4 |
LF sub-band ratios 0–2 | uint8 in register, ÷ 255 |
|
5–6 |
HF sub-band ratios 0–1 | uint8 in register, ÷ 255 |
Dry contact
| Measurement | Offsets | Fields | Decoding |
|---|---|---|---|
| Dry contact (synchronous) | 0 |
State | uint8 in register (0 open, 1 closed) |
| Asynchronous dry contact (Alarm mode) | 0 |
State | uint8 in register (0 open, 1 closed) |
Document Version: 1.2
Last Updated: 2026-06-02