Merge b647-twincat: ADS sum-read (opt-in) + TwinCAT diagnostics on /hosts (#645 #310/#314, #612 docs)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 19:33:22 -04:00
17 changed files with 1463 additions and 49 deletions
@@ -43,6 +43,28 @@
class="form-control form-control-sm" />
<div class="form-text">0 = push immediately. Increase to coalesce high-churn signals.</div>
</div>
<div class="col-md-4 mb-3">
<div class="form-check form-switch mt-4">
<InputCheckbox id="tcSumRead" @bind-Value="_form.UseSumRead" @bind-Value:after="EmitAsync"
class="form-check-input" />
<label class="form-check-label" for="tcSumRead">Batch polled reads (ADS sum-read)</label>
</div>
<div class="form-text">One round-trip per chunk instead of per tag. Falls back to single reads if the target refuses it. Default off.</div>
</div>
<div class="col-md-4 mb-3">
<label class="form-label" for="tcSumReadMax">Sum-read max items</label>
<InputNumber id="tcSumReadMax" @bind-Value="_form.SumReadMaxItems" @bind-Value:after="EmitAsync"
min="1" max="500" class="form-control form-control-sm" />
<div class="form-text">Symbols per sum-read command (1-500, default 200).</div>
</div>
<div class="col-md-4 mb-3">
<div class="form-check form-switch mt-4">
<InputCheckbox id="tcDiagnostics" @bind-Value="_form.DiagnosticsEnabled" @bind-Value:after="EmitAsync"
class="form-check-input" />
<label class="form-check-label" for="tcDiagnostics">PLC diagnostics on /hosts</label>
</div>
<div class="form-text">Up to 4 extra reads per device per probe tick. Default off (not yet live-gated).</div>
</div>
</div>
</div>
</section>
@@ -151,6 +173,9 @@
public bool UseNativeNotifications { get; set; } = true;
public bool EnableControllerBrowse { get; set; } = false;
public int NotificationMaxDelayMs { get; set; } = 0;
public bool UseSumRead { get; set; } = false;
public int SumReadMaxItems { get; set; } = 200;
public bool DiagnosticsEnabled { get; set; } = false;
// Probe
public bool ProbeEnabled { get; set; } = true;
@@ -168,6 +193,9 @@
UseNativeNotifications = o.UseNativeNotifications,
EnableControllerBrowse = o.EnableControllerBrowse,
NotificationMaxDelayMs = o.NotificationMaxDelayMs,
UseSumRead = o.UseSumRead,
SumReadMaxItems = o.SumReadMaxItems,
DiagnosticsEnabled = o.DiagnosticsEnabled,
ProbeEnabled = o.Probe.Enabled,
ProbeIntervalSeconds = (int)o.Probe.Interval.TotalSeconds,
ProbeTimeoutSeconds = (int)o.Probe.Timeout.TotalSeconds,
@@ -181,6 +209,9 @@
UseNativeNotifications = UseNativeNotifications,
EnableControllerBrowse = EnableControllerBrowse,
NotificationMaxDelayMs = NotificationMaxDelayMs,
UseSumRead = UseSumRead,
SumReadMaxItems = SumReadMaxItems,
DiagnosticsEnabled = DiagnosticsEnabled,
Probe = new TwinCATProbeOptions
{
Enabled = ProbeEnabled,