The present specification defines "SenML Features", each identified by a "feature name" (a text string) and a "feature code" (an unsigned integer less than 53).
The specific version of a SenML pack is composed of a set of features. The SenML version number (
bver field) is then a bitmap of these features represented as an unsigned integer, specifically the sum of, for each feature present, two taken to the power of the feature code of that feature (
Figure 1).
__ 52 fc
version = \ present(fc) ⋅ 2
/__ fc = 0
where present(fc) is 1 if the feature with the feature code
fc is present, 0 otherwise. (The expression 2
fc can be implemented as
1 << fc in C and related languages.)
Representing features as a bitmap within a number is quite efficient as long as feature codes are sparingly allocated (see also
Section 6).
Compatibility with the existing SenML version number, 10 decimal (0b1010), requires reserving four of the least significant bit positions for the base version as described in
Section 3. There is an upper limit to the range of the integer numbers that can be represented in all SenML representations: practical JSON limits this to 2
53-1 [
RFC 7493]. This means the feature codes 4 to 52 are available, one of which is taken by the feature defined in
Section 4, leaving 48 for allocation. (The current version 10 (with all other feature codes unset) can be visualized as
0b00000000000000000000000000000000000000000000000001010.) For a lifetime of this scheme of several decades, approximately two feature codes per year or fewer should be allocated. Note that less generally applicable features can always be communicated via fields labeled with names that end with the "_" character ("must-understand fields"). See
Section 4.4 of
RFC 8428 for details.
Most representations visible to engineers working with SenML will use decimal numbers. For instance, 26 (0b11010, 0x1a) denotes a version that adds the "Secondary Units" feature (
Section 4). This is slightly unwieldy but will be quickly memorized in practice.
As a general observation, ending up over time with dozens of individually selectable optional extensions may lead to too many variants of what is supported by different implementations, reducing interoperability. So, in practice, it is still desirable to batch up extensions that are expected to be supported together into a single feature bit, leading to a sort of hybrid between completely independent extensions and a linear version scheme. This is also another reason why a space of 48 remaining feature codes should suffice for a while.
The last paragraph of
Section 4.4 of
RFC 8428 may be read to give the impression that SenML version numbers are totally ordered, i.e., that an implementation that understands version n also always understands all versions k < n. If this ever was true for SenML versions before 10, it certainly is no longer true with this specification.
Any SenML pack that sets feature bits beyond the first four will lead to a version number that actually is greater than 10, so the requirement in
Section 4.4 of
RFC 8428 will prevent false interoperability with version 10 implementations.
Implementations that do implement feature bits beyond the first four, i.e., versions greater than 10, will instead need to perform a bitwise comparison of the feature bitmap as described in this specification and ensure that all features indicated are understood before using the pack. For example, an implementation that implements basic SenML (version number 10) plus only a future feature code 5 will accept version number 42, but it would not be able to work with a pack indicating version number 26 (base specification plus feature code 4). (If the implementation
requires feature code 5 without being backwards compatible, it will accept 42, but not 10.)