Namespace Placeholders
Introduction
A namespace provides a structured way to organize and reference data, ensuring that information from different systems can be identified, contextualized, and reused consistently across the enterprise.
Unified Namespace (UNS)
A Unified Namespace (UNS) is an architectural concept used in modern industrial and IIoT (Industrial Internet of Things) environments to create a single source of truth for all data streams within an enterprise. By establishing a common hierarchical naming structure (often dot- or slash-delimited), the UNS lets different systems—PLCs, SCADA, MES, ERP, IoT devices—publish and consume data within one consistent framework.
Key benefits of a UNS:
Central Data Repository: All real-time data is collected, published, and consumed in a single place (e.g., an MQTT broker).
Hierarchical Organization: Commonly forms paths like factory.line1.machineA.temperature, conveying clear context.
Semantic Context: Each level of the hierarchy reflects a real-world concept (site, line, machine, sensor, etc.).
Scalability and Extensibility: Adding new devices or systems is easier when they join the already-defined structure.
ISA-95 Standard
ISA-95 (ANSI/ISA-95 / IEC 62264) is an international standard that defines models and terminology for integrating control systems with enterprise systems. In essence, it:
Describes Manufacturing Operations Levels:
Levels 0–1: Sensors, actuators, the physical process.
Level 2: Control systems (PLCs, DCS, SCADA).
Level 3: Manufacturing Execution Systems (MES).
Level 4: Business systems like ERP.
Promotes Interoperability: Provides a framework for how data and functionality should flow between these levels.
Defines Hierarchies: Enterprise → Site → Area → Line → Cell → Machine → etc.
How UNS and ISA-95 Work Together
A UNS typically leverages the ISA-95 hierarchy to organize topics and data points (e.g., Enterprise.Site.Area.Line.Machine.Sensor). This alignment:
Ensures consistent naming across IT and OT.
Simplifies integration for new devices or software.
Creates a foundation for advanced analytics (digital twins, machine learning, etc.).
Overview: EasyEdge Namespace Placeholders
EasyEdge uses placeholders to dynamically build payloads (e.g., MQTT topics, REST payloads) by inserting runtime data such as hierarchical names, values, timestamps, and more.
This document details the namespace-based placeholders, how to configure them, and how to use them for flexible custom payload generation. Below you will find:
Namespace Structure Placeholders
Dynamic Segmenting (head[x], tail[x], segment[x], parent[x])
Separators Configuration (prefix, defaultSeparator, lastSeparator)
Tag Value and Metadata Placeholders (including conversions)
Timestamp Placeholders (real, emulated, last touch, fallback)
Namespace Structure Placeholders
namespace.tag.name
Description: Represents the entire path (formerly known as “fullName”).
Example:
If the hierarchical path is: Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature
namespace.tag.name → "Enterprise1.SiteA.Area02.Line1.MachineA.Temperature"
namespace.tag.leaf
Description: Returns the last segment in the hierarchy (sometimes called the “leaf”). An alias for namespace.tag.rsegment[0].
Example:
For Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature: namespace.tag.leaf → "Temperature"
For MachineA → Pressure: namespace.tag.leaf → "Pressure"
For a single-segment namespace (e.g., Temperature): namespace.tag.leaf → "Temperature"
namespace.tag.root
Description: Returns the first (top) segment in the hierarchy.
Example:
For Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature: namespace.tag.root → "Enterprise1"
For Temperature (only one segment): namespace.tag.root → "Temperature"
namespace.tag.thing
Description: An alias for namespace.tag.parent[0], i.e., the entire path minus the leaf (one-level parent).
Behavior:
If multiple segments exist, it returns all but the last.
If only one segment exists, it returns an empty string.
Example:
For Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature: namespace.tag.thing → "Enterprise1.SiteA.Area02.Line1.MachineA"
For MachineA → Temperature: namespace.tag.thing → "MachineA"
For a single segment (Temperature): namespace.tag.thing → ""
Dynamic Segmenting
EasyEdge provides several ways to dynamically access or build partial paths from the namespace.
namespace.tag.segment[x]
Description:
Returns the segment at position x using forward indexing (left to right).
Index 0 corresponds to the leftmost segment (the very beginning of the path).
Counting then continues one by one toward the right.
Example (Namespace: Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature):
namespace.tag.segment[0] → "Enterprise1"
namespace.tag.segment[1] → "SiteA"
namespace.tag.segment[2] → "Area02"
namespace.tag.segment[3] → "Line1"
namespace.tag.segment[4] → "MachineA"
namespace.tag.segment[5] → "Temperature"
namespace.tag.rsegment[x]
Description:
Returns the segment at position x using reverse indexing (right to left).
Index 0 corresponds to the rightmost segment (the very end of the path).
Counting then continues one by one toward the left.
Example (Namespace: Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature):
namespace.tag.segment[0] → "Temperature"
namespace.tag.segment[1] → "MachineA"
namespace.tag.segment[2] → "Line1"
namespace.tag.segment[3] → "Area02"
namespace.tag.segment[4] → "SiteA"
namespace.tag.segment[5] → "Enterprise1"
namespace.tag.head[x]
Description: Returns the first (x+1) segments of the namespace.
Example (Namespace: Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature):
namespace.tag.head[0] → "Enterprise1"
namespace.tag.head[1] → "Enterprise1.SiteA"
namespace.tag.head[2] → "Enterprise1.SiteA.Area02"
...
namespace.tag.tail[x]
Description: Returns the last (x+1) segments of the namespace.
Example (Namespace: Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature):
namespace.tag.tail[0] → "Temperature"
namespace.tag.tail[1] → "MachineA.Temperature"
namespace.tag.tail[2] → "Line1.MachineA.Temperature"
...
namespace.tag.parent[x]
Description: Returns the entire path minus the last (x+1) segments, 0-based indexing.
Interpretation:
parent[0] = the path minus the last segment (equivalent to namespace.tag.thing).
parent[1] = the path minus the last two segments.
parent[2] = minus the last three, etc.
Example (Namespace: Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature):
namespace.tag.parent[0] → "Enterprise1.SiteA.Area02.Line1.MachineA"
namespace.tag.parent[1] → "Enterprise1.SiteA.Area02.Line1"
namespace.tag.parent[2] → "Enterprise1.SiteA.Area02"
namespace.tag.parent[5] → "" (empty if removing 6 segments from a 6-segment name)
Configuring Separators
EasyEdge allows runtime configuration of how segments are joined together, enabling flexible display or payload-building patterns.
You can set three parameters:
namespace.prefix
A string inserted before the first segment, even before any separator.
Default could be "" (empty) or something like "/".
namespace.lastSeparator
The separator used only before the final (leaf) segment.
Useful if you want the last delimiter to differ from the default, e.g., . instead of /.
namespace.defaultSeparator
The main separator used between all other segments (except the last).
Example Configuration
namespace.prefix = ""
namespace.lastSeparator = "."
namespace.defaultSeparator = "/"
Given an original path: Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature
Segments are: [Enterprise1, SiteA, Area02, Line1, MachineA, Temperature]
Using the above config:
Between all but the last: use "/"
Before the last element: use "."
No prefix (empty string)
Result: Enterprise1/SiteA/Area02/Line1/MachineA.Temperature
This flexibility lets you produce specialized topic or path formats without manually concatenating strings.
Tag Value and Metadata Placeholder
Tag Value
namespace.tag.value returns the latest value in its native format. However, sometimes you need conversions:
Placeholder
Description
Example
namespace.tag.value
Latest value in native format
23.5
(for a float sensor value)
namespace.tag.value.asString
Converts the value to a string representation
"23.5"
namespace.tag.value.asFloat
Converts to floating-point
23.5
namespace.tag.value.asInt
Converts to integer (truncating decimals)
23
namespace.tag.value.asBool
Converts to boolean (nonzero → true, zero → false)
true
namespace.tag.value.asHex
Converts to hexadecimal format
"17"
(if value = 23)
Additional Tag Metadata
EasyEdge also provides unit- and data-type–related placeholders for richer contextualization.
Placeholder
Description
Example
namespace.tag.unit.name
The user-friendly name of the unit of measure
"Celsius" or "Fahrenheit"
namespace.tag.unit.symbol
The symbolic representation of the unit
"ºC" or "ºF"
namespace.tag.unit.exponent
The exponent factor for scaling the unit
(if applicable)
0
namespace.tag.dataType
The data type used for the tag
(e.g., REAL, INTEGER, STRING)
"REAL"
Examples:
namespace.tag.unit.name → "Fahrenheit"
namespace.tag.unit.symbol → "ºF"
namespace.tag.unit.exponent → 0
namespace.tag.dataType → "REAL"
Timestamp Placeholders
EasyEdge tracks multiple timestamps for each tag to reflect different points in its data lifecycle:
Real (asset-provided) – extRealTimestamp*
Emulated (when the eNode receives data) – extEmulTimestamp*
Last Touch (last time the eNode processed the data) – lastTouchTimestamp*
Default / Fallback – tries Real → Emulated → Last Touch
Real Timestamps: namespace.tag.timestamp.real.*
Examples:
namespace.tag.timestamp.real.sec
namespace.tag.timestamp.real.milli
namespace.tag.timestamp.real.micro
namespace.tag.timestamp.real.nano
namespace.tag.timestamp.real.iso If the sensor includes an internal timestamp, these placeholders expose it.
Emulated Timestamps: namespace.tag.timestamp.emulated.*
Examples:
namespace.tag.timestamp.emulated.sec
namespace.tag.timestamp.emulated.milli
namespace.tag.timestamp.emulated.micro
namespace.tag.timestamp.emulated.nano
namespace.tag.timestamp.emulated.iso Created automatically upon data arrival if a “real” timestamp is missing or not used.
Last Touch Timestamps: namespace.tag.timestamp.lastTouch.*
Examples:
namespace.tag.timestamp.lastTouch.sec
namespace.tag.timestamp.lastTouch.milli
namespace.tag.timestamp.lastTouch.micro
namespace.tag.timestamp.lastTouch.nano
namespace.tag.timestamp.lastTouch.iso Indicates the most recent time the eNode processed or updated the value.
Default / Fallback Timestamps: namespace.tag.timestamp.*
Description: If you only want one timestamp that picks the best available, use these placeholders. They follow the chain Real → Emulated → Last Touch.
Examples:
namespace.tag.timestamp.sec
namespace.tag.timestamp.milli
namespace.tag.timestamp.micro
namespace.tag.timestamp.nano
namespace.tag.timestamp.iso
Putting It All Together
Example 1: Simple MQTT Payload
{
"path": "${namespace.tag.name}",
"leaf": "${namespace.tag.leaf}",
"thing": "${namespace.tag.thing}",
"value": ${namespace.tag.value},
"timestampIso": "${namespace.tag.timestamp.iso}"
}
Given a namespace like Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature and default fallback timestamp logic:
path → "Enterprise1.SiteA.Area02.Line1.MachineA.Temperature"
leaf → "Temperature"
thing → "Enterprise1.SiteA.Area02.Line1.MachineA" (minus last segment)
value → e.g., 23.5
timestampIso → e.g., "2025-02-23T14:30:00Z"
Example 2: Using parent[x]
topic = "${namespace.tag.parent[1]}/${namespace.tag.leaf}"
payload = "temp=${namespace.tag.value.asFloat}&ts=${namespace.tag.timestamp.milli}"
For Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature,
namespace.tag.parent[1] = "Enterprise1.SiteA.Area02.Line1"
namespace.tag.leaf = "Temperature"
Topic → Enterprise1.SiteA.Area02.Line1/Temperature
Payload → temp=23.5&ts=1708706400123
Example 3: Configurable Separators
If you set:
namespace.prefix = "/"
namespace.defaultSeparator = "/"
namespace.lastSeparator = "."
And the original segments are Enterprise1 → SiteA → Area02 → Line1 → MachineA → Temperature, You will get /Enterprise1/SiteA/Area02/Line1/MachineA.Temperature.
Example 4: Converting Value Formats
{
"fullName": "${namespace.tag.name}",
"valueString": "${namespace.tag.value.asString}",
"valueHex": "${namespace.tag.value.asHex}",
"timestampSec": ${namespace.tag.timestamp.sec}
}
For a sensor reading 45, you might get:
{
"fullName": "Line1.MachineA.Speed",
"valueString": "45",
"valueHex": "0x2D",
"timestampSec": 1708706400
}
Example 5: Displaying Unit and Data Type
{
"path": "${namespace.tag.name}",
"dataType": "${namespace.tag.dataType}",
"unitName": "${namespace.tag.unit.name}",
"unitSymbol": "${namespace.tag.unit.symbol}",
"value": ${namespace.tag.value},
"timestampMilli": ${namespace.tag.timestamp.milli}
}
If dataType is REAL, unit.name is "Celsius", and unit.symbol is "ºC", then:
{
"path": "Enterprise1.SiteA.Area02.Line1.MachineA.Temperature",
"dataType": "REAL",
"unitName": "Celsius",
"unitSymbol": "ºC",
"value": 23.5,
"timestampMilli": 1708706400123
}
Best Practices
Adopt an ISA-95-Aligned Hierarchy Use the standard’s structure (Enterprise → Site → Area → Line → Machine, etc.) to keep data organized.
Use namespace.prefix Sparingly Only if you need a global prefix like "/" or "\\" for certain protocols or systems.
Differentiate namespace.tag.name vs. namespace.tag.leaf
name = entire path
leaf = last segment only
namespace.tag.thing for “All But Leaf” This is an alias for parent[0]. If you need to climb higher up, use parent[x].
Value Conversions Use .asString, .asFloat, .asInt, etc. to ensure the payload format matches your use case.
Units and Data Types
Use namespace.tag.unit.* placeholders to provide context for the measurement.
Use namespace.tag.dataType to clarify the underlying data format.
Choose the Right Timestamp
Real if you trust the device clock.
Emulated if the device clock is missing or inaccurate.
Last Touch if you specifically need the eNode’s last-processing time.
Default if you want a “best guess” automatically.
Combine Head/Tail If you need a partial path from the top or bottom, head[x] and tail[x] are simpler than manual substring operations.
Check Single-Segment Names If your namespace is just "Temperature", thing or parent[0] will be empty.
Conclusion
By leveraging these EasyEdge namespace placeholders, you can build custom payloads that:
Fully reflect a UNS-based, ISA-95-aligned structure,
Dynamically adjust separators and partial paths,
Include converted values, unit information, data types, and rich timestamp data.
This flexible architecture means you can handle any depth of hierarchy, any data format, and multiple time sources, without resorting to clumsy string manipulations or ad-hoc code. As your operation scales or modifies devices and systems, your data remains consistently organized and easily consumable.
Last updated