Skip to content

Machinechat JEDI's Flexible Data Decoding with JavaScript Codecs

Extend JEDI's data handling capabilities to work with your unique data formats using custom JavaScript decoders. This feature provides maximum flexibility, enabling JEDI to adapt to incoming data from diverse sources like HTTP, MQTT, and more.

Note

This features is available in Machinechat JEDI v3.8.5 or newer.

How it Works

graph TD
    subgraph "Data Collector"
    DataReceived("Data Received by Collector") --> NameExtraction("Extract Codec Name")
    end

    subgraph "JEDI Core"
    NameExtraction --> CodecLookup("Lookup codec.js in Codecs Folder")
    CodecLookup -- Yes --> JSExecution("Execute decode() function")
    CodecLookup -- No --> ErrorReturn("Return Error to Collector")
    JSExecution --> MetricFormatting("Format Metrics as JSON")
    MetricFormatting --> JEDIMetrics("Send to JEDI Metrics Processing")
    JEDIMetrics --> CollectorResponse("Return Response to Collector")
    end
  1. Configuration: When setting up a data collector (e.g., configuring an HTTP endpoint, an MQTT topic, or a serial port) that support custom decoding, you'll have the option to enable JavaScript-based decoding.

  2. Codec Selection JEDI uses a data-collector-specific mechanism to identify the correct JavaScript codec file. This might involve:

    • HTTP: Use route /v1/javascript/{codec-name}
    • MQTT: (Coming soon) Component of the MQTT topic structure
  3. Execution: JEDI loads the associated JavaScript file and calls the decode(context, input) function within it.

    • context: An object with additional information about the received data (collector-specific)
    • input: The raw payload received by the data collector.
  4. Decoding: Within the decode function, your JavaScript code does the following:

    • Reads the input
    • Extracts the nodeID of your data source
    • Parses and prepares your metric values, including types and optional units.
  5. Return JSON: Format the decoded information into the required JSON structure:

{
    "nodeID": {extracted nodeID},
    "metrics": { 
        "metric_name_1": { "value": ..., "stype": ..., "ptype": ..., "units": ..., "precision": ...},
        "metric_name_2": {... },
        ... // Additional metrics
    }
}

The Metric Object

The "metrics" key in the decoded JSON response is a map that contains individual metric objects. Each metric object serves as a structured representation of a single data point you're sending to JEDI. Here's a detailed look at the properties within a metric object:

  • value (required): This is the core measurement or data point you're sending. The data type can be a number (representing integers or floating-point values), a string, or a boolean (true or false).

  • stype (optional): This stands for "semantic type" and is a user-defined string that provides additional context or meaning to your metric. It helps categorize and organize your data within JEDI for better analysis. For instance, you could define a semantic type of "room_temperature" for a temperature sensor reading.

  • ptype (required): This represents the primitive data type of the value property. Supported values are:

    • "float64": For double-precision floating-point numbers (e.g., sensor readings, percentages).
    • "string": For text data (e.g., descriptive labels, IDs).
    • "boolean": For true/false values (e.g., device on/off status).
  • units (optional): A string specifying the measurement units associated with the value. This helps in interpreting the data correctly (e.g., "°C" for temperature, "%" for humidity).

  • precision (optional): An integer specifying the number of decimal places to display when presenting the value. This provides control over the level of detail shown for floating-point numbers.

Example Metric Object

Here's an example of a metric object representing a temperature reading:

"temperature": {
    "value": 25.4,
    "ptype": "float64",
    "units": "Celsius",
    "precision": 1  // Display one decimal place
}

By providing these properties within your metric objects, you ensure JEDI can correctly interpret, store, and visualize your custom data from various sources.

Decoding Across Data Collectors

While the mechanism for selecting the JavaScript codec will vary between data collectors, the core decoding logic within the decode function remains consistent.

Example (generic-sensor.js)

function decode(context, input) {
    // Your decoding logic here, potentially adapting based on 'context'

    return {
        "nodeID": /* Extract Node ID */,  
        "metrics": {
           // Define your metrics as before        
        }
    };
}

Example: Custom Data Decoding with HTTP Data Collector

  1. Route: When an HTTP request arrives at /v1/javascript/{codec-name}, JEDI searches for a file named {codec-name}.js within "codecs" folder, located inside JEDI's installation folder.

  2. Execution: Your decode(context, input) function within the codec file is called.

    • context: An object with additional request information (currently unused).
    • input: The raw payload of your HTTP request.
  3. Decoding: Implement your logic within the decode function to:

    • Read the input
    • Extract the nodeID of your data source
    • Parse and organize your metric values, including types and optional units.
  4. Return JSON: Format the decoded information into the required JSON structure:

    {
        "nodeID": {extracted nodeID},
        "metrics": { 
            "metric_name_1": { "value": ..., "stype": ..., "ptype": ..., "units": ..., "precision": ...},
            "metric_name_2": {... },
            ... // Additional metrics
        }
    }
    

Simple Example (simple-sensor.js)

Let's assume your sensor sends a JSON payload like this:

{
    "deviceId": 12345,
    "temperature": 25.4,
    "humidity": 68,
    "pressure": 1013
}

Your simple-sensor.js decoder could look like this:

function decode(context, input) {
    const payload = JSON.parse(input);

    return {
        "nodeID": payload.deviceId.toString(),  // Convert deviceId to string
        "metrics": {
            "temperature": { "value": payload.temperature, "ptype": "float64", "units": "Celsius" }, 
            "humidity": { "value": payload.humidity, "ptype": "float64", "units": "%" },
            "pressure": { "value": payload.pressure, "ptype": "float64", "units": "hPa" }
        }
    };
}

Note

Error Handling: Include error checking and exception handling within your JavaScript codec to ensure robust data processing.

Need help? Contact our support team: support@machinechat.io