Skip to content

Commit 6a19ab2

Browse files
Merge branch 'shdr-local-timestamps-output'
2 parents 78bc351 + 89a66a6 commit 6a19ab2

13 files changed

Lines changed: 186 additions & 115 deletions

File tree

adapter/MTConnect.NET-Adapter/DataSource.cs

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ protected override void OnRead()
5050
var rnd = new Random();
5151
var ts = DateTime.Now;
5252

53-
//AddObservation("Xload", x, ts);
54-
//AddObservation("Yload", x, ts);
55-
//AddObservation("Zload", x, ts);
53+
AddObservation("Xload", x, ts);
54+
AddObservation("Yload", x, ts);
55+
AddObservation("Zload", x, ts);
5656

5757

5858
//var datasetEntries = new List<IDataSetEntry>();
@@ -90,7 +90,7 @@ protected override void OnRead()
9090
//AddObservation(timeSeries);
9191

9292

93-
////app.DataSource.AddAsset(CuttingTool(device.Uuid, j));
93+
//AddAsset(new CuttingToolAsset(j));
9494
//j += 23.3455;
9595

9696

@@ -102,35 +102,35 @@ protected override void OnRead()
102102
//app.DataSource.AddDevice(device2);
103103

104104

105-
var warning = new ConditionFaultStateObservationInput("L2p1system", Observations.ConditionLevel.WARNING, ts);
106-
warning.ConditionId = "asdfjkl";
107-
warning.NativeCode = "404";
108-
warning.Message = "Not Found";
109-
warning.Qualifier = Observations.ConditionQualifier.LOW;
110-
AddObservation(warning);
111-
112-
//switch (i)
113-
//{
114-
// case 0:
115-
// var warning = new ConditionFaultStateObservationInput("L2p1system", Observations.ConditionLevel.WARNING, ts);
116-
// warning.NativeCode = "404";
117-
// warning.Message = "Not Found";
118-
// warning.Qualifier = Observations.ConditionQualifier.LOW;
119-
// app.DataSource.AddObservation(warning);
120-
// break;
121-
122-
// case 1:
123-
// var fault = new ConditionFaultStateObservationInput("L2p1system", Observations.ConditionLevel.FAULT, ts);
124-
// fault.NativeCode = "400";
125-
// fault.Message = "Bad Request";
126-
// app.DataSource.AddObservation(fault);
127-
// break;
128-
129-
// case 2:
130-
// var condition = new ConditionFaultStateObservationInput("L2p1system", Observations.ConditionLevel.NORMAL, ts);
131-
// app.DataSource.AddObservation(condition);
132-
// break;
133-
//}
105+
//var warning = new ConditionFaultStateObservationInput("L2p1system", Observations.ConditionLevel.WARNING, ts);
106+
//warning.ConditionId = "asdfjkl";
107+
//warning.NativeCode = "404";
108+
//warning.Message = "Not Found";
109+
//warning.Qualifier = Observations.ConditionQualifier.LOW;
110+
//AddObservation(warning);
111+
112+
switch (i)
113+
{
114+
case 0:
115+
var warning = new ConditionFaultStateObservationInput("L2p1system", Observations.ConditionLevel.WARNING, ts);
116+
warning.NativeCode = "404";
117+
warning.Message = "Not Found";
118+
warning.Qualifier = Observations.ConditionQualifier.LOW;
119+
AddObservation(warning);
120+
break;
121+
122+
case 1:
123+
var fault = new ConditionFaultStateObservationInput("L2p1system", Observations.ConditionLevel.FAULT, ts);
124+
fault.NativeCode = "400";
125+
fault.Message = "Bad Request";
126+
AddObservation(fault);
127+
break;
128+
129+
case 2:
130+
var condition = new ConditionFaultStateObservationInput("L2p1system", Observations.ConditionLevel.NORMAL, ts);
131+
AddObservation(condition);
132+
break;
133+
}
134134

135135
x++;
136136
i++;

adapter/MTConnect.NET-Adapter/MTConnect.NET-Adapter.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
</ItemGroup>
3232

3333
<ItemGroup>
34+
<None Update="adapter.config.yaml">
35+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
36+
</None>
3437
<None Update="adapter.config.default.yaml">
3538
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
3639
</None>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
id: PatrickAdapter
2+
deviceKey: OKUMA-Lathe
3+
4+
modules:
5+
6+
- shdr:
7+
port: 7878
8+
timeZoneOutput: ET
9+
10+
- mqtt:
11+
server: localhost
12+
port: 1883

adapter/Modules/MTConnect.NET-AdapterModule-SHDR/Module.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class Module : MTConnectAdapterModule
2222

2323
private readonly object _lock = new object();
2424
private readonly ModuleConfiguration _configuration;
25+
private readonly TimeZoneInfo _timeZoneInfo;
2526
private readonly AgentClientConnectionListener _connectionListener;
2627
private readonly Dictionary<string, AgentClient> _clients = new Dictionary<string, AgentClient>();
2728
private CancellationTokenSource _stop;
@@ -34,6 +35,8 @@ public Module(string id, object moduleConfiguration) : base(id)
3435
_configuration = AdapterApplicationConfiguration.GetConfiguration<ModuleConfiguration>(moduleConfiguration);
3536
if (_configuration == null) _configuration = new ModuleConfiguration();
3637

38+
_timeZoneInfo = GetTimeZone(_configuration);
39+
3740
_connectionListener = new AgentClientConnectionListener(_configuration.Port, _configuration.Heartbeat);
3841
_connectionListener.ClientConnected += AgentClientConnected;
3942
_connectionListener.ClientDisconnected += AgentClientDisconnected;
@@ -66,8 +69,12 @@ public override bool AddObservations(IEnumerable<IObservationInput> observations
6669
if (!dataItems.IsNullOrEmpty())
6770
{
6871
var shdrDataItems = new List<ShdrDataItem>();
69-
foreach (var x in dataItems) shdrDataItems.Add(new ShdrDataItem(x));
70-
var shdrLine = ShdrDataItem.ToString(shdrDataItems);
72+
foreach (var x in dataItems)
73+
{
74+
shdrDataItems.Add(new ShdrDataItem(x));
75+
}
76+
77+
var shdrLine = ShdrDataItem.ToString(shdrDataItems, timeZoneInfo: _timeZoneInfo);
7178
WriteLine(shdrLine);
7279
}
7380

@@ -78,6 +85,8 @@ public override bool AddObservations(IEnumerable<IObservationInput> observations
7885
foreach (var x in messages)
7986
{
8087
var shdrModel = new ShdrMessage(x);
88+
shdrModel.TimeZoneInfo = _timeZoneInfo;
89+
8190
var shdrLine = shdrModel.ToString();
8291
WriteLine(shdrLine);
8392
}
@@ -90,6 +99,8 @@ public override bool AddObservations(IEnumerable<IObservationInput> observations
9099
foreach (var x in conditions)
91100
{
92101
var shdrModel = new ShdrFaultState(new ConditionFaultStateObservationInput(x));
102+
shdrModel.TimeZoneInfo = _timeZoneInfo;
103+
93104
var shdrLine = shdrModel.ToString();
94105
WriteLine(shdrLine);
95106
}
@@ -102,6 +113,8 @@ public override bool AddObservations(IEnumerable<IObservationInput> observations
102113
foreach (var x in dataSets)
103114
{
104115
var shdrModel = new ShdrDataSet(new DataSetObservationInput(x));
116+
shdrModel.TimeZoneInfo = _timeZoneInfo;
117+
105118
var shdrLine = shdrModel.ToString();
106119
WriteLine(shdrLine);
107120
}
@@ -114,6 +127,8 @@ public override bool AddObservations(IEnumerable<IObservationInput> observations
114127
foreach (var x in tables)
115128
{
116129
var shdrModel = new ShdrTable(new TableObservationInput(x));
130+
shdrModel.TimeZoneInfo = _timeZoneInfo;
131+
117132
var shdrLine = shdrModel.ToString();
118133
WriteLine(shdrLine);
119134
}
@@ -126,6 +141,8 @@ public override bool AddObservations(IEnumerable<IObservationInput> observations
126141
foreach (var x in timeSeries)
127142
{
128143
var shdrModel = new ShdrTimeSeries(new TimeSeriesObservationInput(x));
144+
shdrModel.TimeZoneInfo = _timeZoneInfo;
145+
129146
var shdrLine = shdrModel.ToString();
130147
WriteLine(shdrLine);
131148
}
@@ -359,5 +376,27 @@ private static IEnumerable<string> SplitLines(string line)
359376

360377
#endregion
361378

379+
380+
private static TimeZoneInfo GetTimeZone(ModuleConfiguration configuration)
381+
{
382+
if (configuration != null)
383+
{
384+
if (!string.IsNullOrEmpty(configuration.TimeZoneOutput))
385+
{
386+
var timeZoneDefinition = MTConnectTimeZone.Get(configuration.TimeZoneOutput);
387+
if (timeZoneDefinition != null)
388+
{
389+
var timeZoneInfo = timeZoneDefinition.ToTimeZoneInfo();
390+
if (timeZoneInfo != null)
391+
{
392+
return timeZoneInfo;
393+
}
394+
}
395+
}
396+
}
397+
398+
return TimeZoneInfo.Utc;
399+
}
400+
362401
}
363402
}

adapter/Modules/MTConnect.NET-AdapterModule-SHDR/ModuleConfiguration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public class ModuleConfiguration
3232
/// </summary>
3333
public int ReconnectInterval { get; set; }
3434

35+
/// <summary>
36+
/// Sets the TimeZone to use when timestamps are output from the Agent
37+
/// </summary>
38+
public string TimeZoneOutput { get; set; }
39+
3540

3641
public ModuleConfiguration()
3742
{
@@ -40,6 +45,7 @@ public ModuleConfiguration()
4045
Heartbeat = 10000;
4146
ConnectionTimeout = 5000;
4247
ReconnectInterval = 10000;
48+
TimeZoneOutput = "Z";
4349
}
4450
}
4551
}

libraries/MTConnect.NET-Common/Input/ObservationInput.cs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2023 TrakHound Inc., All Rights Reserved.
1+
// Copyright (c) 2025 TrakHound Inc., All Rights Reserved.
22
// TrakHound Inc. licenses this file to you under the MIT license.
33

44
using MTConnect.Observations;
@@ -40,6 +40,11 @@ public class ObservationInput : IObservationInput
4040
/// </summary>
4141
public long Timestamp { get; set; }
4242

43+
/// <summary>
44+
/// The TimeZone that is configured to Output
45+
/// </summary>
46+
public TimeZoneInfo TimeZoneInfo { get; set; }
47+
4348
/// <summary>
4449
/// The frequency at which the values were observed at
4550
/// </summary>
@@ -255,5 +260,43 @@ private static byte[] CreateChangeId(IObservationInput observationInput, bool in
255260

256261
return null;
257262
}
263+
264+
protected static string GetTimestampString(long timestamp, double duration = 0, TimeZoneInfo timeZoneInfo = null)
265+
{
266+
if (timestamp > 0)
267+
{
268+
var dateTime = timestamp.ToDateTime();
269+
var dateTimeOffset = MTConnectTimeZone.GetTimestamp(dateTime, timeZoneInfo);
270+
271+
if (dateTimeOffset.Offset != TimeSpan.Zero)
272+
{
273+
if (duration > 0)
274+
{
275+
return $"{dateTimeOffset.ToString("o")}@{duration}";
276+
}
277+
else
278+
{
279+
return dateTimeOffset.ToString("o");
280+
}
281+
}
282+
else
283+
{
284+
if (duration > 0)
285+
{
286+
return $"{dateTimeOffset.UtcDateTime.ToString("o")}@{duration}";
287+
}
288+
else
289+
{
290+
return dateTimeOffset.UtcDateTime.ToString("o");
291+
}
292+
}
293+
}
294+
else if (duration > 0)
295+
{
296+
return $"@{duration}";
297+
}
298+
299+
return null;
300+
}
258301
}
259302
}

libraries/MTConnect.NET-SHDR/Shdr/ShdrAsset.cs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ public class ShdrAsset
6767
/// </summary>
6868
public long Timestamp { get; set; }
6969

70+
/// <summary>
71+
/// The TimeZone that is configured to Output
72+
/// </summary>
73+
public TimeZoneInfo TimeZoneInfo { get; set; }
74+
7075

7176
private byte[] changeId;
7277
/// <summary>
@@ -156,7 +161,7 @@ public string ToString(bool multiline = false)
156161
var multilineId = StringFunctions.RandomString(10);
157162

158163
var header = $"|{AssetDesignator}|{AssetId}|{AssetType}|--multiline--{multilineId}";
159-
if (Timestamp > 0) header = $"{Timestamp.ToDateTime().ToString("o")}{header}";
164+
if (Timestamp > 0) header = $"{GetTimestampString(Timestamp, timeZoneInfo: TimeZoneInfo)}{header}";
160165

161166
var xml = XmlFunctions.FormatXml(Xml, true, false, true);
162167

@@ -169,21 +174,21 @@ public string ToString(bool multiline = false)
169174
}
170175
else
171176
{
172-
if (Timestamp > 0) return $"{Timestamp.ToDateTime().ToString("o")}|{AssetDesignator}|{AssetId}|{AssetType}|{Xml}";
177+
if (Timestamp > 0) return $"{GetTimestampString(Timestamp, timeZoneInfo: TimeZoneInfo)}|{AssetDesignator}|{AssetId}|{AssetType}|{Xml}";
173178
else return $"|{AssetDesignator}|{AssetId}|{AssetType}|{Xml}";
174179
}
175180
}
176181

177182
return null;
178183
}
179184

180-
private static string ToString(ShdrAsset asset, bool ignoreTimestamp = false)
185+
private static string ToString(ShdrAsset asset, bool ignoreTimestamp = false, TimeZoneInfo timeZoneInfo = null)
181186
{
182187
if (asset != null && !string.IsNullOrEmpty(asset.AssetId) && !string.IsNullOrEmpty(asset.Xml))
183188
{
184189
if (asset.Timestamp > 0 && !ignoreTimestamp)
185190
{
186-
return $"{asset.Timestamp.ToDateTime().ToString("o")}|{AssetDesignator}|{asset.AssetId}|{asset.AssetType}|{asset.Xml}";
191+
return $"{GetTimestampString(asset.Timestamp, timeZoneInfo: timeZoneInfo)}|{AssetDesignator}|{asset.AssetId}|{asset.AssetType}|{asset.Xml}";
187192
}
188193
else
189194
{
@@ -597,5 +602,26 @@ private static ShdrAsset FromLine(string input, long timestamp = 0)
597602
}
598603

599604
#endregion
605+
606+
607+
protected static string GetTimestampString(long timestamp, TimeZoneInfo timeZoneInfo = null)
608+
{
609+
if (timestamp > 0)
610+
{
611+
var dateTime = timestamp.ToDateTime();
612+
var dateTimeOffset = MTConnectTimeZone.GetTimestamp(dateTime, timeZoneInfo);
613+
614+
if (dateTimeOffset.Offset != TimeSpan.Zero)
615+
{
616+
return dateTimeOffset.ToString("o");
617+
}
618+
else
619+
{
620+
return dateTimeOffset.UtcDateTime.ToString("o");
621+
}
622+
}
623+
624+
return null;
625+
}
600626
}
601627
}

0 commit comments

Comments
 (0)