90bfcbe47a
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
85 lines
5.7 KiB
Markdown
85 lines
5.7 KiB
Markdown
# Address Space
|
|
|
|
The server serves **two OPC UA namespaces** under one shared root folder. Identity is owned by
|
|
`V3NodeIds` (`src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/V3NodeIds.cs`) and `AddressSpaceRealm`; the tree is
|
|
built from the deploy artifact (see `docs/IncrementalSync.md`), not by driver discovery at runtime.
|
|
|
|
| Realm | Namespace URI | Subtree | NodeId `s=` identifier |
|
|
|---|---|---|---|
|
|
| `Raw` | `https://zb.com/otopcua/raw` | `/raw` device tree: Folder → Driver → Device → TagGroup → Tag | the node's **RawPath** (e.g. `Plant/Modbus/dev1/Speed`) |
|
|
| `Uns` | `https://zb.com/otopcua/uns` | UNS tree: Area → Line → Equipment → signal | slash-joined `Area/Line/Equipment[/EffectiveName]` |
|
|
|
|
`OtOpcUaNodeManager` registers both URIs (raw is index `NamespaceIndexes[0]`, UNS `[1]`). The retired
|
|
single namespace `https://zb.com/otopcua/ns` and the `EquipmentNodeIds` scheme no longer exist. The realm
|
|
travels beside the identifier at every sink seam (`IOpcUaAddressSpaceSink`); it is never parsed out of the
|
|
id string. Authoring and semantics: `docs/Raw.md`, `docs/Uns.md`.
|
|
|
|
## Root folder
|
|
|
|
`OtOpcUaNodeManager.CreateAddressSpace` creates **one** shared root `FolderState` — identifier and browse
|
|
name `OtOpcUa` (`V3NodeIds.SharedRootFolderId`), minted in the **raw** namespace — under the standard
|
|
`Objects` folder with an `Organizes` reference. Top-level Raw folders and top-level UNS Areas both parent
|
|
under it. The identifier is a display name, not a path segment; the data-plane authorizer maps it onto the
|
|
trie's zero-segment realm-root scope (`docs/security.md`). The application URI is
|
|
`OpcUaApplicationHostOptions.ApplicationUri` (default `urn:OtOpcUa`); there is no per-driver namespace.
|
|
|
|
## NodeId scheme
|
|
|
|
Segments are validated by `RawPaths.ValidateSegment` (no embedded `/`, no leading/trailing whitespace;
|
|
ordinal, case-sensitive). `V3NodeIds.Raw(rawPath)` is a pass-through; `V3NodeIds.Uns(...)` /
|
|
`UnsChild(parent, segment)` build UNS ids.
|
|
|
|
| Node | Realm | `s=` identifier | Example |
|
|
|---|---|---|---|
|
|
| Shared root | Raw | `OtOpcUa` | `OtOpcUa` |
|
|
| Raw folder / driver / device / tag group / tag | Raw | its own RawPath | `Plant/Modbus/dev1/Speed` |
|
|
| UNS Area / Line / Equipment folder | Uns | `Area`, `Area/Line`, `Area/Line/Equipment` | `packaging/line-1/press-07` |
|
|
| UNS reference variable (`UnsTagReference`), virtual tag, scripted alarm | Uns | `Area/Line/Equipment/EffectiveName` | `packaging/line-1/press-07/speed` |
|
|
|
|
Area, Line and Equipment names must match `^[a-z0-9-]{1,32}$` (`docs/Uns.md`). EffectiveNames are unique per
|
|
equipment across references, virtual tags and scripted alarms.
|
|
|
|
## One source, fanned to both namespaces
|
|
|
|
Every device value has exactly one source: the raw tag's node, keyed by RawPath. A `UnsTagReference`
|
|
projects that raw tag into an equipment as a UNS variable that carries an `Organizes` reference to its raw
|
|
node and mirrors it. `DriverHostActor` fans one driver publish for a RawPath to the raw NodeId **and** every
|
|
referencing UNS NodeId with identical value, quality and timestamp. Writes via either NodeId route to the
|
|
same driver reference under the same realm-qualified `WriteOperate` gate. Native alarms materialise once at
|
|
the raw tag (`ConditionId = RawPath`) and fan through notifiers to the raw device folder and every
|
|
referencing equipment folder. Both NodeIds register the same historian tagname.
|
|
|
|
## Materialisation
|
|
|
|
`AddressSpaceComposer` turns the deployment artifact into an `AddressSpaceComposition`;
|
|
`AddressSpaceApplier` (both in `src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/`) walks it (`MaterialiseHierarchy`,
|
|
`MaterialiseRawSubtree`, `MaterialiseUnsReferences`, `MaterialiseEquipmentVirtualTags`,
|
|
`MaterialiseScriptedAlarms`, ...) into the write-only `IOpcUaAddressSpaceSink`, whose production binding
|
|
`SdkAddressSpaceSink` forwards to `OtOpcUaNodeManager`, the `CustomNodeManager2` that owns the
|
|
`FolderState` / `BaseDataVariableState` instances. Variables are created through `EnsureVariable`:
|
|
`ValueRank` is `OneDimension` with `ArrayDimensions=[arrayLength]` for array tags and `Scalar` otherwise;
|
|
`AccessLevel` carries the write bit only for writable nodes (array nodes only when the driver can write the
|
|
array); `Historizing` plus the `HistoryRead` bit are set when a historian tagname is supplied.
|
|
|
|
The nodes start `BadWaitingForInitialData` until the first read or subscription push. Datatype names resolve
|
|
through `OtOpcUaNodeManager.ResolveBuiltInDataType`; each driver first maps its native type into
|
|
`DriverDataType` (Galaxy: `Driver.Galaxy/Browse/DataTypeMap.cs`).
|
|
|
|
## Driver discovery is the browse picker, not the address space
|
|
|
|
`ITagDiscovery.DiscoverAsync` (streaming into `IAddressSpaceBuilder`: `Folder` / `Variable` /
|
|
`AddProperty`, each variable described by a `DriverAttributeInfo`) feeds the `/raw` browse-commit flow via
|
|
`Commons/Browsing/DiscoveryDriverBrowser`: the operator browses a device, picks leaves and commits them as
|
|
raw tags, which then reach the server as an ordinary deployment. Drivers that signal backend change via
|
|
`IRediscoverable` only raise an operator "re-browse" prompt — the served tree never changes on its own.
|
|
See `docs/IncrementalSync.md`. `GenericDriverNodeManager` (`Core/OpcUa/`) is leftover scaffolding with no
|
|
production caller.
|
|
|
|
## Key source files
|
|
|
|
- `src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/V3NodeIds.cs`, `AddressSpaceRealm.cs` — identity authority
|
|
- `src/Core/ZB.MOM.WW.OtOpcUa.Commons/Types/RawPaths.cs` — RawPath/segment rules
|
|
- `src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OtOpcUaNodeManager.cs`, `SdkAddressSpaceSink.cs` — SDK materialisation
|
|
- `src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/AddressSpaceComposer.cs`, `AddressSpaceApplier.cs` — compose and apply
|
|
- `src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/ITagDiscovery.cs`, `IAddressSpaceBuilder.cs`, `DriverAttributeInfo.cs` — discovery-side contracts
|