Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e545f2d
docs(testing): seed issue-132 writeup skeleton
ottobolyos Apr 25, 2026
b13df33
docs(testing): scope asset-count dataset-representation defect
ottobolyos Apr 25, 2026
bee83f1
test(common): add red tests for auto-generated assetCount representation
ottobolyos Apr 25, 2026
05d78ee
docs(testing): document red-test matrix for issue-132
ottobolyos Apr 25, 2026
b499e30
docs(testing): document library fix and breaking change for issue-132
ottobolyos Apr 25, 2026
b4d0a3f
test(common): guard asset-count auto-generator vs non-DataSet repr
ottobolyos Apr 25, 2026
0076e9b
docs(testing): document issue-132 regression pin coverage
ottobolyos Apr 25, 2026
6bbef4e
docs(testing): defer issue-132 mqtt e2e to post-bootstrap follow-up
ottobolyos Apr 25, 2026
5ffe200
docs(testing): author issue-132 campaign summary
ottobolyos Apr 25, 2026
b8f21ce
chore(docs): remove internal planning leak from committed tree
ottobolyos Apr 27, 2026
d928089
fix(sysml-import): emit DefaultRepresentation per result-class genera…
ottobolyos May 1, 2026
7ac6ab5
feat(common): re-emit Result-Class DataItems with DATA_SET representa…
ottobolyos May 1, 2026
8b338af
test(common-tests): pin DataItem class-level DATA_SET contracts
ottobolyos May 1, 2026
0e7159d
fix(sysml-import): emit SubTypes enum for Interface DataItems
ottobolyos May 1, 2026
eabde9d
feat(common): re-emit Interface DataItems with REQUEST/RESPONSE subtypes
ottobolyos May 1, 2026
7c42971
test(common-tests): pin Interface DataItem REQUEST/RESPONSE subtype enum
ottobolyos May 1, 2026
90b51e5
fix(common): bump ControllersComponent MinimumVersion to v2.0
ottobolyos May 1, 2026
566b262
fix(sysml-import): route Pallet measurements through MTConnectMeasure…
ottobolyos May 1, 2026
3000897
feat(common): re-emit Pallet measurements with rich TypeId/ctor scaff…
ottobolyos May 1, 2026
8cd8217
test(common-tests): pin Pallet measurement TypeId + ctor contract
ottobolyos May 1, 2026
9a374f4
test(json-cppagent): scaffold project + AssetCount DATA_SET wire-shap…
ottobolyos May 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static MeasurementModel Create(MTConnectMeasurementModel importModel)

public string RenderModel()
{
var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "Assets.Measurement.scriban");
var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "Pallets.Measurement.scriban");
return template.Render(this);
}

Expand Down
33 changes: 25 additions & 8 deletions build/MTConnect.NET-SysML-Import/CSharp/TemplateRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,14 @@ public static void Render(MTConnectModel mtconnectModel, string outputPath)
else if (typeof(MTConnectCompositionType).IsAssignableFrom(type)) template = CompositionType.Create((MTConnectCompositionType)exportModel);
else if (typeof(MTConnectComponentType).IsAssignableFrom(type))
{
if (((MTConnectComponentType)exportModel).Type == "Controllers") ((MTConnectComponentType)exportModel).MinimumVersion = new Version(1, 0);
// Surface the SysML-declared introduction year
// for every Component, including the Controllers
// organizer AssociationClass (introduced='2.0').
// The earlier override that hard-coded Controllers
// to v1.0 contradicted the spec — the
// `Profile:normative introduced='2.0'` record
// on the Controllers UML AssociationClass is the
// authoritative source.
template = ComponentType.Create((MTConnectComponentType)exportModel);
}
else if (typeof(MTConnectMeasurementModel).IsAssignableFrom(type))
Expand All @@ -101,15 +108,15 @@ public static void Render(MTConnectModel mtconnectModel, string outputPath)
{
template = CuttingToolMeasurementModel.Create((MTConnectMeasurementModel)exportModel);
}
else
else if (exportModel.Id?.StartsWith("Assets.Pallet.") == true)
{
// Non-CuttingTools measurement (e.g. Assets.Pallet.*) — no fallback
// template exists yet, so log and continue rather than silently
// dropping the model.
Console.Error.WriteLine(
$"warn: MeasurementModel '{exportModel.Id}' has no template — " +
"only Assets.CuttingTools.* is currently rendered. Skipping.");
template = MeasurementModel.Create((MTConnectMeasurementModel)exportModel);
}
// No fallback: every measurement in the v2.x SysML routes
// through one of the two prefixes above. A future model
// adding a third measurement package will surface here as a
// null template (NullReferenceException downstream) — preferable
// to a silent drop with a stderr warning that nothing watches.
}
else if (typeof(MTConnectClassModel).IsAssignableFrom(type) && exportModel.Id?.EndsWith("Result") == true)
{
Expand Down Expand Up @@ -193,6 +200,16 @@ public static void Render(MTConnectModel mtconnectModel, string outputPath)
((ClassModel)template).IsPartial = true;
((ClassModel)template).IsAbstract = false;
break;
case "Assets.Pallet.Measurement":
// Partial + concrete so a hand-written
// partial can supply the `Type` property
// and the `Measurement(IMeasurement)` ctor
// that the per-subtype rich template
// (`Pallets.Measurement.scriban`) chains
// to via `: base(measurement)`.
((ClassModel)template).IsPartial = true;
((ClassModel)template).IsAbstract = false;
break;
}

templates.Add(template);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,89 @@ namespace MTConnect.Interfaces
public const DataItemCategory CategoryId = DataItemCategory.{{category}};
public const string TypeId = "{{type}}";
public const string NameId = "{{default_name}}";
{{ if (units_enum) }}public const string DefaultUnits = {{units_enum}};{{ end }}
{{ if (units_enum) }}public const string DefaultUnits = {{units_enum}};{{ end }}
public new const string DescriptionText = "{{description}}";

public override string TypeDescription => DescriptionText;
{{ if (maximum_version_enum) }}public override System.Version MaximumVersion => {{maximum_version_enum}};{{ end }}
{{ if (minimum_version_enum) }}public override System.Version MinimumVersion => {{minimum_version_enum}};{{ end }}
{{ if (minimum_version_enum) }}public override System.Version MinimumVersion => {{minimum_version_enum}};{{ end }}

{{ if ((sub_types | array.size) > 0) }}{{ i = 0 }}
public new enum SubTypes
{
{{- for sub_type in sub_types }}{{ i = i + 1 }}
/// <summary>
/// {{sub_type.description}}
/// </summary>
{{sub_type.name}}
{{- if (i < (sub_types | array.size)) }},
{{ end }}
{{- end }}
}

{{ end }}
public {{name}}()
{
Category = CategoryId;
Type = TypeId;
{{ if (units_enum) }}Units = DefaultUnits;{{ end }}
}

{{- if ((sub_types | array.size) > 0) }}

public {{name}}(
string parentId,
SubTypes subType
)
{
Id = CreateId(parentId, NameId, GetSubTypeId(subType));
Category = CategoryId;
Type = TypeId;
SubType = subType.ToString();
Name = NameId;
{{ if (units_enum) }}Units = DefaultUnits;{{ end }}
}

public override string SubTypeDescription => GetSubTypeDescription(SubType);

{{- if ((sub_types | array.size) > 0) }}{{ i = 0 }}

public new static string GetSubTypeDescription(string subType)
{
var s = subType.ConvertEnum<SubTypes>();
switch (s)
{
{{- for sub_type in sub_types }}{{ i = i + 1 }}
case SubTypes.{{sub_type.name}}: return "{{sub_type.description}}";
{{- end }}
}

return null;
}
{{- end }}
{{- if ((sub_types | array.size) > 0) }}{{ i = 0 }}

public new static string GetSubTypeId(SubTypes subType)
{
switch (subType)
{
{{- for sub_type in sub_types }}{{ i = i + 1 }}
case SubTypes.{{sub_type.name}}: return "{{sub_type.name}}";
{{- end }}
}

return null;
}
{{- end }}
{{ else }}

public {{name}}(string deviceId)
{
Id = CreateId(deviceId, NameId);
Category = CategoryId;
Type = TypeId;
Name = NameId;
}
{{- end }}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright (c) 2025 TrakHound Inc., All Rights Reserved.
// TrakHound Inc. licenses this file to you under the MIT license.

namespace MTConnect.Assets.Pallet.Measurements
namespace {{namespace}}
{
/// <summary>
/// {{description}}
/// </summary>
public class {{name}} : Measurement
public class {{name}} : Measurement, I{{name}}
{
public const string TypeId = "{{type_id}}";
public const string CodeId = "{{code_id}}";
Expand All @@ -15,22 +15,19 @@ namespace MTConnect.Assets.Pallet.Measurements
public {{name}}()
{
Type = TypeId;
Code = CodeId;
{{ if (units_enum) }}Units = {{units_enum}};{{ end }}
}

public {{name}}(double value)
{
Type = TypeId;
Code = CodeId;
Value = value;
{{ if (units_enum) }}Units = {{units_enum}};{{ end }}
}

public {{name}}(IMeasurement measurement) : base(measurement)
{
Type = TypeId;
Code = CodeId;
{{ if (units_enum) }}Units = {{units_enum}};{{ end }}
}
}
Expand Down
5 changes: 0 additions & 5 deletions libraries/MTConnect.NET-Common/Agents/MTConnectAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1171,11 +1171,6 @@ private Device NormalizeDevice(IDevice device)
assetcount.Device = obj;
assetcount.Container = obj;
assetcount.Name = AssetCountDataItem.NameId;
// ASSET_COUNT is a DATA_SET representation per MTConnect Part 2
// (UML _19_0_3_68e0225_1640602520420_217627_44). The generated
// AssetCountDataItem still defaults Representation to VALUE; override
// it here so the auto-injected DataItem matches the spec.
assetcount.Representation = DataItemRepresentation.DATA_SET;
dataItemList.Add(assetcount);
dataItemTypes.Add(AssetCountDataItem.TypeId);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) 2024 TrakHound Inc., All Rights Reserved.
// Copyright (c) 2025 TrakHound Inc., All Rights Reserved.
// TrakHound Inc. licenses this file to you under the MIT license.

// MTConnect SysML v2.3 : UML ID = _2024x_68e0225_1727795946018_306044_24580

namespace MTConnect.Assets.Pallet
{
/// <summary>
Expand All @@ -11,7 +9,27 @@ namespace MTConnect.Assets.Pallet
public class HeightMeasurement : Measurement, IHeightMeasurement
{
public new const string DescriptionText = "Height of the PhysicalAsset";
public const string TypeId = "Height";
public const string CodeId = "";


public HeightMeasurement()
{
Type = TypeId;

}

public HeightMeasurement(double value)
{
Type = TypeId;
Value = value;

}

public HeightMeasurement(IMeasurement measurement) : base(measurement)
{
Type = TypeId;

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace MTConnect.Assets.Pallet
/// <summary>
/// Constrained scalar value associated with an Asset
/// </summary>
public interface IMeasurement
public partial interface IMeasurement
{
/// <summary>
/// Maximum value for the measurement.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) 2024 TrakHound Inc., All Rights Reserved.
// Copyright (c) 2025 TrakHound Inc., All Rights Reserved.
// TrakHound Inc. licenses this file to you under the MIT license.

// MTConnect SysML v2.3 : UML ID = _2024x_68e0225_1727795955654_438848_24650

namespace MTConnect.Assets.Pallet
{
/// <summary>
Expand All @@ -11,7 +9,27 @@ namespace MTConnect.Assets.Pallet
public class LengthMeasurement : Measurement, ILengthMeasurement
{
public new const string DescriptionText = "Length of the PhysicalAsset";
public const string TypeId = "Length";
public const string CodeId = "";


public LengthMeasurement()
{
Type = TypeId;

}

public LengthMeasurement(double value)
{
Type = TypeId;
Value = value;

}

public LengthMeasurement(IMeasurement measurement) : base(measurement)
{
Type = TypeId;

}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) 2024 TrakHound Inc., All Rights Reserved.
// Copyright (c) 2025 TrakHound Inc., All Rights Reserved.
// TrakHound Inc. licenses this file to you under the MIT license.

// MTConnect SysML v2.3 : UML ID = _2024x_68e0225_1727795985316_21813_24755

namespace MTConnect.Assets.Pallet
{
/// <summary>
Expand All @@ -11,7 +9,27 @@ namespace MTConnect.Assets.Pallet
public class LoadedHeightMeasurement : Measurement, ILoadedHeightMeasurement
{
public new const string DescriptionText = "Loaded height of the PhysicalAsset";
public const string TypeId = "LoadedHeight";
public const string CodeId = "";


public LoadedHeightMeasurement()
{
Type = TypeId;

}

public LoadedHeightMeasurement(double value)
{
Type = TypeId;
Value = value;

}

public LoadedHeightMeasurement(IMeasurement measurement) : base(measurement)
{
Type = TypeId;

}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) 2024 TrakHound Inc., All Rights Reserved.
// Copyright (c) 2025 TrakHound Inc., All Rights Reserved.
// TrakHound Inc. licenses this file to you under the MIT license.

// MTConnect SysML v2.3 : UML ID = _2024x_68e0225_1727796000098_310953_24825

namespace MTConnect.Assets.Pallet
{
/// <summary>
Expand All @@ -11,7 +9,27 @@ namespace MTConnect.Assets.Pallet
public class LoadedLengthMeasurement : Measurement, ILoadedLengthMeasurement
{
public new const string DescriptionText = "Loaded length of the PhysicalAsset";
public const string TypeId = "LoadedLength";
public const string CodeId = "";


public LoadedLengthMeasurement()
{
Type = TypeId;

}

public LoadedLengthMeasurement(double value)
{
Type = TypeId;
Value = value;

}

public LoadedLengthMeasurement(IMeasurement measurement) : base(measurement)
{
Type = TypeId;

}
}
}
Loading
Loading