PUBLISH MODEL Functional Keyword
| Feature | Since Version | Notes |
|---|---|---|
PUBLISH MODEL |
>v1.6.0 | Publishes structured data using predefined models |
Overview
- Description:
Publishes structured JSON data to an MQTT topic using a predefined model schema. This command is used within
ACTIONblocks to create consistent, well-formed JSON payloads without manual string construction. It combines event-driven logic with structured data models.
Signature
- Syntax:
Parameters
<ModelName>: The name of a previously defined model (usingDEFINE MODEL ... COLLAPSED)"<topicPath>": The MQTT topic where the JSON payload will be publishedfieldName = <value>: Field assignments matching the model's defined fields
Prerequisites
Before using PUBLISH MODEL, you must define a model with the COLLAPSED keyword:
DEFINE MODEL <ModelName> COLLAPSED
ADD <FIELD_TYPE> "<field_name>"
ADD <FIELD_TYPE> "<field_name>"
...
Key Points:
- COLLAPSED means the model has no WITH TOPIC - it's a template, not an automatic trigger
- Models used with PUBLISH MODEL are schemas/templates for structured data
- Field types include: STRING, INT, DOUBLE, BOOL, OBJECT, ARRAY
Field Value Sources
1. Direct Literals
2. Action Variables
SET "sensor_id" WITH TOPIC POSITION 1
PUBLISH MODEL MyModel TO "output/topic" WITH
sensor_id = {sensor_id}
3. JSON Extraction with GET JSON
PUBLISH MODEL MyModel TO "output/topic" WITH
temperature = (GET JSON "temperature" IN PAYLOAD AS DOUBLE)
sensor_name = (GET JSON "name" IN PAYLOAD AS STRING)
4. Topic Data with GET TOPIC
PUBLISH MODEL MyModel TO "output/topic" WITH
status = GET TOPIC "system/current/status"
last_value = GET TOPIC "sensors/last/reading"
5. Calculations and Expressions
PUBLISH MODEL MyModel TO "output/topic" WITH
efficiency = ({produced} / {target} * 100)
total = ({passed} + {failed})
6. Timestamps
PUBLISH MODEL MyModel TO "output/topic" WITH
timestamp = TIMESTAMP "UTC"
unix_time = TIMESTAMP "UNIX"
Note: Within PUBLISH MODEL field assignments, TIMESTAMP uses the format TIMESTAMP "format" (without the WITH keyword). This is different from standalone usage where TIMESTAMP WITH "format" is required.
7. Conditional Values
PUBLISH MODEL MyModel TO "output/topic" WITH
priority = IF {severity} EQUALS "HIGH" THEN 1 ELSE 2
status = IF {count} > 100 THEN "FULL" ELSE "OK"
8. Nested Objects
PUBLISH MODEL MyModel TO "output/topic" WITH
metadata = {
"source": {sensor_id},
"quality": {quality_score},
"validated": TRUE
}
Usage Examples
Basic Example: Simple Sensor Record
DEFINE MODEL SensorRecord COLLAPSED
ADD STRING "sensor_id"
ADD DOUBLE "temperature"
ADD STRING "timestamp"
DEFINE ACTION LogSensorData
ON TOPIC "sensors/+/data" DO
SET "sensor_id" WITH TOPIC POSITION 1
PUBLISH MODEL SensorRecord TO "sensors/processed/" + {sensor_id} WITH
sensor_id = {sensor_id}
temperature = PAYLOAD
timestamp = TIMESTAMP "UTC"
Test:
Publish to: sensors/temp001/data
Payload: 25.5
Result in: sensors/processed/temp001
{
"sensor_id": "temp001",
"temperature": 25.5,
"timestamp": "2025-10-25T14:30:15Z"
}
Intermediate Example: JSON Data Extraction
DEFINE MODEL SensorDataRecord COLLAPSED
ADD STRING "sensor_id"
ADD STRING "sensor_type"
ADD DOUBLE "temperature"
ADD DOUBLE "pressure"
ADD STRING "timestamp"
ADD STRING "quality_status"
DEFINE ACTION ProcessSensorJSON
ON TOPIC "sensors/+/json_data" DO
SET "sensor_id" WITH TOPIC POSITION 1
// Extract data from JSON payload using GET JSON
SET "temperature_val" WITH (GET JSON "temperature" IN PAYLOAD AS DOUBLE)
SET "pressure_val" WITH (GET JSON "pressure" IN PAYLOAD AS DOUBLE)
SET "sensor_type" WITH (GET JSON "type" IN PAYLOAD AS STRING)
SET "quality" WITH (GET JSON "quality_status" IN PAYLOAD AS STRING)
// Publish structured sensor record
PUBLISH MODEL SensorDataRecord TO "sensors/processed/" + {sensor_id} WITH
sensor_id = {sensor_id}
sensor_type = {sensor_type}
temperature = {temperature_val}
pressure = {pressure_val}
timestamp = TIMESTAMP "UTC"
quality_status = {quality}
Test:
Publish to: sensors/temp001/json_data
Payload: {
"temperature": 75.5,
"pressure": 101.3,
"type": "environmental",
"quality_status": "GOOD"
}
Result in: sensors/processed/temp001
{
"sensor_id": "temp001",
"sensor_type": "environmental",
"temperature": 75.5,
"pressure": 101.3,
"timestamp": "2025-10-25T14:30:15Z",
"quality_status": "GOOD"
}
Advanced Example: Alarm Generation
DEFINE MODEL AlarmRecord COLLAPSED
ADD STRING "alarm_id"
ADD STRING "equipment_id"
ADD STRING "alarm_type"
ADD DOUBLE "trigger_value"
ADD DOUBLE "threshold"
ADD STRING "severity"
ADD STRING "message"
ADD STRING "timestamp"
ADD BOOL "auto_generated"
DEFINE ACTION JSONAlarmProcessor
ON TOPIC "alarms/+/json_input" DO
SET "equipment_id" WITH TOPIC POSITION 1
// Extract alarm data from JSON payload
SET "alarm_type" WITH (GET JSON "alarm_type" IN PAYLOAD AS STRING)
SET "current_value" WITH (GET JSON "current_value" IN PAYLOAD AS DOUBLE)
SET "threshold_value" WITH (GET JSON "threshold" IN PAYLOAD AS DOUBLE)
SET "severity_level" WITH (GET JSON "severity" IN PAYLOAD AS STRING)
SET "alarm_message" WITH (GET JSON "message" IN PAYLOAD AS STRING)
// Generate structured alarm record
PUBLISH MODEL AlarmRecord TO "alarms/structured/" + {equipment_id} WITH
alarm_id = (RANDOM UUID)
equipment_id = {equipment_id}
alarm_type = {alarm_type}
trigger_value = {current_value}
threshold = {threshold_value}
severity = {severity_level}
message = {alarm_message}
timestamp = TIMESTAMP "UTC"
auto_generated = TRUE
// Route based on severity
IF {severity_level} EQUALS "CRITICAL" THEN
PUBLISH TOPIC "alarms/critical/" + {equipment_id} WITH {alarm_message}
Differences from Basic Models
| Aspect | Basic Model (WITH TOPIC) | Action Model (COLLAPSED) |
|---|---|---|
| Definition | DEFINE MODEL Name WITH TOPIC "..." |
DEFINE MODEL Name COLLAPSED |
| Trigger | Automatic on topic changes | Manual via PUBLISH MODEL in actions |
| Control | Triggered by field marked AS TRIGGER |
Full control in action logic |
| When to Use | Automatic data transformation pipelines | Event-driven, conditional data creation |
GET JSON - Extracting JSON Data
GET JSON is commonly used with PUBLISH MODEL to extract fields from JSON payloads:
Syntax
Parameters
<field_name>: The JSON field to extract (supports dot notation for nested fields)<source>: UsuallyPAYLOADor a{variable}containing JSON<TYPE>: One ofSTRING,INT,DOUBLE,BOOL
Examples
Simple field:
Nested field:
From variable:
SET "json_data" WITH GET TOPIC "config/settings"
SET "threshold" WITH (GET JSON "limits.max" IN {json_data} AS DOUBLE)
Best Practices
1. Always Use Type Casting with GET JSON
✅ Correct:
❌ Incorrect:
2. Use COLLAPSED for Action Models
✅ Correct:
❌ Incorrect:
3. Validate Extracted Data
SET "value" WITH (GET JSON "value" IN PAYLOAD AS DOUBLE)
IF {value} < 0 OR {value} > 100 THEN
PUBLISH TOPIC "errors/validation" WITH "Invalid value: " + {value}
ELSE
PUBLISH MODEL ValidatedData TO "processed/data" WITH
value = {value}
validated = TRUE
4. Handle Missing JSON Fields
SET "optional_field" WITH (GET JSON "optional" IN PAYLOAD AS STRING)
IF {optional_field} EQUALS EMPTY THEN
SET "optional_field" WITH "DEFAULT_VALUE"
Use Cases
Event Logging
Create structured log entries when specific events occur: - Equipment state changes - Production milestones - Alarm occurrences - User actions
Data Transformation
Convert raw data into standardized formats: - JSON to structured records - Multiple sources to single record - Unit conversions and calculations - Data enrichment
Report Generation
Build reports when conditions are met: - Shift summaries - Quality reports - Performance analyses - Compliance records
Alarm Management
Generate standardized alarms from various triggers: - Threshold violations - State changes - Error conditions - Maintenance alerts
Integration with Python
Combine PUBLISH MODEL with Python for advanced processing:
# Script Name: DataProcessor
def validate_and_enrich(json_data):
import json
data = json.loads(json_data)
# Validation logic
if data.get('temperature', 0) < 0:
return {"error": "Invalid temperature", "valid": False}
# Enrichment
data['validated'] = True
data['quality_score'] = calculate_quality(data)
return json.dumps(data)
DEFINE MODEL ProcessedSensorData COLLAPSED
ADD STRING "sensor_id"
ADD DOUBLE "temperature"
ADD DOUBLE "quality_score"
ADD BOOL "validated"
ADD STRING "timestamp"
DEFINE ACTION PythonModelIntegration
ON TOPIC "sensors/+/raw" DO
SET "sensor_id" WITH TOPIC POSITION 1
CALL PYTHON "DataProcessor.validate_and_enrich"
WITH (PAYLOAD)
RETURN AS {processed}
PUBLISH MODEL ProcessedSensorData TO "sensors/processed/" + {sensor_id} WITH
sensor_id = {sensor_id}
temperature = (GET JSON "temperature" IN {processed} AS DOUBLE)
quality_score = (GET JSON "quality_score" IN {processed} AS DOUBLE)
validated = (GET JSON "validated" IN {processed} AS BOOL)
timestamp = TIMESTAMP "UTC"
Important Syntax Notes
TIMESTAMP in PUBLISH MODEL
Within PUBLISH MODEL field assignments, TIMESTAMP has a special syntax:
✅ Correct (in PUBLISH MODEL):
❌ Incorrect (in PUBLISH MODEL):
Compare to standalone usage:
// Outside PUBLISH MODEL, use WITH:
PUBLISH TOPIC "time" WITH TIMESTAMP WITH "UTC"
ADD "timestamp" WITH TIMESTAMP WITH "UTC"
// Inside PUBLISH MODEL, don't use WITH:
PUBLISH MODEL MyModel TO "topic" WITH
timestamp = TIMESTAMP "UTC"
Notes & Additional Information
PUBLISH MODELcreates JSON output automatically - no manual JSON string construction needed- All field names must match those defined in the model
- Field values can be any valid LOT expression
- The resulting JSON is published to the specified topic
TIMESTAMPsyntax within field assignments isTIMESTAMP "format"(withoutWITH)- Use with database routes to store structured data in OpenSearch, MongoDB, PostgreSQL, etc.