title: "Getting Started New Solution — First Solution Creation with Tags, Simulator, and Dashboard" tags: [getting-started, beginner, first-solution, simulator, tutorial] description: "Create a complete starter solution: tags, Value Simulator device, historian logging, basic alarms, and a dashboard display" version: "1.0" author: "Tatsoft"
...
Build a complete starter solution from scratch: create tags organized by asset, connect a Value Simulator for testing, configure historian logging and basic alarms, and create a dashboard to visualize everything.
...
Use when:
...
| Category | Items |
|---|---|
| Tools | open_solution, get_table_schema, write_objects, get_objects, list_protocols, list_elements, designer_action, get_solution_info |
| Tables | UnsTags, DevicesChannels, DevicesNodes, DevicesPoints, HistorianHistorianTags, HistorianHistorianTables, AlarmsItems, DisplaysList |
open_solution('MyFirstSolution', template='Blank')
...
After open_solution completes, the full engineering context is delivered. Proceed to the next step — do not pre-fetch schemas.
Fetch the tag schema first:
...
Naming convention: Use consistent asset paths so the same display template can be reused for Tank1, Tank2, etc. via asset navigation.
The Value Simulator generates changing data for testing — no real device needed. It's a built-in protocol.
list_protocols('ValueSimulator')
This returns the protocol-specific field formats for Channel, Node, and Point configuration. Never guess these formats — always fetch first.
get_table_schema('DevicesChannels,DevicesNodes,DevicesPoints')
Devices follow a strict pipeline: Channel → Node → Point. All three are required, and dependencies must exist before referencing objects.
...
Adapt the protocol-specific fields (Address, ProtocolOptions, etc.) based on what list_protocols('ValueSimulator') returned.
Most solutions include a default StorageLocation and Table1:
...
get_table_schema('HistorianStorageLocations,HistorianHistorianTables')
get_table_schema('HistorianHistorianTags')
...
DeadBand: minimum value change before logging (0 = log every change)Deviation: overrides interval-based logging when value changes significantlyAlarms use predefined groups: Critical, Warning, AuditTrail.
...
Repeat a similar pattern for Tank2 tags as appropriate.
Now build the operator interface. For a starter solution, write directly into the predefined MainPage display.
list_elements('Dashboard,TrendChart,CircularGauge,TextBlock')
get_table_schema('DisplaysList')
{
"table_type": "DisplaysList",
"data": [{
"ObjectName": "MainPage",
"PanelType": "Dashboard",
"Columns": 4,
"Rows": 3,
"Content": [
{
"Type": "TextBlock",
"Text": "Plant Overview",
"Column": 0, "Row": 0, "ColumnSpan": 4,
"FontSize": 24, "HorizontalAlignment": "Center"
},
{
"Type": "CircularGauge",
"Value": "@Tag.Plant/Tank1/Level.Value",
"Minimum": 0, "Maximum": 100,
"Column": 0, "Row": 1,
"Header": "Tank 1 Level"
},
{
"Type": "CircularGauge",
"Value": "@Tag.Plant/Tank1/Temperature.Value",
"Minimum": 0, "Maximum": 100,
"Column": 1, "Row": 1,
"Header": "Tank 1 Temp"
},
{
"Type": "CircularGauge",
"Value": "@Tag.Plant/Tank2/Level.Value",
"Minimum": 0, "Maximum": 100,
"Column": 2, "Row": 1,
"Header": "Tank 2 Level"
},
{
"Type": "CircularGauge",
"Value": "@Tag.Plant/Tank2/Temperature.Value",
"Minimum": 0, "Maximum": 100,
"Column": 3, "Row": 1,
"Header": "Tank 2 Temp"
},
{
"Type": "TrendChart",
"Column": 0, "Row": 2, "ColumnSpan": 4,
"Pens": [
{ "TagName": "@Tag.Plant/Tank1/Level", "Color": "#FF2196F3", "Label": "T1 Level" },
{ "TagName": "@Tag.Plant/Tank2/Level", "Color": "#FFFF9800", "Label": "T2 Level" }
]
}
]
}]
}
...
Note: Verify TrendChart Pens schema against list_elements('TrendChart') output — the exact property names may vary.
designer_action('start_runtime')
The Value Simulator starts feeding changing data. Historian begins logging. Alarms evaluate against the setpoints. The dashboard shows live values.
After starting runtime:
get_solution_info() — confirm object counts match expectationsdesigner_action('navigate', 'Displays', 'Draw', 'MainPage') — dashboard should show live gauge valuesdesigner_action('navigate', 'Alarms', 'AlarmsMonitor') — alarms should evaluate against limits when simulator values cross setpointsdesigner_action('navigate', 'Historian', 'HistorianMonitor') — confirm tag values are being loggedTo adapt this starter for a real device instead of Value Simulator:
list_protocols('ValueSimulator') with the target protocol (e.g., list_protocols('ModbusTCP'), list_protocols('OPCUA'))| Mistake | Why It Happens | How to Avoid |
|---|---|---|
| Guessing protocol field formats | Skipping list_protocols | Always call list_protocols before writing device tables |
| Bare tag names in DevicesPoints | Forgetting asset path | Always use full path: Plant/Tank1/Level |
| Creating unnecessary HistorianTables | Not checking defaults | Check get_objects('HistorianHistorianTables') first |
| Omitting PanelType on dashboard | Seems optional | Always set PanelType explicitly |
| Pre-fetching all schemas at once | Over-eager optimization | Fetch each module's schema only when ready to write it |
| Screenshotting to verify writes | Unnecessary self-validation | Trust write_objects success. User sees live updates |
...