New: the AI firewall watches every module and explains each incident in plain words. See how it works

Write your own codec

Copy a library codec or write a new table codec, check it against test vectors, publish it, and manage its revisions.

When the library has no codec for your sensor, or you want different output from a library codec, you write your own. Your codecs are tables in JSON, not scripts: Hermetry never runs code from a codec. You publish them in your organisation, and your devices and profiles can use them like library codecs.

Writing codecs needs the permission to add, change and delete your own LoRaWAN codecs (administrators by default). Every publish and delete is audited.

Two ways to start

Save a copy of a library codec

Best when a library codec is close to what you need.

  1. Open Devices > ⋯ > LoRaWAN codecs and open the library codec.
  2. Select Save a copy.
  3. The editor opens with the library table, the id t.<library id> (change it if you like), origin tenant and a source line naming the copied codec and revision.
  4. Change the table, select Check, then Publish.

Start a new codec

  1. In the codecs drawer select New codec.
  2. Enter the Id and paste or write the table under Codec table (JSON). The editor offers an outline to start from.
  3. Select Check, then Publish.

Ids

Your codec ids start with t., followed by 2 to 62 lower-case letters, digits or dashes, for example t.cold-room-probe. The id never changes later. An id already used in your organisation is refused: a codec with this id exists. Choose another id.

The codec table

A codec is a JSON document. Its main fields:

FieldRequiredMeaning
idYesThe codec id (t.…)
titleYesA readable name, up to 160 characters
vendorYesThe device maker, up to 64 characters
modelsNoModel names this codec covers (up to 64)
fportsNoFPorts it decodes (1–255, up to 64). Leave out for every port.
ouiNoMaker codes: the first 6 hexadecimal digits of the DevEUI, upper case (up to 32). Used by the automatic choice.
kindNolayout (fields at fixed byte positions) or tlv (channel, type, data records)
framesFor layoutHow to tell frames apart (by fport, length, min_length, a marker byte or masked bits) and the fields of each
channels, types, attributes, defaultFor tlvThe record definitions
testsYes, at least oneTest vectors: fport, hex, and the expected values (up to 200)

A field in a layout frame has at (byte offset), field (output key), fmt (the byte format), and optionally scale, digits, offset, unit and enum. Formats include u8, i8, u16be, u16le, i16be, i16le, u24be, u24le, u32be, u32le, i32be, i32le, f32be, f32le, hex, ascii and bit splits of a byte.

Unknown top-level fields are refused. JavaScript decoders are not accepted: this is a JavaScript decoder. Only the table format is accepted.

Example

A sensor that sends, on FPort 2, battery in mV (2 bytes), temperature in tenths of °C (2 bytes, signed) and humidity in % (1 byte):

{
  "id": "t.room-sensor",
  "title": "Room sensor, temperature and humidity",
  "vendor": "Example maker",
  "models": ["RS-1"],
  "fports": [2],
  "kind": "layout",
  "frames": [
    {
      "fport": 2,
      "min_length": 5,
      "fields": [
        { "at": 0, "field": "battery", "fmt": "u16be", "unit": "mV" },
        { "at": 2, "field": "temperature", "fmt": "i16be", "scale": 0.1, "unit": "°C" },
        { "at": 4, "field": "humidity", "fmt": "u8", "unit": "%" }
      ]
    }
  ],
  "tests": [
    { "name": "normal reading", "fport": 2, "hex": "0BC4010A32",
      "expect": { "battery": 3012, "temperature": 26.6, "humidity": 50 } }
  ]
}

Scaled values are rounded to 2 decimals unless the field sets digits.

Check and publish

Check runs every test vector and shows each as Passes or Fails, with What differs. When all pass: Every test vector passes. Publishing makes it available to your devices and routers.

Publish runs the same checks again and refuses the codec with Not published: and the reason:

Reason shownMeaning
the text is not valid JSON.Fix the JSON syntax.
a field is missing or not allowed (…).A required field is missing or an unknown field is present.
the id must be t. followed by lower-case letters, digits and dashes.Fix the id.
the codec is larger than 40960 bytes.Your codecs are limited to 40 KB.
the tables are not in the expected format (…).A frame or field definition is wrong.
a codec needs at least one test vector.Add a test vector.
some test vectors fail (see below).Fix the table or the expected values.
a published version decoded keys this one no longer does (…). Publish it under a new id instead.See revisions below.
another of your codecs already covers models.Two of your codecs cannot claim the same model.

Tables nest at most 32 levels deep.

Revisions

Every publish of an existing codec creates a new revision. To protect your flows and dashboards, a new revision may add keys but never remove or rename one, and never change a key’s unit. If you need to drop or rename keys, publish under a new id and move your devices to it.

Revisions on the codec’s page lists every revision with its size and number of keys.

Your codec and the library

Your codecs are tried before the library’s in the automatic choice. A copy keeps the library codec’s maker codes and FPorts, so devices of that maker on Automatic move to your copy as soon as you publish it. One of your codecs may claim the same model as a library codec; that is how you override the library for your devices.

Delete a codec

Open your codec and select Delete. The codec leaves your list; devices and profiles that chose it decode with the automatic choice from then on. Its revisions are kept, and the id never changes meaning: if you create the same id again, it must follow the revision rule against the deleted codec’s last revision.