Files
3yearplan/schemas/classes/_base.json
Joseph Doherty cd85159951 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>
2026-04-17 12:54:17 -04:00

266 lines
11 KiB
JSON

{
"$schema": "../format/equipment-class.schema.json",
"classId": "_base",
"extends": null,
"version": "0.1.0",
"displayName": "Base Equipment",
"description": "Universal metadata that every equipment in the OtOpcUa estate exposes regardless of vendor, protocol, or machine type. References: OPC UA Companion Spec OPC 40010 (Machinery) for the Identification component, ISO 22400 for KPI inputs, OPC UA Part 9 for the alarm summary fields, the 3-year-plan handoff §Canonical Model Integration for the canonical state vocabulary. Every equipment-class template should `extends: \"_base\"`; consumers (OtOpcUa, Redpanda, dbt) can rely on every machine surfacing this set.",
"applicability": {},
"signals": [
{
"name": "ProductInstanceUri",
"displayName": "Product Instance URI",
"category": "Identity",
"dataType": "String",
"description": "Globally unique URI identifying this specific physical asset (OPC 40010 ProductInstanceUri). Default derivation: `urn:otopcua:equipment:{EquipmentUuid}`. Operators can override per equipment if a vendor-issued URI exists.",
"isRequired": true
},
{
"name": "Manufacturer",
"displayName": "Manufacturer",
"category": "Identity",
"dataType": "String",
"description": "Equipment manufacturer name (OPC 40010). Static; operator-set at equipment registration.",
"isRequired": true
},
{
"name": "Model",
"displayName": "Model",
"category": "Identity",
"dataType": "String",
"description": "Equipment model designator (OPC 40010). Static; operator-set.",
"isRequired": true
},
{
"name": "SerialNumber",
"displayName": "Serial Number",
"category": "Identity",
"dataType": "String",
"description": "Manufacturer-assigned serial number (OPC 40010). Optional but strongly recommended.",
"isRequired": false
},
{
"name": "MachineCode",
"displayName": "Machine Code",
"category": "Identity",
"dataType": "String",
"description": "Operator colloquial identifier (e.g. `machine_001`). Sourced from `Equipment.MachineCode` in the OtOpcUa central config DB.",
"isRequired": true
},
{
"name": "ZTag",
"displayName": "ZTag (ERP ID)",
"category": "Identity",
"dataType": "String",
"description": "ERP equipment identifier. Sourced from `Equipment.ZTag` in the central config DB. Optional in OtOpcUa schema; required in equipment templates that depend on ERP integration.",
"isRequired": false
},
{
"name": "SAPID",
"displayName": "SAP PM ID",
"category": "Identity",
"dataType": "String",
"description": "SAP Plant Maintenance equipment identifier. Sourced from `Equipment.SAPID`. Optional.",
"isRequired": false
},
{
"name": "EquipmentUuid",
"displayName": "Equipment UUID",
"category": "Identity",
"dataType": "String",
"description": "Immutable UUIDv4 identifying this equipment across systems and time. The permanent join key for downstream events / dbt / Redpanda. Sourced from `Equipment.EquipmentUuid`.",
"isRequired": true
},
{
"name": "HardwareRevision",
"displayName": "Hardware Revision",
"category": "Identity",
"dataType": "String",
"description": "Hardware revision (OPC 40010). Optional.",
"isRequired": false
},
{
"name": "SoftwareRevision",
"displayName": "Software Revision",
"category": "Identity",
"dataType": "String",
"description": "Firmware / software revision (OPC 40010). Optional. Some drivers can read this dynamically (FANUC FOCAS via cnc_sysinfo, Beckhoff via TwinCAT.SystemInfo); others rely on operator-set static values.",
"isRequired": false
},
{
"name": "DeviceClass",
"displayName": "Device Class",
"category": "Identity",
"dataType": "String",
"description": "Equipment class identifier — same value as `Equipment.EquipmentClassRef`. Lets clients classify equipment without a separate config lookup. Required so consumers can route by class.",
"isRequired": true
},
{
"name": "AssetLocation",
"displayName": "Asset Location",
"category": "Identity",
"dataType": "String",
"description": "Free-text physical location supplementary to the UNS path (e.g. `Bay 3, Row 12`). Optional.",
"isRequired": false
},
{
"name": "YearOfConstruction",
"displayName": "Year of Construction",
"category": "Identity",
"dataType": "Int16",
"description": "Year the equipment was manufactured (OPC 40010 YearOfConstruction). Optional.",
"isRequired": false
},
{
"name": "ManufacturerUri",
"displayName": "Manufacturer URI",
"category": "Identity",
"dataType": "String",
"description": "Manufacturer's website / namespace URI (OPC 40010). Optional.",
"isRequired": false
},
{
"name": "DeviceManual",
"displayName": "Device Manual",
"category": "Identity",
"dataType": "String",
"description": "URL or path to operator/maintenance manual for this equipment (OPC 40010). Optional.",
"isRequired": false
},
{
"name": "DriverType",
"displayName": "Driver Type",
"category": "Diagnostic",
"dataType": "String",
"description": "OtOpcUa driver type populating this equipment (Galaxy / ModbusTcp / AbCip / AbLegacy / S7 / TwinCat / Focas / OpcUaClient). Sourced from the driver instance.",
"isRequired": true
},
{
"name": "ConnectionState",
"displayName": "Connection State",
"category": "Status",
"dataType": "Int32",
"description": "Driver-side connection state to the underlying equipment. 0 = Disconnected, 1 = Connected, 2 = Reconnecting, 3 = Faulted. Always available from the driver — does not require the equipment to support any particular protocol feature.",
"isRequired": true
},
{
"name": "LastDataTimestamp",
"displayName": "Last Data Timestamp",
"category": "Status",
"dataType": "DateTime",
"description": "UTC timestamp of the most recent successful data read from this equipment. Updated by the driver on every successful read regardless of value change. Lets consumers detect silent data loss even when ConnectionState reports Connected.",
"isRequired": true
},
{
"name": "OperationMode",
"displayName": "Operation Mode",
"category": "Status",
"dataType": "String",
"description": "Operating mode per OPC 40010 MachineryOperationMode enum: Auto, Manual, Maintenance, Service, Setup, Other. Optional — many machine types (e.g. instruments) don't have an operation mode.",
"isRequired": false
},
{
"name": "HasActiveAlarms",
"displayName": "Has Active Alarms",
"category": "Alarm",
"dataType": "Boolean",
"description": "True when one or more alarms are currently active on this equipment. Quick-check field — full alarm detail comes via OPC UA Part 9 alarm subscription.",
"isRequired": true
},
{
"name": "ActiveAlarmCount",
"displayName": "Active Alarm Count",
"category": "Alarm",
"dataType": "Int32",
"description": "Number of currently active alarms on this equipment. 0 when none. Required even for machines that don't natively support alarms (always 0 in that case).",
"isRequired": true
},
{
"name": "HighestActiveAlarmSeverity",
"displayName": "Highest Active Alarm Severity",
"category": "Alarm",
"dataType": "String",
"description": "Severity of the most severe currently active alarm: None / Low / Medium / High / Critical. Lets dashboards filter equipment with critical alarms without subscribing to full alarm streams.",
"isRequired": true
},
{
"name": "TotalRunSeconds",
"displayName": "Total Run Seconds (Lifetime)",
"category": "Counter",
"dataType": "Int64",
"unit": "s",
"description": "Lifetime total seconds the equipment has been in Running state. Optional — many equipment types don't track this; for those that do, value is monotonically increasing across power cycles.",
"isRequired": false,
"isHistorized": true
},
{
"name": "TotalCycles",
"displayName": "Total Cycles (Lifetime)",
"category": "Counter",
"dataType": "Int64",
"description": "Lifetime total operation cycles (parts produced, machining cycles, packaging cycles, etc. — class-specific definition). Optional.",
"isRequired": false,
"isHistorized": true
},
{
"name": "CurrentWorkOrder",
"displayName": "Current Work Order",
"category": "Process",
"dataType": "String",
"description": "Currently-running work order / job number / batch ID. Often sourced via Layer 3 (System Platform) push to the equipment, or via direct ERP integration. Optional.",
"isRequired": false
},
{
"name": "CurrentPartNumber",
"displayName": "Current Part Number",
"category": "Process",
"dataType": "String",
"description": "Currently-running part / product number. Optional.",
"isRequired": false
},
{
"name": "CurrentRecipe",
"displayName": "Current Recipe",
"category": "Process",
"dataType": "String",
"description": "Currently-loaded recipe / program identifier. Optional.",
"isRequired": false
},
{
"name": "CurrentOperator",
"displayName": "Current Operator",
"category": "Process",
"dataType": "String",
"description": "Currently-logged-in operator on this equipment (where supported). Optional. Privacy: in some jurisdictions, operator names are personal data — surface as operator badge ID rather than name where applicable.",
"isRequired": false
},
{
"name": "CurrentShift",
"displayName": "Current Shift",
"category": "Process",
"dataType": "String",
"description": "Current shift identifier (A/B/C, Day/Night/Swing, etc. — site-specific). Optional.",
"isRequired": false
}
],
"alarms": [
{
"alarmId": "communication-loss",
"displayName": "Communication Loss",
"severity": "High",
"description": "Driver lost communication with the equipment. Raised when ConnectionState transitions away from Connected; cleared when restored. Universal across all equipment classes."
},
{
"alarmId": "data-stale",
"displayName": "Data Stale",
"severity": "Medium",
"description": "ConnectionState reports Connected but LastDataTimestamp has not advanced beyond the driver's expected polling interval. Indicates silent data loss. Universal."
}
],
"stateModel": {
"states": ["Running", "Idle", "Faulted", "Starved", "Blocked"],
"derivationNotes": "Canonical machine state vocabulary per the 3-year-plan handoff §Canonical Model Integration. State derivation lives at Layer 3 (Aveva System Platform / Ignition) — OtOpcUa exposes the raw signals (RunState if available from the equipment, ConnectionState, HasActiveAlarms, OperationMode, plus class-specific signals like cycle-in-progress flags) and Layer 3 derives the canonical state. Reserved for future addition to the standard set: Changeover, Maintenance, Setup."
}
}