Files
lmxopcua/docs/v2/focas-deployment.md
2026-04-26 04:54:28 -04:00

6.3 KiB

FOCAS deployment guide

Per-driver runbook for deploying the FANUC FOCAS driver. See docs/drivers/FOCAS.md for the per-feature reference and focas-version-matrix.md for the per-CNC-series capability surface.

Operator config-knob cheat sheet

Knob Where Default Notes
Devices[].HostAddress FocasDriverOptions.Devices focas://{ip}[:{port}]
Devices[].Series FocasDriverOptions.Devices Unknown Drives per-series range validation in FocasCapabilityMatrix.
Devices[].OverrideParameters FocasDriverOptions.Devices null MTB-specific parameter numbers for Feed/Rapid/Spindle/Jog overrides. null suppresses the Override/ subtree.
Probe.Enabled FocasDriverOptions.Probe true Background reachability probe.
Probe.Interval FocasDriverOptions.Probe 00:00:05 Probe cadence.
FixedTree.ApplyFigureScaling FocasDriverOptions.FixedTree true Divide position values by 10^decimal-places (issue #262).
AlarmProjection.Mode FocasDriverOptions.AlarmProjection ActiveOnly ActiveOnly keeps today's behaviour. ActivePlusHistory polls cnc_rdalmhistry on connect + on HistoryPollInterval ticks (issue #267, plan PR F3-a).
AlarmProjection.HistoryPollInterval FocasDriverOptions.AlarmProjection 00:05:00 Cadence of the history poll. Operator dashboards run the default; high-frequency rigs can drop to 30 s.
AlarmProjection.HistoryDepth FocasDriverOptions.AlarmProjection 100 Most-recent-N ring-buffer entries pulled per poll. Hard-capped at 250 so misconfigured values can't blast the wire session.

Sample appsettings.json snippet for ActivePlusHistory

{
  "Drivers": {
    "FOCAS": {
      "Devices": [
        { "HostAddress": "focas://10.0.0.5:8193", "Series": "Series30i" }
      ],
      "AlarmProjection": {
        "Mode": "ActivePlusHistory",
        "HistoryPollInterval": "00:05:00",
        "HistoryDepth": 100
      }
    }
  }
}

The history projection emits each unseen entry through IAlarmSource.OnAlarmEvent with SourceTimestampUtc set from the CNC's reported wall-clock — keep CNC clocks on UTC so the dedup key (OccurrenceTime, AlarmNumber, AlarmType) stays stable across DST transitions.

Write safety — issue #269, plan PR F4-b

The FOCAS driver supports cnc_wrparam and cnc_wrmacro writes behind multiple independent opt-ins. A misdirected parameter write can put the CNC in a bad state, so the runbook below MUST be followed before flipping the granular kill switches on.

Operator pre-checks (every deployment, every change)

  1. CNC must be in MDI mode. Most parameter writes fail with EW_PASSWD (surfaces as BadUserAccessDenied) unless the CNC is in MDI. The server-side write returns immediately with the access-denied status; no value reaches the wire.
  2. Parameter-write switch enabled on the CNC pendant. Even in MDI mode protected parameters require the operator to physically enable the parameter-write switch. Without it cnc_wrparam returns EW_PASSWD. Plan PR F4-d will land an OPC UA-side unlock workflow; today the only path is the pendant.
  3. Verify each tag's address against the FANUC manual. Ranges vary per CNC series; the focas-version-matrix capability matrix rejects out-of-range numbers at startup, but address-vs-meaning is the operator's job.
  4. Dry run with Writable = true but Writes.AllowParameter = false. Staged opt-in catches mis-mapped tags: every PARAM write returns BadNotWritable until you flip the granular flag, so you can confirm the tag list before any wire write fires.

LDAP group requirements

Per docs/security.md the server-layer ACL maps SecurityClassification to LDAP groups. Post-F4-b:

Tag kind LDAP group required
PARAM:N (writable) WriteConfigure — heaviest write tier; matches commissioning roles
MACRO:N (writable) WriteOperate — standard HMI recipe / setpoint group
PMC R/G/F (writable) WriteOperate
Read-only ReadOnly

Per the feedback_acl_at_server_layer design note, the FOCAS driver declares the classification but does NOT enforce it; DriverNodeManager applies the gate before the driver's WriteAsync ever runs. A user without WriteConfigure who attempts a PARAM: write gets BadUserAccessDenied from the server with no driver-level audit entry — the OPC UA layer's audit log catches it.

Audit-log expectations

Every successful write produces:

  • An OPC UA AuditWriteEvent (server layer — see docs/security.md "Audit logging").
  • A FOCAS driver-level Serilog entry tagged Driver=FOCAS DriverInstanceId=... TagName=... Address=... ResultStatus=....
  • A Writes/LastWriteAt and Writes/LastWriteStatus diagnostic counter refresh on the device's Diagnostics/ fixed-tree node (planned; populated as F4-c lands).

Failures to write (BadUserAccessDenied, BadCommunicationError, etc.) produce the same audit entries with the failure status code so a post-incident reviewer sees the same shape regardless of whether the write succeeded.

Granular config example

{
  "Drivers": {
    "FOCAS": {
      "Devices": [
        { "HostAddress": "focas://10.0.0.5:8193", "Series": "Series30i" }
      ],
      "Writes": {
        "Enabled": true,
        "AllowMacro": true,        // recipe / setpoint writes — operator role
        "AllowParameter": false    // commissioning only — keep locked except during planned work
      },
      "Tags": [
        { "Name": "Recipe.PartCount", "DeviceHostAddress": "focas://10.0.0.5:8193",
          "Address": "MACRO:500", "DataType": "Int32",
          "Writable": true, "WriteIdempotent": true },
        { "Name": "MaxFeedrate", "DeviceHostAddress": "focas://10.0.0.5:8193",
          "Address": "PARAM:1815", "DataType": "Int32",
          "Writable": false   /* keep read-only until commissioning window */ }
      ]
    }
  }
}

Flipping AllowParameter on for the commissioning window (and back off afterward) is the recommended deployment cadence — the granular kill switch is a lightweight runtime toggle, not a config-DB redeploy.