A Modbus register is sixteen bits and nothing else. What those bits mean lives in a document somebody emailed you.
A LonWorks network variable carries its own type. Two devices that agree on the type exchange a temperature without anyone deciding whether it’s tenths of a degree. That difference is the reason the protocol exists, and it’s also the reason commissioning a LonWorks network feels nothing like commissioning a Modbus one.
Here’s how the mechanism actually works in ISO/IEC 14908-1, and where the standard stops and LonMark takes over.
Table of Contents
It’s a message with the top bit set
Network variables aren’t a separate protocol. They’re a special case of application message.
Every APDU starts with a single header byte the standard calls destin_type:
| Pattern | Meaning |
|---|---|
00xxxxxx | Generic application message — 64 codes |
1dxxxxxx | Network variable — d is direction, 1 outgoing, 0 incoming |
011xxxxx | Network management — 32 codes |
0101xxxx | Diagnostic — 16 codes |
0100xxxx | Foreign frame — 16 codes |
When the top bit is 1, a second header byte follows. The six remaining bits of the first byte combine with that second byte to form a 14-bit network variable selector.
That selector is the whole addressing mechanism for network variable data. Not a register number, not a device address — a 14-bit value that two variables share when they’re connected.
Byte order, since you’ll need it for captures: first byte received is leftmost, 2- and 4-byte quantities are big-endian, leftmost bit in a byte is most significant, arrays run lowest element first.
Every compliant device must accept at least 16 bytes of data plus the destin_type. That’s the floor, not a typical size.
What a connection is
A connection exists when three things line up:
- An output variable on the sender has a selector value
- An input variable on one or more receivers has the same selector value
- The output is bound to those receivers through an address table entry
Both halves are required. Matching selectors with no address table entry means nothing propagates. An address table entry with mismatched selectors means the update arrives and gets discarded.
That’s the shape of most binding faults. When a value isn’t moving, you’re looking for which of the two halves is missing.
Turnaround connections. An output can be bound to an input on the same device. The standard calls this a turnaround connection, and it still counts as one even when the output also goes out to other devices across the network.
What happens on an update
The send side, in order:
- Application writes the output variable
- Application layer checks for an address table entry — if there’s no reader, nothing is sent at all
- If there is, it builds a packet with the selector and the value, hands it down
- It then checks for aliases, builds a packet per alias selector carrying the primary’s value, and sends each of those too
Step 2 is worth sitting with. An unbound output variable generates no traffic whatsoever. A device can look completely silent on a capture and be working perfectly — it just has nothing bound.
The receive side:
- Compare the incoming selector against local selectors
- No match → discard, silently
- Match on a primary → update that variable
- Match on an alias → update the primary the alias points to
Propagation properties
Polled. Doesn’t propagate on its own at all. It moves only when a requester sends a request/response message carrying the selector. This uses the session layer’s request/response service underneath — which means everything about the idempotent rule and request/response timers applies.
Synchronous. For a non-polled output, synchronous means every value the application writes gets propagated. Non-synchronous means intermediate values may be skipped, and how that’s decided is left to the implementation. If you need every transition on the wire, you need synchronous.
When it propagates is the application’s call, not the protocol’s. It might send on every write, or only on change. The standard imposes one requirement: for a multi-byte variable, the application must ensure the propagated data is self-consistent. Don’t ship half an old value and half a new one.
Service and priority are configured per connection. Acknowledged, unacknowledged, unacknowledged-repeated, priority, authenticated — all set when the variable is bound, not fixed by the variable itself.
Aliases
An alias inherits length, direction, and type from its primary. It always carries a different selector, and it may have a different destination address.
The point is to let one variable answer to several selectors. Without them, a device with many connections can hit selector conflicts — the same selector value needed for two different variables on the same device. Aliases route around that.
The practical consequence: an alias update writes the primary’s value. There is no separate storage. If you’re tracing a value that changes without an obvious source, check whether an alias is bound to something you weren’t looking at.
The poll that returns nothing
A device in the offline state sends no network variable messages. One exception: poll it and it responds with the correct selector and no data.
Now the trap. That exact response — selector, no data — is also what you get when:
- The device has no matching selector at all
- An authenticated poll failed
Three different faults, one identical response. A missing variable, an offline device, and a failed authentication are indistinguishable at the wire level. If you’re debugging a poll that returns empty, you have to rule out all three separately.
For comparison, when a request to an offline device is a plain application message rather than a network variable poll, the response sets destin_type to 63. A foreign frame gets 79. Only the network variable case is ambiguous.
Error notification
The application always has the status of its last transaction available.
For acknowledged updates: success is all expected acknowledgements received. Failure is one or more missing.
For unacknowledged updates: the standard defines no failure events. Implementations may post failures from internal errors on the transmitting device, but nothing about delivery.
For polled variables, which always use request/response: success is all targets returning values. A failure event is posted when either
- no responding target had valid data — no matching variable, or offline — or
- one or more expected responses never arrived. For aliases, this rule applies to the primary and its aliases collectively.
One exception, and it’s obscure enough to be worth memorising. A polled variable that has a turnaround connection and is also connected to variables on other devices will post a failure event if all the other devices return offline responses — even though the local turnaround connection answered its own poll successfully.
So a device can respond to itself correctly and still report failure. If you’ve ever seen a device flag a poll failure on a variable you can watch updating locally, that’s the mechanism.
Where the standard stops
ISO/IEC 14908-1 defines the mechanism: selectors, connections, aliases, propagation, error handling.
It also defines SNVT as a term — standard network variable types are variables with agreed-upon semantics, interpreted the same way by every application, and the standard names them as the basis for interoperability. There’s protocol machinery to match. A network variable info query can return NV_INFO_SNVT_INDEX, and the response carries a snvt_type_index — encoded as zero when the variable isn’t a SNVT at all. Devices also carry an SNVT table area with descriptor records and extension records as part of self-documentation.
What the standard explicitly puts out of scope is the definition of specific SNVTs. It says so in as many words. The protocol knows a variable has a type index; it does not say what index 17 means.
That type library, along with configuration property types (SCPTs and UCPTs) and functional profiles, comes from LonMark. None of those three terms appears anywhere in the four ISO parts.
The distinction matters when you’re reading a spec. “Complies with ISO/IEC 14908-1” says the device speaks the protocol and can report a type index. It says nothing about whether that index maps to a type another vendor’s device will interpret the same way. Data-level interoperability is a LonMark claim, and it’s the one worth checking.
FAQ
What’s a network variable selector? A 14-bit value formed from six bits of the APDU header byte plus a second byte. Two variables are connected when they share a selector and an address table entry binds them.
Why isn’t my bound variable updating? Check both halves of the connection. Matching selectors with no address table entry sends nothing. An address table entry with mismatched selectors delivers an update that gets discarded on arrival.
Why does my poll return no data? Three possible causes, indistinguishable on the wire: the device is offline, it has no matching selector, or an authenticated poll failed.
What’s the difference between a network variable and an explicit message? A network variable carries a typed value to a selector. An explicit message carries arbitrary application data and is what you use for events, file transfer, parameter blocks, or tunnelling another protocol.
Are SNVTs part of ISO/IEC 14908? Partly. The standard defines what a SNVT is and carries a type index for it in network variable info queries. It explicitly leaves the definition of specific SNVTs out of scope. SCPTs, UCPTs and functional profiles aren’t mentioned in the standard at all — those come from LonMark.
Can an output be connected to an input on the same device? Yes — a turnaround connection. It stays a turnaround connection even if the output also goes to other devices.
Does an unbound output generate traffic? No. The application layer checks for an address table entry first and sends nothing if there isn’t one.
