LoRaWAN Device Profiles and Payload Decoders
Device Profiles and Payload Decoders
A LoRaWAN device sends raw bytes, and without context those bytes mean nothing. A device profile supplies the context: a decoder that turns bytes into named values, the field definitions those values populate, and the display defaults that decide what shows on a dashboard. Every device in ioX-Pulse references exactly one profile.
Define it once per device model and every unit of that model inherits it. That is what makes bringing your own hardware a configuration job rather than an integration project, and it is why a sensor from a manufacturer we have never met can be reporting named, charted, alertable readings the same afternoon you unbox it.
- A JavaScript decoder written to the standard codec shape, run server-side on every uplink
- A test panel that runs your decoder against a pasted hex payload before any device depends on it
- Fields with types, units and rollup behavior, so charts and gauges know what they are looking at
- Formula fields for values the device never sends, computed from the ones it does
- Named downlink commands defined once and available on every device using the profile
- A manufacturer library to start from, so most devices need no JavaScript at all
Three things in one place
What a Device Profile Contains
A profile is the definition of a device model, and it holds three separate things that are easy to confuse.
1F 00 B4
The decoder
A function that receives the raw payload and returns named values. It runs on the server on every uplink, so nothing depends on the device or the network doing anything clever.
The fields
The named values themselves, each with a type, a unit, and a declared behavior over time. Fields are what rules, charts and dashboards bind to.
The display defaults
Which field is primary and which is secondary, so a device list or a widget shows the reading that matters without being configured device by device.
A profile can also carry named downlink commands and a dashboard layout, both covered further down.
Devices reference the profile rather than copying it, so editing the profile changes every device using it.
Trusted by teams monitoring critical infrastructure
One function, run on every uplink
Writing the Decoder
The decoder is a single JavaScript function written to the standard LoRaWAN codec shape, the same one manufacturers publish alongside their hardware. If your vendor supplies a decoder, it will usually run here with no changes at all.
function decodeUplink(input) {
// input.bytes -> number[] of payload bytes
// input.fPort -> the LoRaWAN port the device used
// input.recvTime -> a Date object, when the message arrived
return {
data: {
temperature: input.bytes[0] - 40,
battery_percent: input.bytes[1],
},
warnings: [], // optional, surfaced in the device's Events tab
errors: [], // optional, marks the uplink as decode-failed
};
}
Keys must match your fields
The keys you return under data must match the identifiers of your fields. Anything else you return is ignored.
Extras still show in the test panel
Ignored keys are still visible while testing, which is useful when you are working out a payload format from a datasheet.
Before a single device depends on it, test it against a real payload:
- 1Paste a hex payload and the port into the test panel.
- 2Run it.
- 3Read the decoded object and any warnings or errors it produced.
Four types, three behaviors
Fields: What Your Devices Produce
A field is a named value with a type. The type decides what can be stored and how it is validated; a second setting decides how the value behaves over time, which is what lets a chart roll it up correctly without you thinking about it.
Optional unit and decimal places, plus min and max — used for validation and to scale gauge widgets correctly.
26.0 °CText values.
"door_open"True or false states.
trueA calendar date such as an install or service date. Always set manually rather than decoded, and usable in formulas as whole days.
2026-03-14How the value accumulates
For Number fields you also declare how the value accumulates, which decides what a chart does with it.
Gauge RIGHT FOR ALMOST EVERY SENSOR
A current reading. Charts average it within each bucket.
Counter
A value that only increases, such as total flow or lifetime distance. Charts difference it across buckets to show the change rather than the total.
Absolute
A value that is replaced rather than accumulated.
From a distance reading to a fill level
A Worked Example: Tank Depth to Percent Full
An ultrasonic sensor in the lid of a tank does not report how full the tank is. It reports how far away the liquid is. Turning one into the other needs a number the device does not know and cannot send: how far the sensor sits above the bottom.
-
1
The decoder produces
distance_mmStraight from the payload — the gap between the sensor and the surface of the liquid.
-
2
Add a static field,
mount_height_mmA static field has a default value and no source path, so it is part of the profile rather than something the device reports. Set the default to the mounting height you use most; any individual tank that differs can override it on its own device.
-
3
Add a formula field,
fill_percentComputed from the two:
fill_percentround(max(0, min(100, ((mount_height_mm - distance_mm) / mount_height_mm) * 100 ))) -
4
Set
fill_percentas the primary display fieldSo every tank on this profile shows a percentage in the device list and on its dashboard rather than a distance in millimeters.
Nothing about that is per device
Register the next two hundred tanks against the same profile and they arrive knowing what to compute, what to call it, and what to show. The only per-device step is the handful whose sensor sits at a different height.
Why the min and max are there
A sensor reading a splash, or an empty tank, can produce a distance outside the expected range. Without clamping you get a fill level above 100 or below zero on a customer's dashboard.
Formula fields support abs, min, max, round, floor, ceil, sqrt and pow, along with the usual arithmetic operators.
Bring a payload you already have
Try It With Your Own Payload
The fastest way to know whether this works for your hardware is to run one of your own uplinks through the decoder test panel.
Try It With Your Own Payload
A free trial takes a card but does not charge it. Paste a real hex payload from your own sensor into the decoder test panel and see it resolve into named fields before you commit to anything.
Start Your Free TrialNot every value arrives every time
Values That Do Not Arrive on Every Uplink
Plenty of devices report a state only when it changes. A valve sends open, then says nothing for a week. Handled naively, a dashboard looking at the last hour shows no data, and an operator concludes the device is dead.
Retain last value
Turn it on for the field and it keeps showing the last reported state rather than emptying out when the last change scrolls out of the window.
A declared battery source
Mark one field as the profile's battery source and battery level is understood as such across the platform, rather than being just another number that happens to be called battery.
Commands that write back
A downlink command can write its own result into a field when the device acknowledges it, so the state you commanded and the state you display cannot drift apart.
Per device, not per profile
Correcting a Sensor That Reads High
Real sensors drift. That is a property of the individual unit, not of the model — which is why correction sits on the device rather than on the profile.
A thermometer reads half a degree high against a reference.
A flow meter under-reports by two percent.
A humidity probe has aged past its accuracy window.
The decoder, the fields, the units and the display defaults — everything true of every unit of that model.
- Edit it once, every device follows
- Nothing here is unit-specific
Calibration is a scale and an offset on one field of one device — because the drift belongs to that unit.
- No change to the decoder, the profile, or the device itself
- The other four hundred devices on that profile are untouched
A scale and an offset, on one field
The value everyone sees matches reality without touching the decoder, the profile, or the device itself. Correcting one thermometer does not change the other four hundred devices that share its profile.
The other direction
Sending Commands Back to the Device
A decoder turns bytes from the device into fields. A downlink goes the other way: a command sent to the device. Define it once on the profile as a named template and it is available on every device using that profile.
Uplink — the decoder
Bytes from the device become named fields.
Downlink — the encoder
An operator's inputs become the bytes the device expects.
What a command template holds
Five parts, defined once on the profile.
A stable key
Identifies the command and cannot be changed after creation, so anything referencing it keeps working. Choose it deliberately.
A display name
What an operator sees when picking a command, rather than the key.
An encoder
A function that turns the inputs an operator supplies into the bytes the device expects.
Require device ACK CONFIRMED FRAME
Sends the command as a confirmed frame, so the device has to acknowledge it on its next uplink rather than the command being assumed delivered.
On ACK, set field NO DRIFT
Writes a value into a field once the device confirms. The displayed state follows what the device actually did, not what was requested.
Start from something tested
The Manufacturer Profile Library
Most devices need no JavaScript at all. The library covers common sensors from major manufacturers, and starting from an entry gives you a working profile without writing a line of code.
Filter by region, by manufacturer, or by searching across device name, manufacturer, firmware and LoRaWAN version. Each entry shows what it includes, which depending on the device can be the decoder, the field set, named downlink commands and a prebuilt dashboard.
Pick one, name your copy, and you have a profile you own and can edit.
Your copy is yours
Editing it never reaches back into the library.
No silent changes
The library updating never silently changes a profile your devices depend on.
Need a variant? Clone
If you already have a profile that works, clone that instead and start from something you have already proven in the field.
The honest version
Writing Decoders Yourself Against Starting From the Library
Plenty of teams already decode payloads somewhere — in a Lambda, a middleware layer, or a script somebody wrote and left. Here is the same work, done both ways.
| The job | Your own decoding layer | With device profiles |
|---|---|---|
| A new sensor model | Read the datasheet, write it, deploy it | Start from a library entry, or paste the vendor's decoder in |
| Testing before it goes live | A test harness you built and maintain | Paste a hex payload into the panel and run it |
| A value the device does not send | Compute it downstream, in another system | A formula field on the profile |
| Charting a counter correctly | Remember which values are counters, everywhere | Declare it once on the field |
| A sensor that reads high | A special case in your code, forever | Calibrate that one device |
| Sending a command | A second integration, in the other direction | A named template on the same profile |
| Adding four hundred of the same device | Nothing, if it already works | Nothing, because they reference the profileA DRAW |
Common Questions About LoRaWAN Payload Decoders
If your question is not here, email sales@iox-connect.com and you will get a straight answer
It is a small function that turns the raw bytes a LoRaWAN device transmits into named values such as temperature or battery level. In ioX-Pulse the decoder is JavaScript written to the standard codec shape, it lives on the device profile, and it runs on the server on every uplink, so the device and the network do not need to know anything about it.
A device profile is the definition of a device model: the decoder, the fields those decoded values populate, the display defaults, and optionally named downlink commands and a dashboard layout. Every device references exactly one profile, and editing the profile changes every device using it.
Usually yes, unchanged. Manufacturer decoders are written to the same standard codec shape, so they generally run as they are. Paste it in and test it against a real payload before assigning devices to the profile.
Yes, and that is the point of this page. Any LoRaWAN device can be described by a profile. Start from the manufacturer library if your device is in it, paste the vendor's decoder if it is not, or write your own against the signature above.
With a formula field, computed from other fields on the profile, including static ones that describe the installation rather than the reading. A depth sensor plus a mounting height gives you a fill percentage; the device never has to know how tall the tank is.
Values you return that do not match a field identifier are ignored, and you can return warnings or errors explicitly. Warnings appear in the device's Events tab, and errors mark the uplink as failed to decode, so a bad payload is visible rather than silently producing a wrong reading.
Your sensor, decoded this week
Ready to Bring Your Own Hardware?
Start a free trial and decode a real payload from your own device, or send us the model and the datasheet and we will tell you whether it is already in the library.



