Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the full workflow, validation, and

- `companion-specs/` — draft OPC UA companion specifications, one folder per domain.
- `Generators/` — draft Companion Specification for electrical power **Generator Sets (GenSets)**: the information model (`Opc.Ua.Generators.NodeSet2.xml`), the NodeId assignments (`Opc.Ua.Generators.NodeIds.csv`), the specification document, and `tools/build_model.py` — a generator that emits the NodeSet, CSV, and reference tables from a single source of truth.
- `wot-specs/` — Web of Things specification drafts and their supporting tools/examples, kept separate from OPC UA Core and domain companion-specification work.
- `WoT-Binding/` — draft **OPC UA — Web of Things (WoT) Binding**: a standalone revision of OPC 10101 that describes an OPC UA interface as a W3C Thing Description / Thing Model — preserving the official `uav` vocabulary, the Read / Write / Observe / Call and security mappings, and the URI rules — and adds a collision-safe model/platform vocabulary, NamespaceUri-qualified model-name hints beside definitive NodeIds, plus bidirectional NodeSet2 conversion. The semantic/readable mapping is primary, the complete `uav:nodes` projection is added only for source facts not yet expressible by the vocabulary, unmapped WoT members survive as pointer-addressed NodeSet extension residue, and `uav:nodeSet` is reserved for explicit byte archival or a demonstrated final fallback. Contains the specification, the JSON-LD context, an extension/preservation JSON Schema, worked examples, and a standard-library `tools/validate_local.py`.
- `WoT-Connectivity/` — draft **OPC UA — WoT Connectivity** (additive revision **1.1**): a **registry-first** revision of OPC 10100-1 that layers a W3C Thing Model / Thing Description **document registry** over the abstract [`xregistry/`](core-specs/xregistry/) base model (`WoTRegistryType` subtypes `RegistryType`; `ThingDescriptionGroupType`/`ThingModelGroupType` subtype `GroupType`; `ThingDescriptionFileType`/`ThingModelFileType` subtype the abstract `WoTDocumentType` `ResourceType`), exposed as a well-known `WoTRegistry` Object under the **Server** object (`i=2253`). The stored documents/versions are canonical; the OPC UA AddressSpace is a **derived, shadow-switched, generational projection** (Thing Models → types, Thing Descriptions → instances, affordances → Variables/Methods/EventTypes, links → References, forms → binder plans) with a `Refresh` Method, validation/load/refresh events, and desired/active version lifecycle. The full **OPC 10100-1 v1.02** model is **incorporated into the same combined NodeSet and namespace** — preserving every published NodeId (`1..172`), type and method signature — and its superseded management surface is marked `Deprecated` (per OPC 11030); the revised WoT Binding `uav` vocabulary is a normative JSON-LD dependency (not a NodeSet `RequiredModel`). Contains the specification, the generated combined NodeSet (`Opc.Ua.WoTCon.NodeSet2.xml`) / CSV, the pinned 1.02 sources under `legacy/`, the canonical `tools/build_model.py`, a standard-library `tools/validate_local.py`, and worked examples.
- `core-specs/` — draft **extensions to the base OPC UA specification** (proposed additions to the `http://opcfoundation.org/UA/` namespace), intended for submission to an OPC Foundation Working Group. Each encoding/catalog folder below contains only the **normative** spec documents, its `README.md`, and the **base reference schema**; all tooling, examples, generated (non-base) schemas, and the shared validation package live under `core-specs/extras/` (a parallel, mirrored tree).
- `observability-export/` — draft *OPC UA — Observability Export*: a small, transport-neutral layer that lets a Server, or a companion specification, declare **how its data lands in an observability system** — as OpenTelemetry (OTEL) **metrics, logs and traces** — so a generic read-only **bridge** can forward it over the **classic client/server (RPC) interface** and, **optionally**, over **PubSub (Part 14)** without understanding the domain. Contains the base NodeSet, CSV, and specification document, plus one **standardized subfolder per companion spec** (`pumps/`, `robotics/`, `facets/`, `di/`), each holding the companion-spec **addendum(s)** and the instance-overlay `NodeSet2.xml`. The generator tooling and example descriptor sources live under `core-specs/extras/observability-export/` (below). A non-normative **overview deck** ([`core-specs/observability-export/README.md`](core-specs/observability-export/README.md)) summarizes the why, what and how.
- `avro-encoding/` — **Apache Avro (binary)** DataEncoding: a Part 6 mapping of the full OPC UA type model and a Part 14 **PubSub** message mapping, including **Action invoke/response** and **Discovery** messages. Reversible (`decode(encode(x)) == x`), with a NodeSet-driven schema generator and a SchemaId handshake.
Expand Down
773 changes: 773 additions & 0 deletions wot-specs/WoT-Binding/OPC-UA-WoT-Binding.md

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions wot-specs/WoT-Binding/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# OPC UA — Web of Things (WoT) Binding

A complete, standalone draft revision of the OPC UA companion specification for Web of Things connectivity. It is not an addendum: the specification can be read on its own. It preserves every namespace, prefix, term, and normative behaviour of the published baseline and adds a collision-safe model and platform vocabulary together with semantic-first, bidirectional NodeSet2 conversion.

> Experimental and non-normative. Nothing here is official or endorsed by the OPC Foundation or the W3C; `opcfoundation.org` namespace URIs are used for prototyping only.

## Purpose

- Describe an OPC UA interface as a W3C Thing Description or Thing Model, using the preserved Read / Write / Observe / Call and security vocabulary.
- Express the structural facts of an OPC UA type — composition, references, groups, units, scaling, configuration, metadata, and modelling rules — in a Thing Model.
- Pair definitive ExpandedNodeIds with NamespaceUri-qualified model names such as `ua:HasOrderedComponent` so type-level concepts remain semantically readable without weakening instance identity.
- Convert between an OPC UA NodeSet2 information model and a Thing Description or Thing Model without loss through the semantic/readable vocabulary, adding the complete `uav:nodes` projection only when source facts cannot yet be expressed. Unmapped WoT members survive as pointer-addressed NodeSet extension residue; `uav:nodeSet` is reserved for explicit byte archival or a demonstrated final fallback.

## Sources

- [OPC 10101 — OPC UA for WoT Binding](https://reference.opcfoundation.org/specs/OPC-10101/) — the published version superseded by this draft.
- [W3C Web of Things (WoT) Thing Description 1.1](https://www.w3.org/TR/wot-thing-description11/) and [WoT Binding Templates](https://www.w3.org/TR/wot-binding-templates/).
- [OPC 10000-3](https://reference.opcfoundation.org/specs/OPC-10000-3/), [10000-4](https://reference.opcfoundation.org/specs/OPC-10000-4/), [10000-5](https://reference.opcfoundation.org/specs/OPC-10000-5/), [10000-6](https://reference.opcfoundation.org/specs/OPC-10000-6/), [10000-7](https://reference.opcfoundation.org/specs/OPC-10000-7/).
- [QUDT](http://qudt.org/) for quantity kinds and units; [RFC 6901](https://www.rfc-editor.org/rfc/rfc6901), [RFC 4648](https://www.rfc-editor.org/rfc/rfc4648), and [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986).
- Two architecture decision records (ADR 0029 and ADR 0032) are used only as design inputs for the model vocabulary; a design-input crosswalk is kept, informatively, under [`../extras/WoT-Binding/adr-to-uav-crosswalk.md`](../extras/WoT-Binding/adr-to-uav-crosswalk.md) — **not** in the normative specification. No vocabulary, prefix, or namespace of those inputs is reused.

## Artifacts

- [`OPC-UA-WoT-Binding.md`](OPC-UA-WoT-Binding.md) — the full specification.
- [`opc-ua-wot-binding.context.jsonld`](opc-ua-wot-binding.context.jsonld) — the JSON-LD context binding the `uav` prefix and every documented term.
- [`opc-ua-wot-binding.schema.json`](opc-ua-wot-binding.schema.json) — the extension and preservation JSON Schema (2020-12).
- [`examples/`](examples/) — worked examples:
- [`01-opcua-td-pump.jsonld`](examples/01-opcua-td-pump.jsonld) — a Thing Description using the preserved Read / Write / Observe / Call and security vocabulary.
- [`02-thing-model-pump.jsonld`](examples/02-thing-model-pump.jsonld) — a Thing Model using the model and platform vocabulary.
- [`03-nodeset-preservation-envelope.jsonld`](examples/03-nodeset-preservation-envelope.jsonld) — a `uav:nodeSet` preservation envelope carrying a canonical NodeSet2 baseline.
- [`04-type-reference-modelling-rule.jsonld`](examples/04-type-reference-modelling-rule.jsonld) — type, semantic model-name/reference (including `ua:HasOrderedComponent` plus its `i=49` fallback), and modelling-rule mappings.
- [`05-native-node-model.jsonld`](examples/05-native-node-model.jsonld) — the exceptional schema-complete `uav:nodes` representation without an opaque envelope.
- [`tools/validate_local.py`](tools/validate_local.py) — the deterministic, standard-library validator.

## Namespace and prefix

The vocabulary namespace is `http://opcfoundation.org/UA/WoT-Binding/`, bound to the prefix `uav`. Both are preserved unchanged from the published baseline.

## Validation

Run the validator from the repository root (standard library only, no dependencies):

```bash
python wot-specs/WoT-Binding/tools/validate_local.py
```

It checks that every JSON and JSON-LD artifact parses, that the context contains every documented `uav` term, that each example declares the `uav` context, that the native example uses `uav:NodeModel` profile `1.0` without an envelope, that each exceptional envelope's base64 and SHA-256 are valid and decode to a well-formed `UANodeSet` root, that internal relative references resolve, that every NodeId-valued readable term in an example is a portable ExpandedNodeId (never the session-local `ns=<index>` form), that `@type: uav:eventType` is never paired with `uav:isEvent: false`, and that no forbidden vendor prefix, namespace, or legacy modelling-language name appears. It prints `OK` and exits `0` on success.
84 changes: 84 additions & 0 deletions wot-specs/WoT-Binding/examples/01-opcua-td-pump.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"@context": [
"https://www.w3.org/2022/wot/td/v1.1",
{ "uav": "http://opcfoundation.org/UA/WoT-Binding/" },
"../opc-ua-wot-binding.context.jsonld"
],
"@type": "uav:object",
"id": "urn:dev:opcua:pump-01",
"title": "Pump 01",
"description": "A Thing Description of a single OPC UA Object using only the preserved OPC 10101 vocabulary: Read, Write, Observe (Monitor) and Call, plus the explicit OPC UA security schemes.",
"uav:browseName": "nsu=http://example.com/demo/pump;Pump",
"uav:id": "nsu=http://example.com/demo/pump;s=Pump",
"links": [
{ "rel": "uav:componentOf", "href": "nsu=http://example.com/demo/pump;s=Line01" }
],
"securityDefinitions": {
"opcua_channel_sc": {
"scheme": "uav:channelsec",
"uav:securityMode": "SignAndEncrypt",
"uav:securityPolicy": "Aes256_Sha256_RsaPss"
},
"opcua_authentication_sc": {
"scheme": "uav:authentication",
"uav:userIdentityToken": "UserName"
},
"opcua_sc": {
"scheme": "combo",
"allOf": ["opcua_channel_sc", "opcua_authentication_sc"]
}
},
"security": "opcua_sc",
"base": "opc.tcp://opcuademo.com:4840",
"properties": {
"pumpSpeed": {
"@type": "uav:variable",
"title": "Pump Speed",
"uav:browseName": "nsu=http://example.com/demo/pump;PumpSpeed",
"uav:browsePath": "/Objects/{http://example.com/demo/pump}Pump/{http://example.com/demo/pump}PumpSpeed",
"type": "number",
"unit": "rpm",
"readOnly": true,
"observable": true,
"forms": [
{
"href": "/?id=nsu=http://example.com/demo/pump;s=PumpSpeed",
"contentType": "application/octet-stream",
"op": ["readproperty", "observeproperty"]
}
]
},
"speedSetpoint": {
"@type": "uav:variable",
"title": "Speed Setpoint",
"uav:browseName": "nsu=http://example.com/demo/pump;SpeedSetpoint",
"uav:browsePath": "/Objects/{http://example.com/demo/pump}Pump/{http://example.com/demo/pump}SpeedSetpoint",
"type": "number",
"unit": "rpm",
"readOnly": false,
"observable": true,
"forms": [
{
"href": "/?id=nsu=http://example.com/demo/pump;s=SpeedSetpoint",
"contentType": "application/octet-stream",
"op": ["readproperty", "writeproperty", "observeproperty"]
}
]
}
},
"actions": {
"reset": {
"@type": "uav:method",
"title": "Reset",
"uav:browseName": "nsu=http://example.com/demo/pump;Reset",
"uav:browsePath": "/Objects/{http://example.com/demo/pump}Pump/{http://example.com/demo/pump}Reset",
Comment thread
marcschier marked this conversation as resolved.
Outdated
"forms": [
{
"href": "/?id=nsu=http://example.com/demo/pump;s=Reset",
"contentType": "application/octet-stream",
"op": ["invokeaction"]
}
]
}
}
}
114 changes: 114 additions & 0 deletions wot-specs/WoT-Binding/examples/02-thing-model-pump.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
{
"@context": [
"https://www.w3.org/2022/wot/td/v1.1",
{
"uav": "http://opcfoundation.org/UA/WoT-Binding/",
"pump": "http://example.com/demo/pump#",
"qudt-quantitykind": "http://qudt.org/vocab/quantitykind/"
},
"../opc-ua-wot-binding.context.jsonld"
],
"@type": ["tm:ThingModel", "uav:objectType"],
"title": "PumpType",
"description": "A Thing Model of an OPC UA ObjectType that exercises the model and platform vocabulary: composition, groups, membership, references, units and scaling, configuration, metadata and modelling rules.",
"uav:browseName": "nsu=http://example.com/demo/pump;PumpType",
"uav:id": "nsu=http://example.com/demo/pump;i=1001",
"uav:isComposite": true,
"uav:includeInherited": true,
"uav:additionalProperties": false,
"uav:nameNamespace": "http://example.com/demo/pump#",
"uav:semanticId": "http://example.com/ontology/Pump",
"uav:congruentTypeName": "pump:PumpType",
"uav:congruentType": "nsu=http://example.com/demo/pump;i=1001",
"uav:contains": ["Impeller"],
"uav:metadata": {
"revision": 3,
"maintainer": "Modeling Working Group"
},
"uav:propertyGroups": [
{
"title": "Operational",
"description": "Live operational data.",
"uav:semanticId": "http://example.com/ontology/Operational"
},
{ "title": "Nameplate" }
],
"uav:eventGroups": [{ "title": "Diagnostics" }],
"uav:actionGroups": [{ "title": "Maintenance" }],
"links": [
{
"rel": "uav:componentModel",
"href": "./04-type-reference-modelling-rule.jsonld",
"uav:refName": "Impeller",
"uav:refId": "i=47"
},
{
"rel": "pump:DriveReference",
"href": "https://example.com/models/MotorType.tm.jsonld",
"uav:refName": "Drive",
"uav:refId": "nsu=http://example.com/demo/pump;i=4002"
},
{ "rel": "uav:capability", "href": "https://example.com/capabilities/telemetry" },
{ "rel": "uav:reference", "href": "https://example.com/models/NameplateType.tm.jsonld" }
],
"properties": {
"pumpSpeed": {
"@type": "uav:variableType",
"title": "Pump Speed",
"uav:browseName": "nsu=http://example.com/demo/pump;PumpSpeed",
"type": "number",
"unit": "qudt-quantitykind:AngularVelocity",
"uav:modellingRule": "Mandatory",
"uav:memberOf": "Operational",
"uav:unitProperty": "/properties/pumpSpeed/unit",
"uav:scaleFactor": 0.1,
"uav:decimalPlaces": 2,
"observable": true,
"readOnly": true
},
"serialNumber": {
"@type": "uav:variableType",
"title": "Serial Number",
"uav:browseName": "nsu=http://example.com/demo/pump;SerialNumber",
"type": "string",
"uav:modellingRule": "Mandatory",
"uav:memberOf": "Nameplate"
},
"stage": {
"@type": "uav:variableType",
"title": "Stage",
"uav:browseName": "nsu=http://example.com/demo/pump;Stage",
"type": "number",
"uav:modellingRule": "MandatoryPlaceholder",
"uav:memberOf": "Operational"
}
},
"actions": {
"reset": {
"@type": "uav:method",
"title": "Reset",
"uav:browseName": "nsu=http://example.com/demo/pump;Reset",
"uav:modellingRule": "Optional",
"uav:memberOf": "Maintenance",
"uav:actionConfiguration": { "timeoutMs": 5000, "confirm": true },
"uav:externalSchema": "https://example.com/schemas/reset-args.json"
}
},
"events": {
"overTemperature": {
"@type": "uav:eventType",
"title": "Over Temperature",
"uav:isEvent": true,
"uav:browseName": "nsu=http://example.com/demo/pump;OverTemperatureEventType",
"uav:memberOf": "Diagnostics",
"uav:semanticId": "http://example.com/ontology/OverTemperature",
"uav:eventConfiguration": { "severity": 500 },
"data": {
"type": "object",
"properties": {
"temperature": { "type": "number", "unit": "qudt-quantitykind:Temperature" }
}
}
}
}
}
Loading
Loading