Skip to main content

What are Models?

Models in LoT are like database schemas for MQTT data. They define the structure of your data, ensure consistency across your system, and provide automatic JSON formatting.
Models transform raw MQTT messages into structured, typed data - eliminating the need for external data transformation layers.

Model Capabilities

Define fields with specific types (STRING, INT, DOUBLE, BOOL, ARRAY) to create consistent data schemas.
Automatically explode incoming JSON payloads into individual topics for easy field access.
Combine data from multiple MQTT topics into a single structured output.
Perform inline calculations and conditional logic to derive new values.

How Models Work

Models do more than format data. They aggregate values from multiple MQTT topics, scale across device fleets with wildcards, compute derived metrics inline, and apply conditional logic — all within the broker, with zero external code. Here’s how the core flow works.

Receiving JSON Payloads

When a device sends a full telemetry payload, you often need to access individual fields independently — for threshold alerts, dashboard widgets, or other models. All models automatically handle this by “exploding” incoming JSON payloads into individual topics:
DEFINE MODEL SensorData WITH TOPIC "sensors/device1/data"
When JSON arrives at sensors/device1/data:
{
  "temperature": 23.5,
  "humidity": 65,
  "status": "active"
}
LoT automatically creates:
  • sensors/device1/data/temperature23.5
  • sensors/device1/data/humidity65
  • sensors/device1/data/status"active"
This “explosion” behavior allows you to subscribe to individual fields or use them in other models and actions.

Producing Structured Output

When downstream systems — databases, dashboards, REST APIs — expect a specific JSON schema, a model guarantees that format on every publish. When a model triggers (either automatically or via action), it publishes structured JSON combining all its fields:
DEFINE MODEL EquipmentStatus WITH TOPIC "equipment/formatted"
    ADD STRING "equipment_id" WITH TOPIC "equipment/id"
    ADD STRING "status" WITH TOPIC "equipment/status" AS TRIGGER
    ADD INT "runtime_hours" WITH TOPIC "equipment/runtime"
    ADD STRING "last_update" WITH TIMESTAMP "UTC"
Produces:
{
  "equipment_id": "PUMP001",
  "status": "RUNNING",
  "runtime_hours": 1250,
  "last_update": "2025-10-25T14:30:15Z"
}

Aggregating Multiple Sources

When you need a unified equipment dashboard from scattered PLC topics, or a combined production report from sensors across different lines, a single model pulls live values from many independent topics and merges them into one structured output — replacing external aggregation scripts or middleware entirely. Each field draws from a different source topic, but the model waits for the trigger field (status) to update before publishing a combined snapshot:
DEFINE MODEL EquipmentStatus WITH TOPIC "equipment/status/formatted"
    ADD STRING "equipment_id" WITH TOPIC "equipment/current/id"
    ADD STRING "status" WITH TOPIC "equipment/current/status" AS TRIGGER
    ADD INT "runtime_hours" WITH TOPIC "equipment/current/runtime"
    ADD DOUBLE "efficiency" WITH TOPIC "equipment/current/efficiency"
    ADD BOOL "maintenance_required" WITH TOPIC "equipment/current/maintenance_flag"
    ADD STRING "last_update" WITH TIMESTAMP "UTC"

Building Nested Objects with Indentation

When your API or database expects grouped fields — such as a metadata object inside a sensor reading, or a status block with nested maintenance details — use the OBJECT type to produce nested JSON directly. Fields indented one level deeper than ADD OBJECT become properties of that sub-object — the same way ADD fields under DEFINE MODEL become top-level properties.
DEFINE MODEL SensorWithMetadata WITH TOPIC "sensors/+/formatted"
    ADD STRING "sensor_id" WITH TOPIC "sensors/+/id"
    ADD DOUBLE "value" WITH TOPIC "sensors/+/value" AS TRIGGER
    ADD STRING "unit" WITH "celsius"
    ADD OBJECT "metadata"
        ADD STRING "location" WITH TOPIC "sensors/+/location"
        ADD INT "floor" WITH TOPIC "sensors/+/floor"
        ADD STRING "building" WITH TOPIC "sensors/+/building"
    ADD STRING "timestamp" WITH TIMESTAMP "UTC"
Produces:
{
  "sensor_id": "TEMP001",
  "value": 25.5,
  "unit": "celsius",
  "metadata": {
    "location": "Room 101",
    "floor": 3,
    "building": "Building A"
  },
  "timestamp": "2025-10-25T14:30:15Z"
}
The indentation level determines the nesting. Fields at the same depth as ADD OBJECT (like "timestamp" above) return to the parent object.
Indentation must be consistent. Use either tabs or spaces throughout your model — mixing them will cause parsing errors. Each nesting level adds one indentation step.

What Else Can Models Do?

The examples above cover the fundamentals, but models go much further:
  • Nested Objects — Use the OBJECT type with indentation to group related fields into sub-objects, producing clean nested JSON hierarchies. See examples →
  • Wildcard Models — Define one model with + wildcards and it automatically handles every matching device. One definition, hundreds of instances, zero duplication. See examples →
  • Inline Calculations — Compute efficiency percentages, unit conversions, and running averages directly inside the model definition — no external processing needed. See examples →
  • Conditional Logic — Dynamically tag field values based on live data: label readings as "HIGH" or "NORMAL", flag quality as "PASS" or "FAIL", assign priority levels.
  • Action-Published Templates — Use COLLAPSED models as reusable schemas, then publish them from actions with full control over timing, routing, and conditional decisions. Learn more →
For example, a single wildcard model automatically scales across every matching device — one definition handles your entire fleet: See the full wildcard example →

Model Types

LoT supports three model patterns, each suited for different scenarios:
PatternUse When
Basic ModelYou want automatic triggering on data changes
Template Model (COLLAPSED)You need control over when and where data is created
Inheritance (FROM)You have related data types sharing common fields

Basic Models

Basic models automatically trigger and publish structured data when their trigger field updates:
DEFINE MODEL SensorReading WITH TOPIC "sensors/formatted/temperature"
    ADD STRING "sensor_id" WITH "TEMP001"
    ADD DOUBLE "value" WITH TOPIC "sensors/raw/temperature" AS TRIGGER
    ADD STRING "unit" WITH "celsius"
    ADD STRING "timestamp" WITH TIMESTAMP "UTC"
Key characteristics:
  • WITH TOPIC specifies where output is published
  • AS TRIGGER defines which field change causes publication
  • Runs automatically when trigger field updates

Template Models (COLLAPSED)

Template models are reusable schemas for dynamic data creation from within actions. The COLLAPSED keyword indicates they have no automatic trigger:
DEFINE MODEL AlarmRecord COLLAPSED
    ADD STRING "alarm_id"
    ADD STRING "equipment_id"
    ADD STRING "severity"
    ADD STRING "timestamp"

DEFINE ACTION ProcessAlarm
ON TOPIC "alarms/+/input" DO
    SET "equip_id" WITH TOPIC POSITION 2
    
    PUBLISH MODEL AlarmRecord TO "alarms/structured/" + {equip_id} WITH
        alarm_id = (RANDOM UUID)
        equipment_id = {equip_id}
        severity = (GET JSON "severity" IN PAYLOAD AS STRING)
        timestamp = TIMESTAMP "UTC"
Key characteristics:
  • COLLAPSED means no automatic trigger
  • Published explicitly with PUBLISH MODEL
  • Full control over when and where data is created
Learn how to publish template models from actions in Publishing Models.

Model Inheritance (FROM)

Create model families with shared fields using the FROM keyword:
DEFINE MODEL BaseAlert COLLAPSED
    ADD STRING "alert_id"
    ADD STRING "timestamp"
    ADD STRING "severity"

DEFINE MODEL TemperatureAlert FROM BaseAlert
    ADD DOUBLE "temperature_value"
    ADD DOUBLE "threshold"
Key characteristics:
  • Child models inherit all parent fields
  • Add specialized fields as needed
  • Promotes code reuse and consistency
Learn more about designing model hierarchies in Model Inheritance.

Data Sources

Model fields can be populated from various sources:
Use static values for constants like units, default thresholds, or fixed identifiers that never change:
DEFINE MODEL StaticExample WITH TOPIC "output/static"
    ADD STRING "unit" WITH "celsius"
    ADD INT "default_threshold" WITH 100
    ADD BOOL "enabled" WITH TRUE

Next Steps

Model Syntax

Learn the complete syntax for defining model fields and triggers.

Model Inheritance

Create model families with shared fields using FROM.