TrakHound / MTConnect.NET

Fully featured .NET library in C# to build MTConnect Agent, Adapter, and Client Applications. Pre-built Agents with Windows Installers. Support for Windows and Linux. Supports MTConnect Versions up to 2.3. Supports .NET Framework 4.6.1 up to .NET 8

Home Page:http://www.TrakHound.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ObservationInput.ChangeId not unique.

MRIIOT opened this issue · comments

Different DataItems have the same ChangeId. It appears that the ChangeId is calcuated from ObservationInput.Values, in which case, the values for both of these observations are the same.

image

image

image

@MRIIOT Yes it looks like you are correct that the ChangeId property does not include the DataItemKey and wouldn't necessarily be unique across multiple DataItems. I'm not sure if I ever intended it to be unique across DataItems but I could see how that could be useful so I will add the below to the new version (the new version already contains a new property called ChangeIdWithTimestamp):

ObservationInput class

/// <summary>
/// An MD5 Hash of the Observation that can be used for comparison
/// </summary>
public byte[] ChangeId
{
    get
    {
        if (_changeId == null) _changeId = CreateChangeId(this, false);
        return _changeId;
    }
}

/// <summary>
/// An MD5 Hash of the Observation including the Timestamp that can be used for comparison
/// </summary>
public byte[] ChangeIdWithTimestamp
{
    get
    {
        if (_changeIdWithTimestamp == null) _changeIdWithTimestamp = CreateChangeId(this, true);
        return _changeIdWithTimestamp;
    }
}

private static byte[] CreateChangeId(IObservationInput observationInput, bool includeTimestamp)
{
    if (observationInput != null)
    {
        if (observationInput.IsUnavailable) return Observation.Unavailable.ToMD5HashBytes();

        if (!observationInput.Values.IsNullOrEmpty())
        {
            var sb = new StringBuilder();

            // Add DeviceKey (if specified)
            if (!string.IsNullOrEmpty(observationInput.DeviceKey)) sb.Append($"{observationInput.DeviceKey}:::");

            // Add DataItemKey
            sb.Append($"{observationInput.DataItemKey}::");

            // Add Timestamp
            if (includeTimestamp) sb.Append($"timestamp={observationInput.Timestamp}:");

            // Create String with ValueKey=Value segments
            foreach (var value in observationInput.Values) sb.Append($"{value.Key}={value.Value}:");

            // Get Bytes from StringBuilder
            char[] a = new char[sb.Length];
            sb.CopyTo(0, a, 0, sb.Length);

            // Convert StringBuilder result to UTF8 MD5 Bytes
            return _utf8.GetBytes(a).ToMD5HashBytes();
        }
    }

    return null;
}

Usage

using MTConnect;
using MTConnect.Shdr;

var selectedProgram = new ShdrDataItem("f_sim_p1_prg_name_sel", "O1");
var currentProgram = new ShdrDataItem("f_sim_p1_prg_name_cur", "O1");

Console.WriteLine(selectedProgram.ChangeId.ToMD5HashString());
Console.WriteLine(currentProgram.ChangeId.ToMD5HashString());
Console.WriteLine(selectedProgram.ChangeIdWithTimestamp.ToMD5HashString());
Console.WriteLine(currentProgram.ChangeIdWithTimestamp.ToMD5HashString());

Output

b65afdacd38f2f8a1dc6b54be4e3c366
e87ba8b60d085c1d773a72ef2ce722c1
e4da170843aa01338821c42d3a80a30f
a4589821d9005b86ab22a61428407297

Thanks. I was wondering where half my dataitems went. What is the purpose of ObservationInput?

The ObservationInput class is used anytime you are adding data to an MTConnectAgent or you don't know the Type and other information about the DataItem (such as an independent SHDR adapter) as it is essentially just a Key pointing to the DataItemId or Name and a list Values.

ObservationInput differs from the Observation class in that the Observation class has all of the MTConnect properties (Type, Category, Representation, etc) and handles things like validation.

You can see how the ObservationInput class is used to add data to an MTConnectAgent by looking at the MTConnectAgent.AddObservation() method.

ObservationInput is also used as a base class for the ShdrDataItem, ShdrCondition, ShdrTable, etc. classes so they can all be handled similarly.

This should be fixed in the latest v5.0.0 release I just published. Let me know if you find anything else.

Thanks,
-Patrick

Works as expected.