Add _base equipment-class template for universal cross-machine metadata that every machine in the OtOpcUa estate exposes regardless of vendor, protocol, or machine type. References OPC UA Companion Spec OPC 40010 (Machinery) for the Identification component (Manufacturer, Model, ProductInstanceUri, SerialNumber, HardwareRevision, SoftwareRevision, YearOfConstruction, ManufacturerUri, DeviceManual, AssetLocation) plus the MachineryOperationMode enum (Auto, Manual, Maintenance, Service, Setup, Other), OPC UA Part 9 for the alarm summary fields (HasActiveAlarms, ActiveAlarmCount, HighestActiveAlarmSeverity), ISO 22400 for the lifetime counter fields (TotalRunSeconds, TotalCycles) that feed Availability + Performance KPIs at Layer 3, and the 3-year-plan handoff §"Canonical Model Integration" for the canonical state vocabulary (Running / Idle / Faulted / Starved / Blocked) declared in _base.stateModel. Includes the OtOpcUa five-identifier set (EquipmentUuid, MachineCode, ZTag, SAPID, plus DeviceClass = EquipmentClassRef) so every machine surfaces the join keys downstream consumers need; ConnectionState + LastDataTimestamp + DriverType for driver-side observability that does not require any particular equipment-protocol feature; optional production context (CurrentWorkOrder, CurrentPartNumber, CurrentRecipe, CurrentOperator, CurrentShift) marked isRequired: false since not every machine type surfaces these. Plus two universal alarm definitions (communication-loss, data-stale) that apply to every equipment regardless of class.

Equipment-class.schema.json gains an `extends` field for class inheritance — child classes inherit signals, alarms, and stateModel from the parent and can add new ones or override individual entries by name. Convention: `_` prefix on classId marks an abstract base class (e.g. `_base`) intended only to be extended, not assigned directly to equipment via Equipment.EquipmentClassRef.

FANUC CNC class updated to extends: "_base"; redundant identity signals (Version, ActiveAlarmCount) removed since they're now in the base; remaining FANUC-specific signals updated with cross-references showing how they feed into the base signals at Layer 3 (RunState → canonical Running/Idle/Faulted derivation; AlarmActive → HasActiveAlarms / HighestActiveAlarmSeverity; PartsCount → TotalCycles; MainProgramNumber → CurrentRecipe).

Format-decisions.md adds D9 (rationale for `_base` + `extends` inheritance, with references to OPC 40010 / Part 9 / ISO 22400 / handoff) and D10 (signal `category` drives OPC UA folder placement, per OPC 40010 Identification + Status pattern, with a category-to-folder mapping table).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-04-17 12:54:09 -04:00
parent 6b0883ff95
commit cd85159951
4 changed files with 315 additions and 12 deletions

View File

@@ -54,3 +54,32 @@ Signal names (level 6) are vocabulary-level identifiers — they live inside an
## D8 — `applicability.drivers` lists OtOpcUa drivers explicitly
**Why**: the schemas repo is OT-side-focused. The OtOpcUa driver enumeration is the closest thing to a canonical "how do you get raw data from this equipment" vocabulary that exists across the org. If a future class is populated by a non-OtOpcUa source, the field becomes optional or extends. For now, listing OtOpcUa driver IDs makes the consumer-side validation (per `lmxopcua/docs/v2/plan.md` decision #111 — driver type ↔ namespace kind) trivial.
## D9 — `_base` class with `extends` inheritance for cross-machine metadata
**Why**: every machine in the estate, regardless of vendor or protocol, exposes a common metadata core — identity (Manufacturer, Model, SerialNumber, plus the OtOpcUa five-identifier set EquipmentUuid/EquipmentId/MachineCode/ZTag/SAPID), connection state, alarm summary, optional production context (work order, recipe, operator). Repeating these in every class template would invite drift: one class would forget HighestActiveAlarmSeverity, another would name SerialNumber differently, etc.
Solution: a single `_base` class (in `classes/_base.json`) declares the common set; every other class `extends: "_base"` and inherits the signals, alarms, and stateModel. The child class adds its specifics (axes for a CNC, registers for a Modbus device, etc.) and can override individual base entries by `name` if needed.
References for the `_base` content:
- **OPC UA Companion Spec OPC 40010 (Machinery)** — for the Identification component (Manufacturer, Model, ProductInstanceUri, SerialNumber, HardwareRevision, SoftwareRevision, YearOfConstruction, ManufacturerUri, DeviceManual, AssetLocation) and MachineryOperationMode enum (Auto, Manual, Maintenance, Service, Setup, Other)
- **OPC UA Part 9 (Alarms & Conditions)** — for the alarm summary fields (HasActiveAlarms, ActiveAlarmCount, HighestActiveAlarmSeverity)
- **3-year-plan handoff §"Canonical Model Integration"** — for the canonical state vocabulary (Running / Idle / Faulted / Starved / Blocked) declared in `_base.stateModel`
- **ISO 22400 (Manufacturing KPIs)** — for the lifetime counter fields (TotalRunSeconds, TotalCycles) that feed Availability + Performance KPIs at Layer 3
Convention: `_` prefix on the classId marks an abstract base class — clients should not assign `_base` directly to any equipment via `Equipment.EquipmentClassRef` (it has no specifics; it's only meant to be extended).
## D10 — Signal `category` drives OPC UA exposure pattern, not just dashboard filtering
**Why**: aligning with OPC 40010 Machinery's Identification + Status + (machine-specific) folder pattern. The `category` field on each signal (`Identity`, `Status`, `Process`, `Position`, `Velocity`, `Counter`, `Alarm`, `Diagnostic`, etc.) tells the OtOpcUa NodeManager which sub-folder to place the signal in under the equipment node:
| Category | OPC UA folder | Value source |
|----------|---------------|--------------|
| `Identity` | `Identification` | Static, from `Equipment` row in central config DB (operator-set) — except where the driver can read it dynamically (e.g. FANUC `SeriesNumber` from `cnc_sysinfo()`) |
| `Status` | `Status` | Dynamic, from driver |
| `Diagnostic` | `Diagnostic` | Dynamic, from driver or from OtOpcUa runtime |
| `Alarm` | `Alarms` (synthetic — full OPC UA Part 9 alarm subscription is separate) | Dynamic |
| `Process`, `Position`, `Velocity`, `Acceleration`, `Temperature`, `Pressure`, `Flow`, `Counter`, `Setpoint`, `Command` | (machine-specific folders by category) | Dynamic, from driver |
| `Other` | `Misc` | Dynamic |
This means the same template field describes both consumer behavior (filter / categorize) and OtOpcUa exposure (which folder, which value-source pattern). Avoids a separate "where does this go in OPC UA" annotation.