docs(#36): rig live gate PASS (two runs, reset echo held 751 ms on run 2); seed retargeted to String nodes; register row 120 — OPC UA scalar writes go out as String variants
Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
This commit is contained in:
@@ -9,12 +9,19 @@ set -euo pipefail
|
||||
#
|
||||
# What it creates (site-a / site id 1, connection id 1 "OPC PLC Simulator"):
|
||||
# - Template HandshakeDemo
|
||||
# * Trigger (Boolean) <- ns=3;s=Motor.Running writable, NOT simulated (holds what is written)
|
||||
# * Complete (Boolean) <- ns=3;s=Pump.Running writable, NOT simulated
|
||||
# * Payload (Double) <- ns=3;s=Motor.Speed writable, NOT simulated
|
||||
# * Trigger (String) <- ns=3;s=TestChildObject.TestString writable, NOT simulated (holds what is written)
|
||||
# * Complete (String) <- ns=3;s=JoeAppEngine.BTCS writable, NOT simulated
|
||||
# * Handshake (Call) — the reset-aware overload; returns the HandshakeResult fields
|
||||
# * Device (ValueChange on Trigger) — plays the PLC: on Trigger==true sets Complete=true
|
||||
# * Device (ValueChange on Trigger) — plays the PLC: on Trigger=="True" sets Complete="True"
|
||||
# and clears Trigger (so the next run's trigger is a fresh edge)
|
||||
#
|
||||
# WHY STRING NODES, NOT THE Boolean/Double ones (Motor.Running, Pump.Running, Motor.Speed):
|
||||
# a data-sourced SCALAR write leaves the InstanceActor as its codec-encoded STRING ("True",
|
||||
# "42.5") and RealOpcUaClient wraps it in a plain Variant, so opc-plc answers BadTypeMismatch
|
||||
# (0x80740000) for every non-String node — observed live 2026-09-10 (deferred-work register
|
||||
# row 120). Only List values are decoded before the write. The two String nodes above are
|
||||
# the rig's only writable String scalars, so the flags are the strings "True"/"False";
|
||||
# the reset-echo ordering this gate proves is identical either way.
|
||||
# - Instance handshake-demo-1, bound + deployed
|
||||
#
|
||||
# Not idempotent (names must be unique). To re-seed:
|
||||
@@ -37,18 +44,19 @@ TEMPLATE_ID=$("$CLI" template create "${A[@]}" --name HandshakeDemo \
|
||||
echo " id=$TEMPLATE_ID"
|
||||
|
||||
echo "2/5 Adding data-sourced attributes..."
|
||||
"$CLI" template attribute add "${A[@]}" --template-id "$TEMPLATE_ID" --name Trigger --data-type Boolean --data-source "ns=3;s=Motor.Running" --description "Handshake trigger (writable, not simulated)" > /dev/null
|
||||
"$CLI" template attribute add "${A[@]}" --template-id "$TEMPLATE_ID" --name Complete --data-type Boolean --data-source "ns=3;s=Pump.Running" --description "Handshake completion flag (writable, not simulated)" > /dev/null
|
||||
"$CLI" template attribute add "${A[@]}" --template-id "$TEMPLATE_ID" --name Payload --data-type Double --data-source "ns=3;s=Motor.Speed" --description "Batch payload" > /dev/null
|
||||
"$CLI" template attribute add "${A[@]}" --template-id "$TEMPLATE_ID" --name Trigger --data-type String --data-source "ns=3;s=TestChildObject.TestString" --description "Handshake trigger flag as a string (writable String node, not simulated; see header)" > /dev/null
|
||||
"$CLI" template attribute add "${A[@]}" --template-id "$TEMPLATE_ID" --name Complete --data-type String --data-source "ns=3;s=JoeAppEngine.BTCS" --description "Handshake completion flag as a string (writable String node, not simulated; see header)" > /dev/null
|
||||
|
||||
echo "3/5 Adding the Handshake (Call) script — reset-aware overload..."
|
||||
read -r -d '' HANDSHAKE_CODE <<'CS' || true
|
||||
// Gitea #36: reset Complete=false, WAIT for the device to echo it, then batch+trigger, then wait
|
||||
// for Complete=true. Run this twice: the second run is the one the plain overload got wrong.
|
||||
var values = new Dictionary<string, object?> { ["Payload"] = 42.5 };
|
||||
// Gitea #36: reset Complete="False", WAIT for the device to echo it, then batch+trigger, then wait
|
||||
// for Complete=="True". Run this twice: the second run is the one the plain overload got wrong.
|
||||
// String flags because the rig's OPC UA sim rejects non-String scalar writes (register row 120);
|
||||
// the batch carries no payload values — the trigger alone rides the batch leg.
|
||||
var values = new Dictionary<string, object?>();
|
||||
var hs = await Attributes.WriteBatchAndWaitAsync(
|
||||
values, "Trigger", true, "Complete", true, System.TimeSpan.FromSeconds(20),
|
||||
"Complete", false, System.TimeSpan.FromSeconds(10));
|
||||
values, "Trigger", "True", "Complete", "True", System.TimeSpan.FromSeconds(20),
|
||||
"Complete", "False", System.TimeSpan.FromSeconds(10));
|
||||
Log.Info($"handshake matched={hs.Matched} phase={hs.Phase} timedOut={hs.TimedOut} resetFailed={hs.ResetFailed}");
|
||||
return new { Matched = hs.Matched, Phase = hs.Phase.ToString(), TimedOut = hs.TimedOut, ResetFailed = hs.ResetFailed, Error = hs.ErrorMessage ?? "" };
|
||||
CS
|
||||
@@ -64,8 +72,8 @@ read -r -d '' DEVICE_CODE <<'CS' || true
|
||||
var t = await Attributes.GetAsync("Trigger");
|
||||
var ts = t?.ToString();
|
||||
if (!((t is bool b && b) || ts == "1" || string.Equals(ts, "true", System.StringComparison.OrdinalIgnoreCase))) return null;
|
||||
await Attributes.SetAsync("Complete", true);
|
||||
await Attributes.SetAsync("Trigger", false);
|
||||
await Attributes.SetAsync("Complete", "True");
|
||||
await Attributes.SetAsync("Trigger", "False");
|
||||
return null;
|
||||
CS
|
||||
"$CLI" template script add "${A[@]}" --template-id "$TEMPLATE_ID" --name Device --trigger-type ValueChange \
|
||||
@@ -74,7 +82,7 @@ CS
|
||||
echo "5/5 Creating, binding and deploying instance $INSTANCE_NAME..."
|
||||
INSTANCE_ID=$("$CLI" instance create "${A[@]}" --name "$INSTANCE_NAME" --template-id "$TEMPLATE_ID" --site-id "$SITE_ID" | json_id)
|
||||
"$CLI" instance set-bindings "${A[@]}" --id "$INSTANCE_ID" \
|
||||
--bindings "[[\"Trigger\",$CONNECTION_ID],[\"Complete\",$CONNECTION_ID],[\"Payload\",$CONNECTION_ID]]" > /dev/null
|
||||
--bindings "[[\"Trigger\",$CONNECTION_ID],[\"Complete\",$CONNECTION_ID]]" > /dev/null
|
||||
"$CLI" instance deploy "${A[@]}" --id "$INSTANCE_ID" > /dev/null
|
||||
echo " instance id=$INSTANCE_ID"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user