← Communication
This document is focused on server-side usage:
- how to decode each field into business data,
- what units to expose in APIs and dashboards,
- how to handle keepalive vs measurement payloads,
- what to do with invalid or unsupported data.
- The manufacturer provides reference decoding examples (for example JavaScript) to accelerate integration on common LoRaWAN platforms.
Reference JavaScript decoder (ChirpStack / TTN)
harvestree_decoder.js — reference decoder for ChirpStack (v3/v4) and The Things Network. Copy it into your LoRaWAN application payload codec. MOIZ updates this file to match the latest decoding documentation.
Uplink structure
| Bytes |
Field |
Meaning |
Decoding |
0 |
command_id |
Metadata byte (do not use for business logic) |
uint8 |
1..4 |
port1..4 |
Port measurement type codes |
uint8 × 4 |
5..7 |
serial_number |
Device serial number |
24-bit little-endian |
8 |
boardTemperature |
Internal board temperature |
°C = byte - 40 |
9 |
baseTemperature |
Internal base temperature |
°C = byte - 40 |
10..12 |
Packed power + status |
Battery, thermogenerator, status |
bit-unpack (below) |
>=13 |
Port measurements |
Concatenated data for configured ports |
variable length |
Packed fields (bytes 10..12)
- Storage voltage (mV):
bytes[10] + ((bytes[11] & 0x03) << 8) + 3300
- Thermogenerator voltage (mV):
((bytes[11] >> 2) & 0x3F) + ((bytes[12] & 0x0F) << 6)
- Status nibble:
(bytes[12] >> 4) & 0x0F
Status interpretation
status & 0x03 == 0: keepalive (no measurement section expected)
status & 0x03 == 1: normal measurement payload
status & 0x03 == 2: alarm payload
- On alarm payloads, higher bits indicate alarm source flags (port/system)
Measurement keys for APIs and dashboards
Naming: <key>_<port> or <key>_<port>_<suffix>, with <port> in 1..4 (examples below use port 1).
Reserved port codes (0x11, 0x15, 0x17) are not used in production configurations.
Temperature
| Measurement |
JSON keys (port 1) |
Meaning |
Unit / type |
| PT1000 |
pt_1 |
RTD temperature |
°C (int16, scale 0.1) |
| Thermocouple type K |
tck_1_cjt, tck_1_hjt |
Cold / hot junction |
°C (int16, scale 0.1) each |
| Thermocouple type J |
tcj_1_cjt, tcj_1_hjt |
Cold / hot junction |
°C (int16, scale 0.1) each |
| Thermocouple type T |
tct_1_cjt, tct_1_hjt |
Cold / hot junction |
°C (int16, scale 0.1) each |
| Thermocouple type N |
tcn_1_cjt, tcn_1_hjt |
Cold / hot junction |
°C (int16, scale 0.1) each |
| Thermocouple type S |
tcs_1_cjt, tcs_1_hjt |
Cold / hot junction |
°C (int16, scale 0.1) each |
| Thermocouple type E |
tce_1_cjt, tce_1_hjt |
Cold / hot junction |
°C (int16, scale 0.1) each |
| Thermocouple type B |
tcb_1_cjt, tcb_1_hjt |
Cold / hot junction |
°C (int16, scale 0.1) each |
| Thermocouple type R |
tcr_1_cjt, tcr_1_hjt |
Cold / hot junction |
°C (int16, scale 0.1) each |
| Digital temperature probe (ref A) |
dtempA_1 |
Probe temperature |
°C (int16, scale 0.1) |
| Infrared (ref A) |
irA_1 |
Object temperature |
°C (int16, scale 0.1) |
Environmental
| Measurement |
JSON keys (port 1) |
Meaning |
Unit / type |
| Temperature and humidity |
weatherA_1_temp, weatherA_1_humidity, weatherA_1_frost |
Air temperature, humidity, frost index |
°C, %RH, frost byte |
Voltage
| Measurement |
JSON keys (port 1) |
Meaning |
Unit / type |
| DC voltage |
dcv_1 |
Single-ended DC |
mV (int16, scale 0.1) |
| AC voltage (RMS) |
acv_1, acv_1_hz |
RMS + fundamental frequency |
mV RMS, Hz (int16, scale 0.1) |
| DC differential voltage |
dcdv_1 |
Differential DC |
mV (int16, scale 0.1) |
| AC differential voltage (RMS) |
acdv_1, acdv_1_hz |
RMS + frequency |
mV RMS, Hz (int16, scale 0.1) |
| DC differential + external amplifier |
dcdvEx_1 |
Amplified differential DC |
float32 (project-defined unit) |
| AC differential + external amplifier (RMS) |
acdvEx_1, acdvEx_1_hz |
RMS + frequency |
float32, Hz |
Magnetic field
| Measurement |
JSON keys (port 1) |
Meaning |
Unit / type |
| DC magnetic sensor |
dcmh_1 |
DC magnetic quantity |
float32 (project-defined unit) |
| AC magnetic sensor (RMS) |
acmh_1, acmh_1_hz |
RMS + frequency |
float32, Hz |
Current
| Measurement |
JSON keys (port 1) |
Meaning |
Unit / type |
| DC current (voltage difference) |
dccs_1 |
DC current from ΔU sensing |
float32 (project-defined unit) |
| AC current (voltage difference, RMS) |
accs_1, accs_1_hz |
RMS + frequency |
float32, Hz |
| DC current (magnetic sensor) |
dcch_1 |
DC current from magnetic pickup |
float32 (project-defined unit) |
| AC current (magnetic sensor, RMS) |
acch_1, acch_1_hz |
RMS + frequency |
float32, Hz |
Industrial analog
| Measurement |
JSON keys (port 1) |
Meaning |
Unit / type |
| 4–20 mA loop |
fourtwenty_1 |
Loop quantity |
float32 (project-defined unit) |
| Potentiometer |
pot_1 |
Position / calibrated quantity |
float32 (project-defined unit) |
Vibration
| Measurement |
JSON keys (port 1) |
Meaning |
Unit / type |
| Analog 1-axis vibration |
vib_1_rms_lf, vib_1_rms_hf, vib_1_ratio_lf_0..2, vib_1_ratio_hf_0..1 |
LF/HF RMS + sub-band energy ratios |
RMS (int16, scale 0.01); ratios (uint8 / 255) |
| Measurement |
JSON keys (port 1) |
Meaning |
Unit / type |
| Dry contact (synchronous) |
dryc_1 |
Contact state |
uint8 (0 open, 1 closed) |
| Asynchronous dry contact (Alarm mode) |
async_dryc_1 |
Contact state on alarm check |
uint8 (0 open, 1 closed) |
Integration rules (backend)
- Use
serial_number (from payload) as a practical key for device identification and data organization in ingest pipelines.
- Persist raw payload and decoded JSON for traceability.
- For
int16 scaled values, apply scale before storing business metrics (0.1 step).
- For
float32 channels, unit is application-dependent; expose unit metadata from your device configuration context.
- If
status indicates keepalive, do not expect measurement keys.
- If payload length is inconsistent with configured port measurements, reject the frame and flag decoding error.
Dashboard recommendations
- Separate clearly:
- device health metrics (
storageVoltage, thermogenVoltage, internal temperatures),
- process metrics (port measurements),
- alarm state (
status + source flags).
Example decoded payloads
Keepalive frame
{
"serial_number": 23104,
"boardTemperature": 16,
"baseTemperature": 45,
"storageVoltage": 3600,
"thermogenVoltage": 52,
"status": 0
}
Measurement frame (PT1000 on port 1)
{
"serial_number": 23118,
"boardTemperature": 23,
"baseTemperature": 30,
"storageVoltage": 3600,
"thermogenVoltage": 49,
"status": 1,
"pt_1": 25.0
}