diff --git a/src/ScadaLink.Communication/Protos/sitestream.proto b/src/ScadaLink.Communication/Protos/sitestream.proto
new file mode 100644
index 0000000..0d0ebe0
--- /dev/null
+++ b/src/ScadaLink.Communication/Protos/sitestream.proto
@@ -0,0 +1,52 @@
+syntax = "proto3";
+option csharp_namespace = "ScadaLink.Communication.Grpc";
+package sitestream;
+
+import "google/protobuf/timestamp.proto";
+
+service SiteStreamService {
+ rpc SubscribeInstance(InstanceStreamRequest) returns (stream SiteStreamEvent);
+}
+
+message InstanceStreamRequest {
+ string correlation_id = 1;
+ string instance_unique_name = 2;
+}
+
+message SiteStreamEvent {
+ string correlation_id = 1;
+ oneof event {
+ AttributeValueUpdate attribute_changed = 2;
+ AlarmStateUpdate alarm_changed = 3;
+ }
+}
+
+enum Quality {
+ QUALITY_UNSPECIFIED = 0;
+ QUALITY_GOOD = 1;
+ QUALITY_UNCERTAIN = 2;
+ QUALITY_BAD = 3;
+}
+
+enum AlarmStateEnum {
+ ALARM_STATE_UNSPECIFIED = 0;
+ ALARM_STATE_NORMAL = 1;
+ ALARM_STATE_ACTIVE = 2;
+}
+
+message AttributeValueUpdate {
+ string instance_unique_name = 1;
+ string attribute_path = 2;
+ string attribute_name = 3;
+ string value = 4;
+ Quality quality = 5;
+ google.protobuf.Timestamp timestamp = 6;
+}
+
+message AlarmStateUpdate {
+ string instance_unique_name = 1;
+ string alarm_name = 2;
+ AlarmStateEnum state = 3;
+ int32 priority = 4;
+ google.protobuf.Timestamp timestamp = 5;
+}
diff --git a/src/ScadaLink.Communication/ScadaLink.Communication.csproj b/src/ScadaLink.Communication/ScadaLink.Communication.csproj
index 30d0b03..0d77342 100644
--- a/src/ScadaLink.Communication/ScadaLink.Communication.csproj
+++ b/src/ScadaLink.Communication/ScadaLink.Communication.csproj
@@ -7,15 +7,18 @@
true
+
+
+
+
-
-
-
-
+
+
+
diff --git a/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs b/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs
new file mode 100644
index 0000000..4eb8b44
--- /dev/null
+++ b/src/ScadaLink.Communication/SiteStreamGrpc/Sitestream.cs
@@ -0,0 +1,1396 @@
+//
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: sitestream.proto
+//
+#pragma warning disable 1591, 0612, 3021, 8981
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace ScadaLink.Communication.Grpc {
+
+ /// Holder for reflection information generated from sitestream.proto
+ public static partial class SitestreamReflection {
+
+ #region Descriptor
+ /// File descriptor for sitestream.proto
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static SitestreamReflection() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "ChBzaXRlc3RyZWFtLnByb3RvEgpzaXRlc3RyZWFtGh9nb29nbGUvcHJvdG9i",
+ "dWYvdGltZXN0YW1wLnByb3RvIk0KFUluc3RhbmNlU3RyZWFtUmVxdWVzdBIW",
+ "Cg5jb3JyZWxhdGlvbl9pZBgBIAEoCRIcChRpbnN0YW5jZV91bmlxdWVfbmFt",
+ "ZRgCIAEoCSKoAQoPU2l0ZVN0cmVhbUV2ZW50EhYKDmNvcnJlbGF0aW9uX2lk",
+ "GAEgASgJEj0KEWF0dHJpYnV0ZV9jaGFuZ2VkGAIgASgLMiAuc2l0ZXN0cmVh",
+ "bS5BdHRyaWJ1dGVWYWx1ZVVwZGF0ZUgAEjUKDWFsYXJtX2NoYW5nZWQYAyAB",
+ "KAsyHC5zaXRlc3RyZWFtLkFsYXJtU3RhdGVVcGRhdGVIAEIHCgVldmVudCLI",
+ "AQoUQXR0cmlidXRlVmFsdWVVcGRhdGUSHAoUaW5zdGFuY2VfdW5pcXVlX25h",
+ "bWUYASABKAkSFgoOYXR0cmlidXRlX3BhdGgYAiABKAkSFgoOYXR0cmlidXRl",
+ "X25hbWUYAyABKAkSDQoFdmFsdWUYBCABKAkSJAoHcXVhbGl0eRgFIAEoDjIT",
+ "LnNpdGVzdHJlYW0uUXVhbGl0eRItCgl0aW1lc3RhbXAYBiABKAsyGi5nb29n",
+ "bGUucHJvdG9idWYuVGltZXN0YW1wIrABChBBbGFybVN0YXRlVXBkYXRlEhwK",
+ "FGluc3RhbmNlX3VuaXF1ZV9uYW1lGAEgASgJEhIKCmFsYXJtX25hbWUYAiAB",
+ "KAkSKQoFc3RhdGUYAyABKA4yGi5zaXRlc3RyZWFtLkFsYXJtU3RhdGVFbnVt",
+ "EhAKCHByaW9yaXR5GAQgASgFEi0KCXRpbWVzdGFtcBgFIAEoCzIaLmdvb2ds",
+ "ZS5wcm90b2J1Zi5UaW1lc3RhbXAqXAoHUXVhbGl0eRIXChNRVUFMSVRZX1VO",
+ "U1BFQ0lGSUVEEAASEAoMUVVBTElUWV9HT09EEAESFQoRUVVBTElUWV9VTkNF",
+ "UlRBSU4QAhIPCgtRVUFMSVRZX0JBRBADKl0KDkFsYXJtU3RhdGVFbnVtEhsK",
+ "F0FMQVJNX1NUQVRFX1VOU1BFQ0lGSUVEEAASFgoSQUxBUk1fU1RBVEVfTk9S",
+ "TUFMEAESFgoSQUxBUk1fU1RBVEVfQUNUSVZFEAIyagoRU2l0ZVN0cmVhbVNl",
+ "cnZpY2USVQoRU3Vic2NyaWJlSW5zdGFuY2USIS5zaXRlc3RyZWFtLkluc3Rh",
+ "bmNlU3RyZWFtUmVxdWVzdBobLnNpdGVzdHJlYW0uU2l0ZVN0cmVhbUV2ZW50",
+ "MAFCH6oCHFNjYWRhTGluay5Db21tdW5pY2F0aW9uLkdycGNiBnByb3RvMw=="));
+ descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+ new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, },
+ new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ScadaLink.Communication.Grpc.Quality), typeof(global::ScadaLink.Communication.Grpc.AlarmStateEnum), }, null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.InstanceStreamRequest), global::ScadaLink.Communication.Grpc.InstanceStreamRequest.Parser, new[]{ "CorrelationId", "InstanceUniqueName" }, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.SiteStreamEvent), global::ScadaLink.Communication.Grpc.SiteStreamEvent.Parser, new[]{ "CorrelationId", "AttributeChanged", "AlarmChanged" }, new[]{ "Event" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AttributeValueUpdate), global::ScadaLink.Communication.Grpc.AttributeValueUpdate.Parser, new[]{ "InstanceUniqueName", "AttributePath", "AttributeName", "Value", "Quality", "Timestamp" }, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AlarmStateUpdate), global::ScadaLink.Communication.Grpc.AlarmStateUpdate.Parser, new[]{ "InstanceUniqueName", "AlarmName", "State", "Priority", "Timestamp" }, null, null, null, null)
+ }));
+ }
+ #endregion
+
+ }
+ #region Enums
+ public enum Quality {
+ [pbr::OriginalName("QUALITY_UNSPECIFIED")] Unspecified = 0,
+ [pbr::OriginalName("QUALITY_GOOD")] Good = 1,
+ [pbr::OriginalName("QUALITY_UNCERTAIN")] Uncertain = 2,
+ [pbr::OriginalName("QUALITY_BAD")] Bad = 3,
+ }
+
+ public enum AlarmStateEnum {
+ [pbr::OriginalName("ALARM_STATE_UNSPECIFIED")] AlarmStateUnspecified = 0,
+ [pbr::OriginalName("ALARM_STATE_NORMAL")] AlarmStateNormal = 1,
+ [pbr::OriginalName("ALARM_STATE_ACTIVE")] AlarmStateActive = 2,
+ }
+
+ #endregion
+
+ #region Messages
+ [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")]
+ public sealed partial class InstanceStreamRequest : pb::IMessage
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new InstanceStreamRequest());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ScadaLink.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[0]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public InstanceStreamRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public InstanceStreamRequest(InstanceStreamRequest other) : this() {
+ correlationId_ = other.correlationId_;
+ instanceUniqueName_ = other.instanceUniqueName_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public InstanceStreamRequest Clone() {
+ return new InstanceStreamRequest(this);
+ }
+
+ /// Field number for the "correlation_id" field.
+ public const int CorrelationIdFieldNumber = 1;
+ private string correlationId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string CorrelationId {
+ get { return correlationId_; }
+ set {
+ correlationId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "instance_unique_name" field.
+ public const int InstanceUniqueNameFieldNumber = 2;
+ private string instanceUniqueName_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string InstanceUniqueName {
+ get { return instanceUniqueName_; }
+ set {
+ instanceUniqueName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as InstanceStreamRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(InstanceStreamRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (CorrelationId != other.CorrelationId) return false;
+ if (InstanceUniqueName != other.InstanceUniqueName) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (CorrelationId.Length != 0) hash ^= CorrelationId.GetHashCode();
+ if (InstanceUniqueName.Length != 0) hash ^= InstanceUniqueName.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (CorrelationId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(CorrelationId);
+ }
+ if (InstanceUniqueName.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(InstanceUniqueName);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (CorrelationId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(CorrelationId);
+ }
+ if (InstanceUniqueName.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(InstanceUniqueName);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (CorrelationId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(CorrelationId);
+ }
+ if (InstanceUniqueName.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(InstanceUniqueName);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(InstanceStreamRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.CorrelationId.Length != 0) {
+ CorrelationId = other.CorrelationId;
+ }
+ if (other.InstanceUniqueName.Length != 0) {
+ InstanceUniqueName = other.InstanceUniqueName;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ if ((tag & 7) == 4) {
+ // Abort on any end group tag.
+ return;
+ }
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ CorrelationId = input.ReadString();
+ break;
+ }
+ case 18: {
+ InstanceUniqueName = input.ReadString();
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ if ((tag & 7) == 4) {
+ // Abort on any end group tag.
+ return;
+ }
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 10: {
+ CorrelationId = input.ReadString();
+ break;
+ }
+ case 18: {
+ InstanceUniqueName = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ }
+
+ [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")]
+ public sealed partial class SiteStreamEvent : pb::IMessage
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SiteStreamEvent());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ScadaLink.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[1]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public SiteStreamEvent() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public SiteStreamEvent(SiteStreamEvent other) : this() {
+ correlationId_ = other.correlationId_;
+ switch (other.EventCase) {
+ case EventOneofCase.AttributeChanged:
+ AttributeChanged = other.AttributeChanged.Clone();
+ break;
+ case EventOneofCase.AlarmChanged:
+ AlarmChanged = other.AlarmChanged.Clone();
+ break;
+ }
+
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public SiteStreamEvent Clone() {
+ return new SiteStreamEvent(this);
+ }
+
+ /// Field number for the "correlation_id" field.
+ public const int CorrelationIdFieldNumber = 1;
+ private string correlationId_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string CorrelationId {
+ get { return correlationId_; }
+ set {
+ correlationId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "attribute_changed" field.
+ public const int AttributeChangedFieldNumber = 2;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ScadaLink.Communication.Grpc.AttributeValueUpdate AttributeChanged {
+ get { return eventCase_ == EventOneofCase.AttributeChanged ? (global::ScadaLink.Communication.Grpc.AttributeValueUpdate) event_ : null; }
+ set {
+ event_ = value;
+ eventCase_ = value == null ? EventOneofCase.None : EventOneofCase.AttributeChanged;
+ }
+ }
+
+ /// Field number for the "alarm_changed" field.
+ public const int AlarmChangedFieldNumber = 3;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ScadaLink.Communication.Grpc.AlarmStateUpdate AlarmChanged {
+ get { return eventCase_ == EventOneofCase.AlarmChanged ? (global::ScadaLink.Communication.Grpc.AlarmStateUpdate) event_ : null; }
+ set {
+ event_ = value;
+ eventCase_ = value == null ? EventOneofCase.None : EventOneofCase.AlarmChanged;
+ }
+ }
+
+ private object event_;
+ /// Enum of possible cases for the "event" oneof.
+ public enum EventOneofCase {
+ None = 0,
+ AttributeChanged = 2,
+ AlarmChanged = 3,
+ }
+ private EventOneofCase eventCase_ = EventOneofCase.None;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public EventOneofCase EventCase {
+ get { return eventCase_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearEvent() {
+ eventCase_ = EventOneofCase.None;
+ event_ = null;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as SiteStreamEvent);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(SiteStreamEvent other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (CorrelationId != other.CorrelationId) return false;
+ if (!object.Equals(AttributeChanged, other.AttributeChanged)) return false;
+ if (!object.Equals(AlarmChanged, other.AlarmChanged)) return false;
+ if (EventCase != other.EventCase) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (CorrelationId.Length != 0) hash ^= CorrelationId.GetHashCode();
+ if (eventCase_ == EventOneofCase.AttributeChanged) hash ^= AttributeChanged.GetHashCode();
+ if (eventCase_ == EventOneofCase.AlarmChanged) hash ^= AlarmChanged.GetHashCode();
+ hash ^= (int) eventCase_;
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (CorrelationId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(CorrelationId);
+ }
+ if (eventCase_ == EventOneofCase.AttributeChanged) {
+ output.WriteRawTag(18);
+ output.WriteMessage(AttributeChanged);
+ }
+ if (eventCase_ == EventOneofCase.AlarmChanged) {
+ output.WriteRawTag(26);
+ output.WriteMessage(AlarmChanged);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (CorrelationId.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(CorrelationId);
+ }
+ if (eventCase_ == EventOneofCase.AttributeChanged) {
+ output.WriteRawTag(18);
+ output.WriteMessage(AttributeChanged);
+ }
+ if (eventCase_ == EventOneofCase.AlarmChanged) {
+ output.WriteRawTag(26);
+ output.WriteMessage(AlarmChanged);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (CorrelationId.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(CorrelationId);
+ }
+ if (eventCase_ == EventOneofCase.AttributeChanged) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(AttributeChanged);
+ }
+ if (eventCase_ == EventOneofCase.AlarmChanged) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(AlarmChanged);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(SiteStreamEvent other) {
+ if (other == null) {
+ return;
+ }
+ if (other.CorrelationId.Length != 0) {
+ CorrelationId = other.CorrelationId;
+ }
+ switch (other.EventCase) {
+ case EventOneofCase.AttributeChanged:
+ if (AttributeChanged == null) {
+ AttributeChanged = new global::ScadaLink.Communication.Grpc.AttributeValueUpdate();
+ }
+ AttributeChanged.MergeFrom(other.AttributeChanged);
+ break;
+ case EventOneofCase.AlarmChanged:
+ if (AlarmChanged == null) {
+ AlarmChanged = new global::ScadaLink.Communication.Grpc.AlarmStateUpdate();
+ }
+ AlarmChanged.MergeFrom(other.AlarmChanged);
+ break;
+ }
+
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ if ((tag & 7) == 4) {
+ // Abort on any end group tag.
+ return;
+ }
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ CorrelationId = input.ReadString();
+ break;
+ }
+ case 18: {
+ global::ScadaLink.Communication.Grpc.AttributeValueUpdate subBuilder = new global::ScadaLink.Communication.Grpc.AttributeValueUpdate();
+ if (eventCase_ == EventOneofCase.AttributeChanged) {
+ subBuilder.MergeFrom(AttributeChanged);
+ }
+ input.ReadMessage(subBuilder);
+ AttributeChanged = subBuilder;
+ break;
+ }
+ case 26: {
+ global::ScadaLink.Communication.Grpc.AlarmStateUpdate subBuilder = new global::ScadaLink.Communication.Grpc.AlarmStateUpdate();
+ if (eventCase_ == EventOneofCase.AlarmChanged) {
+ subBuilder.MergeFrom(AlarmChanged);
+ }
+ input.ReadMessage(subBuilder);
+ AlarmChanged = subBuilder;
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ if ((tag & 7) == 4) {
+ // Abort on any end group tag.
+ return;
+ }
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 10: {
+ CorrelationId = input.ReadString();
+ break;
+ }
+ case 18: {
+ global::ScadaLink.Communication.Grpc.AttributeValueUpdate subBuilder = new global::ScadaLink.Communication.Grpc.AttributeValueUpdate();
+ if (eventCase_ == EventOneofCase.AttributeChanged) {
+ subBuilder.MergeFrom(AttributeChanged);
+ }
+ input.ReadMessage(subBuilder);
+ AttributeChanged = subBuilder;
+ break;
+ }
+ case 26: {
+ global::ScadaLink.Communication.Grpc.AlarmStateUpdate subBuilder = new global::ScadaLink.Communication.Grpc.AlarmStateUpdate();
+ if (eventCase_ == EventOneofCase.AlarmChanged) {
+ subBuilder.MergeFrom(AlarmChanged);
+ }
+ input.ReadMessage(subBuilder);
+ AlarmChanged = subBuilder;
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ }
+
+ [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")]
+ public sealed partial class AttributeValueUpdate : pb::IMessage
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AttributeValueUpdate());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ScadaLink.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[2]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public AttributeValueUpdate() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public AttributeValueUpdate(AttributeValueUpdate other) : this() {
+ instanceUniqueName_ = other.instanceUniqueName_;
+ attributePath_ = other.attributePath_;
+ attributeName_ = other.attributeName_;
+ value_ = other.value_;
+ quality_ = other.quality_;
+ timestamp_ = other.timestamp_ != null ? other.timestamp_.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public AttributeValueUpdate Clone() {
+ return new AttributeValueUpdate(this);
+ }
+
+ /// Field number for the "instance_unique_name" field.
+ public const int InstanceUniqueNameFieldNumber = 1;
+ private string instanceUniqueName_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string InstanceUniqueName {
+ get { return instanceUniqueName_; }
+ set {
+ instanceUniqueName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "attribute_path" field.
+ public const int AttributePathFieldNumber = 2;
+ private string attributePath_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string AttributePath {
+ get { return attributePath_; }
+ set {
+ attributePath_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "attribute_name" field.
+ public const int AttributeNameFieldNumber = 3;
+ private string attributeName_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string AttributeName {
+ get { return attributeName_; }
+ set {
+ attributeName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "value" field.
+ public const int ValueFieldNumber = 4;
+ private string value_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string Value {
+ get { return value_; }
+ set {
+ value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "quality" field.
+ public const int QualityFieldNumber = 5;
+ private global::ScadaLink.Communication.Grpc.Quality quality_ = global::ScadaLink.Communication.Grpc.Quality.Unspecified;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ScadaLink.Communication.Grpc.Quality Quality {
+ get { return quality_; }
+ set {
+ quality_ = value;
+ }
+ }
+
+ /// Field number for the "timestamp" field.
+ public const int TimestampFieldNumber = 6;
+ private global::Google.Protobuf.WellKnownTypes.Timestamp timestamp_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::Google.Protobuf.WellKnownTypes.Timestamp Timestamp {
+ get { return timestamp_; }
+ set {
+ timestamp_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as AttributeValueUpdate);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(AttributeValueUpdate other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (InstanceUniqueName != other.InstanceUniqueName) return false;
+ if (AttributePath != other.AttributePath) return false;
+ if (AttributeName != other.AttributeName) return false;
+ if (Value != other.Value) return false;
+ if (Quality != other.Quality) return false;
+ if (!object.Equals(Timestamp, other.Timestamp)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (InstanceUniqueName.Length != 0) hash ^= InstanceUniqueName.GetHashCode();
+ if (AttributePath.Length != 0) hash ^= AttributePath.GetHashCode();
+ if (AttributeName.Length != 0) hash ^= AttributeName.GetHashCode();
+ if (Value.Length != 0) hash ^= Value.GetHashCode();
+ if (Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) hash ^= Quality.GetHashCode();
+ if (timestamp_ != null) hash ^= Timestamp.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (InstanceUniqueName.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(InstanceUniqueName);
+ }
+ if (AttributePath.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(AttributePath);
+ }
+ if (AttributeName.Length != 0) {
+ output.WriteRawTag(26);
+ output.WriteString(AttributeName);
+ }
+ if (Value.Length != 0) {
+ output.WriteRawTag(34);
+ output.WriteString(Value);
+ }
+ if (Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) {
+ output.WriteRawTag(40);
+ output.WriteEnum((int) Quality);
+ }
+ if (timestamp_ != null) {
+ output.WriteRawTag(50);
+ output.WriteMessage(Timestamp);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (InstanceUniqueName.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(InstanceUniqueName);
+ }
+ if (AttributePath.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(AttributePath);
+ }
+ if (AttributeName.Length != 0) {
+ output.WriteRawTag(26);
+ output.WriteString(AttributeName);
+ }
+ if (Value.Length != 0) {
+ output.WriteRawTag(34);
+ output.WriteString(Value);
+ }
+ if (Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) {
+ output.WriteRawTag(40);
+ output.WriteEnum((int) Quality);
+ }
+ if (timestamp_ != null) {
+ output.WriteRawTag(50);
+ output.WriteMessage(Timestamp);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (InstanceUniqueName.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(InstanceUniqueName);
+ }
+ if (AttributePath.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(AttributePath);
+ }
+ if (AttributeName.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(AttributeName);
+ }
+ if (Value.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Value);
+ }
+ if (Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Quality);
+ }
+ if (timestamp_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Timestamp);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(AttributeValueUpdate other) {
+ if (other == null) {
+ return;
+ }
+ if (other.InstanceUniqueName.Length != 0) {
+ InstanceUniqueName = other.InstanceUniqueName;
+ }
+ if (other.AttributePath.Length != 0) {
+ AttributePath = other.AttributePath;
+ }
+ if (other.AttributeName.Length != 0) {
+ AttributeName = other.AttributeName;
+ }
+ if (other.Value.Length != 0) {
+ Value = other.Value;
+ }
+ if (other.Quality != global::ScadaLink.Communication.Grpc.Quality.Unspecified) {
+ Quality = other.Quality;
+ }
+ if (other.timestamp_ != null) {
+ if (timestamp_ == null) {
+ Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+ }
+ Timestamp.MergeFrom(other.Timestamp);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ if ((tag & 7) == 4) {
+ // Abort on any end group tag.
+ return;
+ }
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ InstanceUniqueName = input.ReadString();
+ break;
+ }
+ case 18: {
+ AttributePath = input.ReadString();
+ break;
+ }
+ case 26: {
+ AttributeName = input.ReadString();
+ break;
+ }
+ case 34: {
+ Value = input.ReadString();
+ break;
+ }
+ case 40: {
+ Quality = (global::ScadaLink.Communication.Grpc.Quality) input.ReadEnum();
+ break;
+ }
+ case 50: {
+ if (timestamp_ == null) {
+ Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+ }
+ input.ReadMessage(Timestamp);
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ if ((tag & 7) == 4) {
+ // Abort on any end group tag.
+ return;
+ }
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 10: {
+ InstanceUniqueName = input.ReadString();
+ break;
+ }
+ case 18: {
+ AttributePath = input.ReadString();
+ break;
+ }
+ case 26: {
+ AttributeName = input.ReadString();
+ break;
+ }
+ case 34: {
+ Value = input.ReadString();
+ break;
+ }
+ case 40: {
+ Quality = (global::ScadaLink.Communication.Grpc.Quality) input.ReadEnum();
+ break;
+ }
+ case 50: {
+ if (timestamp_ == null) {
+ Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+ }
+ input.ReadMessage(Timestamp);
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ }
+
+ [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")]
+ public sealed partial class AlarmStateUpdate : pb::IMessage
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AlarmStateUpdate());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ScadaLink.Communication.Grpc.SitestreamReflection.Descriptor.MessageTypes[3]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public AlarmStateUpdate() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public AlarmStateUpdate(AlarmStateUpdate other) : this() {
+ instanceUniqueName_ = other.instanceUniqueName_;
+ alarmName_ = other.alarmName_;
+ state_ = other.state_;
+ priority_ = other.priority_;
+ timestamp_ = other.timestamp_ != null ? other.timestamp_.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public AlarmStateUpdate Clone() {
+ return new AlarmStateUpdate(this);
+ }
+
+ /// Field number for the "instance_unique_name" field.
+ public const int InstanceUniqueNameFieldNumber = 1;
+ private string instanceUniqueName_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string InstanceUniqueName {
+ get { return instanceUniqueName_; }
+ set {
+ instanceUniqueName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "alarm_name" field.
+ public const int AlarmNameFieldNumber = 2;
+ private string alarmName_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string AlarmName {
+ get { return alarmName_; }
+ set {
+ alarmName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// Field number for the "state" field.
+ public const int StateFieldNumber = 3;
+ private global::ScadaLink.Communication.Grpc.AlarmStateEnum state_ = global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ScadaLink.Communication.Grpc.AlarmStateEnum State {
+ get { return state_; }
+ set {
+ state_ = value;
+ }
+ }
+
+ /// Field number for the "priority" field.
+ public const int PriorityFieldNumber = 4;
+ private int priority_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int Priority {
+ get { return priority_; }
+ set {
+ priority_ = value;
+ }
+ }
+
+ /// Field number for the "timestamp" field.
+ public const int TimestampFieldNumber = 5;
+ private global::Google.Protobuf.WellKnownTypes.Timestamp timestamp_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::Google.Protobuf.WellKnownTypes.Timestamp Timestamp {
+ get { return timestamp_; }
+ set {
+ timestamp_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as AlarmStateUpdate);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(AlarmStateUpdate other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (InstanceUniqueName != other.InstanceUniqueName) return false;
+ if (AlarmName != other.AlarmName) return false;
+ if (State != other.State) return false;
+ if (Priority != other.Priority) return false;
+ if (!object.Equals(Timestamp, other.Timestamp)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (InstanceUniqueName.Length != 0) hash ^= InstanceUniqueName.GetHashCode();
+ if (AlarmName.Length != 0) hash ^= AlarmName.GetHashCode();
+ if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) hash ^= State.GetHashCode();
+ if (Priority != 0) hash ^= Priority.GetHashCode();
+ if (timestamp_ != null) hash ^= Timestamp.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (InstanceUniqueName.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(InstanceUniqueName);
+ }
+ if (AlarmName.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(AlarmName);
+ }
+ if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) {
+ output.WriteRawTag(24);
+ output.WriteEnum((int) State);
+ }
+ if (Priority != 0) {
+ output.WriteRawTag(32);
+ output.WriteInt32(Priority);
+ }
+ if (timestamp_ != null) {
+ output.WriteRawTag(42);
+ output.WriteMessage(Timestamp);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (InstanceUniqueName.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(InstanceUniqueName);
+ }
+ if (AlarmName.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(AlarmName);
+ }
+ if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) {
+ output.WriteRawTag(24);
+ output.WriteEnum((int) State);
+ }
+ if (Priority != 0) {
+ output.WriteRawTag(32);
+ output.WriteInt32(Priority);
+ }
+ if (timestamp_ != null) {
+ output.WriteRawTag(42);
+ output.WriteMessage(Timestamp);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (InstanceUniqueName.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(InstanceUniqueName);
+ }
+ if (AlarmName.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(AlarmName);
+ }
+ if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) State);
+ }
+ if (Priority != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Priority);
+ }
+ if (timestamp_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Timestamp);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(AlarmStateUpdate other) {
+ if (other == null) {
+ return;
+ }
+ if (other.InstanceUniqueName.Length != 0) {
+ InstanceUniqueName = other.InstanceUniqueName;
+ }
+ if (other.AlarmName.Length != 0) {
+ AlarmName = other.AlarmName;
+ }
+ if (other.State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) {
+ State = other.State;
+ }
+ if (other.Priority != 0) {
+ Priority = other.Priority;
+ }
+ if (other.timestamp_ != null) {
+ if (timestamp_ == null) {
+ Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+ }
+ Timestamp.MergeFrom(other.Timestamp);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ if ((tag & 7) == 4) {
+ // Abort on any end group tag.
+ return;
+ }
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 10: {
+ InstanceUniqueName = input.ReadString();
+ break;
+ }
+ case 18: {
+ AlarmName = input.ReadString();
+ break;
+ }
+ case 24: {
+ State = (global::ScadaLink.Communication.Grpc.AlarmStateEnum) input.ReadEnum();
+ break;
+ }
+ case 32: {
+ Priority = input.ReadInt32();
+ break;
+ }
+ case 42: {
+ if (timestamp_ == null) {
+ Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+ }
+ input.ReadMessage(Timestamp);
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ if ((tag & 7) == 4) {
+ // Abort on any end group tag.
+ return;
+ }
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 10: {
+ InstanceUniqueName = input.ReadString();
+ break;
+ }
+ case 18: {
+ AlarmName = input.ReadString();
+ break;
+ }
+ case 24: {
+ State = (global::ScadaLink.Communication.Grpc.AlarmStateEnum) input.ReadEnum();
+ break;
+ }
+ case 32: {
+ Priority = input.ReadInt32();
+ break;
+ }
+ case 42: {
+ if (timestamp_ == null) {
+ Timestamp = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+ }
+ input.ReadMessage(Timestamp);
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ }
+
+ #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs b/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs
new file mode 100644
index 0000000..172be57
--- /dev/null
+++ b/src/ScadaLink.Communication/SiteStreamGrpc/SitestreamGrpc.cs
@@ -0,0 +1,145 @@
+//
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: sitestream.proto
+//
+#pragma warning disable 0414, 1591, 8981, 0612
+#region Designer generated code
+
+using grpc = global::Grpc.Core;
+
+namespace ScadaLink.Communication.Grpc {
+ public static partial class SiteStreamService
+ {
+ static readonly string __ServiceName = "sitestream.SiteStreamService";
+
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context)
+ {
+ #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION
+ if (message is global::Google.Protobuf.IBufferMessage)
+ {
+ context.SetPayloadLength(message.CalculateSize());
+ global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter());
+ context.Complete();
+ return;
+ }
+ #endif
+ context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message));
+ }
+
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ static class __Helper_MessageCache
+ {
+ public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T));
+ }
+
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ static T __Helper_DeserializeMessage(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser parser) where T : global::Google.Protobuf.IMessage
+ {
+ #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION
+ if (__Helper_MessageCache.IsBufferMessage)
+ {
+ return parser.ParseFrom(context.PayloadAsReadOnlySequence());
+ }
+ #endif
+ return parser.ParseFrom(context.PayloadAsNewBuffer());
+ }
+
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ static readonly grpc::Marshaller __Marshaller_sitestream_InstanceStreamRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::ScadaLink.Communication.Grpc.InstanceStreamRequest.Parser));
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ static readonly grpc::Marshaller __Marshaller_sitestream_SiteStreamEvent = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::ScadaLink.Communication.Grpc.SiteStreamEvent.Parser));
+
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ static readonly grpc::Method __Method_SubscribeInstance = new grpc::Method(
+ grpc::MethodType.ServerStreaming,
+ __ServiceName,
+ "SubscribeInstance",
+ __Marshaller_sitestream_InstanceStreamRequest,
+ __Marshaller_sitestream_SiteStreamEvent);
+
+ /// Service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::ScadaLink.Communication.Grpc.SitestreamReflection.Descriptor.Services[0]; }
+ }
+
+ /// Base class for server-side implementations of SiteStreamService
+ [grpc::BindServiceMethod(typeof(SiteStreamService), "BindService")]
+ public abstract partial class SiteStreamServiceBase
+ {
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ public virtual global::System.Threading.Tasks.Task SubscribeInstance(global::ScadaLink.Communication.Grpc.InstanceStreamRequest request, grpc::IServerStreamWriter responseStream, grpc::ServerCallContext context)
+ {
+ throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// Client for SiteStreamService
+ public partial class SiteStreamServiceClient : grpc::ClientBase
+ {
+ /// Creates a new client for SiteStreamService
+ /// The channel to use to make remote calls.
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ public SiteStreamServiceClient(grpc::ChannelBase channel) : base(channel)
+ {
+ }
+ /// Creates a new client for SiteStreamService that uses a custom CallInvoker.
+ /// The callInvoker to use to make remote calls.
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ public SiteStreamServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ /// Protected parameterless constructor to allow creation of test doubles.
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ protected SiteStreamServiceClient() : base()
+ {
+ }
+ /// Protected constructor to allow creation of configured clients.
+ /// The client configuration.
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ protected SiteStreamServiceClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ public virtual grpc::AsyncServerStreamingCall SubscribeInstance(global::ScadaLink.Communication.Grpc.InstanceStreamRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
+ {
+ return SubscribeInstance(request, new grpc::CallOptions(headers, deadline, cancellationToken));
+ }
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ public virtual grpc::AsyncServerStreamingCall SubscribeInstance(global::ScadaLink.Communication.Grpc.InstanceStreamRequest request, grpc::CallOptions options)
+ {
+ return CallInvoker.AsyncServerStreamingCall(__Method_SubscribeInstance, null, options, request);
+ }
+ /// Creates a new instance of client from given ClientBaseConfiguration.
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ protected override SiteStreamServiceClient NewInstance(ClientBaseConfiguration configuration)
+ {
+ return new SiteStreamServiceClient(configuration);
+ }
+ }
+
+ /// Creates service definition that can be registered with a server
+ /// An object implementing the server-side handling logic.
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ public static grpc::ServerServiceDefinition BindService(SiteStreamServiceBase serviceImpl)
+ {
+ return grpc::ServerServiceDefinition.CreateBuilder()
+ .AddMethod(__Method_SubscribeInstance, serviceImpl.SubscribeInstance).Build();
+ }
+
+ /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic.
+ /// Note: this method is part of an experimental API that can change or be removed without any prior notice.
+ /// Service methods will be bound by calling AddMethod on this object.
+ /// An object implementing the server-side handling logic.
+ [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
+ public static void BindService(grpc::ServiceBinderBase serviceBinder, SiteStreamServiceBase serviceImpl)
+ {
+ serviceBinder.AddMethod(__Method_SubscribeInstance, serviceImpl == null ? null : new grpc::ServerStreamingServerMethod(serviceImpl.SubscribeInstance));
+ }
+
+ }
+}
+#endregion
diff --git a/tests/ScadaLink.Communication.Tests/Grpc/ProtoRoundtripTests.cs b/tests/ScadaLink.Communication.Tests/Grpc/ProtoRoundtripTests.cs
new file mode 100644
index 0000000..d49a421
--- /dev/null
+++ b/tests/ScadaLink.Communication.Tests/Grpc/ProtoRoundtripTests.cs
@@ -0,0 +1,129 @@
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
+using ScadaLink.Communication.Grpc;
+
+namespace ScadaLink.Communication.Tests.Grpc;
+
+public class ProtoRoundtripTests
+{
+ [Theory]
+ [InlineData(Quality.Good)]
+ [InlineData(Quality.Uncertain)]
+ [InlineData(Quality.Bad)]
+ [InlineData(Quality.Unspecified)]
+ public void AttributeValueUpdate_RoundTrip(Quality quality)
+ {
+ var timestamp = Timestamp.FromDateTimeOffset(
+ new DateTimeOffset(2026, 3, 21, 12, 0, 0, TimeSpan.Zero));
+
+ var original = new AttributeValueUpdate
+ {
+ InstanceUniqueName = "Site1.Pump01",
+ AttributePath = "Modules.PressureModule",
+ AttributeName = "CurrentPressure",
+ Value = "42.5",
+ Quality = quality,
+ Timestamp = timestamp
+ };
+
+ var bytes = original.ToByteArray();
+ var deserialized = AttributeValueUpdate.Parser.ParseFrom(bytes);
+
+ Assert.Equal(original.InstanceUniqueName, deserialized.InstanceUniqueName);
+ Assert.Equal(original.AttributePath, deserialized.AttributePath);
+ Assert.Equal(original.AttributeName, deserialized.AttributeName);
+ Assert.Equal(original.Value, deserialized.Value);
+ Assert.Equal(original.Quality, deserialized.Quality);
+ Assert.Equal(original.Timestamp, deserialized.Timestamp);
+ Assert.Equal(timestamp.Seconds, deserialized.Timestamp.Seconds);
+ Assert.Equal(timestamp.Nanos, deserialized.Timestamp.Nanos);
+ }
+
+ [Theory]
+ [InlineData(AlarmStateEnum.AlarmStateNormal)]
+ [InlineData(AlarmStateEnum.AlarmStateActive)]
+ [InlineData(AlarmStateEnum.AlarmStateUnspecified)]
+ public void AlarmStateUpdate_RoundTrip(AlarmStateEnum state)
+ {
+ var timestamp = Timestamp.FromDateTimeOffset(
+ new DateTimeOffset(2026, 3, 21, 12, 30, 0, TimeSpan.Zero));
+
+ var original = new AlarmStateUpdate
+ {
+ InstanceUniqueName = "Site1.Pump01",
+ AlarmName = "HighPressure",
+ State = state,
+ Priority = 3,
+ Timestamp = timestamp
+ };
+
+ var bytes = original.ToByteArray();
+ var deserialized = AlarmStateUpdate.Parser.ParseFrom(bytes);
+
+ Assert.Equal(original.InstanceUniqueName, deserialized.InstanceUniqueName);
+ Assert.Equal(original.AlarmName, deserialized.AlarmName);
+ Assert.Equal(original.State, deserialized.State);
+ Assert.Equal(original.Priority, deserialized.Priority);
+ Assert.Equal(original.Timestamp, deserialized.Timestamp);
+ }
+
+ [Fact]
+ public void SiteStreamEvent_OneOf_AttributeChanged()
+ {
+ var evt = new SiteStreamEvent
+ {
+ CorrelationId = "corr-123",
+ AttributeChanged = new AttributeValueUpdate
+ {
+ InstanceUniqueName = "Site1.Pump01",
+ AttributePath = "Modules.PressureModule",
+ AttributeName = "CurrentPressure",
+ Value = "42.5",
+ Quality = Quality.Good,
+ Timestamp = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow)
+ }
+ };
+
+ Assert.Equal(SiteStreamEvent.EventOneofCase.AttributeChanged, evt.EventCase);
+ Assert.NotNull(evt.AttributeChanged);
+ Assert.Null(evt.AlarmChanged);
+
+ // Round-trip
+ var bytes = evt.ToByteArray();
+ var deserialized = SiteStreamEvent.Parser.ParseFrom(bytes);
+
+ Assert.Equal(SiteStreamEvent.EventOneofCase.AttributeChanged, deserialized.EventCase);
+ Assert.Equal("corr-123", deserialized.CorrelationId);
+ Assert.Equal("42.5", deserialized.AttributeChanged.Value);
+ }
+
+ [Fact]
+ public void SiteStreamEvent_OneOf_AlarmChanged()
+ {
+ var evt = new SiteStreamEvent
+ {
+ CorrelationId = "corr-456",
+ AlarmChanged = new AlarmStateUpdate
+ {
+ InstanceUniqueName = "Site1.Pump01",
+ AlarmName = "HighPressure",
+ State = AlarmStateEnum.AlarmStateActive,
+ Priority = 1,
+ Timestamp = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow)
+ }
+ };
+
+ Assert.Equal(SiteStreamEvent.EventOneofCase.AlarmChanged, evt.EventCase);
+ Assert.NotNull(evt.AlarmChanged);
+ Assert.Null(evt.AttributeChanged);
+
+ // Round-trip
+ var bytes = evt.ToByteArray();
+ var deserialized = SiteStreamEvent.Parser.ParseFrom(bytes);
+
+ Assert.Equal(SiteStreamEvent.EventOneofCase.AlarmChanged, deserialized.EventCase);
+ Assert.Equal("corr-456", deserialized.CorrelationId);
+ Assert.Equal(AlarmStateEnum.AlarmStateActive, deserialized.AlarmChanged.State);
+ Assert.Equal(1, deserialized.AlarmChanged.Priority);
+ }
+}