arrow-left

Only this pageAll pages
gitbookPowered by GitBook
1 of 7

Guides

Loading...

Integrations

Loading...

Loading...

Functions & Data Processing

Loading...

Loading...

How to Use JavaScript for Custom Rule Conditions in Qubitro

By following this guide, you can customize Qubitro rule functions using JavaScript to create dynamic conditions.

This guide explains how to use JavaScript within Qubitro’s rule functions to define custom conditions and automate actions based on real-time data.

A few notes to remember:

circle-info

Rule Functions operate only on real-time data – They cannot query historical data from the database.

circle-info

Each Rule Function executes a single pre-configured action – It does not support executing multiple actions within one function.

circle-info

Actions are predefined during function setup – The trigger() function executes only the action assigned when creating the rule.


Although the examples here focus on environmental monitoring and geofencing, the same approach applies to any scenario requiring event-driven automation.

hashtag
Accessing Data with Predefined Keys

Qubitro provides a simple way to access sensor values in JavaScript using predefined keys. These keys allow you to reference the latest device data without complex parsing.

hashtag
Syntax and Usage

Define variables using predefined keys:

Each variable directly pulls the corresponding real-time value from the incoming data.

hashtag
Writing Rule Conditions

With variables defined, you can create logical conditions to decide when the function should trigger an action.

hashtag
Example: Trigger an Action Based on Temperature and Humidity

This function triggers an action if the temperature is above 25°C and humidity exceeds 70%.

hashtag
Utilizing the trigger() Function

The trigger() function is used to execute predefined action when conditions are met.

hashtag
Example: Alert When Temperature and Humidity Are Too High

hashtag
Practical Implementations

hashtag
Example 1: Geofencing a Restricted Area

This example ensures that a device does not enter a restricted assembly area. If it does, the function triggers an alert.

hashtag
Example 2: Advanced Environmental Monitoring

function run(){
    let temperature = ${{TEMPERATURE}};
    let humidity = ${{HUMIDITY}};
    let light = ${{LIGHT}};
    let motion = ${{MOTION}};
    let voltage = ${{VDD}};
}
function run() {
    let temperature = ${{TEMPERATURE}};
    let humidity = ${{HUMIDITY}};

    if (temperature > 25 && humidity > 70) {
        trigger(); // Executes the pre-configured action
    }
}
function run() {
    let temperature = ${{TEMPERATURE}};
    let humidity = ${{HUMIDITY}};

    if (temperature > 30 && humidity > 80) {
        trigger(); // This executes the pre-configured action (e.g., send a notification)
    }
}
function run() {
    let coordinates = ${{coordinates}}; // Assuming format [latitude, longitude]

    // Convert coordinates array to an object
    let incomingLocation = {
        lat: coordinates[0],
        lon: coordinates[1]
    };

    // Define the restricted zone (assembly area)
    const restrictedZone = {
        A: { lat: 40.822608, lon: 29.352864 },
        B: { lat: 40.822652, lon: 29.353246 },
        C: { lat: 40.822289, lon: 29.352890 },
        D: { lat: 40.822327, lon: 29.353346 }
    };

    // Check if the incoming coordinates fall within the restricted area
    const isInsideRectangle = (point, rect) => {
        const minLat = Math.min(rect.A.lat, rect.B.lat, rect.C.lat, rect.D.lat);
        const maxLat = Math.max(rect.A.lat, rect.B.lat, rect.C.lat, rect.D.lat);
        const minLon = Math.min(rect.A.lon, rect.B.lon, rect.C.lon, rect.D.lon);
        const maxLon = Math.max(rect.A.lon, rect.B.lon, rect.C.lon, rect.D.lon);

        return point.lat >= minLat && point.lat <= maxLat && point.lon >= minLon && point.lon <= maxLon;
    };

    if (isInsideRectangle(incomingLocation, restrictedZone)) {
        trigger(); // Triggers the predefined alert (e.g., send a warning notification)
    }
}
function run() {
    let temperature = ${{TEMPERATURE}};
    let humidity = ${{HUMIDITY}};
    let lightLevel = ${{LIGHT}};
    let co2Level = ${{CO2}};

    // Trigger alert if temperature is too high and humidity is too low
    if (temperature > 28 && humidity < 40) {
        trigger(); // Executes the pre-configured alert
    }

    // Trigger alert if light levels drop too low while CO2 is high
    if (lightLevel < 200 && co2Level > 1000) {
        trigger(); // Executes the pre-configured alert
    }

    // Immediate action required for extreme conditions
    if (temperature > 35 || humidity > 80 || co2Level > 1500) {
        trigger(); // Executes the pre-configured alert
    }
}

How to Decode Uplink Messages with Qubitro Decoder Functions

By following this guide, you can customize Qubitro decoder functions to decode various sensor payloads and extract valuable network metrics from any LNS integration.

This guide explains how to use Qubitro’s decoder functions to parse raw uplink messages received via LNS integrations—such as The Things Stack, Loriot, and others.

Although the examples here refer to decoding sensor data (like temperature or humidity), these functions work the same way for any LNS provider.

hashtag
Key Concepts

Decoder Function

A custom function that Qubitro automatically invokes with an input object containing the uplink message’s raw data, the fPort, and additional metadata.

hashtag
Input Properties

• bytes: A byte array representing the raw data payload.

• fPort: The port number used for the uplink message.

• metadata: Rich network details from the LNS (e.g., signal quality, gateway information), regardless of the provider.

hashtag
How It Works

Qubitro supplies the decoder function with an input object that includes all necessary properties.

Your function should extract the required sensor values by converting raw bytes into human-readable data. You can also extract network metrics—like RSSI and SNR—from the metadata.

hashtag
Accessing Input Properties

Create a simple decoder function that extracts the raw bytes, fPort, and metadata:

hashtag
Decoding a Temperature Sensor Message

In this example, assume that the sensor sends temperature data encoded in two bytes. The function converts these bytes into a decimal temperature value:

hashtag
Decoding Temperature and Humidity Data

This example demonstrates handling multiple sensor readings. The function first checks if the payload is long enough and then extracts temperature and humidity from the last four bytes:

hashtag
Accessing Metadata for Network Metrics

Decoder functions can also extract network metrics (such as SNR and RSSI) from the metadata. This example demonstrates how to do so:

function decoder(input) {
  var bytes = input.bytes;       // Retrieve the raw data payload
  var fPort = input.fPort;       // Retrieve the fPort number
  var metadata = input.metadata; // Retrieve LNS metadata

  return {}; // Customize and return a JSON object as needed
}
function decoder(input) {
  const bytes = input.bytes;
  const fPort = input.fPort;

  // Combine two bytes into one number and adjust the scale (divide by 100)
  const temperature = ((bytes[0] << 8) + bytes[1]) / 100;

  return {
    "bytes": bytes,
    "fPort": fPort,
    "temperature": temperature,
  };
}
function decoder(input) {
  var bytes = input.bytes;
  var fPort = input.fPort;
  var data = {};

  // Ensure the payload contains enough data for both sensors
  if (bytes.length < 4) {
    return { error: 'Payload too short' };
  }

  // Extract bytes for temperature and humidity
  var temperatureBytes = bytes.slice(bytes.length - 4, bytes.length - 2);
  var humidityBytes = bytes.slice(bytes.length - 2);

  // Convert the byte arrays into 16-bit integers and scale accordingly
  var temperature = ((temperatureBytes[0] << 8) | temperatureBytes[1]) / 100.0;
  var humidity = ((humidityBytes[0] << 8) | humidityBytes[1]) / 100.0;

  data["temperature"] = temperature;
  data["humidity"] = humidity;

  return data;
}
function decoder(input) {
  var bytes = input.bytes;       // Sensor data payload
  var fPort = input.fPort;       // fPort value
  var metadata = input.metadata; // LNS metadata from the uplink
  var snr, rssi;

  // Extract network metrics if available (works with any LNS provider)
  if (metadata && metadata.gws && metadata.gws.length > 0) {
    snr = metadata.gws[0].snr;   // SNR from the first gateway
    rssi = metadata.gws[0].rssi; // RSSI from the first gateway
  }

  // Additionally decode sensor-specific data (example calculations)
  return {
    STATUS: bytes[0] & 0x01, // Sensor status
    BATTERY: (25 + (bytes[1] & 0x0f)) / 10, // Battery level estimate
    COUNT: (bytes[7] << 16) | (bytes[6] << 8) | bytes[5], // Count extracted from multiple bytes
    SNR: snr,   // Signal-to-noise ratio from metadata
    RSSI: rssi  // Received signal strength indicator from metadata
  };
}

Guides

Explore the recommended guides below to quickly familiarize yourself with core platform features and workflows.

hashtag
Getting Started with Qubitro

This page helps you quickly get started with Qubitro by recommending essential guides and documentation. Follow these steps to set up your first project, connect devices, and explore core features.

hashtag
🚦 Start Here

hashtag
Creating Your First Project

Start your IoT journey by setting up your project in Qubitro.

hashtag
Adding Your First Device

Easily add, configure, and manage IoT devices.

hashtag
Visualizing Data with Dashboards

Build interactive dashboards to monitor real-time device data.

hashtag
🛠️ Essential Features

hashtag
Understanding Time Series Storage

Learn about data storage and retrieval options.

Working with Functions

Automate tasks using Decoder, Transformation, Rule, and Scheduled functions.

hashtag
Managing API and External Credentials

Securely integrate Qubitro with other services.


Need more help? Visit our complete or contact .

Developerschevron-right
documentation
supportarrow-up-right

How to Publish and Decode Multiple Hex Payloads via MQTT on Qubitro

Learn how to publish multiple hex payloads using MQTTX and decode them using Qubitro’s Decoder Function. This guide walks you through secure MQTT setup, payload formatting, and real-time data decoding

This guide shows how to:

  • ✅ Send multiple hex payloads using MQTTX

  • ✅ Use a custom Qubitro to decode GPS and sensor data

  • ✅ View structured decoded data in the Qubitro portal


hashtag
🧩 Prerequisites

  • A

  • An existing Device


hashtag
Step 1: Get Your Qubitro MQTT Credentials

  1. Go to your device in the Qubitro Portal

  2. Click the MQTT Credentials tab

  3. Copy:


hashtag
Step 2: Configure MQTTX (Secure Connection)

Open MQTTX and configure your connection as shown below:

  • Name: broker.qubitro.com

  • Host: mqtts://broker.qubitro.com

  • Port: 8883

circle-check

Click Connect to establish a secure MQTT connection.


hashtag
Step 3: Add Decoder Function in Qubitro

1. Go to your device → Functions tab

2. Click Add Function → Choose Decoder Function

3. Paste the following JavaScript code:

circle-check

You can also test a single hex payload on the Qubitro Portal to verify your decoder.

  1. Save and activate the function.

hashtag
Step 4: Publish Multiple Hex Payloads

  1. Go to the Publish tab in MQTTX.

  2. In the topic field, paste your Device ID.

  3. Set the payload type to JSON.

  1. Click the green send button to publish the message.

hashtag
Step 5: View Decoded Data

Open the Storage tab in your Qubitro device and you’ll see structured decoded values like:


You’ve successfully:

• Connected MQTTX to Qubitro securely

• Published multiple hex payloads

• Used a custom decoder to parse sensor/GPS values

• Verified decoded output in Qubitro

Your device's MQTT credentials
Device ID (used as Username and topic)
  • Device Token (used as Password)

  • Host: broker.qubitro.com

  • Port: 8883 (SSL) or 1883 (non-SSL)

  • Topic: Device ID

  • Client ID: (same as Device ID)

  • Username: Device ID

  • Password: Device Token

  • SSL/TLS: ✅ Enabled

  • SSL Secure: ✅ Enabled

  • Certificate: CA signed server certificate

  • Use the following payload:
    Qubitro accountarrow-up-right
    MQTTX Desktop Apparrow-up-right
    function decoder(input) {
      const longitude = ((input.bytes[0] << 24) | (input.bytes[1] << 16) | (input.bytes[2] << 8) | (input.bytes[6] & 0xC0)) /1000000;
      const latitude = ((input.bytes[3] << 24) | (input.bytes[4] << 16) | (input.bytes[5] << 8) | ((input.bytes[6] & 0x30) << 2)) /1000000;
      const hMSL32 = ((((input.bytes[6] & 0x0F) << 8 ) + input.bytes[7]) * 2) - 191;
      const hAccCoeff = (input.bytes[8] & 0xE0) >> 5;
      const vAccCoeff = (input.bytes[8] & 0x1C) >> 2;
      const heading = ((input.bytes[8] & 0x03) << 2) + ((input.bytes[9] & 0xC0) >> 6);
      const speed = (input.bytes[9] & 0x3F);
      const battery = ((input.bytes[10]*256) + input.bytes[11]);
      const year = (input.bytes[12] >> 2) + 2000;
      const month = ((input.bytes[12] & 0x03) << 2) + ((input.bytes[13] & 0xC0) >> 6);
      const day = (input.bytes[13] & 0x3E) >> 1;
      const hour = ((input.bytes[13] & 0x01) << 4) + ((input.bytes[14] & 0xF0) >> 4);
      const minute = ((input.bytes[14] & 0x0F) << 2) + ((input.bytes[15] & 0xC0) >> 6);
      const second = (input.bytes[15] & 0x3F);
      const timestampSeconds = Math.floor(new Date(year, month, day, hour, minute, second).getTime() / 1000);
    
      return {
        longitude,
        latitude,
        coordinates: [latitude, longitude],
        hMSL32,
        hAccCoeff,
        vAccCoeff,
        heading,
        speed,
        battery,
        time: timestampSeconds
      };
    }
    {
      "payload_hex": "00C08802808560A184000FFB648EAD0F,00c088028085909784000ffb648ead46,00c089028085109284000ffe648ead89,00c088028085e09c84000ffe648eadcb"
    }

    How to Use JSONata for Real-Time Data Transformation in Qubitro

    This guide explains how to use JSONata expressions in Qubitro Transformation Functions to manipulate and structure real-time data before it is stored or used for automated actions.

    JSONata provides a flexible, lightweight way to filter, calculate, and restructure data without writing traditional code.

    A few things to remember:

    circle-info

    Data can be modified on-the-fly before storage and automation.

    circle-info

    TF applies immediately to incoming data, whether raw or already decoded.

    hashtag
    How Transformation Functions Work in Qubitro

    Once a device sends data, TF automatically applies the JSONata expression configured by the user.

    If a Decoder Function exists, it will process raw data first, and then TF will apply JSONata expressions on the decoded output. If there is no decoder, TF will apply transformations directly to the published data.

    hashtag
    Basic JSONata Syntax

    Here are some core JSONata concepts:

    • Mathematical functions: $sum(values), $average(values), $max(values), $min(values).

    • Ternary operators: condition ? trueValue : falseValue.

    • String and numeric literals: "text" for strings, 42 for numbers.

    hashtag
    Practical Implementations

    hashtag
    Example 1: Flattening Nested JSON

    Convert a multi-level JSON object into a flat structure for better Qubitro compatibility.

    1

    hashtag
    Incoming Data:

    2

    JSONata Expression:

    hashtag
    Example 2: Extracting Values from Arrays

    Transform an array of objects into structured key-value pairs.

    1

    hashtag
    Incoming Data:

    2

    JSONata Expression:

    hashtag
    Example 3: Performing Mathematical Calculations

    Use JSONata to compute sums, averages, and find min/max values dynamically.

    1

    hashtag
    Incoming Data:

    2

    JSONata Expression:

    hashtag
    Example 4: Time Formatting and Duration Calculation

    Modify timestamps into human-readable formats or compute durations.

    1

    hashtag
    Incoming Data:

    2

    JSONata Expression:

    hashtag
    Example 5: Dynamically Accessing Data Using $lookup()

    This method is useful when field names may change dynamically.

    1

    hashtag
    Incoming Data:

    2

    JSONata Expression:

    Using the root object: $ refers to the root JSON object.

  • Accessing fields: fieldname retrieves a specific property.

  • 3

    Transformed Data:

    3

    Transformed Data:

    3

    Transformed Data:

    3

    Transformed Data:

    3

    Transformed Data:

    {
      "sensor_type": "temperature",
      "current_temperature": 22,
      "average_temperature": 21
    }
    {
      "temperature_value": 22,
      "humidity_value": 55
    }
    {
      "sum": 75,
      "average": 15,
      "max": 25,
      "min": 5
    }
    {
      "start_date": "2020-01-01",
      "end_date": "2020-01-01",
      "duration_hours": "4 hours"
    }
    {
      "temp_value": 22,
      "humidity_value": 78
    }
    {
      "sensor": {
        "type": "temperature",
        "readings": {
          "current": 22,
          "average": 21
        }
      }
    }
    {
      "sensor_type": sensor.type,
      "current_temperature": sensor.readings.current,
      "average_temperature": sensor.readings.average
    }
    {
      "sensors": [
        {"type": "temperature", "value": 22},
        {"type": "humidity", "value": 55}
      ]
    }
    {
      "temperature_value": sensors[type='temperature'].value,
      "humidity_value": sensors[type='humidity'].value
    }
    {
      "values": [5, 10, 15, 20, 25]
    }
    {
      "sum": $sum(values),
      "average": $average(values),
      "max": $max(values),
      "min": $min(values)
    }
    {
      "event": {
        "start_time": "2020-01-01T08:00:00Z",
        "end_time": "2020-01-01T12:00:00Z"
      }
    }
    {
      "start_date": $fromMillis($toMillis(event.start_time), '[Y0001]-[M01]-[D01]'),
      "end_date": $fromMillis($toMillis(event.end_time), '[Y0001]-[M01]-[D01]'),
      "duration_hours": ($toMillis(event.end_time) - $toMillis(event.start_time)) / (1000*60*60) & " hours"
    }
    {
      "sensorData": {
        "temperature": 22,
        "humidity": 78
      }
    }
    {
      "temp_value": $lookup(sensorData, 'temperature'),
      "humidity_value": $lookup(sensorData, 'humidity')
    }
    rectangle-historyProjectchevron-right
    swap-arrowsNo-Code Integrationschevron-right
    tower-broadcastMQTTchevron-right
    brackets-curlyHTTPchevron-right
    chart-mixedMonitoringchevron-right
    Time Series Storagechevron-right
    boltFunctionschevron-right
    Decoder Function
    spinner