Files
aquacom-gateway-suite/docs/configuration/configuration-reference.md
T
2026-10-05 20:32:13 +02:00

5759 lines
51 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
\# 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.