\# AquaCom Integration Gateway – Configuration Reference \## 1. Purpose This document defines the configuration model for the \*\*AquaCom Integration Gateway\*\*. It is the authoritative human-readable reference for: \- configuration sections; \- configuration fields; \- required and optional values; \- defaults; \- validation rules; \- relationships between configuration areas; \- example configuration. The configuration model shall remain implementation-language independent. Machine-readable validation schemas shall be maintained separately under: ```text schemas/ ``` This document explains what the configuration means. The schema files define what configuration is syntactically and structurally valid. \--- \# 2. Configuration principles Gateway configuration shall be: \- external to the application executable; \- machine-readable; \- versioned; \- schema-validated; \- suitable for source control; \- portable between environments; \- explicit about identifiers; \- independent of runtime object allocation. Production secrets shall not be stored directly in normal version-controlled configuration. Configuration syntax shown in this document uses YAML for readability. The final implementation may use YAML, JSON, TOML, or another structured format, provided that the semantic model defined here is preserved. \--- \# 3. Configuration hierarchy The gateway configuration shall conceptually contain: ```yaml configVersion: 1 gateway: ... logging: ... diagnostics: ... security: ... opcua: ... history: ... storage: ... stations: ... ``` The top-level configuration sections are: | Section | Purpose | |---|---| | `configVersion` | Configuration schema version | | `gateway` | Gateway identity and runtime behavior | | `logging` | Logging configuration | | `diagnostics` | Diagnostics and metrics behavior | | `security` | Shared security configuration | | `opcua` | OPC UA server configuration | | `history` | Historical subsystem configuration | | `storage` | Historical repositories and storage destinations | | `stations` | AquaCom station definitions | \--- \# 4. Configuration version \## 4.1 `configVersion` \*\*Type:\*\* integer \*\*Required:\*\* yes Defines the version of the gateway configuration schema. Example: ```yaml configVersion: 1 ``` The application shall reject configuration using an unsupported schema version. Configuration migration between incompatible schema versions shall be explicit. The application shall not silently reinterpret an incompatible configuration format. \--- \# 5. Gateway configuration Example: ```yaml gateway: id: aquacom-gateway-01 displayName: Central AquaCom Gateway timezone: Europe/Stockholm startup: allowDegradedStartup: true shutdown: gracefulTimeout: 30s ``` \--- \## 5.1 `gateway.id` \*\*Type:\*\* string \*\*Required:\*\* yes Stable identifier for this gateway instance. Example: ```yaml id: aquacom-gateway-01 ``` Requirements: \- must be unique within the relevant operational environment; \- shall remain stable across software restart; \- shall normally remain stable across software upgrade; \- shall not be based on runtime-generated identifiers. This identifier may be used in: \- diagnostics; \- logging; \- historical metadata; \- OPC UA namespace generation; \- audit records. \--- \## 5.2 `gateway.displayName` \*\*Type:\*\* string \*\*Required:\*\* no Human-readable name. Example: ```yaml displayName: Central AquaCom Gateway ``` Changing this value shall not change the gateway's stable identity. \--- \## 5.3 `gateway.timezone` \*\*Type:\*\* timezone identifier \*\*Required:\*\* yes Defines the gateway's configured local timezone. Example: ```yaml timezone: Europe/Stockholm ``` UTC shall normally be used internally. This timezone may be used for: \- presentation; \- interpretation of timestamps where the source does not include timezone information; \- diagnostics. A station may override this value. \--- \# 6. Startup configuration \## 6.1 `gateway.startup.allowDegradedStartup` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Defines whether the gateway may start when non-critical external dependencies are unavailable. Example: ```yaml startup: allowDegradedStartup: true ``` If enabled, failures such as an unavailable optional storage destination shall not necessarily prevent live AquaCom acquisition or OPC UA startup. Critical configuration errors shall always prevent startup. \--- \# 7. Shutdown configuration \## 7.1 `gateway.shutdown.gracefulTimeout` \*\*Type:\*\* duration \*\*Default:\*\* implementation-defined Defines the maximum time allowed for controlled shutdown. Example: ```yaml shutdown: gracefulTimeout: 30s ``` During this period the gateway should attempt to: ```text stop new acquisition finish or cancel active transactions persist synchronization state flush durable state stop OPC UA close storage ``` \--- \# 8. Logging configuration Example: ```yaml logging: level: information structured: true telegramLogging: enabled: false includePayload: false retention: maxFiles: 14 maxFileSize: 100MB ``` \--- \## 8.1 `logging.level` \*\*Type:\*\* enumeration \*\*Required:\*\* no Typical values: ```text trace debug information warning error critical ``` Production default should normally be: ```yaml level: information ``` \--- \## 8.2 `logging.structured` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Enables structured logging where supported by the implementation. Structured log records should support fields such as: ```text timestamp severity component stationId pointId operation correlationId message error ``` \--- \# 9. AquaCom telegram logging Example: ```yaml telegramLogging: enabled: false includePayload: false ``` Telegram logging shall be treated as a diagnostic capability. It shall not be enabled by default in production. \--- \## 9.1 `logging.telegramLogging.enabled` \*\*Type:\*\* boolean \*\*Default:\*\* `false` Enables AquaCom telegram-level logging. \--- \## 9.2 `logging.telegramLogging.includePayload` \*\*Type:\*\* boolean \*\*Default:\*\* `false` Defines whether raw telegram payload is included. If enabled, operators shall consider: \- storage consumption; \- operational sensitivity; \- possible exposure of process information. \--- \# 10. Diagnostics configuration Example: ```yaml diagnostics: enabled: true opcua: exposeGatewayDiagnostics: true exposeStationDiagnostics: true exposeStorageDiagnostics: true metrics: enabled: true ``` \--- \## 10.1 `diagnostics.enabled` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Enables gateway diagnostics. Disabling this shall not disable required internal error handling. \--- \## 10.2 `diagnostics.opcua.exposeGatewayDiagnostics` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Exposes gateway-level diagnostic nodes through OPC UA. \--- \## 10.3 `diagnostics.opcua.exposeStationDiagnostics` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Exposes per-station communication and synchronization diagnostics. \--- \## 10.4 `diagnostics.opcua.exposeStorageDiagnostics` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Exposes historical-storage diagnostics. \--- \## 10.5 `diagnostics.metrics.enabled` \*\*Type:\*\* boolean \*\*Default:\*\* implementation-defined Enables runtime metrics. The metrics transport or technology is implementation-specific. \--- \# 11. Shared security configuration Example: ```yaml security: secretsProvider: type: environment certificates: directory: ./certificates ``` This section contains shared security behavior. Protocol-specific settings belong under their corresponding subsystem. \--- \# 12. Secret handling \## 12.1 `security.secretsProvider.type` Defines how secrets are supplied. Possible implementations may include: ```text environment file operating-system secret store container secret external secret service ``` Production secrets shall not normally appear directly in the gateway configuration. Example: ```yaml database: username: gateway\_user passwordSecret: HISTORY\_DB\_PASSWORD ``` rather than: ```yaml password: SuperSecretPassword123 ``` \--- \# 13. OPC UA configuration Example: ```yaml opcua: enabled: true application: name: AquaCom Integration Gateway uri: urn:example:aquacom-gateway endpoint: bindAddress: 0.0.0.0 port: 4840 path: /aquacom namespace: uri: urn:example:aquacom rootName: AquaCom dataAccess: enabled: true historicalAccess: enabled: true repository: local-history maxValuesPerRead: 10000 maxConcurrentReads: 10 security: allowNone: false certificate: gateway-opcua trustMode: explicit ``` \--- \# 14. `opcua.enabled` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Controls whether the OPC UA server is started. The gateway architecture shall permit AquaCom acquisition and historical storage to operate independently where practical if OPC UA is disabled. \--- \# 15. OPC UA application identity \## 15.1 `opcua.application.name` Human-readable OPC UA application name. Example: ```yaml name: AquaCom Integration Gateway ``` \--- \## 15.2 `opcua.application.uri` Stable application URI. Example: ```yaml uri: urn:example:aquacom-gateway ``` The URI should remain stable for an installed gateway instance. \--- \# 16. OPC UA endpoint Example: ```yaml endpoint: bindAddress: 0.0.0.0 port: 4840 path: /aquacom ``` \--- \## 16.1 `opcua.endpoint.bindAddress` Defines the interface on which the OPC UA endpoint listens. Production deployments should consider binding only to the required OT network interface. \--- \## 16.2 `opcua.endpoint.port` \*\*Type:\*\* integer Example: ```yaml port: 4840 ``` Port conflict shall be detected during startup. \--- \## 16.3 `opcua.endpoint.path` Optional OPC UA endpoint path. Example: ```yaml path: /aquacom ``` \--- \# 17. OPC UA namespace Example: ```yaml namespace: uri: urn:example:aquacom rootName: AquaCom ``` \--- \## 17.1 `opcua.namespace.uri` Stable namespace URI used for gateway-specific nodes. Changing this value may affect client configurations and shall therefore be treated as a compatibility-impacting change. \--- \## 17.2 `opcua.namespace.rootName` Human-readable root object name. Changing this value shall not automatically alter stable NodeIds. \--- \# 18. OPC UA Data Access \## 18.1 `opcua.dataAccess.enabled` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Enables exposure of configured current values. \--- \# 19. OPC UA Historical Access Example: ```yaml historicalAccess: enabled: true repository: local-history maxValuesPerRead: 10000 maxConcurrentReads: 10 ``` \--- \## 19.1 `opcua.historicalAccess.enabled` \*\*Type:\*\* boolean Enables OPC UA Historical Access. If enabled, a queryable history repository must be configured. \--- \## 19.2 `opcua.historicalAccess.repository` \*\*Type:\*\* storage repository identifier \*\*Required when Historical Access is enabled\*\* Example: ```yaml repository: local-history ``` The referenced destination must implement the History Repository capability. A sink-only destination is invalid here. \--- \## 19.3 `opcua.historicalAccess.maxValuesPerRead` \*\*Type:\*\* positive integer Limits the number of values returned in one historical response. Example: ```yaml maxValuesPerRead: 10000 ``` Larger responses shall use OPC UA continuation where required. \--- \## 19.4 `opcua.historicalAccess.maxConcurrentReads` \*\*Type:\*\* positive integer Limits concurrent historical requests. This protects the gateway and historical repository against excessive resource usage. \--- \# 20. OPC UA security configuration Example: ```yaml security: allowNone: false certificate: gateway-opcua trustMode: explicit userAuthentication: enabled: false ``` \--- \## 20.1 `opcua.security.allowNone` \*\*Type:\*\* boolean \*\*Default:\*\* `false` Controls whether an unsecured OPC UA endpoint is permitted. Production configuration should normally use: ```yaml allowNone: false ``` \--- \## 20.2 `opcua.security.certificate` Reference to an externally configured certificate identity. Private keys shall not be embedded directly in configuration committed to source control. \--- \## 20.3 `opcua.security.trustMode` Possible values may include: ```text explicit managed ``` `explicit` means client certificates must be explicitly trusted. The exact supported trust modes depend upon the selected OPC UA implementation. \--- \# 21. Historical subsystem configuration Example: ```yaml history: enabled: true liveHistorization: enabled: true deduplication: enabled: true conflictPolicy: reject synchronization: enabled: true resumeAfterRestart: true backfill: enabled: true priority: low maxRequestsPerSecond: 2 spool: enabled: true maxSize: 20GB maxAge: 30d overflowPolicy: stop-history ``` \--- \# 22. `history.enabled` \*\*Type:\*\* boolean Enables the gateway historical subsystem. This includes historical pipeline functionality. Individual stations and points may still enable or disable history independently. \--- \# 23. Live historization \## 23.1 `history.liveHistorization.enabled` \*\*Type:\*\* boolean Determines whether live current values may also be submitted to the historical pipeline. Example: ```yaml liveHistorization: enabled: true ``` This setting does not replace per-point history configuration. Both global and point-level configuration shall permit history before a live value is historized. \--- \# 24. Deduplication Example: ```yaml deduplication: enabled: true conflictPolicy: reject ``` \--- \## 24.1 `history.deduplication.enabled` \*\*Type:\*\* boolean \*\*Recommended:\*\* `true` Historical processing should normally be idempotent. \--- \## 24.2 `history.deduplication.conflictPolicy` Defines behavior when two different values have the same logical historical identity. Allowed conceptual values: ```text reject keep-first keep-last version ``` Recommended default: ```yaml conflictPolicy: reject ``` A conflict shall generate diagnostics. \--- \# 25. History synchronization Example: ```yaml synchronization: enabled: true resumeAfterRestart: true ``` \--- \## 25.1 `history.synchronization.enabled` Enables synchronization-state management. \--- \## 25.2 `history.synchronization.resumeAfterRestart` \*\*Type:\*\* boolean \*\*Recommended:\*\* `true` If enabled, the gateway restores historical synchronization watermarks and continues incomplete synchronization after restart. \--- \# 26. Backfill configuration Example: ```yaml backfill: enabled: true priority: low maxRequestsPerSecond: 2 ``` \--- \## 26.1 `history.backfill.enabled` Enables retrieval of missing AquaCom history following communication interruption. Actual availability depends upon: \- AquaCom protocol support; \- RTU capabilities; \- verified station configuration. \--- \## 26.2 `history.backfill.priority` Defines scheduling priority relative to other AquaCom operations. Supported values may include: ```text low normal ``` Recommended: ```yaml priority: low ``` Live acquisition shall normally take precedence. \--- \## 26.3 `history.backfill.maxRequestsPerSecond` Optional history-retrieval rate limit. Used to prevent large backfill operations from consuming all available station communication capacity. \--- \# 27. Durable spool configuration Example: ```yaml spool: enabled: true path: ./data/spool maxSize: 20GB maxAge: 30d overflowPolicy: stop-history ``` \--- \## 27.1 `history.spool.enabled` \*\*Recommended:\*\* `true` Enables persistent delivery buffering. \--- \## 27.2 `history.spool.path` Location of persistent spool data where the selected implementation requires an explicit path. The path must be writable. \--- \## 27.3 `history.spool.maxSize` Maximum spool size. Example: ```yaml maxSize: 20GB ``` The gateway shall provide diagnostics before reaching this limit. \--- \## 27.4 `history.spool.maxAge` Optional maximum retention time for pending spool records. Care shall be taken before enabling automatic age-based deletion. \--- \## 27.5 `history.spool.overflowPolicy` Defines behavior if the spool cannot accept additional data. Conceptual values: ```text stop-history reject-new drop-oldest fail-gateway ``` Recommended production default: ```yaml overflowPolicy: stop-history ``` Dropping historical information silently shall not be permitted. \--- \# 28. Storage configuration Example: ```yaml storage: destinations: - id: local-history type: repository driver: example-local-db required: true capabilities: write: true query: true connection: path: ./data/history - id: enterprise-historian type: sink driver: example-historian required: true connection: endpoint: historian.example.local credentialSecret: HISTORIAN\_CREDENTIAL - id: archive type: sink driver: ndjson required: false connection: directory: ./archive ``` \--- \# 29. Storage destination identifiers \## 29.1 `storage.destinations\[].id` \*\*Type:\*\* string \*\*Required:\*\* yes Stable identifier for the storage destination. Example: ```yaml id: local-history ``` Must be unique. Other configuration sections reference destinations using this identifier. \--- \# 30. Storage destination type \## 30.1 `storage.destinations\[].type` Defines the architectural role. Conceptual values: ```text repository sink repository-and-sink ``` Meaning: | Type | Query | Write | |---|---|---| | `repository` | yes | implementation-dependent | | `sink` | no | yes | | `repository-and-sink` | yes | yes | The exact schema may represent capabilities instead of this combined enumeration. \--- \# 31. Storage driver \## 31.1 `storage.destinations\[].driver` Defines the implementation adapter. Example: ```yaml driver: example-local-db ``` The value is implementation-specific. Business logic shall not depend directly on this value. \--- \# 32. Required and optional destinations \## 32.1 `storage.destinations\[].required` \*\*Type:\*\* boolean Defines whether successful delivery to the destination is required before a spool record may be considered fully delivered. Example: ```yaml required: true ``` If: ```yaml required: false ``` failure shall generate diagnostics but shall not indefinitely block cleanup of records that have reached all required destinations. \--- \# 33. Storage capabilities Example: ```yaml capabilities: write: true query: true ``` This may be validated against the selected driver. A repository used for OPC UA Historical Access must have: ```yaml query: true ``` \--- \# 34. Storage retry configuration A storage destination may contain: ```yaml retry: enabled: true initialDelay: 2s maximumDelay: 5m multiplier: 2 ``` Retry policy shall be independent for each destination. Storage retries shall not block AquaCom live acquisition. \--- \# 35. Station configuration Example: ```yaml stations: - id: PS001 displayName: Wastewater Pump Station 001 enabled: true timezone: Europe/Stockholm transport: type: tcp host: 192.0.2.10 port: 1234 aquacom: address: 101 profile: default acquisition: live: enabled: true pollingInterval: 5s requestTimeout: 3s retryCount: 2 history: enabled: true backfillEnabled: true pointDefinitions: sourceType: atf path: ./stations/PS001.atf ``` \--- \# 36. `stations\[].id` \*\*Type:\*\* string \*\*Required:\*\* yes Stable gateway identifier for the station. Example: ```yaml id: PS001 ``` Requirements: \- unique within the gateway; \- stable across restart; \- stable across IP-address changes; \- stable across display-name changes. The station ID may form part of: ```text PointId OPC UA NodeId historical identity logs diagnostics ``` \--- \# 37. `stations\[].displayName` Human-readable station name. Example: ```yaml displayName: Wastewater Pump Station 001 ``` Changing this shall not change the stable station identity. \--- \# 38. `stations\[].enabled` \*\*Type:\*\* boolean \*\*Default:\*\* `true` Controls whether the gateway actively communicates with the station. A disabled station configuration may remain visible diagnostically. \--- \# 39. Station timezone \## 39.1 `stations\[].timezone` Optional station-specific timezone. If omitted, the gateway timezone is inherited. Example: ```yaml timezone: Europe/Stockholm ``` This configuration is important where AquaCom timestamps lack explicit timezone information. \--- \# 40. Transport configuration Example: ```yaml transport: type: tcp host: 192.0.2.10 port: 1234 connectTimeout: 5s idleTimeout: 30s ``` Transport-specific fields are conditional on `type`. \--- \# 41. `transport.type` Defines the AquaCom transport implementation. Potential supported values may include: ```text tcp serial serial-over-ip ``` Only implemented and verified transport types shall be accepted. \--- \# 42. TCP transport Example: ```yaml transport: type: tcp host: 192.0.2.10 port: 1234 connectTimeout: 5s ``` \--- \## 42.1 `transport.host` Hostname or IP address. This value is not the station's stable identity. \--- \## 42.2 `transport.port` TCP port used for AquaCom communication. The default shall not be invented if it is not formally defined for the target equipment. Where no verified standard value exists, explicit configuration shall be required. \--- \## 42.3 `transport.connectTimeout` Maximum connection establishment time. \--- \# 43. Serial transport Conceptual example: ```yaml transport: type: serial port: /dev/ttyS0 baudRate: 9600 dataBits: 8 stopBits: 1 parity: none ``` Actual values shall be determined from validated AquaCom documentation and target-device requirements. Codex shall not insert assumed AquaCom serial defaults without evidence. \--- \# 44. AquaCom station protocol configuration Example: ```yaml aquacom: address: 101 profile: default ``` This section contains AquaCom-specific station configuration. Only verified protocol concepts shall be introduced here. \--- \## 44.1 `aquacom.address` Station address or AquaCom identifier required by the verified protocol implementation. The representation is protocol-dependent. It shall not be assumed to be identical to `stations\[].id`. \--- \## 44.2 `aquacom.profile` Optional reference to an AquaCom protocol profile. Profiles may be useful where different controller generations or configurations require different verified protocol behaviors. Example: ```yaml profile: app700 ``` A profile shall never enable guessed protocol behavior. \--- \# 45. Acquisition configuration Each station contains: ```yaml acquisition: live: ... history: ... ``` Live acquisition and historical acquisition shall be independently configurable. \--- \# 46. Live acquisition Example: ```yaml live: enabled: true pollingInterval: 5s requestTimeout: 3s retryCount: 2 ``` \--- \## 46.1 `acquisition.live.enabled` Enables current-value acquisition for the station. \--- \## 46.2 `acquisition.live.pollingInterval` Defines the normal polling period. The implementation shall validate unreasonable values. Example: ```yaml pollingInterval: 5s ``` \--- \## 46.3 `acquisition.live.requestTimeout` Maximum allowed time for an AquaCom live transaction before timeout handling. \--- \## 46.4 `acquisition.live.retryCount` Number of immediate or near-immediate retries permitted before normal communication-failure logic takes over. Retries shall not create an uncontrolled retry storm. \--- \# 47. Station historical acquisition Example: ```yaml history: enabled: true backfillEnabled: true maxBackfillAge: 7d ``` \--- \## 47.1 `acquisition.history.enabled` Enables AquaCom historical retrieval for the station. This requires verified support for the station/controller type. \--- \## 47.2 `acquisition.history.backfillEnabled` Enables automatic recovery following communication interruption. \--- \## 47.3 `acquisition.history.maxBackfillAge` Optional limit on how far back the gateway will automatically request history. Example: ```yaml maxBackfillAge: 7d ``` This protects against unexpected very large historical queries. A value beyond this range may require an explicit administrative operation. \--- \# 48. Point definition source Points may originate from sources such as: ```text ATF static configuration engineering data import future external configuration service ``` Example: ```yaml pointDefinitions: sourceType: atf path: ./stations/PS001.atf ``` \--- \## 48.1 `pointDefinitions.sourceType` Potential values: ```text atf inline file ``` Only implemented source types shall be accepted. \--- \## 48.2 `pointDefinitions.path` Path to an external point-definition file. File changes shall be validated before activation. \--- \# 49. Inline point definitions Conceptual example: ```yaml points: - id: LEVEL displayName: Wet well level description: Measured wet well level source: reference: ... dataType: float engineeringUnit: m scaling: enabled: false live: enabled: true history: enabled: true opcua: enabled: true historizing: true storage: enabled: true ``` The exact AquaCom source-reference syntax shall only be defined when supported by verified protocol or ATF semantics. \--- \# 50. Point identifier \## 50.1 `points\[].id` \*\*Required:\*\* yes Stable point identifier within the station. Example: ```yaml id: LEVEL ``` Logical identity may become: ```text station:PS001/point:LEVEL ``` Changing `displayName` shall not change this identifier. \--- \# 51. Point display name \## 51.1 `points\[].displayName` Human-readable presentation name. Example: ```yaml displayName: Wet well level ``` May be changed without creating a new logical process point. \--- \# 52. Point source reference Example: ```yaml source: reference: ... ``` Defines how the point maps to AquaCom. The content is intentionally unspecified until AquaCom mapping rules are verified. Codex shall not invent source-reference syntax. \--- \# 53. Point data type \## 53.1 `points\[].dataType` Logical canonical data type. Possible values may include: ```text boolean integer unsigned-integer float double string ``` The final supported set shall be defined by the canonical data model. \--- \# 54. Engineering unit \## 54.1 `points\[].engineeringUnit` Optional engineering unit. Examples: ```yaml engineeringUnit: m ``` ```yaml engineeringUnit: l/s ``` ```yaml engineeringUnit: °C ``` Engineering units should use a controlled representation where feasible. \--- \# 55. Point scaling Example: ```yaml scaling: enabled: true multiplier: 0.1 offset: 0 ``` Scaling is applied after verified AquaCom decoding and before creation of the canonical value. The raw value may optionally be retained diagnostically. \--- \# 56. Point live configuration Example: ```yaml live: enabled: true ``` Controls whether the point participates in current-state processing. \--- \# 57. Point history configuration Example: ```yaml history: enabled: true ``` Controls whether historical information is processed for the point. \--- \# 58. Point OPC UA configuration Example: ```yaml opcua: enabled: true historizing: true ``` \--- \## 58.1 `points\[].opcua.enabled` Controls whether the point is exposed through OPC UA. \--- \## 58.2 `points\[].opcua.historizing` Controls whether the OPC UA Variable advertises historical capability. If enabled: \- point history must be enabled; \- OPC UA Historical Access must be enabled; \- a queryable repository must be configured. \--- \# 59. Explicit NodeId override Optional example: ```yaml opcua: enabled: true nodeId: station/PS001/point/LEVEL ``` Normally the gateway should generate deterministic NodeIds from stable station and point identifiers. Manual override should only be required for compatibility or migration scenarios. Duplicate NodeIds shall be rejected. \--- \# 60. Point storage configuration Example: ```yaml storage: enabled: true destinations: - local-history - enterprise-historian ``` If `destinations` is omitted, a global/default routing policy may be used. \--- \# 61. Storage routing The system shall support routing history to selected destinations. Example: ```yaml storage: enabled: true destinations: - local-history - enterprise-historian ``` Different points may therefore use different storage policies if required. \--- \# 62. History source behavior A point may theoretically receive historical data from: ```text live historization AquaCom historical retrieval AquaCom report retrieval future import ``` The canonical `AcquisitionSource` shall preserve the origin. Storage routing shall not normally depend upon raw AquaCom message types. \--- \# 63. Timestamp configuration Station timestamp behavior may include: ```yaml timestamps: sourceTimezone: Europe/Stockholm maximumFutureDeviation: 5m maximumPastDeviation: 365d ambiguousDstPolicy: reject ``` \--- \## 63.1 `timestamps.sourceTimezone` Used to interpret device timestamps without explicit timezone information. Defaults to: ```text station timezone ``` then: ```text gateway timezone ``` if no station timezone exists. \--- \## 63.2 `timestamps.maximumFutureDeviation` Maximum permitted source timestamp ahead of gateway time before it is flagged. \--- \## 63.3 `timestamps.maximumPastDeviation` Optional sanity threshold for implausibly old values. Historical backfill behavior may legitimately require values much older than normal live values. The implementation shall distinguish history from erroneous live timestamps. \--- \## 63.4 `timestamps.ambiguousDstPolicy` Defines behavior when a source local timestamp is ambiguous during daylight-saving transition. Possible conceptual values: ```text reject prefer-earlier prefer-later mark-uncertain ``` Recommended behavior is either: ```text mark-uncertain ``` or: ```text reject ``` depending on operational requirements. \--- \# 64. Communication health configuration A station may define thresholds such as: ```yaml health: degradedAfterFailures: 2 offlineAfterFailures: 5 staleAfter: 30s ``` \--- \## 64.1 `health.degradedAfterFailures` Consecutive failed transactions before communication changes to a degraded state. \--- \## 64.2 `health.offlineAfterFailures` Consecutive failed transactions before the station is considered offline. This value must be greater than or equal to the degraded threshold. \--- \## 64.3 `health.staleAfter` Maximum age of a current value before quality may be changed to stale/uncertain/bad according to configured behavior. \--- \# 65. Retry behavior Transport, AquaCom transactions and storage destinations may each have separate retry policies. These retries shall not be combined into an uncontrolled nested retry loop. Retry configuration should define: ```yaml retry: initialDelay: 1s maximumDelay: 1m multiplier: 2 jitter: true ``` Exact supported fields are implementation-specific. \--- \# 66. Configuration inheritance Where practical, the gateway may support default configuration inheritance. Example: ```yaml defaults: station: acquisition: live: pollingInterval: 5s health: degradedAfterFailures: 2 offlineAfterFailures: 5 ``` Then a station may override: ```yaml stations: - id: PS001 acquisition: live: pollingInterval: 2s ``` If implemented, inheritance rules must be deterministic and documented. Implicit multi-level inheritance should be avoided if it makes effective configuration difficult to understand. \--- \# 67. Configuration validation rules The configuration validator shall detect at least: ```text unsupported configVersion duplicate gateway/station/point/storage identifiers duplicate OPC UA NodeIds missing referenced storage destinations Historical Access enabled without queryable repository point historizing enabled without history capability unsupported transport type unsupported storage driver invalid timezone invalid durations invalid numeric limits invalid security configuration required secrets not available nonexistent required files invalid ATF or point-definition references history enabled for unsupported station profile configuration contradictions ``` \--- \# 68. Cross-field validation Examples of required relationships follow. If: ```yaml opcua: historicalAccess: enabled: true ``` then: ```text a queryable history repository must exist. ``` If: ```yaml point: opcua: historizing: true ``` then: ```text point history must be enabled. ``` If: ```yaml history: enabled: false ``` then point-level historical acquisition shall not become active. If: ```yaml station: acquisition: history: enabled: true ``` but the configured AquaCom profile has no verified historical implementation, validation shall fail or the station history feature shall be explicitly marked unavailable. It shall not silently use guessed AquaCom behavior. \--- \# 69. Configuration activation Configuration shall follow: ```text Load ↓ Parse ↓ Schema validation ↓ Semantic validation ↓ Dependency validation ↓ Activation ``` Invalid configuration shall not partially activate. Where dynamic reload is supported: ```text Current valid configuration │ ▼ New configuration │ ▼ Validate ┌───────┴────────┐ │ │ valid invalid │ │ ▼ ▼ activate retain existing ``` \--- \# 70. Dynamic configuration Changes may be classified as: ```text runtime-safe controlled-restart full-restart ``` Examples that may eventually be runtime-safe: ```text logging level polling intervals selected diagnostics storage retry intervals ``` Changes likely requiring controlled restart or resource reconstruction: ```text OPC UA application certificate OPC UA namespace URI transport type storage driver type persistent storage path ``` Exact behavior shall be defined by the implementation. \--- \# 71. Configuration compatibility The gateway shall distinguish: ```text configuration schema compatibility OPC UA namespace compatibility storage schema compatibility protocol profile compatibility ``` A configuration schema change shall not automatically require an OPC UA namespace change. \--- \# 72. Example minimal configuration ```yaml configVersion: 1 gateway: id: aquacom-gateway-01 timezone: Europe/Stockholm logging: level: information diagnostics: enabled: true opcua: enabled: true application: name: AquaCom Integration Gateway uri: urn:example:aquacom-gateway endpoint: bindAddress: 0.0.0.0 port: 4840 namespace: uri: urn:example:aquacom dataAccess: enabled: true historicalAccess: enabled: false security: allowNone: false certificate: gateway-opcua history: enabled: false storage: destinations: \[] stations: - id: PS001 enabled: true transport: type: tcp host: 192.0.2.10 port: 1234 aquacom: address: 101 acquisition: live: enabled: true pollingInterval: 5s pointDefinitions: sourceType: atf path: ./stations/PS001.atf ``` This configuration represents: ```text AquaCom live acquisition ↓ OPC UA current values ``` without historical functionality. \--- \# 73. Example configuration with history ```yaml configVersion: 1 gateway: id: aquacom-gateway-01 timezone: Europe/Stockholm logging: level: information diagnostics: enabled: true opcua: enabled: true application: name: AquaCom Integration Gateway uri: urn:example:aquacom-gateway endpoint: bindAddress: 0.0.0.0 port: 4840 namespace: uri: urn:example:aquacom dataAccess: enabled: true historicalAccess: enabled: true repository: local-history maxValuesPerRead: 10000 security: allowNone: false certificate: gateway-opcua history: enabled: true liveHistorization: enabled: true deduplication: enabled: true conflictPolicy: reject synchronization: enabled: true resumeAfterRestart: true backfill: enabled: true priority: low maxRequestsPerSecond: 2 spool: enabled: true path: ./data/spool maxSize: 20GB overflowPolicy: stop-history storage: destinations: - id: local-history type: repository-and-sink driver: local-history required: true capabilities: write: true query: true connection: path: ./data/history - id: central-historian type: sink driver: enterprise-historian required: true capabilities: write: true query: false connection: endpoint: historian.example.local credentialSecret: CENTRAL\_HISTORIAN\_CREDENTIAL - id: archive type: sink driver: ndjson required: false capabilities: write: true query: false connection: directory: ./archive stations: - id: PS001 displayName: Wastewater Pump Station 001 enabled: true timezone: Europe/Stockholm transport: type: tcp host: 192.0.2.10 port: 1234 connectTimeout: 5s aquacom: address: 101 profile: default acquisition: live: enabled: true pollingInterval: 5s requestTimeout: 3s retryCount: 2 history: enabled: true backfillEnabled: true maxBackfillAge: 7d timestamps: sourceTimezone: Europe/Stockholm maximumFutureDeviation: 5m health: degradedAfterFailures: 2 offlineAfterFailures: 5 staleAfter: 30s pointDefinitions: sourceType: atf path: ./stations/PS001.atf ``` \--- \# 74. Example resulting data flow Using the configuration above: ```text PS001 │ │ AquaCom ▼ Gateway │ ├────────► Current-State Service │ │ │ ▼ │ OPC UA DA │ └────────► Historical Pipeline │ ▼ Durable Spool │ ┌─────────┼─────────────┐ │ │ │ ▼ ▼ ▼ Local History Central Archive Repository Historian │ ▼ OPC UA HA ``` \--- \# 75. Recommended configuration file organization Small installations may use one file: ```text config/ └── gateway.yaml ``` Larger installations should be able to split configuration logically: ```text config/ ├── gateway.yaml ├── opcua.yaml ├── storage.yaml ├── defaults.yaml │ └── stations/ ├── PS001.yaml ├── PS002.yaml ├── PS003.yaml └── ... ``` The implementation may support file inclusion or configuration-directory loading. Regardless of physical layout, the resulting configuration model shall be equivalent to the logical model described in this document. \--- \# 76. Recommended station-file organization For a larger number of AquaCom installations: ```text config/ └── stations/ │ ├── PS001/ │ ├── station.yaml │ └── station.atf │ ├── PS002/ │ ├── station.yaml │ └── station.atf │ └── PS003/ ├── station.yaml └── station.atf ``` This allows station-specific engineering configuration to remain grouped. \--- \# 77. Relationship to ATF Where ATF files are used, configuration and ATF have separate responsibilities. Conceptually: ```text station.yaml │ ├── transport ├── communication ├── acquisition ├── history ├── security/context └── ATF reference │ ▼ station.atf │ └── AquaCom station capability / point definition ``` ATF-specific semantics shall be documented under: ```text docs/protocol/ ``` once verified. The generic configuration model shall not duplicate all information contained in the ATF unless required for overrides or normalization. \--- \# 78. Point overrides The architecture should permit gateway-specific metadata to augment imported point definitions. Conceptual example: ```yaml pointOverrides: LEVEL: displayName: Wet well level engineeringUnit: m opcua: enabled: true historizing: true INTERNAL\_DIAGNOSTIC\_17: opcua: enabled: false history: enabled: false ``` This permits an imported ATF point model to remain unchanged while gateway behavior is customized. \--- \# 79. Configuration precedence If multiple configuration sources are supported, precedence shall be explicit. Recommended conceptual order: ```text built-in safe defaults ↓ global configuration ↓ station configuration ↓ point definition source ↓ explicit point override ``` Later layers may override earlier values only where permitted. Secrets are resolved independently and shall not be written back into the effective configuration. \--- \# 80. Effective configuration The gateway should provide a diagnostic mechanism for viewing the effective non-secret configuration. For example: ```text configured polling interval effective polling interval configured storage routing effective point properties selected AquaCom profile selected OPC UA NodeId ``` This significantly improves troubleshooting. Secret values shall be redacted. \--- \# 81. Configuration audit Changes to active configuration should be auditable. An audit event should identify: ```text configuration version previous configuration identity/hash new configuration identity/hash activation timestamp result operator/source where known ``` The exact implementation is technology-dependent. \--- \# 82. Safe configuration behavior When configuration is incomplete or contradictory, prefer explicit failure over implicit behavior. Examples: Do not automatically select an arbitrary repository if: ```yaml opcua: historicalAccess: enabled: true ``` and multiple repositories exist but none is identified. Do not silently enable insecure OPC UA because certificate configuration failed. Do not invent AquaCom transport defaults if no verified defaults exist. Do not activate historical retrieval for an unsupported AquaCom controller profile. \--- \# 83. Configuration design rule Configuration should express \*\*intent\*\*, not implementation internals. Prefer: ```yaml history: enabled: true ``` over implementation-specific concepts such as: ```yaml instantiateHistoryWorkerThread: true ``` Prefer: ```yaml required: true ``` over: ```yaml deleteSpoolRecordAfterDestination2: false ``` The configuration model shall remain understandable independently of implementation language. \--- \# 84. Configuration schema files Machine-readable schemas should be separated approximately as: ```text schemas/ ├── gateway-config.schema.\* ├── station-config.schema.\* ├── point-config.schema.\* └── storage-config.schema.\* ``` Schemas shall encode: ```text required properties types enumerations ranges formats basic structural constraints ``` Cross-component semantic validation may require application-level validation in addition to schema validation. \--- \# 85. Configuration tests Automated tests shall verify at least: ```text minimal valid configuration accepted complete valid configuration accepted duplicate station ID rejected duplicate point ID rejected duplicate OPC UA NodeId rejected missing History Repository rejected when OPC UA HA enabled unknown storage destination rejected invalid timezone rejected invalid duration rejected unsupported transport rejected unsupported AquaCom profile rejected history configuration rejected where implementation support is absent insecure OPC UA production default prevented missing required secret reported point override applied correctly configuration reload failure leaves previous valid configuration active ``` \--- \# 86. Initial implementation recommendation The first configuration implementation should support only the fields required for the initial production scope. The model in this document defines the intended architecture but does not require every optional field to be implemented immediately. Unsupported fields shall be: ```text rejected ``` or explicitly documented as: ```text not implemented ``` They shall not be silently ignored unless the configuration model explicitly permits forward-compatible unknown fields. \--- \# 87. Final configuration rule The configuration system shall preserve the architectural separation of the gateway. In particular: ```text station transport configuration ≠ station identity display name ≠ PointId OPC UA NodeId ≠ runtime object identifier history retrieval ≠ OPC UA HistoryRead storage destination ≠ AquaCom protocol implementation ``` The configuration model shall describe how components are connected without coupling those components internally. The most important configuration principles are: > Stable identifiers shall remain stable even when presentation or transport details change. > Invalid or unsupported AquaCom behavior shall never be activated through configuration by relying on guessed protocol semantics. > Historical acquisition, historical persistence, and OPC UA Historical Access shall remain independently configurable concerns.