> For the complete documentation index, see [llms.txt](https://adatrack.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://adatrack.gitbook.io/docs/documentation/core-concepts/telemetry-decoders.md).

# Telemetry & Decoders

One of AdaTrack's most powerful features is its ability to decode proprietary binary payloads without requiring any changes to the platform's core code. This is achieved through **Dynamic Decoders**.

### What is a Decoder?

A decoder is a small JavaScript function that AdaTrack executes whenever a new UDP packet arrives. Its job is to take a raw array of bytes and transform it into a structured JSON object that AdaTrack can store, visualize, and use for alerting.

### The Decoder Environment

AdaTrack uses the **Goja VM** (a high-performance, pure Go JavaScript engine) to execute your code. The environment is sandboxed for security:

* **No Network Access:** You cannot make HTTP requests.
* **No File System Access:** You cannot read or write files.
* **Limited Standard Library:** Basic JavaScript objects (Math, Date, Array) are available.

### Writing your first Decoder

The decoder must be a function named `Decoder` that accepts two arguments:

1. **`bytes`:** An array of integers representing the raw binary payload.
2. **`port`:** The UDP port on which the packet was received (useful if your device sends different formats on different ports).

#### Example: Simple 4-byte Lat/Lon Decoder

```javascript
function Decoder(bytes, port) {
    // Latitude: 4 bytes, signed, Big Endian, scaled 1,000,000
    var latRaw = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
    var latitude = latRaw / 1000000.0;

    // Longitude: 4 bytes, signed, Big Endian, scaled 1,000,000
    var lonRaw = (bytes[4] << 24) | (bytes[5] << 16) | (bytes[6] << 8) | bytes[7];
    var longitude = lonRaw / 1000000.0;

    return {
        latitude: latitude,
        longitude: longitude,
        battery: bytes[8] // 1 byte battery percent
    };
}
```

### Advanced Bit Manipulation

Since IoT payloads are often highly compressed, you may need to perform bitwise operations. JavaScript's bitwise operators (e.g., `<<`, `|`, `&`) operate on 32-bit signed integers, which makes them ideal for parsing signed binary data.

#### Handling 16-bit Signed Integers (Shorts)

```javascript
// Example: Temperature in centidegrees (2 bytes, Big Endian)
var tempRaw = (bytes[0] << 8) | bytes[1];
if (tempRaw & 0x8000) {
    tempRaw = tempRaw - 0x10000; // Handle negative numbers
}
var temperature = tempRaw / 100.0;
```

### Standard Output Fields

While you can return any JSON object, AdaTrack looks for specific keys to enable certain features:

| Key         | Type     | Purpose                                             |
| ----------- | -------- | --------------------------------------------------- |
| `latitude`  | `number` | Enables real-time map visualization and geofencing. |
| `longitude` | `number` | Enables real-time map visualization and geofencing. |
| `speed`     | `number` | Used for historical path analysis and speed alerts. |
| `battery`   | `number` | Used for battery health monitoring and alerts.      |
| `rssi`      | `number` | Signal strength indicator (dBm).                    |

### Built-in JSON Passthrough

If your payload is already JSON, or the platform decodes the protocol itself (Codec8, Queclink), set the profile's **Decoder type** to **Built-in JSON passthrough** instead of writing a script. No JavaScript runs for these profiles. Choose **JavaScript** whenever you need custom parsing of a binary payload.

### Testing & Debugging

You can test your decoders directly in the **Device Profiles** dashboard:

1. Enter your JavaScript code.
2. Provide a sample payload in Hexadecimal (e.g., `01 02 03 04`).
3. Click **Run Test**.
4. View the resulting JSON object or any error messages generated during execution.

### Error Handling

If your decoder returns `null`, the packet will be ignored, and no data will be stored. It is good practice to validate the length of the `bytes` array before processing it:

```javascript
if (bytes.length < 10) {
    return null; // Not enough data for a valid packet
}
```
