Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
868a9c2
Add Cognex VisionPro integration for AXOpen (PLC & .NET)
peterbarancek Apr 24, 2026
fe01447
Enhance VisionPro protocol: typed data, new tasks, robustness
peterbarancek Apr 28, 2026
05f618d
Add TriggerWithSpecificData support and error propagation
peterbarancek Apr 30, 2026
9e15a23
Refactor task lifecycle, status, and TCP timeout handling
peterbarancek May 6, 2026
c873254
Enhance AxoVisionProNet component functionality
peterbarancek May 28, 2026
446ebb4
wip
PTKu May 29, 2026
5f4ca60
Merge branch 'dev' into 1104-new-featureaxovisionpro-alternative
PTKu May 29, 2026
8b26083
Implement code changes to enhance functionality and improve performance
PTKu May 29, 2026
63bebe0
Update version to 0.57.0 and add AxoVisionProNet documentation
PTKu May 29, 2026
df12fe9
udpate central changelog
PTKu May 29, 2026
1accf09
Add unit tests for AxoDataman, AxoInsight v6 and v24, and AxoVisionPr…
PTKu May 29, 2026
1e64073
Merge branch 'dev' into 1104-new-featureaxovisionpro-alternative
PTKu Jun 1, 2026
54ef113
Merge branch 'dev' into 1104-new-featureaxovisionpro-alternative
peterbarancek Jun 1, 2026
9197ebd
Merge branch 'dev' into 1104-new-featureaxovisionpro-alternative
PTKu Jun 2, 2026
503a435
Merge branch 'dev' into 1104-new-featureaxovisionpro-alternative
PTKu Jun 4, 2026
b9a11ab
Enhance AxoVisionProNet with localization and live view
peterbarancek Jun 10, 2026
2b5459d
Enhance logging, error handling, and serialization
peterbarancek Jun 11, 2026
db75f9e
Improve iframe interactivity and adjust logging level
peterbarancek Jun 12, 2026
7022dff
Change log level to Debug in VisionTcpClient
peterbarancek Jun 12, 2026
11d1b65
Merge branch 'dev' into 1104-new-featureaxovisionpro-alternative
PTKu Jun 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 16 additions & 42 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
### [COMPONENTS.COGNEX.VISION] AxoVisionProNet — TCP/.NET alternative to the PROFINET AxoVisionPro
### [FIX] `AxoKrc5` local E-stop monitoring, 20002 rekey, opt-in task-timeout watchdog

**Note:** PLC fix in `src/components.kuka.robotics/ctrl/src/AxoKrc5/v_5_x_x/`. KRC5-only — `AxoKrc4` is unchanged. **Breaking:** public input `Inputs.Automatic` renamed to `Inputs.LocalEstopOk`. Branch: `1168-bug-update-krc4-following-the-updates-on-krc5` ([#1177](https://github.com/Inxton/AXOpen/pull/1177), refs #1168).
Expand Down Expand Up @@ -85,55 +86,28 @@

### [FIX] `axdev` password guard contradicted the secrets complexity policy

**Note:** Bug fix in `src/axopen.dev`. Branch: `feat/axdev-user-secrets-loader`.
**Note:** Additive change. New component `AxoVisionProNet` in `src/components.cognex.vision/ctrl/src/AxoVisionProNet/`, its .NET twin + TCP protocol stack in `src/components.cognex.vision/src/AXOpen.Components.Cognex.Vision/AxoVisonProNet/`, a Blazor proxy view, and full showcase/doc wiring. No public-API removal; existing `AxoVisionPro` (PROFINET) is unchanged. Branch: `1104-new-featureaxovisionpro-alternative`.

- fix: `AXOpen.Dev.Validation.PasswordValidator` no longer rejects `$ & ( ) *`. These are endorsed by the set-time complexity policy (`configure-secrets.sh` requires a special char from `!@#$%^&*()_+-=`), so a password that satisfied the complexity rule was then rejected at use time by `axdev alf` / `axdev all` with "The PASSWORD contains problematic characters." The blocklist now keeps only genuinely-dangerous shell metacharacters (`` ` \ " ' | ; < > ? [ ] { } `` and whitespace) — safe because arguments reach apax/openssl via CliWrap (no shell). Error message and `PasswordValidatorTests` updated.

**Impact:** `apax alf` / `apax all` accept the same passwords the secrets-setup flow accepts; no more spurious rejection of compliant passwords.

**Testing:** `dotnet test src/axopen.dev/AXOpen.Dev.Tests` — 180 passed.

### [BUILD] `axdev` loads dotnet user-secrets at startup

**Note:** Developer-CLI enhancement in `src/axopen.dev`. No PLC source change, no public-API removal. Branch: `feat/axdev-user-secrets-loader`.

- feat: `AXOpen.Dev.Secrets.UserSecretsLoader` reads dotnet user-secrets into the process environment so PLC verbs resolve `AX_TARGET_PWD` / `AX_USERNAME` without a prior `source load-secrets.sh`. It locates the twin project's `<UserSecretsId>` (probes `../axpansion/twin` then `.`, overridable via the `AX_SECRETS_PROJECT` environment variable), reads its `secrets.json` from the OS user-secrets root, and flattens nested keys with the standard `key:subkey` convention.
- feat: New shared entry point `AxdevApp.Run(args)` calls `UserSecretsLoader.Load()` then builds and runs the command app. Both the packed `dotnet axdev` tool (`AXOpen.Dev.Tool/Program.cs`) and the in-repo dispatcher (`src/scripts/dev.cs`) now call `AxdevApp.Run` instead of `AxdevApp.Build().Run`.
- test: `AXOpen.Dev.Tests/Secrets/UserSecretsLoaderTests.cs` covers apply-from-store, existing-env-wins precedence, missing project / missing store / malformed JSON / no-`UserSecretsId` no-ops, the `AX_SECRETS_PROJECT` override, and nested-key flattening.

**Impact:**
- The template's credential UX (per-project `dotnet user-secrets`) is preserved while removing the bash `source load-secrets.sh` step, so apax verbs can call `axdev` directly on any platform.
- Precedence is non-surprising: an already-set environment variable (or apax variable) always wins over the secrets store; an explicit `-p/--password` still overrides everything in `PlcCommandSettings.ResolvePassword`.

**Risks/Review:**
- Secret loading is best-effort: a missing twin project, missing store, or unreadable JSON is a silent no-op, and the per-command argument guards still report any genuinely missing credential.

**Testing:**
- `dotnet test src/axopen.dev/AXOpen.Dev.Tests` — full suite green (176 passed), including the 8 new `UserSecretsLoaderTests`.

### [BUILD] Dependency-maintenance tooling + AXSharp `0.47.0-alpha.484` bump

**Note:** Build/CI tooling and dependency maintenance. No public-API change, no PLC source change. Branch: `deps-update`.

- feat: `scripts/update-latest-deps.ps1` — bumps all non-AXSharp dependencies (NuGet + npm) to their latest stable versions, sharing common helpers via `scripts/_deps-common.ps1`.
- feat: `scripts/update-vulnerable-deps.ps1` — scans npm and NuGet dependencies for known vulnerabilities and emits a report.
- chore: AXSharp packages bumped to `0.47.0-alpha.484` in `Directory.Packages.props`, with transitive dependencies reconciled. `.config/dotnet-tools.json` updated to match.
- chore: Added `.claude/skills/update-axsharp-version/SKILL.md` — skill for updating AXSharp and Inxton.Operon package versions.
- chore: Removed obsolete `package.json` / `package-lock.json` files across `src/components.abb.robotics`, `src/components.abstractions`, `src/data`, `src/data/src/AXOpen.Data.Blazor`, `src/inspectors`, and a stray `apax.yml`, to clean up the project structure.
- chore: `develop` branch GitVersion mode changed to `ContinuousDeployment`.
- chore: Styling dependencies refreshed (`src/styling/src/package.json` / lock; `momentum.css` regenerated).
- feat: `AxoVisionProNet` (`AXOpen.Components.Cognex.Vision`) — drives a Cognex VisionPro PC over a TCP/.NET channel instead of a PROFINET IO frame. The PLC `Invoke()`s `AxoRemoteTask`s (`Trigger`, `InspectionResult`, `SetRecipe`, `SendSpecificData`, `ReceiveSpecificData`, `TriggerWithSpecificData`, `SendSpecificDataAndTypes`) whose handlers run on the .NET twin; `Restore` is a local `AxoTask`. Use this variant when the camera PC is reachable over the network but is not wired as a PROFINET device.
- feat: `Control` (writable: `TriggerId`, `PartId`, `VariantId`) carries the per-request parameters; read-only `Config` holds the task supervision timers (`InfoTime` 5 s, `ErrorTime` 10 s, `TaskTimeout` 50 s); `Status` surfaces `Accepted`, `TriggerId`, `ErrorCode`, `ActionDescription`, `ErrorDescription`, `RejectReason`. Each remote task is checked for `HasRemoteException` per cycle and its `ErrorDetails` copied into `Status.ErrorDescription`; `Restore()` clears `ErrorCode` and re-arms the tasks. `SendSpecificDataAndTypes` is gated to manual control (commissioning only); `TriggerWithSpecificData` is disabled while `Trigger`/`SendSpecificData`/`SetRecipe` are busy.
- feat: .NET twin TCP protocol stack under `AxoVisonProNet/VisionProtocol/` — `VisionTcpClient` (async connect/send/receive loop with connect-timeout and cancellation), `VisionEnvelope` + `EnvelopeMessages` (framing), and `VisionTypedPayloadSerializer` (typed payload encode/decode). The socket is opened once at host start-up via `InitializeVisionClientAsync(host, port)` on the twin; `AxoVisionProNetSpecificDataContainer` exchanges the typed specific-data payloads.
- feat: `AxoVisionProNetView` (`AXOpen.Components.Cognex.Vision.blazor`) — dedicated proxy view on `AxoComponentContainerView` with `AxoVisionProNetStatusView` / `AxoVisionProNetCommandView` / `AxoVisionProNetSpotView` derivatives, so `RenderableContentControl` auto-selects the dedicated rendering by `Presentation`.
- feat: Showcase — `AxoVisionProNet_Example` (`src/showcase/app/src/components.cognex.vision/Documentation/AxoVisionProNet.st`) demonstrates the sequencer workflow, `TriggerWithSpecificData`, manual/commissioning send, and error recovery; wired into `CognexVision.st`, the Blazor `CognexVision.razor` page, `Program.cs` (`InitializeVisionClientAsync`), and the search registry.
- docs: Added `src/components.cognex.vision/docs/AxoVisionProNet.md` (CONTROLLER / .NET TWIN / BLAZOR tabs), linked it from `toc.yml`, referenced both VisionPro variants in `README.md`, and bumped `src/components.cognex.vision/docs/CHANGELOG.md` + `GitVersion.yml` to `0.57.0`.

**Impact:**
- Routine dependency bumps and vulnerability scanning are now scriptable and reproducible.
- AXSharp consumers build against `0.47.0-alpha.484`.
- Dead npm lockfiles no longer pollute the tree or trigger spurious tooling.
- Applications can integrate a Cognex VisionPro inspection over plain TCP without provisioning a PROFINET device, while keeping the same component-level operate/monitor/spot UX as the PROFINET `AxoVisionPro`.
- Remote-task exceptions are surfaced on `Status.ErrorDescription`/`ErrorCode` and cleared deterministically through `Restore()`.

**Risks/Review:**
- Dependency version bumps can introduce behavioural drift; verify a full `dotnet build` and the styling render after pulling.
- The .NET twin source folder is spelled `AxoVisonProNet` (missing the `i`) while the PLC `ctrl/` and Blazor folders use the correct `AxoVisionProNet`. Class/type names are correct so it compiles; the folder name is a cosmetic inconsistency.
- No automated test coverage was added: the TCP protocol classes (`VisionTcpClient`, `VisionEnvelope`, `VisionTypedPayloadSerializer`) have no xUnit tests in `tests/AXOpen.Components.Cognex.Vision.Tests`, and the ST trigger→result→restore flow has no AxUnit case in `ctrl/test/tests.st`.
- `InitializeVisionClientAsync` must be called by the host before the component runs, otherwise the remote tasks report "REMOTE TASK IS NOT INITIALIZED". The showcase `Program.cs` shows the required wiring (hardcoded demo endpoint `192.168.100.142:8500`).

**Testing:**
- Run `scripts/update-latest-deps.ps1` and `scripts/update-vulnerable-deps.ps1` end-to-end (exit code 0).
- `dotnet build` from solution root succeeds against the bumped package set.
- `apax ib` in `src/components.cognex.vision/ctrl` — PLC library + twin compile (`dotnet ixc`).
- `dotnet build src/components.cognex.vision/src/AXOpen.Components.Cognex.Vision.blazor` — proxy view compiles (verified: 0 errors).
- Showcase `Pages/components-cognex-vision/Documentation/CognexVision.razor`, AxoVisionProNet tab — exercise the sequencer, commissioning send, and error-recovery scenarios against a reachable VisionPro endpoint.

### [CORE] AxoSequencer step-timeout alarm — does not fall after timeout clears

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
USING AXOpen.Core;
USING AXOpen.Messaging;
USING AXOpen.Messaging.Static;
USING AXOpen.Components.Abstractions;
USING Siemens.Simatic.Hardware.Utilities;
USING Siemens.Simatic.MemoryAccess;
USING AXOpen.Timers;

NAMESPACE AXOpen.Components.Cognex.Vision
{S7.extern=ReadWrite}
{#ix-prop: public string DeviceIpAddress}
{#ix-prop: public string Proxy}
CLASS AxoVisionProNet EXTENDS AXOpen.Core.AxoComponent

VAR PUBLIC // TASKS
{#ix-attr:[Container(Layout.Wrap)]}
{#ix-attr:[ComponentDetails("Tasks")]}
{#ix-set:AttributeName = "<#Restore#>"}
RestoreTask : AXOpen.Core.AxoTask;

{#ix-attr:[Container(Layout.Wrap)]}
{#ix-attr:[ComponentDetails("Tasks")]}
{#ix-set:AttributeName = "<#Trigger#>"}
TriggerTask : AXOpen.Core.AxoRemoteTask;

{#ix-attr:[Container(Layout.Wrap)]}
{#ix-attr:[ComponentDetails("Tasks")]}
{#ix-set:AttributeName = "<#InspectionResult#>"}
InspectionResultTask : AXOpen.Core.AxoRemoteTask;

{#ix-attr:[Container(Layout.Wrap)]}
{#ix-attr:[ComponentDetails("Tasks")]}
{#ix-set:AttributeName = "<#SetRecipe#>"}
SetRecipeTask : AXOpen.Core.AxoRemoteTask;

{#ix-attr:[Container(Layout.Wrap)]}
{#ix-attr:[ComponentDetails("Tasks")]}
{#ix-set:AttributeName = "<#SendSpecificData#>"}
SendSpecificDataTask : AXOpen.Core.AxoRemoteTask;




{#ix-attr:[Container(Layout.Wrap)]}
{#ix-attr:[ComponentDetails("Tasks")]}
{#ix-set:AttributeName = "<#ReceiveSpecificData#>"}
ReceiveSpecificDataTask : AXOpen.Core.AxoRemoteTask;

{#ix-attr:[Container(Layout.Wrap)]}
{#ix-attr:[ComponentDetails("Tasks")]}
{#ix-set:AttributeName = "<#TriggerWithSpecificData#>"}
TriggerWithSpecificDataTask : AXOpen.Core.AxoRemoteTask;


{#ix-attr:[Container(Layout.Wrap)]}
{#ix-attr:[ComponentDetails("Tasks")]}
{#ix-set:AttributeName = "<#SendSpecificDataAndTypes#>"}
SendSpecificDataAndTypesTask : AXOpen.Core.AxoRemoteTask;

END_VAR

VAR PUBLIC // CONFIG
{#ix-attr:[Container(Layout.Stack)]}
{#ix-attr:[ComponentDetails("Config")]}
{#ix-attr:[ReadOnly()]}
Config : AxoVisionProNet_Config;
END_VAR

VAR PUBLIC // CONTROL
{#ix-attr:[Container(Layout.Stack)]}
{#ix-attr:[ComponentDetails("Control")]}
Control : AxoVisionProNet_Control;
_hasSpecificData : BOOL;
END_VAR

VAR PUBLIC // STATUS
{#ix-attr:[Container(Layout.Stack)]}
{#ix-attr:[ComponentDetails("Status")]}
Status : AxoVisionProNet_Component_Status;
Messenger : AXOpen.Messaging.Static.AxoMessenger;
TaskMessenger : AXOpen.Messaging.Static.AxoMessenger;
END_VAR



VAR PRIVATE
_progress : INT;
_infoTimer : AXOpen.Timers.OnDelayTimer;
_errorTimer : AXOpen.Timers.OnDelayTimer;

END_VAR

///<summary>
/// Runs tasks and logic of this component.
/// >[!IMPORTANT] This method must or one of its overloads be called cyclically.
///</summary>
METHOD PUBLIC OVERRIDE Run
VAR_INPUT
inParent : IAxoObject;

END_VAR
VAR_OUTPUT

END_VAR


SUPER.Run(inParent);

Messenger.Serve(THIS);

RestoreTask.Run(THIS);


TriggerTask.Execute(THIS);
if TriggerTask.HasRemoteException and not TriggerTask.IsBusy() then
Status.ErrorDescription := TriggerTask.ErrorDetails;
END_IF;

InspectionResultTask.Execute(THIS);
IF InspectionResultTask.HasRemoteException and not InspectionResultTask.IsBusy() then
Status.ErrorDescription := InspectionResultTask.ErrorDetails;
END_IF;

SetRecipeTask.Execute(THIS);
IF SetRecipeTask.HasRemoteException and not SetRecipeTask.IsBusy() then
Status.ErrorDescription := SetRecipeTask.ErrorDetails;
END_IF;

SendSpecificDataTask.SetIsDisabled( not _hasSpecificData);
SendSpecificDataTask.Execute(THIS);
IF SendSpecificDataTask.HasRemoteException and not SendSpecificDataTask.IsBusy() then
Status.ErrorDescription := SendSpecificDataTask.ErrorDetails;
END_IF;

ReceiveSpecificDataTask.SetIsDisabled( not _hasSpecificData);
ReceiveSpecificDataTask.Execute(THIS);
IF ReceiveSpecificDataTask.HasRemoteException and not ReceiveSpecificDataTask.IsBusy() then
Status.ErrorDescription := ReceiveSpecificDataTask.ErrorDetails;
END_IF;

TriggerWithSpecificDataTask.SetIsDisabled(TriggerTask.IsBusy() OR SendSpecificDataTask.IsBusy() OR SetRecipeTask.IsBusy() or not _hasSpecificData);
TriggerWithSpecificDataTask.Execute(THIS);
IF TriggerWithSpecificDataTask.HasRemoteException and not TriggerWithSpecificDataTask.IsBusy() then
Status.ErrorDescription := TriggerWithSpecificDataTask.ErrorDetails;
END_IF;
SendSpecificDataAndTypesTask.SetIsDisabled(not THIS.IsManuallyControllable() or not _hasSpecificData); // This task is only for commissioning purposes, so it can only be executed in manual mode.
SendSpecificDataAndTypesTask.Execute(THIS);
IF SendSpecificDataAndTypesTask.HasRemoteException and not SendSpecificDataAndTypesTask.IsBusy() then
Status.ErrorDescription := SendSpecificDataAndTypesTask.ErrorDetails;
END_IF;


//*************RESTORE********************
RestoreTask.SetIsDisabled(FALSE);
IF RestoreTask.Execute(THIS) THEN
THIS.Restore();
Status.ActionDescription := '<#Component restored#>';
END_IF;
//****************************************




END_METHOD



METHOD PUBLIC Trigger : IAxoTaskState
Trigger := TriggerTask.Invoke(THIS);
END_METHOD

METHOD PUBLIC InspectionResult : IAxoTaskState
InspectionResult := InspectionResultTask.Invoke(THIS);
END_METHOD

METHOD PUBLIC SetRecipe : IAxoTaskState
SetRecipe := SetRecipeTask.Invoke(THIS);
END_METHOD

METHOD PUBLIC SendSpecificData : IAxoTaskState
SendSpecificData := SendSpecificDataTask.Invoke(THIS);
END_METHOD

METHOD PUBLIC ReceiveSpecificData : IAxoTaskState
ReceiveSpecificData := ReceiveSpecificDataTask.Invoke(THIS);
END_METHOD
METHOD PUBLIC TriggerWithSpecificData : IAxoTaskState
TriggerWithSpecificData := TriggerWithSpecificDataTask.Invoke(THIS);
END_METHOD
METHOD PUBLIC SendSpecificDataAndTypes : IAxoTaskState
SendSpecificDataAndTypes := SendSpecificDataAndTypesTask.Invoke(THIS);
END_METHOD

METHOD PROTECTED OVERRIDE ManualControl
THIS._isManuallyControllable := TRUE;


END_METHOD
METHOD PRIVATE CallTimers
VAR_INPUT
signal : BOOL;
END_VAR

_infoTimer.OnDelay(THIS, signal AND Config.InfoTime > LT#0S ,Config.InfoTime);
_errorTimer.OnDelay(THIS, signal AND Config.ErrorTime > LT#0S , Config.ErrorTime);
END_METHOD

///<summary>
/// Restores this component into intial state.
///</summary>
METHOD PUBLIC OVERRIDE Restore
VAR
_index : INT;
END_VAR



TriggerTask.Restore();
SetRecipeTask.Restore();
SendSpecificDataTask.Restore();
SendSpecificDataAndTypesTask.Restore();
InspectionResultTask.Restore();
ReceiveSpecificDataTask.Restore();
TriggerWithSpecificDataTask.Restore();
Status.ActionDescription := '';
Status.ErrorDescription := '';
Status.Accepted := FALSE;
Status.ErrorCode := 0;
Status.RejectReason := '';
RestoreTask.DoneWhen(TRUE);

END_METHOD
END_CLASS
END_NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
NAMESPACE AXOpen.Components.Cognex.Vision
{S7.extern=ReadWrite}
CLASS PUBLIC AxoVisionProNetSpecificData

END_CLASS
END_NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
NAMESPACE AXOpen.Components.Cognex.Vision
{S7.extern=ReadWrite}
{#ix-generic:<TOnline, TPlain>}
CLASS PUBLIC AxoVisionProNetSpecificDataContainer

END_CLASS
END_NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
NAMESPACE AXOpen.Components.Cognex.Vision
{S7.extern=ReadWrite}
{#ix-attr:[Container(Layout.Stack)]}
CLASS PUBLIC AxoVisionProNet_Component_Status

VAR PUBLIC

ActionDescription : String;
ErrorDescription : string;
Accepted : BOOL;
TriggerId : INT;
ErrorCode : INT;
RejectReason : STRING;
END_VAR
END_CLASS
END_NAMESPACE
Loading
Loading