From 7dd64b8ccdf110b9623a235aa49e6683f8754394 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 8 Oct 2026 19:12:13 -0400 Subject: [PATCH] feat(focas): OtOpcUa-owned otopcua-focas-fixture stack (#651) + FOCAS backlog docs (#633) Fixture renamed off ignitionoee's otopcua-focas-sim, port 8193 published, project label, default endpoint 10.100.0.35:8193; infra/dev-environment docs. FOCAS.md: MACRO:3901 parts count, PMC override + cycle-time recipes, won't-do/blocked backlog. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe --- docs/Configuration.md | 2 +- docs/drivers/FOCAS-Test-Fixture.md | 5 +- docs/drivers/FOCAS.md | 103 ++++++++++++++++-- docs/v2/dev-environment.md | 2 +- infra/README.md | 16 ++- scripts/integration/run-focas.ps1 | 2 + .../Docker/docker-compose.yml | 14 ++- .../FocasSimFixture.cs | 4 +- .../Series/WireBackendStatusAndPmcTests.cs | 2 +- 9 files changed, 125 insertions(+), 25 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 5e254b77..38cffc47 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -510,7 +510,7 @@ These are consumed by the driver **integration-test fixtures** (under `tests/Dri | `AB_SERVER_ENDPOINT` | `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests/AbServerFixture.cs` | `10.100.0.35:44818` | | `S7_SIM_ENDPOINT` | `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests/Snap7ServerFixture.cs` | `10.100.0.35:1102` (non-privileged; not S7-standard 102) | | `OPCUA_SIM_ENDPOINT` | `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.IntegrationTests/OpcPlcFixture.cs` | `opc.tcp://10.100.0.35:50000` | -| `OTOPCUA_FOCAS_SIM_ENDPOINT` | `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/FocasSimFixture.cs` | `localhost:8193` | +| `OTOPCUA_FOCAS_SIM_ENDPOINT` | `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/FocasSimFixture.cs` | `10.100.0.35:8193` | > Additional harness/parity/soak env vars (`OTOPCUA_FOCAS_*`, `OTOPCUA_PARITY_*`, `OTOPCUA_SOAK_*`, `OTOPCUA_HARNESS_USE_SQL`) exist only in the test/parity/soak harnesses, not in production source, and are out of scope for this reference. diff --git a/docs/drivers/FOCAS-Test-Fixture.md b/docs/drivers/FOCAS-Test-Fixture.md index 7875aedc..e5651097 100644 --- a/docs/drivers/FOCAS-Test-Fixture.md +++ b/docs/drivers/FOCAS-Test-Fixture.md @@ -52,8 +52,9 @@ message naming the CNC series + documented limit. managed `FocasDriver` end-to-end. A single gate: **Docker compose up** — tests skip when the TCP probe fails, with a -pointer to the compose command. The endpoint defaults to `localhost:8193` -and is overridable via `OTOPCUA_FOCAS_SIM_ENDPOINT`. +pointer to the compose command. The endpoint defaults to `10.100.0.35:8193` +(the OtOpcUa-owned `otopcua-focas-fixture` container, stack `/opt/otopcua-focas`; see +`infra/README.md`) and is overridable via `OTOPCUA_FOCAS_SIM_ENDPOINT`. When the mock is up, `WireFocasClient` dials it over TCP exactly like a real CNC, and the mock's native FOCAS Ethernet responder replies with diff --git a/docs/drivers/FOCAS.md b/docs/drivers/FOCAS.md index 802f10df..5e67e113 100644 --- a/docs/drivers/FOCAS.md +++ b/docs/drivers/FOCAS.md @@ -286,22 +286,69 @@ fallen back to `PositionDecimalPlaces` and published raw counts. numbers whose meaning is MTB-specific, and which no browse can discover. Those go under the device folder alongside the fixed subtree. -### Parts count (`PARAM:6711`) +### Parts count (`MACRO:3901`, or `PARAM:6711`) -There is deliberately **no** dedicated parts-count node (#258): the count is an ordinary CNC parameter, so it -is already readable as a hand-authored `PARAM:` tag (Int32), and a fixed `Parts/` subtree would hard-code -parameter numbers that are control- and MTB-specific. On the standard FANUC 0i / 16i / 30i parameter map: +There is deliberately **no** dedicated parts-count node (#258): the count is an ordinary CNC value, so it +is already readable as a hand-authored tag, and a fixed `Parts/` subtree would hard-code numbers that are +control- and MTB-specific. Two addresses carry it; **which one works depends on the control**: -| Address | Parameter | Meaning | +| Address | What | Use when | |---|---|---| -| `PARAM:6711` | No. 6711 | Number of parts machined (resets with the operator's clear) | -| `PARAM:6712` | No. 6712 | Total number of parts machined (cumulative) | -| `PARAM:6713` | No. 6713 | Number of parts required (the target) | +| `MACRO:3901` | Custom macro system variable #3901 — parts machined (`#3902` = parts required) | **Recommended.** Works over the wire on a Makino 31i-B (Z-34184, G431), where `cnc_rdparam` is refused | +| `PARAM:6711` | CNC parameter No. 6711 — number of parts machined (`6712` total, `6713` required) | Controls that answer `cnc_rdparam` (standard FANUC 0i / 16i / 30i parameter map) | -The count-up trigger (which M code or cycle end increments it) is set by No. 6710 and bit 0 of No. 6700, -so confirm in the machine's parameter manual that the counter is actually enabled and that 6711–6713 mean -what the MTB says they mean before relying on them. Cycle time per part is not provided; the `Timers/` -subtree exposes `CycleSeconds` and a client can difference it across a `PARAM:6711` change. +⚠️ **`PARAM:` reads do not work on the Makino.** Its 31i-B answers `cnc_rdparam` (0x000E) with `EW_FUNC`, so a +`PARAM:6711` tag reads `BadNotSupported` there. `cnc_rdmacro` is accepted, so `MACRO:3901` is the address to +author on that machine. Both are Int32 tags. + +The count-up trigger (which M code or cycle end increments the counter) is set by No. 6710 and bit 0 of No. +6700, so confirm in the machine's manual that the counter is actually enabled before relying on either +address — a disabled counter reads a constant `0` (a *vacant* macro reads `BadNoData`, never `0`; see +[Wire decode corrections](#wire-decode-corrections-2026-10)). A `0` from `MACRO:3901` is therefore a valid +decode of "counter not counting", not a driver fault. Cycle time per part is not provided as a node — see the +[virtual-tag recipe](#recipe-cycle-time-per-part-virtual-tag-272). + +### Recipe: feed / rapid / spindle override via PMC (#259) + +The CNC's override values are ordinary PMC signals (the MTB ladder copies the operator-panel switches into the +G area), so they are readable today with plain PMC tags — read-only, no new driver surface. On the standard +FANUC signal map: + +| Signal | PMC address | Notes | +|---|---|---| +| Feed override `*FV0-*FV7` | `G12` (Byte) | **Inverted**: the byte holds the one's complement. Percent = `255 - value` for a binary-coded switch (`255` = 0%, `155` = 100%); gray-coded/ladder-converted panels differ | +| Rapid override `ROV1`, `ROV2` | `G14.0`, `G14.1` (Bit) | Two bits select 100% / 50% / 25% / F0 | +| Spindle override `SOV0-SOV7` | `G30` (Byte) | Percent, usually a direct 0-150 value | + +Author them as normal PMC tags (`G12`, `G14.0`, `G30` — G is accepted on the 30i family and the 16i). To publish a +percentage rather than the raw byte, derive it with a virtual tag (`255 - ctx.GetTag("{{equip}}/FeedOverrideRaw")`). + +⚠️ **The addresses above are the FANUC *standard* signal assignment; the meaning is defined by the machine +builder's ladder.** Confirm each against the machine's own PMC signal list before trusting the number, and +validate with the panel switches at known positions (read-only observation — never write PMC). **Modal G/M/T +codes are not available**: `cnc_modal` has no known wire command id here (see +[Not ported](#not-ported-633-backlog)). + +### Recipe: cycle time per part (virtual tag, #272) + +A per-part cycle time is **not** a driver feature: `FIXED:Timers/CycleSeconds` and the parts count +(`MACRO:3901` / `PARAM:6711`) are both already readable, and the result is a pure function of them. Author the +count as an equipment tag named `PartsCount` and `FIXED:Timers/CycleSeconds` as `CycleSeconds`, then add a +virtual tag (Double, change-triggered by those two references): + +```csharp +// Average cycle seconds per part since the counters were last cleared. +var parts = (double)ctx.GetTag("{{equip}}/PartsCount").Value; +var cycle = (double)ctx.GetTag("{{equip}}/CycleSeconds").Value; +return parts > 0 ? cycle / parts : null; // no parts yet: no average +``` + +This is a **running average**, valid only while both counters accumulate from the same reset (an operator clearing +one but not the other skews it until they are cleared together). The exact *last-cycle delta* (difference +`CycleSeconds` across a parts-count step) needs the script to remember the previous sample, and virtual-tag scripts +have no documented persistent state (see [`docs/ScriptEditor.md`](../ScriptEditor.md)) — compute that in the +consuming system (e.g. ScadaBridge) from the two raw tags instead. Both inputs hold while either is Bad, per the +quality contract. ## PMC range coalescing @@ -448,6 +495,38 @@ re-interpretation of `cnc_rdparam` (no successful `cnc_rdparam` capture exists o the reference 31i-B refuses it with `EW_FUNC`, which already reads `BadNotSupported` here); and the all-axes multi-block `cnc_rddynamic2` batching (a latency optimisation, not a correctness fix). +## Not ported (#633 backlog) + +The #607 porting backlog (#257-#272) was triaged against this read-only driver. Disposition: + +**Done / documented:** #257 `Status/` fixed subtree, #258 parts count ([`MACRO:3901`](#parts-count-macro3901-or-param6711)), +#259 overrides ([PMC recipe](#recipe-feed--rapid--spindle-override-via-pmc-259)), #265 16i PMC F/G, #266 PMC range +coalescing, #272 ([virtual-tag recipe](#recipe-cycle-time-per-part-virtual-tag-272)). + +**Won't do — the read-only policy (#268-#271).** The FOCAS driver is read-only by design +(`WireFocasClient.WriteAsync` returns `BadNotWritable`) and that is a safety decision for real CNCs, not a +gap: no write infrastructure / per-tag opt-in (#268), no `cnc_wrmacro` / `cnc_wrparam` (#269), no `pmc_wrpmcrng` +or PMC bit read-modify-write (#270), no password / unlock parameter (#271). Nothing in the driver or CLI should be +read as a path toward them. + +**Blocked — need an authoritative wire capture first.** None of the following has a wire command id known to this +repo or to the sister ignitionoee client, and neither mock serves them over the binary wire: + +| Item | Capability | Blocked by | +|---|---|---| +| #259 (modal part) | Modal G / M / T codes (`cnc_modal`) | no wire id | +| #260 | Tool number / tool life, work-coordinate and tool offsets (`cnc_rdtofs` / `rdzofs`) | no wire ids | +| #261 | Operator messages (`cnc_rdopmsg`) and the currently-executing block text (`cnc_rdexecprog`) | no wire ids | +| #263 | `DIAG:` address area (`cnc_diagnoss`) — the highest-value one: a single generic area would unlock many fields | no wire id | +| #264 | Multi-path / multi-channel (`cnc_getpath`) — the wire layer has `PathId` plumbing but no per-device/tag option | no wire id, and no multi-path control to validate against (the Makino is single-path) | +| #267 | Alarm history (`cnc_rdalmhistry`) | no wire id; the live alarm surface ([#647](#alarm-projection)) comes first | + +⚠️ **Do not discover these ids by probing the production Makino.** An unknown or guessed command id could map to a +function that is not a read, and even known ids misbehave on the 31i-B (`cnc_rdparam` 0x000E answers `EW_FUNC`). The +0x00D3 `cnc_getfigure` lesson (see Wire decode corrections) already showed that an id agreed between two mocks can be +fiction. The prerequisite is an authoritative capture: real FWLIB on a Windows host against a **non-production** +control, or a passive capture of an existing FWLIB application's traffic. + ## Further reading - [`docs/v2/driver-specs.md §7`](../v2/driver-specs.md) — full OPC UA node diff --git a/docs/v2/dev-environment.md b/docs/v2/dev-environment.md index b43a6abe..4d29e096 100644 --- a/docs/v2/dev-environment.md +++ b/docs/v2/dev-environment.md @@ -67,7 +67,7 @@ Running record of v2 dev services on the Windows dev VM. Updated on every instal | Dev Galaxy (AVEVA System Platform) | Local install on this dev box — full ArchestrA + Historian + OI-Server stack | v1 baseline | Local COM via MXAccess (`C:\Program Files (x86)\ArchestrA\Framework\bin\ArchestrA.MXAccess.dll`); Historian via `aaH*` services; SuiteLink via `slssvc` | Windows Auth | Galaxy repository DB `ZB` on local SQL Server (separate instance from `otopcua-mssql` — legacy v1 Galaxy DB, not related to v2 config DB) | ✅ **Fully available — Phase 2 lift unblocked.** 27 ArchestrA / AVEVA / Wonderware services running incl. `aaBootstrap`, `aaGR` (Galaxy Repository), `aaLogger`, `aaUserValidator`, `aaPim`, `ArchestrADataStore`, `AsbServiceManager`, `AutoBuild_Service`; full Historian set (`aahClientAccessPoint`, `aahGateway`, `aahInSight`, `aahSearchIndexer`, `aahSupervisor`, `InSQLStorage`, `InSQLConfiguration`, `InSQLEventSystem`, `InSQLIndexing`, `InSQLIOServer`, `InSQLManualStorage`, `InSQLSystemDriver`, `HistorianSearch-x64`); `slssvc` (Wonderware SuiteLink); `OI-Gateway` install present at `C:\Program Files (x86)\Wonderware\OI-Server\OI-Gateway\` (decision #142 AppServer-via-OI-Gateway smoke test now also unblocked) | | GLAuth (LDAP) | Docker container `zb-shared-glauth` on the Linux Docker host — managed via `scadaproj/infra/glauth/` | v2.4.0 | `10.100.0.35:3893` (LDAP plaintext; LDAPS disabled) | Bind account `cn=serviceaccount,dc=zb,dc=local` / `serviceaccount123`; all test users password `password`; baseDN `dc=zb,dc=local` | `scadaproj/infra/glauth/` (source of truth + deploy/verify runbook) | ✅ Running on Docker host. Shared across OtOpcUa, MxAccessGateway, ScadaBridge. OtOpcUa groups: `OtOpcUa-Admins`→Administrator, `OtOpcUa-Designers`→Designer, `OtOpcUa-Viewers`→Viewer. The per-VM NSSM service at `C:\publish\glauth\` and old base DNs `dc=lmxopcua,dc=local` / `dc=otopcua,dc=local` are obsolete. | | OPC Foundation reference server | Not yet built | — | `10.100.0.35:62541` (target) | `user1` / `password1` (reference-server defaults) | — | Pending (needed for Phase 5 OPC UA Client driver testing) | -| FOCAS TCP stub | Not yet built | — | `10.100.0.35:8193` (target) | n/a | — | Pending (built in Phase 5; runs on Docker host) | +| FOCAS fixture (`otopcua-focas-fixture`, vendored focas-mock) | Docker compose at `/opt/otopcua-focas/` on Docker host (source: `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Docker/`) | vendored snapshot | `10.100.0.35:8193` (published; `OTOPCUA_FOCAS_SIM_ENDPOINT`) | n/a | n/a | Owned by OtOpcUa. NB `otopcua-focas-sim` on the same host is **ignitionoee's** mock (#651) — do not touch it | | Modbus simulator (`otopcua-pymodbus:3.13.0`) | Docker compose at `/opt/otopcua-modbus/` on Docker host | pinned 3.13.0 | `10.100.0.35:5020` | n/a | n/a | Stack staged; bring up with `lmxopcua-fix up modbus ` from this VM | | AB CIP fixture (`otopcua-ab-server:libplctag-release`) | Docker compose at `/opt/otopcua-abcip/` on Docker host | source-pinned `release` tag | `10.100.0.35:44818` | n/a | n/a | Stack staged; bring up with `lmxopcua-fix up abcip ` from this VM | | S7 fixture (`otopcua-python-snap7:1.0`) | Docker compose at `/opt/otopcua-s7/` on Docker host | python-snap7 ≥2.0 | `10.100.0.35:1102` | n/a | n/a | Stack staged; bring up with `lmxopcua-fix up s7 s7_1500` from this VM | diff --git a/infra/README.md b/infra/README.md index e8cc302a..d38702df 100644 --- a/infra/README.md +++ b/infra/README.md @@ -37,8 +37,8 @@ ssh dohertj2@10.100.0.35 'docker ps --filter label=project=lmxopcua --format "{{ | Stack dir | Purpose | |---|---| | `/opt/otopcua-mssql` | central SQL (always-on) | - | `/opt/otopcua-modbus` · `/opt/otopcua-abcip` · `/opt/otopcua-s7` · `/opt/otopcua-opcuaclient` · `/opt/otopcua-mqtt` · `/opt/otopcua-mtconnect` | driver fixtures | - | `~/otopcua-ablegacy` · `~/otopcua-focas` | driver fixtures (user-owned) | + | `/opt/otopcua-modbus` · `/opt/otopcua-abcip` · `/opt/otopcua-s7` · `/opt/otopcua-opcuaclient` · `/opt/otopcua-mqtt` · `/opt/otopcua-mtconnect` · `/opt/otopcua-focas` | driver fixtures | + | `~/otopcua-ablegacy` | driver fixture (user-owned) | | `~/otopcua-harness` | Host.IntegrationTests real-mode deps (SQL + GLAuth) — see §4 | - The repo's `tests/.../Docker/` trees are the **source of truth**; the host dirs are mirrored @@ -68,14 +68,22 @@ when it isn't running. Bring one up, `dotnet test`, tear down. Repo compose live | AB Legacy (PCCC) | `otopcua-ab-server` (PCCC mode) | `10.100.0.35:44818` | `AB_LEGACY_COMPOSE_PROFILE=<…> docker compose up -d` (stack `~/otopcua-ablegacy`) | | S7 | `otopcua-python-snap7` | `10.100.0.35:1102` | `docker compose --profile s7_1500 up -d` | | OpcUaClient | `mcr.microsoft.com/iotedge/opc-plc:2.14.10` | `opc.tcp://10.100.0.35:50000` | `docker compose up -d` | -| FOCAS | `otopcua-focas-sim` (vendored focas-mock) | `10.100.0.35:8193` | `docker compose up -d` (stack `~/otopcua-focas`) | +| FOCAS | `otopcua-focas-fixture` (vendored focas-mock, built on the host) | `10.100.0.35:8193` (published) | `docker compose up -d --build` (stack `/opt/otopcua-focas`; rsync the repo's FOCAS `Docker/` dir first) | | MQTT | `eclipse-mosquitto:2.0.22` (+ a publisher sidecar) | `10.100.0.35:8883` TLS+auth · `:1883` plaintext+auth | `MQTT_FIXTURE_USERNAME=otopcua MQTT_FIXTURE_PASSWORD= docker compose up -d` (stack `/opt/otopcua-mqtt`) | | MQTT — Sparkplug B | `otopcua-sparkplug-sim` (project-owned C# edge-node simulator) | same broker; group **`OtOpcUaSim`**, edge nodes **`EdgeA`** / **`EdgeB`**, `EdgeA` device **`Filler1`**, ~2 s cadence | `docker compose --profile sparkplug up -d` (same stack). Answers rebirth NCMDs; restart it to force a fresh birth | | MTConnect | `mtconnect/agent:2.7.0.12` + `python:3.13-alpine` adapter | `http://10.100.0.35:5000` | `docker compose up -d --wait` | **Endpoint overrides** point a suite at a real PLC instead of the sim: `MODBUS_SIM_ENDPOINT` · `AB_SERVER_ENDPOINT` · `S7_SIM_ENDPOINT` · `OPCUA_SIM_ENDPOINT` · -`MQTT_FIXTURE_ENDPOINT` / `MQTT_FIXTURE_PLAIN_ENDPOINT` · `MTCONNECT_AGENT_ENDPOINT`. +`MQTT_FIXTURE_ENDPOINT` / `MQTT_FIXTURE_PLAIN_ENDPOINT` · `MTCONNECT_AGENT_ENDPOINT` · `OTOPCUA_FOCAS_SIM_ENDPOINT`. + +> **`otopcua-focas-sim` on the host is NOT ours (#651).** It is ignitionoee's mock (created by that +> project's `provision-oee-focas.sh` for `ignition-site`; no published port, different defaults: +> big-endian timers, position exponent 3, `fwlib30i64` profile). OtOpcUa's fixture is +> `otopcua-focas-fixture`; the two once shared a name and overwrote each other. Never `docker rm -f`, +> rebuild or `mock_patch` `otopcua-focas-sim` or any `ignition-*`/`oee-*` container from here. The stale +> `~/otopcua-focas` dir on the host predates the rename — do not `compose up` it; retire it after +> `/opt/otopcua-focas` is deployed. > **MQTT needs credentials + material, unlike the other fixtures.** The broker has **no anonymous > fallback on either listener** (deliberate — an anonymous broker would let a bad auth config pass), diff --git a/scripts/integration/run-focas.ps1 b/scripts/integration/run-focas.ps1 index eda39cfe..24a5b0b5 100644 --- a/scripts/integration/run-focas.ps1 +++ b/scripts/integration/run-focas.ps1 @@ -106,6 +106,8 @@ else { Write-Step "dotnet test (wire-backend integration)" $env:OTOPCUA_FOCAS_SIM_PROFILE = $Profile +# The fixture default is the shared Docker host (10.100.0.35:8193); this script runs the mock locally. +if (-not $env:OTOPCUA_FOCAS_SIM_ENDPOINT) { $env:OTOPCUA_FOCAS_SIM_ENDPOINT = "localhost:8193" } dotnet test (Join-Path $integTests "ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests.csproj") ` --configuration $Configuration --no-build --nologo --verbosity minimal diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Docker/docker-compose.yml b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Docker/docker-compose.yml index 77595dc5..d5a6bf2b 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Docker/docker-compose.yml +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Docker/docker-compose.yml @@ -7,6 +7,14 @@ # docker compose -f Docker/docker-compose.yml up -d --wait # docker compose -f Docker/docker-compose.yml down # +# OWNERSHIP (#651): the container/image are named `otopcua-focas-fixture` on +# purpose. The name `otopcua-focas-sim` on 10.100.0.35 belongs to ignitionoee +# (its provision-oee-focas.sh `docker rm -f`s and recreates it for ignition-site); +# an earlier version of this file used that name and the two projects overwrote each +# other's fixture. Never start, stop or rebuild `otopcua-focas-sim` or any +# ignition-* / oee-* container from here. +# Deployed at /opt/otopcua-focas on the Docker host (rsync this Docker/ dir there). +# # One service, one container — the mock's native FOCAS Ethernet responder # auto-detects the binary PDU prefix (`a0 a0 a0 a0`) on the same TCP port # that serves JSON admin commands. Tests that need per-series behaviour @@ -17,14 +25,16 @@ services: focas-sim: - image: otopcua-focas-sim:latest + image: otopcua-focas-fixture:latest build: context: ./focas-mock dockerfile: Dockerfile - container_name: otopcua-focas-sim + container_name: otopcua-focas-fixture ports: - "8193:8193" restart: "no" + labels: + project: lmxopcua command: ["--profile", "FWLIB64"] healthcheck: test: ["CMD-SHELL", "python -c \"import socket; s=socket.create_connection(('127.0.0.1',8193),timeout=2); s.close()\" || exit 1"] diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/FocasSimFixture.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/FocasSimFixture.cs index d46faf6a..d17de3b3 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/FocasSimFixture.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/FocasSimFixture.cs @@ -13,14 +13,14 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests; /// /// /// Single skip gate: is non-null when the -/// localhost:8193 TCP probe fails. Tests call +/// 10.100.0.35:8193 TCP probe (the otopcua-focas-fixture container; override with OTOPCUA_FOCAS_SIM_ENDPOINT) fails. Tests call /// Assert.Skip. /// public sealed class FocasSimFixture : IAsyncDisposable { private const string EndpointEnvVar = "OTOPCUA_FOCAS_SIM_ENDPOINT"; private const string ProfileEnvVar = "OTOPCUA_FOCAS_SIM_PROFILE"; - private const string DefaultHost = "localhost"; + private const string DefaultHost = "10.100.0.35"; private const int DefaultPort = 8193; /// Gets the hostname or IP address of the focas-mock simulator. diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Series/WireBackendStatusAndPmcTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Series/WireBackendStatusAndPmcTests.cs index a981d0a4..1168119b 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Series/WireBackendStatusAndPmcTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Series/WireBackendStatusAndPmcTests.cs @@ -7,7 +7,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests.Series; /// /// Live-wire coverage (focas-mock) for #257 (cnc_statinfo status flags) and #266 (PMC /// range coalescing). Skips cleanly when OTOPCUA_FOCAS_SIM_ENDPOINT (default -/// localhost:8193) is unreachable. Read-only: no write path is exercised. +/// 10.100.0.35:8193, the otopcua-focas-fixture container) is unreachable. Read-only: no write path is exercised. /// [Collection(FocasSimCollection.Name)] public sealed class WireBackendStatusAndPmcTests