syntax = "proto3"; package mxaccess_gateway.v1; option csharp_namespace = "ZB.MOM.WW.MxGateway.Contracts.Proto"; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; // Wire-compatibility policy (ProtobufStyleGuide): this contract evolves // additively only. Never renumber or repurpose an existing field number or // enum value. When a field or enum value is removed, add a `reserved` range // (and `reserved` name) covering it in the same change so a future editor // cannot accidentally reuse the retired tag. // Public client API for MXAccess sessions hosted by the gateway. service MxAccessGateway { rpc OpenSession(OpenSessionRequest) returns (OpenSessionReply); rpc CloseSession(CloseSessionRequest) returns (CloseSessionReply); rpc Invoke(MxCommandRequest) returns (MxCommandReply); rpc StreamEvents(StreamEventsRequest) returns (stream MxEvent); rpc AcknowledgeAlarm(AcknowledgeAlarmRequest) returns (AcknowledgeAlarmReply); // Session-less central alarm feed. The stream opens with the current // active-alarm snapshot (one `active_alarm` per alarm), then a single // `snapshot_complete`, then a `transition` for every subsequent change. // Served by the gateway's always-on alarm monitor; any number of clients // fan out from the single monitor without opening a worker session. rpc StreamAlarms(StreamAlarmsRequest) returns (stream AlarmFeedMessage); // Point-in-time snapshot of the currently-active alarm set served from the // gateway's always-on alarm monitor cache (session-less). Used after a // reconnect to seed Part 9 client state, or to reconcile alarms that may // have been missed during a transport blip. Streamed so callers can // begin processing without buffering the full set. // `QueryActiveAlarmsRequest.alarm_filter_prefix` optionally narrows the // snapshot to alarms whose `alarm_full_reference` starts with the given // prefix; an empty prefix returns the full set. rpc QueryActiveAlarms(QueryActiveAlarmsRequest) returns (stream ActiveAlarmSnapshot); } // Public request shape for QueryActiveAlarms. // Clients may leave `session_id` empty; the gateway currently ignores it and // serves the session-less central-monitor cache. A future version may use it // to scope the snapshot to one session. message QueryActiveAlarmsRequest { string session_id = 1; string client_correlation_id = 2; // Optional filter: when non-empty, only snapshots whose alarm_full_reference // starts with this string are returned. string alarm_filter_prefix = 3; } message OpenSessionRequest { string requested_backend = 1; string client_session_name = 2; string client_correlation_id = 3; google.protobuf.Duration command_timeout = 4; } message OpenSessionReply { string session_id = 1; string backend_name = 2; int32 worker_process_id = 3; uint32 worker_protocol_version = 4; repeated string capabilities = 5; google.protobuf.Duration default_command_timeout = 6; ProtocolStatus protocol_status = 7; // Public gateway contract version implemented by this endpoint. Clients use // this value to reject incompatible generated-code inputs before issuing // command-specific MXAccess calls. uint32 gateway_protocol_version = 8; } message CloseSessionRequest { string session_id = 1; string client_correlation_id = 2; } message CloseSessionReply { string session_id = 1; SessionState final_state = 2; ProtocolStatus protocol_status = 3; } message StreamEventsRequest { string session_id = 1; uint64 after_worker_sequence = 2; } message MxCommandRequest { string session_id = 1; string client_correlation_id = 2; MxCommand command = 3; } message MxCommand { MxCommandKind kind = 1; oneof payload { RegisterCommand register = 10; UnregisterCommand unregister = 11; AddItemCommand add_item = 12; AddItem2Command add_item2 = 13; RemoveItemCommand remove_item = 14; AdviseCommand advise = 15; UnAdviseCommand un_advise = 16; AdviseSupervisoryCommand advise_supervisory = 17; AddBufferedItemCommand add_buffered_item = 18; SetBufferedUpdateIntervalCommand set_buffered_update_interval = 19; SuspendCommand suspend = 20; ActivateCommand activate = 21; WriteCommand write = 22; Write2Command write2 = 23; WriteSecuredCommand write_secured = 24; WriteSecured2Command write_secured2 = 25; AuthenticateUserCommand authenticate_user = 26; ArchestrAUserToIdCommand archestra_user_to_id = 27; AddItemBulkCommand add_item_bulk = 28; AdviseItemBulkCommand advise_item_bulk = 29; RemoveItemBulkCommand remove_item_bulk = 30; UnAdviseItemBulkCommand un_advise_item_bulk = 31; SubscribeBulkCommand subscribe_bulk = 32; UnsubscribeBulkCommand unsubscribe_bulk = 33; SubscribeAlarmsCommand subscribe_alarms = 34; UnsubscribeAlarmsCommand unsubscribe_alarms = 35; AcknowledgeAlarmCommand acknowledge_alarm_command = 36; QueryActiveAlarmsCommand query_active_alarms_command = 37; AcknowledgeAlarmByNameCommand acknowledge_alarm_by_name_command = 38; WriteBulkCommand write_bulk = 39; Write2BulkCommand write2_bulk = 40; WriteSecuredBulkCommand write_secured_bulk = 41; WriteSecured2BulkCommand write_secured2_bulk = 42; ReadBulkCommand read_bulk = 43; PingCommand ping = 100; GetSessionStateCommand get_session_state = 101; GetWorkerInfoCommand get_worker_info = 102; DrainEventsCommand drain_events = 103; ShutdownWorkerCommand shutdown_worker = 104; } } enum MxCommandKind { MX_COMMAND_KIND_UNSPECIFIED = 0; MX_COMMAND_KIND_REGISTER = 1; MX_COMMAND_KIND_UNREGISTER = 2; MX_COMMAND_KIND_ADD_ITEM = 3; MX_COMMAND_KIND_ADD_ITEM2 = 4; MX_COMMAND_KIND_REMOVE_ITEM = 5; MX_COMMAND_KIND_ADVISE = 6; MX_COMMAND_KIND_UN_ADVISE = 7; MX_COMMAND_KIND_ADVISE_SUPERVISORY = 8; MX_COMMAND_KIND_ADD_BUFFERED_ITEM = 9; MX_COMMAND_KIND_SET_BUFFERED_UPDATE_INTERVAL = 10; MX_COMMAND_KIND_SUSPEND = 11; MX_COMMAND_KIND_ACTIVATE = 12; MX_COMMAND_KIND_WRITE = 13; MX_COMMAND_KIND_WRITE2 = 14; MX_COMMAND_KIND_WRITE_SECURED = 15; MX_COMMAND_KIND_WRITE_SECURED2 = 16; MX_COMMAND_KIND_AUTHENTICATE_USER = 17; MX_COMMAND_KIND_ARCHESTRA_USER_TO_ID = 18; MX_COMMAND_KIND_ADD_ITEM_BULK = 19; MX_COMMAND_KIND_ADVISE_ITEM_BULK = 20; MX_COMMAND_KIND_REMOVE_ITEM_BULK = 21; MX_COMMAND_KIND_UN_ADVISE_ITEM_BULK = 22; MX_COMMAND_KIND_SUBSCRIBE_BULK = 23; MX_COMMAND_KIND_UNSUBSCRIBE_BULK = 24; MX_COMMAND_KIND_SUBSCRIBE_ALARMS = 25; MX_COMMAND_KIND_UNSUBSCRIBE_ALARMS = 26; MX_COMMAND_KIND_ACKNOWLEDGE_ALARM = 27; MX_COMMAND_KIND_QUERY_ACTIVE_ALARMS = 28; MX_COMMAND_KIND_ACKNOWLEDGE_ALARM_BY_NAME = 29; MX_COMMAND_KIND_WRITE_BULK = 30; MX_COMMAND_KIND_WRITE2_BULK = 31; MX_COMMAND_KIND_WRITE_SECURED_BULK = 32; MX_COMMAND_KIND_WRITE_SECURED2_BULK = 33; MX_COMMAND_KIND_READ_BULK = 34; MX_COMMAND_KIND_PING = 100; MX_COMMAND_KIND_GET_SESSION_STATE = 101; MX_COMMAND_KIND_GET_WORKER_INFO = 102; MX_COMMAND_KIND_DRAIN_EVENTS = 103; MX_COMMAND_KIND_SHUTDOWN_WORKER = 104; } message RegisterCommand { string client_name = 1; } message UnregisterCommand { int32 server_handle = 1; } message AddItemCommand { int32 server_handle = 1; string item_definition = 2; } message AddItem2Command { int32 server_handle = 1; string item_definition = 2; string item_context = 3; } message RemoveItemCommand { int32 server_handle = 1; int32 item_handle = 2; } message AdviseCommand { int32 server_handle = 1; int32 item_handle = 2; } message UnAdviseCommand { int32 server_handle = 1; int32 item_handle = 2; } message AdviseSupervisoryCommand { int32 server_handle = 1; int32 item_handle = 2; } message AddBufferedItemCommand { int32 server_handle = 1; string item_definition = 2; string item_context = 3; } message SetBufferedUpdateIntervalCommand { int32 server_handle = 1; int32 update_interval_milliseconds = 2; } message SuspendCommand { int32 server_handle = 1; int32 item_handle = 2; } message ActivateCommand { int32 server_handle = 1; int32 item_handle = 2; } message WriteCommand { int32 server_handle = 1; int32 item_handle = 2; MxValue value = 3; int32 user_id = 4; } message Write2Command { int32 server_handle = 1; int32 item_handle = 2; MxValue value = 3; MxValue timestamp_value = 4; int32 user_id = 5; } message WriteSecuredCommand { int32 server_handle = 1; int32 item_handle = 2; int32 current_user_id = 3; int32 verifier_user_id = 4; // Credential-sensitive write value. Implementations must not log this field // unless an explicit redacted value-logging path is enabled. MxValue value = 5; } message WriteSecured2Command { int32 server_handle = 1; int32 item_handle = 2; int32 current_user_id = 3; int32 verifier_user_id = 4; // Credential-sensitive write value. Implementations must not log this field // unless an explicit redacted value-logging path is enabled. MxValue value = 5; MxValue timestamp_value = 6; } message AuthenticateUserCommand { int32 server_handle = 1; string verify_user = 2; // Raw MXAccess credential. Implementations must keep this field out of logs, // metrics labels, command lines, and diagnostics. string verify_user_password = 3; } message ArchestrAUserToIdCommand { int32 server_handle = 1; string user_id_guid = 2; } message AddItemBulkCommand { int32 server_handle = 1; repeated string tag_addresses = 2; } message AdviseItemBulkCommand { int32 server_handle = 1; repeated int32 item_handles = 2; } message RemoveItemBulkCommand { int32 server_handle = 1; repeated int32 item_handles = 2; } message UnAdviseItemBulkCommand { int32 server_handle = 1; repeated int32 item_handles = 2; } message SubscribeBulkCommand { int32 server_handle = 1; repeated string tag_addresses = 2; } // Provider selection / current provider for the alarm feed. UNSPECIFIED on a // SubscribeAlarmsCommand means auto: alarmmgr primary with subtag fallback. enum AlarmProviderMode { ALARM_PROVIDER_MODE_UNSPECIFIED = 0; ALARM_PROVIDER_MODE_ALARMMGR = 1; ALARM_PROVIDER_MODE_SUBTAG = 2; } // Subscribe the worker's alarm consumer to an AVEVA alarm provider. // Subscription expression follows the canonical // `\\\Galaxy!` format (literal "Galaxy" provider). The // worker spins up a wnwrapConsumer-backed subscription on its STA on // first call; subsequent calls are an error (use UnsubscribeAlarms then // SubscribeAlarms to reconfigure). message SubscribeAlarmsCommand { string subscription_expression = 1; // UNSPECIFIED = auto-failover/failback. ALARMMGR/SUBTAG force one provider. AlarmProviderMode forced_mode = 2; // Subtag watch-list resolved by the gateway (GR SQL + config). Empty in pure // alarmmgr mode; in subtag mode it bounds what the consumer can observe. repeated AlarmSubtagTarget watch_list = 3; AlarmFailoverConfig failover = 4; } // Tear down the worker's alarm consumer. No-op if no subscription is // currently active. message UnsubscribeAlarmsCommand { } // One alarm attribute the subtag fallback consumer advises. Addresses are full // MXAccess item references the worker passes straight to AddItem. message AlarmSubtagTarget { string alarm_full_reference = 1; // e.g. "Galaxy!Area.Tank01.Level.HiHi" string source_object_reference = 2; // e.g. "Tank01" string active_subtag = 3; // item address of the in-alarm boolean string acked_subtag = 4; // item address of the acknowledged boolean string ack_comment_subtag = 5; // writable ack-comment attribute (ack write target) string priority_subtag = 6; // optional severity source; empty if absent } message AlarmFailoverConfig { int32 consecutive_failure_threshold = 1; // wnwrap COM failures before switching (>=1) int32 failback_probe_interval_seconds = 2; // probe cadence while degraded (>=1) int32 failback_stable_probes = 3; // clean probes before switching back (>=1) } // Acknowledge a single alarm by its GUID. Operator identity fields are // recorded atomically with the ack transition in the alarm-history log. // The reply's hresult / native_status surfaces AVEVA's // AlarmAckByGUID return code. message AcknowledgeAlarmCommand { // Canonical 8-4-4-4-12 GUID string (e.g. "BCC47053-9542-4D65-BDAA-BCDEA6A32A73"). string alarm_guid = 1; string comment = 2; string operator_user = 3; string operator_node = 4; string operator_domain = 5; string operator_full_name = 6; } // Snapshot the currently-active alarm set. Optional filter prefix scopes // the snapshot to alarms whose alarm_full_reference starts with the // supplied string (matches QueryActiveAlarmsRequest.alarm_filter_prefix). message QueryActiveAlarmsCommand { string alarm_filter_prefix = 1; } // Acknowledge a single alarm by its (name, provider, group) tuple. Used // when the public RPC's AlarmFullReference (Provider!Group.Tag) cannot // be resolved to a GUID directly. The worker invokes // wwAlarmConsumerClass.AlarmAckByName which reaches the same alarm // history path as AlarmAckByGUID. message AcknowledgeAlarmByNameCommand { // Tag/alarm name (e.g. "TestMachine_001.TestAlarm001"). Tag itself // may contain dots; the gateway-side parser splits on the first dot // after the '!' separator. string alarm_name = 1; // AVEVA alarm-provider name (literal "Galaxy" for ArchestrA Galaxies). string provider_name = 2; // Area/group name (e.g. "TestArea"). string group_name = 3; string comment = 4; string operator_user = 5; string operator_node = 6; string operator_domain = 7; string operator_full_name = 8; } message UnsubscribeBulkCommand { int32 server_handle = 1; repeated int32 item_handles = 2; } // Bulk Write — sequential MXAccess Write per entry, on the worker's STA. // MXAccess has no native bulk write; each entry round-trips through the same // single-item Write path the gateway uses today. Per-item failures appear as // BulkWriteResult entries with `was_successful = false` and never throw. message WriteBulkCommand { int32 server_handle = 1; repeated WriteBulkEntry entries = 2; } message WriteBulkEntry { int32 item_handle = 1; MxValue value = 2; int32 user_id = 3; } // Bulk Write2 — sequential MXAccess Write2 (timestamped) per entry. message Write2BulkCommand { int32 server_handle = 1; repeated Write2BulkEntry entries = 2; } message Write2BulkEntry { int32 item_handle = 1; MxValue value = 2; MxValue timestamp_value = 3; int32 user_id = 4; } // Bulk WriteSecured — sequential MXAccess WriteSecured per entry. // Credential-sensitive values (`value`) MUST be kept out of logs, metrics // labels, command lines, and diagnostics — same redaction rules as the // single-item WriteSecured contract. message WriteSecuredBulkCommand { int32 server_handle = 1; repeated WriteSecuredBulkEntry entries = 2; } message WriteSecuredBulkEntry { int32 item_handle = 1; int32 current_user_id = 2; int32 verifier_user_id = 3; // Credential-sensitive write value. Implementations must not log this field // unless an explicit redacted value-logging path is enabled. MxValue value = 4; } // Bulk WriteSecured2 — sequential MXAccess WriteSecured2 (timestamped) per // entry. Same redaction rules apply. message WriteSecured2BulkCommand { int32 server_handle = 1; repeated WriteSecured2BulkEntry entries = 2; } message WriteSecured2BulkEntry { int32 item_handle = 1; int32 current_user_id = 2; int32 verifier_user_id = 3; // Credential-sensitive write value. Implementations must not log this field // unless an explicit redacted value-logging path is enabled. MxValue value = 4; MxValue timestamp_value = 5; } // Bulk Read — snapshot the current value for each requested tag. MXAccess COM // has no synchronous Read; the worker implements ReadBulk as: // // - If the tag is already in the session's item registry AND that item is // currently advised AND the worker has a cached OnDataChange for it, the // reply returns the cached value WITHOUT modifying the existing // subscription (was_cached = true). // - Otherwise the worker takes the snapshot lifecycle itself: AddItem + // Advise, wait up to `timeout_ms` for the first OnDataChange, then // UnAdvise + RemoveItem before returning. The session is left exactly // as it was before the call (was_cached = false). // // `timeout_ms == 0` uses the gateway-configured default (1000 ms). message ReadBulkCommand { int32 server_handle = 1; repeated string tag_addresses = 2; uint32 timeout_ms = 3; } message PingCommand { string message = 1; } message GetSessionStateCommand { } message GetWorkerInfoCommand { } message DrainEventsCommand { uint32 max_events = 1; } message ShutdownWorkerCommand { google.protobuf.Duration grace_period = 1; } message MxCommandReply { string session_id = 1; string correlation_id = 2; MxCommandKind kind = 3; ProtocolStatus protocol_status = 4; // HRESULT captured from MXAccess or a COM exception. This remains separate // from gateway protocol status so MXAccess parity details are not hidden by // transport failures. optional int32 hresult = 5; MxValue return_value = 6; repeated MxStatusProxy statuses = 7; string diagnostic_message = 8; oneof payload { RegisterReply register = 20; AddItemReply add_item = 21; AddItem2Reply add_item2 = 22; AddBufferedItemReply add_buffered_item = 23; SuspendReply suspend = 24; ActivateReply activate = 25; AuthenticateUserReply authenticate_user = 26; ArchestrAUserToIdReply archestra_user_to_id = 27; BulkSubscribeReply add_item_bulk = 28; BulkSubscribeReply advise_item_bulk = 29; BulkSubscribeReply remove_item_bulk = 30; BulkSubscribeReply un_advise_item_bulk = 31; BulkSubscribeReply subscribe_bulk = 32; BulkSubscribeReply unsubscribe_bulk = 33; // Reply payload for BOTH MX_COMMAND_KIND_ACKNOWLEDGE_ALARM (by GUID) // and MX_COMMAND_KIND_ACKNOWLEDGE_ALARM_BY_NAME. There is intentionally // no by-name-specific reply case: the by-name ack carries no outcome // detail beyond the native ack return code, so the worker reuses this // `acknowledge_alarm` payload for both command kinds (the worker's // MxAccessCommandExecutor sets `acknowledge_alarm` for the by-name arm // too). Consumers must dispatch on MxCommandReply.kind, not on the // payload case, to tell the two acks apart. The top-level `hresult` // mirrors AcknowledgeAlarmReplyPayload.native_status and is preferred. AcknowledgeAlarmReplyPayload acknowledge_alarm = 34; QueryActiveAlarmsReplyPayload query_active_alarms = 35; BulkWriteReply write_bulk = 36; BulkWriteReply write2_bulk = 37; BulkWriteReply write_secured_bulk = 38; BulkWriteReply write_secured2_bulk = 39; BulkReadReply read_bulk = 40; SessionStateReply session_state = 100; WorkerInfoReply worker_info = 101; DrainEventsReply drain_events = 102; } } message RegisterReply { int32 server_handle = 1; } message AddItemReply { int32 item_handle = 1; } message AddItem2Reply { int32 item_handle = 1; } message AddBufferedItemReply { int32 item_handle = 1; } message SuspendReply { MxStatusProxy status = 1; } message ActivateReply { MxStatusProxy status = 1; } message AuthenticateUserReply { int32 user_id = 1; } message ArchestrAUserToIdReply { int32 user_id = 1; } message SubscribeResult { int32 server_handle = 1; string tag_address = 2; int32 item_handle = 3; bool was_successful = 4; string error_message = 5; } message BulkSubscribeReply { repeated SubscribeResult results = 1; } // Per-item result for the four bulk write families. `item_handle` mirrors the // request entry's item_handle so callers can correlate inputs to outputs even // when the gateway's per-entry `IConstraintEnforcer.CheckWriteHandleAsync` // filter (see `MxAccessGatewayService.ReplaceWriteBulkEntries` and // `docs/Authorization.md`) dropped some entries before reaching the worker. // Per-item failures populate `error_message` + `hresult` and never raise — // callers iterate and inspect each entry. message BulkWriteResult { int32 server_handle = 1; int32 item_handle = 2; bool was_successful = 3; optional int32 hresult = 4; repeated MxStatusProxy statuses = 5; string error_message = 6; } message BulkWriteReply { repeated BulkWriteResult results = 1; } // Per-tag result for ReadBulk. `was_cached` is true when the value came from // an existing live subscription's last OnDataChange (the worker did not touch // the subscription); false when the worker took the AddItem + Advise + wait + // UnAdvise + RemoveItem snapshot lifecycle itself. // // On `was_successful = true`, `value`, `quality`, `source_timestamp`, and // `statuses` carry the read data (from the cached subscription or the snapshot // lifecycle, depending on `was_cached`) and `error_message` is empty. On // `was_successful = false`, only `server_handle`, `tag_address`, `item_handle` // (when allocated), `was_cached`, and `error_message` are populated; `value`, // `quality`, `source_timestamp`, and `statuses` are left at their proto3 // defaults (null / 0 / null / empty) and must not be read as data — they are // wire-indistinguishable from "value is null with quality bad" data and serve // only as absent markers. ReadBulk has no `hresult` field by design (its // outcomes are timeout / cache / lifecycle states, not MXAccess COM return // codes — see `docs/DesignDecisions.md` "Bulk Command Family"). Per-tag // failures populate `error_message` and never raise — callers iterate and // inspect each entry. message BulkReadResult { int32 server_handle = 1; string tag_address = 2; int32 item_handle = 3; bool was_successful = 4; bool was_cached = 5; MxValue value = 6; int32 quality = 7; google.protobuf.Timestamp source_timestamp = 8; repeated MxStatusProxy statuses = 9; string error_message = 10; } message BulkReadReply { repeated BulkReadResult results = 1; } message SessionStateReply { SessionState state = 1; } message WorkerInfoReply { int32 worker_process_id = 1; string worker_version = 2; string mxaccess_progid = 3; string mxaccess_clsid = 4; } message DrainEventsReply { repeated MxEvent events = 1; } // Reply payload for AcknowledgeAlarmCommand AND // AcknowledgeAlarmByNameCommand — both ack command kinds reuse this // payload case (`MxCommandReply.acknowledge_alarm`); there is no // dedicated by-name reply case. Surfaces AVEVA's native ack return // code (AlarmAckByGUID for the GUID arm, AlarmAckByName for the // by-name arm); 0 means success. The MxCommandReply's hresult field // carries the same value and is preferred for protocol consumers — // this payload exists so the gateway-side WorkerAlarmRpcDispatcher // can echo native_status into AcknowledgeAlarmReply.hresult without // unpacking the outer envelope. message AcknowledgeAlarmReplyPayload { int32 native_status = 1; } // Reply payload for QueryActiveAlarmsCommand. The worker walks // IMxAccessAlarmConsumer.SnapshotActiveAlarms and packs each record as // an ActiveAlarmSnapshot proto for the gateway-side ConditionRefresh // stream. message QueryActiveAlarmsReplyPayload { repeated ActiveAlarmSnapshot snapshots = 1; } message MxEvent { MxEventFamily family = 1; string session_id = 2; int32 server_handle = 3; int32 item_handle = 4; MxValue value = 5; int32 quality = 6; google.protobuf.Timestamp source_timestamp = 7; repeated MxStatusProxy statuses = 8; uint64 worker_sequence = 9; google.protobuf.Timestamp worker_timestamp = 10; google.protobuf.Timestamp gateway_receive_timestamp = 11; optional int32 hresult = 12; string raw_status = 13; oneof body { OnDataChangeEvent on_data_change = 20; OnWriteCompleteEvent on_write_complete = 21; OperationCompleteEvent operation_complete = 22; OnBufferedDataChangeEvent on_buffered_data_change = 23; OnAlarmTransitionEvent on_alarm_transition = 24; OnAlarmProviderModeChangedEvent on_alarm_provider_mode_changed = 25; } } enum MxEventFamily { MX_EVENT_FAMILY_UNSPECIFIED = 0; MX_EVENT_FAMILY_ON_DATA_CHANGE = 1; MX_EVENT_FAMILY_ON_WRITE_COMPLETE = 2; MX_EVENT_FAMILY_OPERATION_COMPLETE = 3; MX_EVENT_FAMILY_ON_BUFFERED_DATA_CHANGE = 4; MX_EVENT_FAMILY_ON_ALARM_TRANSITION = 5; MX_EVENT_FAMILY_ON_ALARM_PROVIDER_MODE_CHANGED = 6; } message OnDataChangeEvent { } message OnWriteCompleteEvent { } message OperationCompleteEvent { } message OnBufferedDataChangeEvent { MxDataType data_type = 1; MxArray quality_values = 2; MxArray timestamp_values = 3; int32 raw_data_type = 4; } // Carries a single MXAccess alarm transition (raise / acknowledge / clear / // re-trigger) in native MXAccess terms. The Part 9 state machine + ACL + // multi-source aggregation lives in lmxopcua's AlarmConditionService; the // gateway is UA-agnostic and forwards the raw payload. message OnAlarmTransitionEvent { // Fully-qualified alarm reference (e.g. "Tank01.Level.HiHi"). Stable across // transitions of the same condition; used by the lmxopcua side to correlate // raise/ack/clear into a single Part 9 condition. string alarm_full_reference = 1; // Galaxy-side source object reference (e.g. "Tank01"). Empty for alarms // that do not bind to a Galaxy object. string source_object_reference = 2; // MxAccess alarm-type qualifier (e.g. "AnalogLimitAlarm.HiHi", "DiscAlarm"). string alarm_type_name = 3; // What kind of state change this event represents. AlarmTransitionKind transition_kind = 4; // Raw MXAccess severity value. Mapping to OPC UA 0-1000 happens server-side // in lmxopcua via MxAccessSeverityMapper; the gateway preserves the native // MXAccess scale. int32 severity = 5; // When the alarm originally entered the active state. Preserved across // acknowledge transitions so the Part 9 condition keeps the original raise // time. Unset on retrigger from a previously-cleared condition. google.protobuf.Timestamp original_raise_timestamp = 6; // When this specific transition occurred (raise time on Raise, ack time on // Acknowledge, clear time on Clear). google.protobuf.Timestamp transition_timestamp = 7; // Operator principal recorded by MXAccess on Acknowledge transitions. // Empty on raise / clear. string operator_user = 8; // Operator-supplied comment recorded by MXAccess on Acknowledge transitions. // Empty on raise / clear or when no comment was supplied. string operator_comment = 9; // MxAccess alarm category (taxonomy bucket configured in the Galaxy // template, e.g. "Process", "Safety", "Diagnostics"). string category = 10; // Human-readable alarm description from the MxAccess alarm definition. string description = 11; // Current alarm value (the value of the source attribute at the moment of // transition). Optional; populated when MxAccess surfaces it. MxValue current_value = 12; // Limit/threshold value that triggered the transition for limit alarms. // Optional; populated for AnalogLimitAlarm-family transitions. MxValue limit_value = 13; // True when this transition came from the subtag-monitoring fallback rather // than the native alarmmgr provider — synthesized from data changes, reduced // fidelity (synthetic GUID, no native raise time). bool degraded = 14; // Which provider produced this transition. AlarmProviderMode source_provider = 15; } message OnAlarmProviderModeChangedEvent { AlarmProviderMode mode = 1; string reason = 2; int32 hresult = 3; // COM HRESULT that triggered failover; 0 on failback google.protobuf.Timestamp at = 4; } enum AlarmTransitionKind { ALARM_TRANSITION_KIND_UNSPECIFIED = 0; ALARM_TRANSITION_KIND_RAISE = 1; ALARM_TRANSITION_KIND_ACKNOWLEDGE = 2; ALARM_TRANSITION_KIND_CLEAR = 3; ALARM_TRANSITION_KIND_RETRIGGER = 4; } // Snapshot of a currently-active MXAccess alarm condition, returned from a // QueryActiveAlarms ConditionRefresh stream. message ActiveAlarmSnapshot { string alarm_full_reference = 1; string source_object_reference = 2; string alarm_type_name = 3; int32 severity = 4; google.protobuf.Timestamp original_raise_timestamp = 5; AlarmConditionState current_state = 6; string category = 7; string description = 8; // When the most recent state transition occurred (last raise, last ack, // last clear). google.protobuf.Timestamp last_transition_timestamp = 9; // Operator who acknowledged the alarm if the current state is ActiveAcked. // Empty otherwise. string operator_user = 10; // Operator comment recorded with the most recent acknowledge if the current // state is ActiveAcked. Empty otherwise. string operator_comment = 11; MxValue current_value = 12; MxValue limit_value = 13; bool degraded = 14; AlarmProviderMode source_provider = 15; } enum AlarmConditionState { ALARM_CONDITION_STATE_UNSPECIFIED = 0; ALARM_CONDITION_STATE_ACTIVE = 1; ALARM_CONDITION_STATE_ACTIVE_ACKED = 2; ALARM_CONDITION_STATE_INACTIVE = 3; } message AcknowledgeAlarmRequest { // Retired: acknowledgement is session-less — it routes to the gateway's // central alarm monitor, not a client worker session. reserved 1; reserved "session_id"; string client_correlation_id = 2; // Fully-qualified alarm reference matching OnAlarmTransitionEvent.alarm_full_reference. string alarm_full_reference = 3; // Operator-supplied comment forwarded to MXAccess. string comment = 4; // Operator principal performing the acknowledgement. The lmxopcua side // resolves this from the OPC UA session prior to invoking the RPC. string operator_user = 5; } message AcknowledgeAlarmReply { // Retired: see AcknowledgeAlarmRequest — acknowledgement is session-less. reserved 1; reserved "session_id"; string correlation_id = 2; ProtocolStatus protocol_status = 3; // Native ack return code echoed from the worker. The worker carries the // ack outcome as a single int32 (AcknowledgeAlarmReplyPayload.native_status, // = AlarmAckByName / AlarmAckByGUID return code; 0 = success); the gateway's // WorkerAlarmRpcDispatcher copies that value here. This is the authoritative // ack-outcome field for the public RPC. Absent only when the worker reply // omitted the value entirely (a protocol violation). optional int32 hresult = 4; // Reserved for a structured MxStatusProxy view of the ack outcome. The // worker by-name/by-GUID ack path produces only the int32 return code // (see `hresult`), so the current gateway leaves this field UNSET on every // reply. Clients must read `hresult` (and `protocol_status`) for the ack // result and must not depend on `status` being populated. MxStatusProxy status = 5; string diagnostic_message = 6; } // Request to attach to the gateway's central alarm feed (StreamAlarms). message StreamAlarmsRequest { string client_correlation_id = 1; // Optional alarm-reference prefix scoping the feed to an equipment // sub-tree. Empty streams every active alarm. string alarm_filter_prefix = 2; } // One message on the StreamAlarms feed. The stream opens with one // `active_alarm` per currently-active alarm, then a single // `snapshot_complete`, then a `transition` for every subsequent change. message AlarmFeedMessage { oneof payload { // Part of the initial active-alarm snapshot (ConditionRefresh). ActiveAlarmSnapshot active_alarm = 1; // Sentinel: the initial snapshot is fully delivered and `transition` // messages follow. Always true when present. bool snapshot_complete = 2; // A live alarm state change (raise / acknowledge / clear). OnAlarmTransitionEvent transition = 3; // Provider-mode status. Emitted once on stream open and again on every // failover/failback so late joiners learn the current mode immediately. AlarmProviderStatus provider_status = 4; } } message AlarmProviderStatus { AlarmProviderMode mode = 1; bool degraded = 2; // true whenever mode == SUBTAG string reason = 3; // human-readable switch reason google.protobuf.Timestamp since = 4; } message MxStatusProxy { // Mirrors the `success` member of the MXAccess MXSTATUS_PROXY struct // (a 16-bit signed value in the COM struct, widened to int32 on the // wire). Despite the name it is NOT a boolean — it is the raw numeric // indicator the worker reads off the COM struct without reinterpretation. // It is carried verbatim for diagnostics; the authoritative success/ // failure of the operation is `category` (MX_STATUS_CATEGORY_OK marks // success), with `detail`, `diagnostic_text`, `raw_category`, and // `raw_detected_by` describing any non-OK outcome. Clients should branch // on `category`, not on a specific `success` value. int32 success = 1; MxStatusCategory category = 2; MxStatusSource detected_by = 3; int32 detail = 4; int32 raw_category = 5; int32 raw_detected_by = 6; string diagnostic_text = 7; } enum MxStatusCategory { MX_STATUS_CATEGORY_UNSPECIFIED = 0; MX_STATUS_CATEGORY_UNKNOWN = 1; MX_STATUS_CATEGORY_OK = 2; MX_STATUS_CATEGORY_PENDING = 3; MX_STATUS_CATEGORY_WARNING = 4; MX_STATUS_CATEGORY_COMMUNICATION_ERROR = 5; MX_STATUS_CATEGORY_CONFIGURATION_ERROR = 6; MX_STATUS_CATEGORY_OPERATIONAL_ERROR = 7; MX_STATUS_CATEGORY_SECURITY_ERROR = 8; MX_STATUS_CATEGORY_SOFTWARE_ERROR = 9; MX_STATUS_CATEGORY_OTHER_ERROR = 10; } enum MxStatusSource { MX_STATUS_SOURCE_UNSPECIFIED = 0; MX_STATUS_SOURCE_UNKNOWN = 1; MX_STATUS_SOURCE_REQUESTING_LMX = 2; MX_STATUS_SOURCE_RESPONDING_LMX = 3; MX_STATUS_SOURCE_REQUESTING_NMX = 4; MX_STATUS_SOURCE_RESPONDING_NMX = 5; MX_STATUS_SOURCE_REQUESTING_AUTOMATION_OBJECT = 6; MX_STATUS_SOURCE_RESPONDING_AUTOMATION_OBJECT = 7; } message MxValue { MxDataType data_type = 1; string variant_type = 2; bool is_null = 3; string raw_diagnostic = 4; int32 raw_data_type = 5; oneof kind { bool bool_value = 10; int32 int32_value = 11; int64 int64_value = 12; float float_value = 13; double double_value = 14; string string_value = 15; google.protobuf.Timestamp timestamp_value = 16; MxArray array_value = 17; bytes raw_value = 18; } } message MxArray { MxDataType element_data_type = 1; string variant_type = 2; repeated uint32 dimensions = 3; string raw_diagnostic = 4; int32 raw_element_data_type = 5; oneof values { BoolArray bool_values = 10; Int32Array int32_values = 11; Int64Array int64_values = 12; FloatArray float_values = 13; DoubleArray double_values = 14; StringArray string_values = 15; TimestampArray timestamp_values = 16; RawArray raw_values = 17; } } message BoolArray { repeated bool values = 1; } message Int32Array { repeated int32 values = 1; } message Int64Array { repeated int64 values = 1; } message FloatArray { repeated float values = 1; } message DoubleArray { repeated double values = 1; } message StringArray { repeated string values = 1; } message TimestampArray { repeated google.protobuf.Timestamp values = 1; } message RawArray { repeated bytes values = 1; } enum MxDataType { MX_DATA_TYPE_UNSPECIFIED = 0; MX_DATA_TYPE_UNKNOWN = 1; MX_DATA_TYPE_NO_DATA = 2; MX_DATA_TYPE_BOOLEAN = 3; MX_DATA_TYPE_INTEGER = 4; MX_DATA_TYPE_FLOAT = 5; MX_DATA_TYPE_DOUBLE = 6; MX_DATA_TYPE_STRING = 7; MX_DATA_TYPE_TIME = 8; MX_DATA_TYPE_ELAPSED_TIME = 9; MX_DATA_TYPE_REFERENCE_TYPE = 10; MX_DATA_TYPE_STATUS_TYPE = 11; MX_DATA_TYPE_ENUM = 12; MX_DATA_TYPE_SECURITY_CLASSIFICATION_ENUM = 13; MX_DATA_TYPE_DATA_QUALITY_TYPE = 14; MX_DATA_TYPE_QUALIFIED_ENUM = 15; MX_DATA_TYPE_QUALIFIED_STRUCT = 16; MX_DATA_TYPE_INTERNATIONALIZED_STRING = 17; MX_DATA_TYPE_BIG_STRING = 18; MX_DATA_TYPE_END = 19; } message ProtocolStatus { ProtocolStatusCode code = 1; string message = 2; } enum ProtocolStatusCode { PROTOCOL_STATUS_CODE_UNSPECIFIED = 0; PROTOCOL_STATUS_CODE_OK = 1; PROTOCOL_STATUS_CODE_INVALID_REQUEST = 2; PROTOCOL_STATUS_CODE_SESSION_NOT_FOUND = 3; PROTOCOL_STATUS_CODE_SESSION_NOT_READY = 4; PROTOCOL_STATUS_CODE_WORKER_UNAVAILABLE = 5; PROTOCOL_STATUS_CODE_TIMEOUT = 6; PROTOCOL_STATUS_CODE_CANCELED = 7; PROTOCOL_STATUS_CODE_PROTOCOL_VIOLATION = 8; PROTOCOL_STATUS_CODE_MXACCESS_FAILURE = 9; } enum SessionState { SESSION_STATE_UNSPECIFIED = 0; SESSION_STATE_CREATING = 1; SESSION_STATE_STARTING_WORKER = 2; SESSION_STATE_WAITING_FOR_PIPE = 3; SESSION_STATE_HANDSHAKING = 4; SESSION_STATE_INITIALIZING_WORKER = 5; SESSION_STATE_READY = 6; SESSION_STATE_CLOSING = 7; SESSION_STATE_CLOSED = 8; SESSION_STATE_FAULTED = 9; }