diff --git a/landing/404.html b/landing/404.html deleted file mode 100644 index 0b31c8f20..000000000 --- a/landing/404.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Page Not Found — ARSAS - - - -
ARSAS404 · Page not found

The requested ARSAS page is not available.

The address may have changed, or the engineering content may have moved into the repository documentation.

- - - diff --git a/landing/about.html b/landing/about.html deleted file mode 100644 index 823a9b808..000000000 --- a/landing/about.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - About ARSAS and Ari Sulistiono — IEC 61850 Engineering - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - Engineering purpose · open source · practical evidence -

Built to make practical IEC 61850 work clearer and faster.

-

ARSAS is an independent open-source Windows engineering workstation created to reduce repetitive setup during IEC 61850 laboratory work, FAT, SAT, commissioning, troubleshooting and multi-vendor integration.

-
-
- -
-
-
- Why ARSAS exists -

Useful testing should begin from the evidence available in the IED.

-

IEC 61850 workflows can lose significant time before the first useful value appears: preparing engineering files, inspecting DataSets, finding usable Report Control Blocks, mapping signals across tools and diagnosing why communication works while reporting remains silent.

-

ARSAS brings live MMS discovery, reporting visibility, GOOSE supervision, file transfer, SCL context, control evidence and diagnostics into one focused workspace.

-
-
- Project principle -

Complement engineering tools—not hide engineering reality.

-

ARSAS does not claim universal interoperability, conformance certification, switching authority or replacement of approved vendor engineering systems. It is designed to expose live behavior, preserve negative evidence and help engineers make better-informed decisions.

-

Capability status, preview scope, limitations and safety boundaries remain explicit throughout the product website.

-
-
-
- -
-
-
- Author and maintainer -

Ari Sulistiono

-

Ari Sulistiono is a substation automation engineer focused on protection and control, IEC 61850 communication, testing, commissioning, troubleshooting and practical engineering productivity.

-

ARSAS turns recurring field and integration problems into a reusable public engineering tool while keeping customer, employer, credential, relay-setting and substation data outside the repository.

- -
-
- Open-source transparency -

The website is the product front door. GitHub is the development workspace.

-

Most users can learn, download and use ARSAS entirely through this website. Developers, contributors and technical reviewers can inspect the source, architecture, license and issue history when deeper detail is needed.

- -
-
-
- -
-
-
-
Start with the product

Download ARSAS without navigating a source-code repository.

The product website provides the stable installer, portable package, checksums, capabilities, screenshots and engineering boundaries in one user-facing route.

- -
-
-
-
- - - - - diff --git a/landing/app.js b/landing/app.js index d80a0d898..d21acf992 100644 --- a/landing/app.js +++ b/landing/app.js @@ -32,6 +32,16 @@ }, { passive: true }); } - const year = document.querySelector('[data-year]'); - if (year) year.textContent = String(new Date().getFullYear()); + const page = document.body.dataset.page; + if (page) { + document.querySelectorAll('[data-nav-page]').forEach(link => { + if (!(link instanceof HTMLAnchorElement)) return; + if (link.dataset.navPage === page) link.setAttribute('aria-current', 'page'); + else link.removeAttribute('aria-current'); + }); + } + + document.querySelectorAll('[data-year]').forEach(node => { + node.textContent = String(new Date().getFullYear()); + }); })(); diff --git a/landing/architecture.html b/landing/architecture.html deleted file mode 100644 index d6b640d84..000000000 --- a/landing/architecture.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - ARSAS Architecture — IEC 61850 Application and Engine - - - - - - - - - - -
-
Application and protocol boundaries

Independent device ownership above a reusable IEC 61850 engine.

ARSAS keeps the engineer-facing Windows workflow separate from protocol implementation. Every IED owns an independent runtime session while ARIEC61850 provides typed services for MMS, reporting, GOOSE, Sampled Values, files, SCL, control, and diagnostics.

-
System boundary
┌──────────────────────────────────────────────────────────────┐
-│                            ARSAS                             │
-│ Explorer · Monitor · SOE · GOOSE · SMV · Files · SCL      │
-│ Diagnostics · Control staging · Evidence · Engineer UX      │
-└──────────────────────────────┬───────────────────────────────┘
-                               │ typed application services
-┌──────────────────────────────▼───────────────────────────────┐
-│                         ARIEC61850                           │
-│ Transport · MMS · Reporting · GOOSE · SMV · Files · SCL   │
-│ Control · Type system · Protocol diagnostics                │
-└──────────────────────┬────────────────────┬──────────────────┘
-                       │ TCP/102            │ process bus
-                  Approved IEDs       Approved capture network
-
Separation of concerns

Protocol behavior remains testable outside the UI.

The application can evolve its workflow and visualization without duplicating protocol rules, while the engine can be validated with deterministic fixtures and reused by other tools.

ARSAS

Project and workflow

Device cards, SCL context, signal selection, persistence, navigation, and task orchestration.

ARSAS

Visualization and evidence

Live grids, events, GOOSE and SMV views, file UX, control staging, and diagnostics.

ARIEC61850

Protocol services

Transport, association, MMS, reporting, GOOSE, Sampled Values, files, SCL, and control.

ARIEC61850

Type and model handling

Live descriptors, object references, DataSets, control blocks, value decoding, and validation.

Shared boundary

Typed contracts

Explicit capabilities and errors rather than UI assumptions leaking into protocol logic.

CI

Compatibility gate

Build-time checks fail explicitly when required engine contracts are missing.

-
Per-device ownership

One IED, one session, one lifecycle.

Connecting, monitoring, transferring files, or staging control for one device must not silently alter another.

Endpoint and identity

IP, port, SCL context, discovered identity, capability state, and reconnect information belong to the device.

MMS association

Association, discovery, requests, reports, file services, and cleanup remain scoped to the IED.

Acquisition plan

Static reports, dynamic coverage, polling points, aliases, and source evidence are per session.

Process-bus context

GOOSE and SMV actions open with the selected IED and model context.

Control context

Control descriptors and command sessions stay with the live association that produced them.

Diagnostics and events

Connection, report, file, sequence, and command evidence retains the affected IED.

-
Smart Reporting architecture

Coverage is proven before polling is reduced.

Configured membership is useful evidence, but it is not proof that every selected point will arrive in a usable stream.

01

Start live values

Read the selected MMS values while report setup is evaluated.

02

Attempt static reporting

Use relevant RCBs and validate the actual DataSet members and order.

03

Cover exact gaps

Build bounded dynamic recovery where the IED and workflow permit writes.

04

Poll the remainder

Schedule only still-uncovered or unverified points in the priority queue.

05

Retain evidence

Associate each update with time, quality, reason, source, alias, and IED context.

-
Runtime scale

Bounded work instead of one task per signal

  • One monitoring loop per IED
  • Priority queue for uncovered points
  • Bounded report draining
  • Latest-value coalescing
  • Batched UI updates
  • Bounded event and diagnostic collections
  • Virtualized grids
Failure semantics

Negative evidence remains visible

Association failures, unsupported services, model mismatches, report gaps, GOOSE anomalies, file errors, and negative command termination remain explicit and attributable.

-
Source documentation

Review the detailed architecture and engine contract.

The repository documents multi-IED ownership, reporting behavior, compatibility, validation boundaries, and clean-room development policy.

-
- - - - diff --git a/landing/control.html b/landing/control.html deleted file mode 100644 index cc2cdb7e5..000000000 --- a/landing/control.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - IEC 61850 Smart Control — Direct and SBO | ARSAS - - - - - - - - - - -
-
Control-model-aware validation

Control the intended object through the sequence the live IED actually requires.

ARSAS does not translate a button label into a blind write. It reads the live control model, resolves the command structure, preserves the required control context, executes the supported Direct or Select-Before-Operate sequence, and presents completion evidence.

-
Direct + SBONormal and enhanced security models
Live descriptorsNamed ctlVal binding from actual MMS types
Typed familiesDPC, SPC, INC/ISC, BSC, and APC
EvidenceService, termination, error, timing, and feedback
-
Discovery before dispatch

The command panel is the final step of model resolution.

A semantic action becomes available only when the live evidence can represent the command without positional guessing or a generic write fallback.

01

Resolve the Data Object

Normalize the selected reference and verify the control-object boundary.

02

Read ctlModel

Determine Direct or SBO and normal or enhanced completion handling.

03

Inspect descriptors

Retrieve Oper, SBOw, and optional Cancel types and locate the named ctlVal.

04

Bind semantic intent

Represent Open, Close, Boolean, Raise, Lower, counter, or setpoint through the actual live type.

05

Execute one sequence

Preserve origin, ctlNum, timestamp, Test, interlock, and synchrocheck values.

06

Record completion evidence

Present service results, CommandTermination, errors, AddCause, elapsed time, and feedback.

-
Supported semantics

Readable actions with type-aware wire handling.

Position / DPC

Open and Close actions with command encoding and feedback treated as separate evidence.

Boolean / SPC

True and False actions represented through the discovered single-point command type.

Pulse / BSC

Raise and Lower semantics for supported binary step command structures.

Counter / INC or ISC

Typed integer values when the live descriptor is usable.

Setpoint / APC

Explicit value entry and type-aware binding for supported analog control objects.

Per-command checks

Test, interlock, and synchrocheck requests remain attached to the exact staged command.

-
Evidence shown

Protocol completion and process response

  • Detected control model and selected sequence
  • Confirmed MMS service result
  • Positive or negative CommandTermination
  • ControlError, AddCause, and LastApplError
  • Control number, origin, request flags, and timing
  • Mapped process feedback where available
Guardrails

Protocol readiness is not switching authority

  • Two-step confirmation for Open and Close
  • No generic command-write fallback
  • Commands disabled when the live descriptor is not ready
  • Negative outcomes remain visible
  • Isolation, authority, and independent verification remain external requirements
-
Validation first

Exercise every control model before energized commissioning.

Validate positive and negative termination, interlock and synchrocheck rejection, Test mode, timeout, Cancel, association loss, competing-client ownership, and feedback in the approved environment.

-
- - - - diff --git a/landing/download.html b/landing/download.html deleted file mode 100644 index 1aa6f9290..000000000 --- a/landing/download.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Download ARSAS for Windows — Direct Installer - - - - - - - - - - - - -
-
Stable release · Windows x64 · self-contained

Download the latest ARSAS installer.

The primary public route is the ARSAS product website. The button below starts the latest stable Windows installer directly without opening a repository or release page.

Latest stable channel · ARSAS 1.6.16
- -
- -
Portable

Portable package

Use the portable ZIP for controlled test laptops or temporary evaluation without a traditional installation workflow.

ARSAS-Windows-x64-Portable.zip · latest stable release
Download portable ZIP
-
- -
-
Release integrity

Verify the package

Keep the installer and its SHA-256 evidence together when preparing controlled FAT, SAT, commissioning, or laboratory work.

-
Installation scope

Prepared for Windows engineering workstations

The package is built self-contained for Windows x64 and is smoke-tested through silent installation, required-file verification, and uninstall before publication.

-
- -
Engineering boundary

Download readiness is not switching authority.

Use ARSAS only inside an approved laboratory or commissioning boundary. Validate the package, network interface, IED scope, control permissions, and test procedure before active use.

-
- - - - - diff --git a/landing/features.html b/landing/features.html deleted file mode 100644 index 9405f8f8d..000000000 --- a/landing/features.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - IEC 61850 Capabilities — MMS, Reporting, GOOSE, Files | ARSAS - - - - - - - - - - - - -
-
Current scope and maturity

IEC 61850 capabilities organized around real commissioning work.

ARSAS connects configured context, live protocol behavior, process-bus traffic, fault records, control evidence, and reusable project state to the same IED session. Maturity labels keep available features separate from preview and roadmap work.

- -
AvailableMMS, Smart Reporting, GOOSE, files, control, SCL-assisted workflows
PreviewSampled Values / SMV engineering workflow
RoadmapFull visual SCL project generation
BoundaryNo conformance, safety, or universal interoperability claim
- -
Available now

A coherent workflow from endpoint to evidence.

The current application covers the highest-friction parts of practical IEC 61850 investigation and validation.

-
MMS

Live model discovery

Discover Logical Devices, Logical Nodes, Data Objects, Data Attributes, values, quality, timestamps, DataSets, RCBs, control objects, and live MMS type descriptors.

  • Independent association per IED
  • Configured and live context together
  • Searchable large-model workspace
  • Association and discovery diagnostics
-
Smart Reporting

Live values without report-engineering blockers

Start selected values through MMS, prefer configured BRCB or URCB coverage, recover exact gaps where permitted, and retain polling for anything still uncovered or unverified.

  • Static buffered and unbuffered reports
  • Exact DataSet member and order validation
  • Association-scoped dynamic DataSet recovery
  • Degraded-report polling fallback
-
GOOSE

Read-only stream inspection

Capture station or process-bus GOOSE through Npcap and retain stream identity, sequence, retransmission, TAL, and ordered payload evidence.

  • APPID, VLAN, MAC, goCBRef
  • stNum, sqNum, Test, ndsCom
  • Ordered allData leaves
  • SCL or live-model binding
-
File services

Fault-record retrieval

Use the selected IED context to probe the MMS file service, browse available paths, and download disturbance or COMTRADE-related records with bounded operations.

  • Per-IED endpoint ownership
  • Directory and service diagnostics
  • Progress and failure visibility
  • Foundation for record-set grouping
-
SCL

Configured-to-live workflow

Open SCD, CID, ICD, IID, SSD, or XML files, extract endpoints, retain project context, and compare configured intent against observed server behavior.

  • Multi-IED endpoint extraction
  • Edition-aware workspace services
  • Configured/live comparison context
  • Export foundation
-
Control

Typed Direct and SBO

Read ctlModel, resolve live command descriptors, execute supported sequences, and show service, termination, timing, error, and feedback evidence.

  • DPC, SPC, INC/ISC, BSC, APC
  • Direct and Select-Before-Operate
  • CommandTermination and AddCause
  • No generic control-write fallback
-
Operations

Live values and SOE

Separate continuous values from semantic events while preserving IED timestamps, quality, report reasons, and originating-device context.

  • Recent-change highlighting
  • Process timestamp semantics
  • Per-IED unread indicators
  • Bounded event collections
-
Scale

Independent multi-IED sessions

Every IED owns its connection, discovery, selected signals, reports, event state, control context, file workflow, and diagnostics.

  • Isolated lifecycle per device
  • One monitor loop per IED
  • Coalesced UI updates
  • Virtualized grids
-
Productivity

Project persistence

Save endpoints, cached model context, selected signals, and workspace state so recurring projects do not restart from zero.

  • Fast reconnect workflow
  • Retained device definitions
  • Persisted selections
  • Reusable diagnostic context
-
- -
Acquisition strategy

Static reports first. Dynamic recovery for gaps. Polling when required.

ARSAS never treats a report candidate as proof of coverage. It validates exact membership and observed behavior while selected live values continue through MMS.

Per-IED acquisition plan
0. Start MMS reads for selected live values
-1. Discover existing DataSets, BRCBs and URCBs
-2. Validate exact members, order and usable coverage
-3. Use a temporary DataSet with a suitable available RCB for gaps*
-4. Keep uncovered or unverified points in bounded polling
-5. Detect missed changes and restore polling fallback
-✓ Show value, quality, IED timestamp, reason and source
-
-* Only when the IED and approved workflow permit writes.
Empty DataSet or no usable RCB?Monitoring continues through bounded polling instead of blocking the engineering workflow.Explore Smart Reporting →
- -
Capability evidence

Live values, GOOSE, and diagnostics in the real application.

-
ARSAS multi-IED live-value workspace

01Multi-IED live values

Selected signals share one workspace while retaining device, quality, timestamp, and acquisition evidence.

-
ARSAS detailed GOOSE subscriber

02GOOSE stream detail

Stream metadata, sequence supervision, payload, retransmissions, and model binding stay visible together.

-
ARSAS communication diagnostics

03Communication diagnostics

Association, service, report, sequence, timing, GOOSE, and frame evidence remain attributable.

-
- -
Engineering preview

Sampled Values / SMV

Per-IED SMV entry points and a viewer direction are available. Production-grade completion still requires deeper stream decoding, SCL binding, scaling, quality supervision, and sustained-performance validation.

Roadmap

Full SCL generation

The target is a visual, validated authoring workspace for IED, communication, DataSet, report, GOOSE, Sampled Values, and Edition-aware export structures.

- -
Start testing

Move from endpoint to evidence in one workspace.

Review the source, capability boundaries, and validation checklist before using active functions in an approved test environment.

-
- - - - - diff --git a/landing/index.html b/landing/index.html deleted file mode 100644 index e2f9df8d9..000000000 --- a/landing/index.html +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - ARSAS — Smart IEC 61850 Engineering Workstation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- Open source · Windows · .NET 8 -

IEC 61850 engineering
without the setup maze.

-

Enter an IED address, discover the live MMS model, select the signals, and begin testing. ARSAS handles reporting complexity with configured BRCB or URCB coverage, dynamic recovery where permitted, and bounded polling when reporting cannot be used.

- -
Live values without manual RCB setupIndependent multi-IED sessionsVisible acquisition evidence
-
-
-
ARSAS IEC 61850 engineering workstation at first launch
-
Static → dynamic → polling
Immediate live values
-
-
-
- -
Smart ReportingBRCB · URCB · dynamic DataSet · polling
Multi-IEDIndependent sessions, monitoring, events, and diagnostics
GOOSE + FilesStream supervision and fault-record retrieval
SCL + ControlConfigured context and typed command evidence
- -
-
-
Smart Reporting

Select the signals. ARSAS handles the acquisition path.

DataSet, BRCB, URCB, reservation, GI, and fallback behavior are verified in the background instead of becoming a manual prerequisite before the engineer can see useful values.

-
-
01
Immediate MMS image

Selected values begin reading while report setup is evaluated.

-
02
Configured reports first

Existing BRCBs, URCBs, and DataSets are discovered and checked for exact coverage.

-
03
Recover exact gaps

A temporary DataSet can be used with a suitable available RCB when writes are permitted.

-
04
Polling safety net

Only uncovered, rejected, unverified, or degraded points remain in bounded polling.

-
-
No report dead end.Empty DataSet, no usable RCB, or rejected write does not block the live-value workflow.Explore Smart Reporting →
-
-
- -
-
Why it matters

Replace days of fragmented preparation with one traceable workflow.

ARSAS is designed for FAT, SAT, commissioning, troubleshooting, research, and controlled laboratory testing where reaching trustworthy evidence matters more than operating several disconnected utilities.

-
Traditional setup

Communication testing starts with tool configuration.

  • Prepare or repair engineering files
  • Map signals across separate tools
  • Create or update DataSets and RCBs
  • Diagnose why values are still unavailable
  • Rebuild context for every IED
ARSAS workflow

Communication testing starts from the IED.

  • Enter an endpoint or open SCL
  • Discover the live model
  • Select the required signals
  • Observe values, quality, time, events, and source
  • Keep every result attached to its IED session
-
-
- -
-
Real application evidence

See the product—not a marketing mockup.

These are current Windows application screenshots showing multi-IED connections, unified live values, SOE, GOOSE supervision, and communication diagnostics.

-
-
ARSAS connected simultaneously to multiple IEC 61850 IEDs

01Independent multi-IED connections

Each IED retains its own MMS association, model, monitoring lifecycle, and diagnostic history.

-
ARSAS unified IEC 61850 live-value viewer

02Unified live-value workspace

Search values from connected IEDs with quality, timestamp, source, and recent-change evidence.

-
ARSAS IEC 61850 sequence-of-events view

03SCADA-style event log

Correlate semantic changes while retaining the originating IED and process timestamp.

-
ARSAS detailed GOOSE subscriber and stream supervision

04Detailed GOOSE supervision

Inspect stream identity, sequence, retransmission, TAL, ordered payload, and model binding.

-
ARSAS communication and frame diagnostics workspace

05Communication diagnostics

Separate network, association, service, report, sequence, and device-behavior problems.

-
-
- -
Practical engineering scope

One workspace from endpoint to evidence.

Implemented, preview, and roadmap capabilities remain explicitly labeled.

-
Available

MMS discovery

Discover the live hierarchy, values, quality, timestamps, DataSets, RCBs, and live type information.

-
Available

Smart Reporting

Use proven static coverage, recover exact gaps where permitted, and poll only what remains uncovered or unverified.

-
Available

GOOSE subscriber

Inspect APPID, VLAN, MAC, goCBRef, DataSet, sequence, TAL, payload, and binding evidence.

-
Available

Fault-record transfer

Browse the MMS file service and retrieve disturbance or COMTRADE-related files in the selected IED context.

-
Available

SCL-assisted workspace

Open common SCL files, retain configured context, compare live behavior, and use Edition-aware export services.

-
Available

Guarded Smart Control

Resolve ctlModel and live command types before supported Direct or SBO execution.

-
Available

SOE and diagnostics

Preserve process timestamps, report reasons, sequence evidence, transfer outcomes, and command results.

-
Engineering preview

Sampled Values

Per-IED SMV entry points and viewer direction while deeper decoding and performance validation continue.

-
Roadmap

Full SCL generation

Visual authoring for IED, communication, DataSet, report, GOOSE, SMV, and export structures.

-
- -
Minutes to useful evidence

Connect. Discover. Select. Test.

The workflow stays understandable even when the IED configuration is incomplete or behaves differently from the engineering model.

-
01

Open SCL or add an IED

Start from configured context or an approved MMS endpoint.

02

Discover the live model

Verify the hierarchy, services, report objects, file capability, and data types.

03

Select the required signals

Choose the process values and control objects needed for the test.

04

Observe and validate

Monitor values, reports, SOE, GOOSE, files, diagnostics, and command completion.

05

Preserve evidence

Keep configured intent, live result, time, quality, source, and diagnostics together.

-
- -
Open engineering

Start from the real IED—not a chain of setup tools.

Build ARSAS from source, review its capability boundaries, and use it only inside an approved laboratory or commissioning workflow.

-
- - - - - diff --git a/landing/partials/download-cta.html b/landing/partials/download-cta.html new file mode 100644 index 000000000..3f978252d --- /dev/null +++ b/landing/partials/download-cta.html @@ -0,0 +1,12 @@ +
+
+
+
+ Start with the product +

Download ARSAS {{ARSAS_VERSION}} for Windows.

+

Use the official installer for normal workstations, choose the portable ZIP for controlled test laptops, and verify the package with published SHA-256 checksums.

+
+ +
+
+
diff --git a/landing/partials/footer.html b/landing/partials/footer.html new file mode 100644 index 000000000..3fe3de6fc --- /dev/null +++ b/landing/partials/footer.html @@ -0,0 +1,20 @@ + + diff --git a/landing/partials/header.html b/landing/partials/header.html new file mode 100644 index 000000000..f275097fe --- /dev/null +++ b/landing/partials/header.html @@ -0,0 +1,22 @@ + + diff --git a/landing/roadmap.html b/landing/roadmap.html deleted file mode 100644 index 39c9b7c54..000000000 --- a/landing/roadmap.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - ARSAS Roadmap — Complete IEC 61850 Engineering Suite - - - - - - - - - - -
-
Transparent product direction

From a capable workstation to a complete IEC 61850 engineering suite.

ARSAS already delivers practical MMS, Smart Reporting, GOOSE, file-transfer, SCL-assisted, diagnostic, and control workflows. The roadmap shows how these foundations will grow into production-grade Sampled Values, full SCL authoring, and reusable test evidence.

-
AvailableImplemented and documented on mainline
PreviewUsable for controlled engineering evaluation
PlannedAccepted direction without a promised date
ResearchFeasibility and architecture under evaluation
-
Current foundation

Strong building blocks already in place.

The future suite extends the existing per-IED runtime and reusable ARIEC61850 engine rather than starting as a disconnected rewrite.

Available

MMS and Smart Reporting

Independent associations, live discovery, BRCB/URCB, dynamic gap recovery, bounded polling, quality, timestamps, SOE, and diagnostics.

Available

GOOSE engineering

Read-only capture, stream supervision, ordered payloads, SCL/live binding, and visible mismatch evidence.

Available

File transfer

MMS file-service probing, browsing, bounded download, and a focused fault-record workflow.

Available

Control validation

Live control-model discovery, typed Direct/SBO sequences, termination, errors, timing, and feedback.

Available

SCL-assisted workflow

Common SCL input, endpoint extraction, configured context, comparison foundations, and export services.

Preview

Sampled Values

Per-IED SMV entry points and viewer workflow ready for deeper decoding, binding, supervision, and performance validation.

-
Milestone 1

Complete fault-record file transfer.

Make IEC 61850 file services dependable across different directory layouts and disturbance-record conventions without vendor assumptions in the application layer.

01

Browse safely

Recursive but bounded navigation, capability discovery, timeout, cancellation, and transparent negative responses.

02

Recognize record sets

Group .cfg, .dat, .hdr, .inf, and approved companion files.

03

Preserve transfer evidence

Progress, retry boundaries, naming, duplicate handling, service results, and sanitized diagnostics.

-
Milestone 2

Production-grade Sampled Values

Develop the SMV viewer into an efficient process-bus engineering tool with stream identity, SCL binding, sample-rate and synchronization evidence, scaling, quality, loss, duplication, sequence, and timing diagnostics.

  • IEC 61850-9-2 / IEC 61869-9 boundaries
  • APPID, VLAN, SVID, smpCnt, confRev, smpSynch
  • Channel names, units, scaling, and phase grouping
  • Rolling visualization without per-sample UI allocation
Definition of done

Observable, bound, and responsive

Representative streams can be decoded, associated with engineering context, supervised, and visualized for sustained periods without degrading the rest of the workstation.

-
Milestone 3

Full visual SCL generation.

Move beyond viewing and bounded export toward validated project authoring that preserves references and avoids hidden data loss.

Project structure

Create and edit IED, AccessPoint, Server, Logical Device, and communication structures.

DataSet authoring

Build ordered members with reference, functional-constraint, and compatibility validation.

Control blocks

Generate report, GOOSE, and Sampled Values control blocks with explicit parameters.

Communication

Validate IP, APPID, MAC, VLAN, priority, redundancy, and cross references.

Edition-aware export

Import, normalize, modify, validate, export, reopen, and compare without silent loss.

Configured versus live

Compare intended project structures against the model and services exposed by the IED.

-
Milestone 4

Unified test and evidence workspace

Connect monitoring, reports, GOOSE, SMV, files, and control into reusable FAT, SAT, commissioning, and regression test plans.

  • Reusable test steps and expected outcomes
  • Pass/fail with engineer review
  • Protocol and process evidence correlation
  • Sanitized HTML, PDF, and CSV packages
Milestone 5

Interoperability and maintainability

Protect quality through deterministic fixtures, capability matrices, compatibility gates, performance budgets, versioned projects, signed releases, checksums, and SBOMs.

-
Open engineering

Contribute evidence, not confidential material.

High-value contributions include reproducible tests, independently authored fixtures with provenance, bounded failure behavior, performance measurements, and clear documentation.

-
- - - - diff --git a/landing/site.json b/landing/site.json index 98b32f0c5..e7f1ec44f 100644 --- a/landing/site.json +++ b/landing/site.json @@ -16,5 +16,16 @@ "installer": "https://github.com/masarray/arsas/releases/latest/download/ARSAS-Windows-x64-Setup.exe", "portable": "https://github.com/masarray/arsas/releases/latest/download/ARSAS-Windows-x64-Portable.zip", "checksums": "https://github.com/masarray/arsas/releases/latest/download/ARSAS-Windows-x64-SHA256SUMS.txt" - } + }, + "pages": [ + {"path": "", "template": "index.html", "changefreq": "weekly", "priority": "1.0", "lastmod": "2026-07-20"}, + {"path": "download.html", "template": "download.html", "changefreq": "weekly", "priority": "0.98", "lastmod": "2026-07-20"}, + {"path": "features.html", "template": "features.html", "changefreq": "monthly", "priority": "0.94", "lastmod": "2026-07-20"}, + {"path": "smart-reporting.html", "template": "smart-reporting.html", "changefreq": "monthly", "priority": "0.95", "lastmod": "2026-07-20"}, + {"path": "control.html", "template": "control.html", "changefreq": "monthly", "priority": "0.90", "lastmod": "2026-07-20"}, + {"path": "architecture.html", "template": "architecture.html", "changefreq": "monthly", "priority": "0.82", "lastmod": "2026-07-20"}, + {"path": "roadmap.html", "template": "roadmap.html", "changefreq": "monthly", "priority": "0.78", "lastmod": "2026-07-20"}, + {"path": "about.html", "template": "about.html", "changefreq": "monthly", "priority": "0.76", "lastmod": "2026-07-20"}, + {"path": "404.html", "template": "404.html", "index": false, "lastmod": "2026-07-20"} + ] } diff --git a/landing/sitemap.xml b/landing/sitemap.xml deleted file mode 100644 index 152e31344..000000000 --- a/landing/sitemap.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - https://masarray.github.io/arsas/2026-07-20weekly1.0 - https://masarray.github.io/arsas/download.html2026-07-20weekly0.98 - https://masarray.github.io/arsas/features.html2026-07-20monthly0.94 - https://masarray.github.io/arsas/smart-reporting.html2026-07-20monthly0.93 - https://masarray.github.io/arsas/control.html2026-07-20monthly0.88 - https://masarray.github.io/arsas/about.html2026-07-20monthly0.84 - https://masarray.github.io/arsas/architecture.html2026-07-20monthly0.80 - https://masarray.github.io/arsas/roadmap.html2026-07-20monthly0.78 - diff --git a/landing/smart-reporting.html b/landing/smart-reporting.html deleted file mode 100644 index 4e31653e1..000000000 --- a/landing/smart-reporting.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - IEC 61850 Smart Reporting — BRCB, URCB & Polling | ARSAS - - - - - - - - - - - - - - -
-
Available now · per IED · evidence-driven

Select the signals.
ARSAS handles the acquisition path.

IEC 61850 reporting is powerful, but checking DataSets, BRCBs, URCBs, trigger options, reservations, GI, and fallback behavior can delay FAT, SAT, and commissioning. ARSAS automates that path so engineers can reach trustworthy live values without first repairing every reporting issue.

Configured BRCB and URCBDynamic recovery where permittedPolling remains available
ARSAS unified IEC 61850 live-value viewer for multiple IEDs
One live-value workspace whether each point comes from a configured report, temporary dynamic coverage, or bounded MMS polling.
- -
Automatic acquisition path

Reporting is optimized per selected point—not treated as an all-or-nothing prerequisite.

ARSAS begins with live MMS values, proves report coverage, repairs exact gaps where allowed, and keeps fallback only where it is still required.

01
Immediate MMS image

Selected values begin reading while report setup is validated.

02
Configured reports first

Discover and validate exact DataSet membership for BRCBs and URCBs.

03
Dynamic gap recovery

Use an association-scoped temporary DataSet with a suitable available RCB where permitted.

04
Bounded polling fallback

Poll only uncovered, rejected, unverified, or degraded points.

No report dead end.Empty DataSet, no usable RCB, rejected write, or missing report change does not block the live-value workflow.Explore all capabilities →
- -
Failure-aware by design

The application does not trust a report merely because an RCB exists.

Coverage must be usable or observed. ARSAS retains MMS verification and can return a point to faster polling when report traffic misses an actual change.

Configured

Usable static BRCB or URCB

Use event-driven reporting while preserving member order, reasons, sequence information, quality, and IED timestamps.

Incomplete

Partial or empty coverage

Attempt dynamic recovery for the exact uncovered selected points when the IED and approved workflow permit writes.

Unavailable

No usable RCB or write permission

Continue with bounded MMS polling rather than forcing the engineer into a separate configuration tool.

Degraded

A real change is missed

Verification records the mismatch and restores polling until event delivery is proven again.

- -
What ARSAS automates

Protocol acquisition work

  • DataSet and RCB discovery
  • Buffered and unbuffered candidate selection
  • Exact member-order and coverage validation
  • GI and report-session setup
  • Dynamic recovery planning
  • Polling scheduling and degraded-report fallback
What remains with the engineer

Engineering authority and scope

  • Select the signals required for the test
  • Approve the IED and network boundary
  • Permit or disable temporary writes
  • Interpret process and diagnostic evidence
  • Follow FAT, SAT, commissioning, and switching procedures
- -
Common questions

Smart Reporting without hidden assumptions.

What happens when a DataSet is empty or no usable RCB is available?

ARSAS keeps the selected points in bounded MMS polling, so the live-value workflow continues instead of being blocked by report configuration.

Does ARSAS support both BRCB and URCB monitoring?

Yes. It discovers configured buffered and unbuffered Report Control Blocks and validates actual DataSet membership before treating a selected point as report-covered.

Does Smart Reporting always modify the IED?

No. Existing static reports are preferred. A temporary DataSet and required writes to a suitable available RCB are attempted only when enabled, supported, and permitted. Otherwise polling remains available.

- -
Engineering boundary

Automatic does not mean uncontrolled.

The engineer selects the required signals. Existing static reporting is preferred. Temporary changes are association-scoped, rejection remains visible, cleanup is attempted where permitted, and polling remains the non-blocking fallback.

-
- - - - - diff --git a/landing/templates/404.html b/landing/templates/404.html new file mode 100644 index 000000000..0451c861b --- /dev/null +++ b/landing/templates/404.html @@ -0,0 +1,39 @@ + + + + + + Page Not Found | ARSAS + + + + + + + + + + + + + + + + + + + + + + + + + + + {{> header}} +
+
404 · Page not found

The requested ARSAS page is not available.

The address may have changed as the product website grows. Continue from the overview, explore current IEC 61850 capabilities or open the official download center.

+
+ {{> footer}} + + diff --git a/landing/templates/about.html b/landing/templates/about.html new file mode 100644 index 000000000..6379a8b0a --- /dev/null +++ b/landing/templates/about.html @@ -0,0 +1,60 @@ + + + + + + About ARSAS and Ari Sulistiono — IEC 61850 Engineering + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{> header}} +
+
Engineering purpose · open source · practical evidence

Built to make practical IEC 61850 work clearer and faster.

ARSAS is an independent open-source Windows engineering workstation created to reduce repetitive setup during IEC 61850 laboratory work, FAT, SAT, commissioning, troubleshooting and multi-vendor integration.

+ +
Why ARSAS exists

Useful testing should begin from the evidence available in the IED.

IEC 61850 workflows can lose significant time before the first useful value appears: preparing engineering files, inspecting DataSets, finding usable Report Control Blocks, mapping signals across tools and diagnosing why communication works while reporting remains silent.

ARSAS brings live MMS discovery, reporting visibility, GOOSE supervision, file transfer, SCL context, control evidence and diagnostics into one focused workspace.

Project principle

Complement engineering tools—not hide engineering reality.

ARSAS does not claim universal interoperability, conformance certification, switching authority or replacement of approved vendor engineering systems. It is designed to expose live behavior, preserve negative evidence and help engineers make better-informed decisions.

Capability status, preview scope, limitations and safety boundaries remain explicit throughout the product website.

+ +
Author and maintainer

{{AUTHOR_NAME}}

Ari Sulistiono is a substation automation engineer focused on protection and control, IEC 61850 communication, testing, commissioning, troubleshooting and practical engineering productivity.

ARSAS turns recurring field and integration problems into a reusable public engineering tool while keeping customer, employer, credential, relay-setting and substation data outside the repository.

Open-source transparency

The website is the product front door. GitHub is the development workspace.

Most users can learn, download and use ARSAS entirely through this website. Developers, contributors and technical reviewers can inspect the source, architecture, license and issue history when deeper detail is needed.

+ +
Engineering commitments

Useful, transparent and bounded.

Professional open-source engineering requires more than feature claims. ARSAS keeps current scope, uncertainty and safety responsibilities visible.

Real application evidence

Product pages use current application screenshots and working workflows instead of conceptual marketing mockups.

Explicit maturity labels

Available, preview, planned and research work are kept separate to avoid overstating readiness.

Negative outcomes remain visible

Association failures, unsupported services, report gaps, file errors and negative command completion are engineering evidence.

User-first distribution

The official website provides installer, portable ZIP, checksums and product guidance without requiring repository navigation.

Source transparency

The public repository remains available for developers, contributors and technical audit.

Data discipline

Customer, credential, relay-setting and substation data must not be used as public examples or committed to the project.

+ + {{> download-cta}} +
+ {{> footer}} + + diff --git a/landing/templates/architecture.html b/landing/templates/architecture.html new file mode 100644 index 000000000..574880397 --- /dev/null +++ b/landing/templates/architecture.html @@ -0,0 +1,95 @@ + + + + + + ARSAS Architecture — IEC 61850 Application and Engine + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{> header}} +
+
Application boundary · protocol engine · independent IED ownership

Independent device sessions above a reusable IEC 61850 engine.

ARSAS keeps the engineer-facing Windows workflow separate from protocol implementation. Every IED owns an independent runtime session while ARIEC61850 provides typed services for transport, MMS, reporting, GOOSE, Sampled Values, files, SCL, control and protocol diagnostics.

+ +
System boundary
┌──────────────────────────────────────────────────────────────┐
+│                            ARSAS                             │
+│ Explorer · Monitor · SOE · GOOSE · Files · SCL · Control   │
+│ Diagnostics · Project state · Engineer-facing evidence       │
+└──────────────────────────────┬───────────────────────────────┘
+                               │ typed application services
+┌──────────────────────────────▼───────────────────────────────┐
+│                         ARIEC61850                           │
+│ Transport · MMS · Reporting · GOOSE · SMV · Files · SCL    │
+│ Control · Type system · Protocol diagnostics                 │
+└──────────────────────┬────────────────────┬──────────────────┘
+                       │ TCP/102            │ process bus
+                  Approved IEDs       Approved capture network
+ +
Separation of concerns

Protocol behavior remains testable outside the UI.

The application can evolve its workflow and visualization without duplicating protocol rules, while the engine can be validated with deterministic fixtures and reused by other engineering tools.

+
ARSAS

Project and workflow

Device cards, SCL context, signal selection, persistence, navigation and task orchestration.

+
ARSAS

Visualization and evidence

Live grids, events, GOOSE and SMV views, file UX, control staging and communication diagnostics.

+
ARIEC61850

Protocol services

Transport, association, MMS, reporting, GOOSE, Sampled Values, files, SCL and control.

+
ARIEC61850

Type and model handling

Live descriptors, object references, DataSets, control blocks, value decoding and validation.

+
Shared boundary

Typed contracts

Explicit capabilities and errors rather than UI assumptions leaking into protocol behavior.

+
CI

Compatibility gates

Build-time checks fail explicitly when required application or engine contracts are missing.

+
+ +
Per-device ownership

One IED, one session, one attributable lifecycle.

Connecting, monitoring, transferring files or staging control for one device must not silently alter another device.

+

Endpoint and identity

IP, port, SCL context, discovered identity, capability state and reconnect information belong to the device.

+

MMS association

Association, discovery, requests, reports, file services and cleanup remain scoped to the IED.

+

Acquisition plan

Static reports, dynamic recovery, polling points, aliases and source evidence are maintained per session.

+

Process-bus context

GOOSE and SMV actions open with the selected IED and available model context.

+

Control context

Control descriptors and command sessions stay with the live association that produced them.

+

Diagnostics and events

Connection, report, file, sequence and command evidence retains the affected IED identity.

+
+ +
Bounded runtime work

Scale without one background task per signal.

ARSAS uses per-IED loops, bounded queues, coalesced values and virtualized grids to keep large engineering workspaces responsive.

+
01

One monitoring loop per IED

Selected values share a controlled acquisition lifecycle instead of spawning unbounded tasks.

+
02

Priority polling for uncovered points

Only points that still require polling are scheduled in a bounded queue.

+
03

Latest-value coalescing

Rapid updates can be combined before the UI receives a bounded batch.

+
04

Bounded history

Events and diagnostics retain useful evidence without growing indefinitely.

+
05

Virtualized grids

Large live models remain navigable without rendering every row at once.

+
+ +
Public product route

Users do not need the source tree to use ARSAS.

The landing website provides downloads, capabilities, engineering boundaries and workflow guidance. Repository detail remains available for developers and technical reviewers.

Technical transparency

Source remains available for deeper review.

Developers can inspect the ARSAS application and reusable ARIEC61850 engine when architecture, contribution or implementation detail is required.

+ + {{> download-cta}} +
+ {{> footer}} + + diff --git a/landing/templates/control.html b/landing/templates/control.html new file mode 100644 index 000000000..8ade1d30b --- /dev/null +++ b/landing/templates/control.html @@ -0,0 +1,97 @@ + + + + + + IEC 61850 Smart Control — Direct and SBO Testing | ARSAS + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{> header}} +
+
+
+ + Control-model-aware validation · explicit guardrails +

Control the intended object through the sequence the live IED requires.

+

ARSAS does not translate a button label into a blind write. It reads the live control model, resolves the command structure, stages the supported Direct or Select-Before-Operate sequence and presents service, termination, timing, error and feedback evidence.

+ +
+
+ +
Direct + SBONormal and enhanced security control models
Live descriptorsNamed ctlVal binding from actual MMS types
Typed familiesDPC, SPC, INC/ISC, BSC and APC
Visible outcomeService, termination, error, timing and feedback
+ +
+
+
Discovery before dispatch

The command panel is the final step of model resolution.

A semantic action becomes available only when the live evidence can represent the command without positional guessing or a generic write fallback.

+
+
01

Resolve the control object

Normalize the selected reference and verify the Data Object boundary before staging an action.

+
02

Read ctlModel

Determine Direct or SBO and normal or enhanced completion handling from the live model.

+
03

Inspect command descriptors

Retrieve Oper, SBOw and optional Cancel types and locate the named ctlVal field.

+
04

Bind semantic intent

Represent Open, Close, Boolean, Raise, Lower, counter or setpoint through the discovered live type.

+
05

Execute one supported sequence

Preserve origin, ctlNum, timestamp, Test, interlock and synchrocheck values throughout the staged command.

+
06

Record completion evidence

Present service results, CommandTermination, ControlError, AddCause, elapsed time and mapped process feedback.

+
+
+
+ +
+
Supported semantic families

Readable engineering actions with type-aware wire handling.

+

Position / DPC

Open and Close actions with command encoding and process feedback treated as separate evidence.

+

Boolean / SPC

True and False actions represented through the discovered single-point command structure.

+

Pulse / BSC

Raise and Lower semantics for supported binary step command types.

+

Counter / INC or ISC

Typed integer values when the live descriptor is complete and usable.

+

Setpoint / APC

Explicit value entry and type-aware binding for supported analog control objects.

+

Per-command checks

Test, interlock and synchrocheck requests remain attached to the exact staged command.

+
+
+ +
+
+
Evidence shown

Protocol completion and process response

  • Detected control model and selected sequence
  • Confirmed MMS service result
  • Positive or negative CommandTermination
  • ControlError, AddCause and LastApplError where available
  • Control number, origin, request flags and timing
  • Mapped process feedback where available
+
Guardrails

Protocol readiness is not switching authority

  • Two-step confirmation for Open and Close
  • No generic command-write fallback
  • Commands disabled when live descriptors are incomplete
  • Negative outcomes remain visible
  • Isolation, authorization and independent verification remain external requirements
+
+
+ +
Validation first

Exercise every supported control model before energized commissioning.

Validate positive and negative termination, interlock and synchrocheck rejection, Test mode, timeout, Cancel behavior, association loss, competing-client ownership and process feedback in an approved environment.

+ + {{> download-cta}} +
+ {{> footer}} + + diff --git a/landing/templates/download.html b/landing/templates/download.html index 9f6d7e034..dd40e09f2 100644 --- a/landing/templates/download.html +++ b/landing/templates/download.html @@ -32,41 +32,29 @@ - - - - + + {{> header}}
Official product route · stable release · Windows x64

Download ARSAS {{ARSAS_VERSION}} for Windows.

This page is the official user-facing distribution center. Download the stable installer directly, choose the portable package for controlled test laptops, or verify the release with published SHA-256 checksums—without navigating the source repository.

Latest stable channel · ARSAS {{ARSAS_VERSION}}
-
- -
Portable

Portable package

Useful for approved test laptops, temporary evaluation or controlled environments where a traditional installation is not preferred.

ARSAS-Windows-x64-Portable.zip · latest stable release
Download portable ZIP
-
+
Portable

Portable package

Useful for approved test laptops, temporary evaluation or controlled environments where a traditional installation is not preferred.

ARSAS-Windows-x64-Portable.zip · latest stable release
Download portable ZIP
-
-
Release integrity

Verify the package

Download the published checksum file and retain it with the package when preparing laboratory, FAT, SAT or commissioning work.

-
System scope

Prepared for Windows engineering workstations

  • Windows 10 or Windows 11, x64
  • Self-contained application package
  • Npcap required for raw-Ethernet GOOSE and Sampled Values workflows
  • Approved laboratory or commissioning network
-
+
Release integrity

Verify the package

Download the published checksum file and retain it with the package when preparing laboratory, FAT, SAT or commissioning work.

System scope

Prepared for Windows engineering workstations

  • Windows 10 or Windows 11, x64
  • Self-contained application package
  • Npcap required for raw-Ethernet GOOSE and Sampled Values workflows
  • Approved laboratory or commissioning network
Before active use

Download readiness is not switching authority.

Confirm the package integrity, network interface, IED scope, access permissions, test procedure and independent verification before using control, report configuration, file access or other active functions.

FreeNo account, subscription or license key
TransparentPublic source, maturity labels and known boundaries
VerifiablePublished checksums and stable release evidence
PracticalInstaller and portable routes for engineering use
Need context first?

Review the real application and current capability scope.

See live MMS discovery, Smart Reporting, GOOSE, fault-record transfer, selected-RCB SCL export, diagnostics and guarded control before installation.

- - - + {{> footer}} diff --git a/landing/templates/features.html b/landing/templates/features.html new file mode 100644 index 000000000..b0e3759d9 --- /dev/null +++ b/landing/templates/features.html @@ -0,0 +1,89 @@ + + + + + + IEC 61850 Software Capabilities — MMS, GOOSE, SCL | ARSAS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{> header}} +
+
+
+ + Current product scope · explicit maturity · real evidence +

IEC 61850 capabilities organized around real testing work.

+

ARSAS connects the live server model, configured SCL context, report behavior, process-bus traffic, fault records, control outcomes and diagnostics to the same IED session. Available, preview and roadmap work remain clearly separated.

+ +
+
+ +
AvailableMMS, reporting, GOOSE, files, SCL-assisted workflows, SOE and control
Multi-IEDIndependent association, monitoring, diagnostics and project state per device
PreviewSampled Values engineering and viewer workflow
BoundaryNo universal interoperability, conformance or switching-authority claim
+ +
+
+
Available now

From endpoint to attributable evidence.

The current application covers the highest-friction parts of practical IEC 61850 investigation, integration and validation.

+
+
MMS

Live model discovery

Discover Logical Devices, Logical Nodes, Data Objects, Data Attributes, values, quality, timestamps, DataSets, RCBs, control objects and live MMS type descriptors.

  • Connect directly by approved IP address
  • Independent association per IED
  • Searchable large-model workspace
  • Configured and live context together
+
Smart Reporting

Report-first acquisition with fallback

Prefer existing BRCB or URCB coverage, validate exact DataSet membership, recover specific gaps where permitted and keep unresolved points in bounded polling.

  • Buffered and unbuffered reports
  • Reservation and ownership visibility
  • Dynamic DataSet recovery when allowed
  • Visible degraded-state fallback
+
GOOSE

Read-only stream inspection

Capture station or process-bus GOOSE through Npcap and retain stream identity, sequence, retransmission, TAL and ordered payload evidence.

  • APPID, VLAN, destination MAC and goCBRef
  • stNum, sqNum, Test and ndsCom
  • Ordered allData leaves
  • SCL or live-model binding
+
Files

Fault-record retrieval

Probe the MMS file service, browse available directories and download disturbance or COMTRADE-related records in the selected IED context.

  • Bounded navigation and transfer
  • Per-IED endpoint ownership
  • Progress and negative-result visibility
  • Record-set grouping foundation
+
SCL

Configured-to-live integration

Open common SCL files, extract endpoints, compare configured intent with observed server behavior and export controlled integration baselines.

  • SCD, CID, ICD, IID, SSD and XML input
  • Edition-aware export services
  • Selected-RCB Edition 1 or 2 export
  • Verified DataSet member retention
+
Control

Typed Direct and SBO validation

Read ctlModel, resolve live command descriptors, execute supported sequences and show service, termination, timing, error and feedback evidence.

  • DPC, SPC, INC/ISC, BSC and APC
  • Direct and Select-Before-Operate
  • CommandTermination and AddCause
  • No generic blind-write fallback
+
Operations

Live values, SOE and diagnostics

Separate continuous values from semantic events while preserving IED timestamps, quality, report reasons, acquisition source and originating-device context.

  • Recent-change highlighting
  • Process timestamp semantics
  • Bounded event collections
  • Association, report and frame diagnostics
+
Scale

Independent multi-IED sessions

Every IED owns its connection, discovery, selected signals, report state, events, control context, file workflow and diagnostics.

  • Isolated lifecycle per device
  • One monitor loop per IED
  • Coalesced UI updates
  • Virtualized engineering grids
+
Productivity

Reusable project state

Save endpoints, cached model context, selected signals and workspace state so recurring projects do not restart from zero.

  • Fast reconnect workflow
  • Retained device definitions
  • Persisted selections
  • Reusable diagnostic context
+
+
+
+ +
+
+
Integration evidence

Selected-RCB SCL export

Inspect read-only RCB availability, choose the reporting path intended for a legacy SAS or gateway, retain verified DataSet members and export a normalized Edition 1 or Edition 2 baseline.

+
Engineering preview

Sampled Values

Per-IED SMV entry points and a viewer workflow are available for controlled evaluation. Production maturity still requires deeper decoding, SCL binding, scaling, quality supervision and sustained-performance validation.

+
+
+ + {{> download-cta}} +
+ {{> footer}} + + diff --git a/landing/templates/index.html b/landing/templates/index.html index 3d134cecd..5d3eec5fb 100644 --- a/landing/templates/index.html +++ b/landing/templates/index.html @@ -35,64 +35,15 @@ { "@context": "https://schema.org", "@graph": [ - { - "@type": "WebSite", - "@id": "{{CANONICAL_ROOT}}#website", - "url": "{{CANONICAL_ROOT}}", - "name": "ARSAS", - "description": "Practical IEC 61850 testing, commissioning and troubleshooting software." - }, - { - "@type": "SoftwareApplication", - "@id": "{{CANONICAL_ROOT}}#software", - "name": "ARSAS", - "alternateName": "ARSAS IEC 61850 Engineering Workstation", - "applicationCategory": "DeveloperApplication", - "applicationSubCategory": "Substation automation engineering software", - "operatingSystem": "Windows 10, Windows 11", - "softwareVersion": "{{ARSAS_VERSION}}", - "description": "Open-source Windows IEC 61850 workstation for live MMS discovery, Smart Reporting, multi-IED monitoring, GOOSE, fault-record file transfer, SCL workflows, diagnostics, SOE and guarded control.", - "url": "{{CANONICAL_ROOT}}", - "downloadUrl": "{{INSTALLER_URL}}", - "codeRepository": "{{REPOSITORY_URL}}", - "license": "https://spdx.org/licenses/GPL-3.0-or-later.html", - "programmingLanguage": ["C#", "XAML"], - "runtimePlatform": ".NET 8", - "author": {"@id": "{{CANONICAL_ROOT}}about.html#ari-sulistiono"}, - "offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD", "category": "Open-source community edition"}, - "featureList": [ - "Live IEC 61850 MMS model discovery", - "BRCB and URCB reporting with visible fallback", - "Independent multi-IED monitoring", - "GOOSE subscription and diagnostics", - "IEC 61850 file transfer and COMTRADE retrieval", - "SCL-assisted engineering and selected-RCB export", - "Guarded Direct and Select-Before-Operate control" - ] - }, - { - "@type": "Person", - "@id": "{{CANONICAL_ROOT}}about.html#ari-sulistiono", - "name": "{{AUTHOR_NAME}}", - "url": "{{CANONICAL_ROOT}}about.html", - "sameAs": ["{{AUTHOR_LINKEDIN}}", "{{AUTHOR_GITHUB}}"] - } + {"@type": "WebSite", "@id": "{{CANONICAL_ROOT}}#website", "url": "{{CANONICAL_ROOT}}", "name": "ARSAS", "description": "Practical IEC 61850 testing, commissioning and troubleshooting software."}, + {"@type": "SoftwareApplication", "@id": "{{CANONICAL_ROOT}}#software", "name": "ARSAS", "alternateName": "ARSAS IEC 61850 Engineering Workstation", "applicationCategory": "DeveloperApplication", "applicationSubCategory": "Substation automation engineering software", "operatingSystem": "Windows 10, Windows 11", "softwareVersion": "{{ARSAS_VERSION}}", "description": "Open-source Windows IEC 61850 workstation for live MMS discovery, Smart Reporting, multi-IED monitoring, GOOSE, fault-record file transfer, SCL workflows, diagnostics, SOE and guarded control.", "url": "{{CANONICAL_ROOT}}", "downloadUrl": "{{INSTALLER_URL}}", "codeRepository": "{{REPOSITORY_URL}}", "license": "https://spdx.org/licenses/GPL-3.0-or-later.html", "programmingLanguage": ["C#", "XAML"], "runtimePlatform": ".NET 8", "author": {"@id": "{{CANONICAL_ROOT}}about.html#ari-sulistiono"}, "offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD", "category": "Open-source community edition"}, "featureList": ["Live IEC 61850 MMS model discovery", "BRCB and URCB reporting with visible fallback", "Independent multi-IED monitoring", "GOOSE subscription and diagnostics", "IEC 61850 file transfer and COMTRADE retrieval", "SCL-assisted engineering and selected-RCB export", "Guarded Direct and Select-Before-Operate control"]}, + {"@type": "Person", "@id": "{{CANONICAL_ROOT}}about.html#ari-sulistiono", "name": "{{AUTHOR_NAME}}", "url": "{{CANONICAL_ROOT}}about.html", "sameAs": ["{{AUTHOR_LINKEDIN}}", "{{AUTHOR_GITHUB}}"]} ] } - - - - + + {{> header}}
@@ -100,72 +51,27 @@ Free and open source · Windows · version {{ARSAS_VERSION}}

IEC 61850 testing software
built for real engineering work.

Enter an approved IED address, discover the live MMS model, select the required signals and begin validation. ARSAS brings reporting, GOOSE, fault records, SCL context, diagnostics and guarded control into one focused Windows workspace.

- +
No account or license keyDirect installer and portable ZIPPublic source and checksums
-
-
ARSAS IEC 61850 engineering workstation first-launch workspace
-
Add IED by IP address
Live model to evidence
-
+
ARSAS IEC 61850 engineering workstation first-launch workspace
Add IED by IP address
Live model to evidence
MMS + ReportingLive discovery, BRCB, URCB, dynamic recovery and polling
GOOSE + FilesStream supervision and COMTRADE-related record retrieval
SCL + IntegrationConfigured/live context and selected-RCB Edition 1/2 export
Control + EvidenceTyped Direct and SBO workflows with visible outcomes
-
-
Why engineers use ARSAS

Start useful validation before setup work consumes the test window.

FAT, SAT and commissioning often lose time to disconnected tools, uncertain engineering files, signal mapping, DataSet inspection and report-control preparation before the first useful value appears.

-
-
Fragmented workflow

Testing starts with tool configuration.

  • Find or repair the engineering file
  • Import and map signals across applications
  • Inspect DataSets and RCB ownership manually
  • Diagnose why reporting remains silent
  • Rebuild context for every IED
-
ARSAS workflow

Testing starts from the IED and available evidence.

  • Add an endpoint or open SCL
  • Discover the live server model
  • Select the signals required for the test
  • Observe value, quality, time, reason and source
  • Keep diagnostics with the originating IED
-
-
-
+
Why engineers use ARSAS

Start useful validation before setup work consumes the test window.

FAT, SAT and commissioning often lose time to disconnected tools, uncertain engineering files, signal mapping, DataSet inspection and report-control preparation before the first useful value appears.

Fragmented workflow

Testing starts with tool configuration.

  • Find or repair the engineering file
  • Import and map signals across applications
  • Inspect DataSets and RCB ownership manually
  • Diagnose why reporting remains silent
  • Rebuild context for every IED
ARSAS workflow

Testing starts from the IED and available evidence.

  • Add an endpoint or open SCL
  • Discover the live server model
  • Select the signals required for the test
  • Observe value, quality, time, reason and source
  • Keep diagnostics with the originating IED
-
-
-
Smart Reporting

Select the signals. ARSAS handles the acquisition path.

Existing BRCBs and URCBs are preferred, exact DataSet coverage is checked, specific gaps can be recovered where writes are permitted, and bounded polling remains available when reporting cannot be trusted.

-
-
01
Immediate MMS image

Selected values begin reading while report setup is evaluated.

-
02
Configured reports first

Discover and validate existing DataSets, BRCBs and URCBs.

-
03
Recover exact gaps

Use temporary coverage only when supported, enabled and permitted.

-
04
Visible fallback

Keep uncovered, rejected or unverified points in bounded polling.

-
-
No report dead end.An empty DataSet, occupied RCB or rejected write does not have to block the live-value workflow.Explore Smart Reporting →
-
-
+
Smart Reporting

Select the signals. ARSAS handles the acquisition path.

Existing BRCBs and URCBs are preferred, exact DataSet coverage is checked, specific gaps can be recovered where writes are permitted, and bounded polling remains available when reporting cannot be trusted.

01
Immediate MMS image

Selected values begin reading while report setup is evaluated.

02
Configured reports first

Discover and validate existing DataSets, BRCBs and URCBs.

03
Recover exact gaps

Use temporary coverage only when supported, enabled and permitted.

04
Visible fallback

Keep uncovered, rejected or unverified points in bounded polling.

No report dead end.An empty DataSet, occupied RCB or rejected write does not have to block the live-value workflow.Explore Smart Reporting →
-
-
-
New integration workflow

Export a cleaner SCL baseline from the live relay evidence.

Inspect available and occupied Report Control Blocks, choose the intended RCB, retain its verified DataSet members and export an Edition 1 or Edition 2 baseline for controlled multi-vendor SAS or gateway integration.

-
ARSAS selected-RCB SCL export workflow with IEC 61850 Edition 1 and Edition 2 options

NewSelected-RCB SCL export

Start from the source SCL or live model, check read-only RCB availability, select the intended reporting path and export a normalized integration baseline without blind XML deletion.

-
-
+
New integration workflow

Export a cleaner SCL baseline from the live relay evidence.

Inspect available and occupied Report Control Blocks, choose the intended RCB, retain its verified DataSet members and export an Edition 1 or Edition 2 baseline for controlled multi-vendor SAS or gateway integration.

ARSAS selected-RCB SCL export workflow with IEC 61850 Edition 1 and Edition 2 options

NewSelected-RCB SCL export

Start from the source SCL or live model, check read-only RCB availability, select the intended reporting path and export a normalized integration baseline without blind XML deletion.

-
-
Real application evidence

See the working product—not a marketing mockup.

Current Windows screenshots show independent IED sessions, unified live values, event correlation, GOOSE supervision and diagnostics.

-
-
ARSAS connected to multiple IEC 61850 IEDs

01Independent multi-IED sessions

Each device retains its own MMS association, model, monitoring state and diagnostic history.

-
ARSAS multi-IED IEC 61850 live-value workspace

02Unified live values

Search selected values with device, quality, timestamp, acquisition source and recent-change evidence.

-
ARSAS IEC 61850 GOOSE analyzer

03Detailed GOOSE supervision

Inspect stream identity, APPID, VLAN, sequence, retransmission, TAL, payload and model binding.

-
ARSAS IEC 61850 communication diagnostics

04Attributable diagnostics

Separate association, service, report, sequence, frame and IED-behavior problems.

-
-
+
Real application evidence

See the working product—not a marketing mockup.

Current Windows screenshots show independent IED sessions, unified live values, event correlation, GOOSE supervision and diagnostics.

ARSAS connected to multiple IEC 61850 IEDs

01Independent multi-IED sessions

Each device retains its own MMS association, model, monitoring state and diagnostic history.

ARSAS multi-IED IEC 61850 live-value workspace

02Unified live values

Search selected values with device, quality, timestamp, acquisition source and recent-change evidence.

ARSAS IEC 61850 GOOSE analyzer

03Detailed GOOSE supervision

Inspect stream identity, APPID, VLAN, sequence, retransmission, TAL, payload and model binding.

ARSAS IEC 61850 communication diagnostics

04Attributable diagnostics

Separate association, service, report, sequence, frame and IED-behavior problems.

-
-
-
Official product route

Learn, download and use ARSAS without navigating source code.

The product website provides the stable installer, portable package, checksums, screenshots, capabilities and engineering boundaries. GitHub remains available for developers, contributors and technical review.

-
Author and maintainer

{{AUTHOR_NAME}}

ARSAS is created and maintained by Ari Sulistiono, a substation automation engineer focused on IEC 61850 communication, protection and control, FAT, SAT, commissioning and practical engineering productivity.

-
-
+
Official product route

Learn, download and use ARSAS without navigating source code.

The product website provides the stable installer, portable package, checksums, screenshots, capabilities and engineering boundaries. GitHub remains available for developers, contributors and technical review.

Author and maintainer

{{AUTHOR_NAME}}

ARSAS is created and maintained by Ari Sulistiono, a substation automation engineer focused on IEC 61850 communication, protection and control, FAT, SAT, commissioning and practical engineering productivity.

Start testing

Move from an approved endpoint to useful IEC 61850 evidence.

Download the stable Windows build, review the current maturity labels and use active features only inside an approved laboratory or commissioning boundary.

- - - + {{> footer}} diff --git a/landing/templates/roadmap.html b/landing/templates/roadmap.html new file mode 100644 index 000000000..744b40515 --- /dev/null +++ b/landing/templates/roadmap.html @@ -0,0 +1,74 @@ + + + + + + ARSAS Roadmap — IEC 61850 Engineering Software Direction + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{> header}} +
+
Transparent maturity · no promised dates · evidence before claims

Grow one capable workstation into a broader IEC 61850 engineering platform.

ARSAS already provides practical MMS, Smart Reporting, GOOSE, file-transfer, SCL-assisted, diagnostic and control workflows. The roadmap shows how those foundations can expand while preserving explicit maturity labels and testable engineering boundaries.

+ +
AvailableImplemented, documented and included in the stable product route
PreviewUsable for controlled engineering evaluation with known limitations
PlannedAccepted product direction without a promised delivery date
ResearchFeasibility and architecture still being evaluated
+ +
Current foundation

Strong building blocks are already available.

Future work extends the existing per-IED runtime and reusable engine instead of creating disconnected utilities.

+
Available

MMS and Smart Reporting

Independent associations, live discovery, BRCB/URCB, specific gap recovery, bounded polling, quality, timestamps, SOE and diagnostics.

+
Available

GOOSE engineering

Read-only capture, stream supervision, ordered payloads, SCL/live binding and visible mismatch evidence.

+
Available

File transfer

MMS file-service probing, browsing, bounded download and a focused fault-record workflow.

+
Available

Control validation

Live control-model discovery, typed Direct/SBO sequences, termination, errors, timing and feedback.

+
Available

SCL-assisted integration

Common SCL input, endpoint extraction, configured context, comparison foundations and selected-RCB export services.

+
Preview

Sampled Values

Per-IED SMV entry points and viewer workflow ready for deeper decoding, binding, supervision and performance validation.

+
+ +
Priority sequence

Finish dependable workflows before expanding breadth.

Roadmap order follows engineering value, failure visibility and reusable engine capability rather than feature-count marketing.

+
01

Deepen fault-record workflows

Improve directory compatibility, record-set recognition, transfer evidence and controlled export.

+
02

Strengthen SCL comparison and export

Expand configured-to-live comparison, validation and integration-oriented output without silent XML assumptions.

+
03

Complete production-grade SMV engineering

Add deeper stream decoding, SCL binding, scaling, quality supervision and sustained-performance validation.

+
04

Build visual SCL authoring

Create validated authoring for IED, communication, DataSet, reporting, GOOSE, SMV and edition-aware export structures.

+
05

Preserve reusable test evidence

Make project state, selected signals, outcomes and diagnostics easier to compare and reuse across recurring work.

+
+ +
Not a promise calendar

Maturity labels are stronger than speculative dates.

Features move from research to preview and available only when their failure semantics, performance and engineering boundaries are sufficiently understood.

Current users first

The stable product remains the priority.

Roadmap work must not make current MMS, reporting, GOOSE, file, SCL, diagnostic or control workflows less dependable or harder to use.

+ + {{> download-cta}} +
+ {{> footer}} + + diff --git a/landing/templates/smart-reporting.html b/landing/templates/smart-reporting.html new file mode 100644 index 000000000..46060ace0 --- /dev/null +++ b/landing/templates/smart-reporting.html @@ -0,0 +1,104 @@ + + + + + + IEC 61850 Smart Reporting — BRCB, URCB and Fallback | ARSAS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{> header}} +
+
+
+ + BRCB · URCB · DataSet coverage · visible fallback +

Select the signals. ARSAS builds a defensible acquisition path.

+

Smart Reporting is not a promise that every selected value will arrive through a report. It is a failure-aware workflow that starts useful MMS reads, evaluates configured reports, proves exact coverage, recovers specific gaps when permitted and retains polling for anything still uncovered or unverified.

+ +
+
+ +
ImmediateSelected MMS values begin while reporting is evaluated
Configured firstExisting DataSets, BRCBs and URCBs are preferred
Exact coverageMembers and order are validated instead of assumed
Fallback retainedUncovered or degraded points remain in bounded polling
+ +
+
+
Per-IED acquisition plan

Static reports first. Specific recovery for gaps. Polling when required.

Every step remains attached to the IED association that produced the evidence, so reporting decisions from one device cannot silently change another.

+
+
01
Start selected MMS reads

Show initial values, quality and timestamps while report objects are inspected.

+
02
Discover configured reporting

Read available DataSets, BRCBs, URCBs, references, reservation state and relevant options.

+
03
Validate exact coverage

Compare selected signals with actual DataSet membership and order rather than relying on names alone.

+
04
Recover specific gaps

Use temporary DataSet coverage with a suitable available RCB only when the IED and approved procedure permit writes.

+
05
Retain visible fallback

Keep rejected, uncovered, unverified or degraded points in a bounded polling schedule.

+
+
No report dead end.An empty DataSet, occupied RCB, rejected write or silent stream does not have to block the live-value workspace.View the complete capability scope →
+
+
+ +
+
+
Problems the workflow makes visible

Communication success does not prove reporting success.

ARSAS keeps negative evidence visible so the engineer can distinguish association, configuration, ownership, trigger and delivery problems.

+
+

Empty or incomplete DataSet

An RCB can exist while its referenced DataSet is empty, incomplete or different from the signals required for the test.

+

RCB already reserved

An unbuffered or buffered report may be owned by another client, reserved by configuration or unavailable for the current association.

+

Configured coverage mismatch

A promising DataSet name is not proof that every selected signal is present in the required order.

+

GI without spontaneous updates

A successful general interrogation can return an initial image while change-triggered reports remain absent or incomplete.

+

Rejected dynamic recovery

The IED may reject DataSet or RCB writes because of capability, access control, configuration or active ownership.

+

Degraded report stream

Missed changes, association loss or invalid delivery evidence can return affected points to bounded polling.

+
+
+
+ +
+
+
Evidence retained

Every update keeps its origin.

  • IED and association context
  • Value and quality
  • IED or process timestamp
  • Report reason where available
  • Report, polling or other acquisition source
  • Coverage and degradation diagnostics
+
Engineering boundary

Automation does not remove approval requirements.

  • Configured reports are preferred before writes are considered
  • Dynamic recovery is conditional and explicit
  • Polling remains a valid fallback, not a hidden failure
  • IED access, project procedure and test authority remain external requirements
  • No universal reporting interoperability claim is made
+
+
+ +
+
Real application evidence

Live values remain attributable across multiple IEDs.

The same workspace shows selected values, quality, timestamps, source and recent-change evidence while each IED retains an independent acquisition lifecycle.

ARSAS IEC 61850 live-value workspace with multi-IED reporting evidence

EvidenceUnified live-value workspace

Selected signals from independent IED sessions retain device, value, quality, time and acquisition context.

+
+ + {{> download-cta}} +
+ {{> footer}} + + diff --git a/scripts/build-product-site.py b/scripts/build-product-site.py index 0d8a1933c..1cb52c701 100644 --- a/scripts/build-product-site.py +++ b/scripts/build-product-site.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Build the ARSAS product website from explicit templates and product data.""" +"""Build the ARSAS product website from explicit templates, partials and product data.""" from __future__ import annotations @@ -9,22 +9,18 @@ import shutil import xml.etree.ElementTree as ET from pathlib import Path +from xml.sax.saxutils import escape ROOT = Path(__file__).resolve().parents[1] SOURCE = ROOT / "landing" TEMPLATES = SOURCE / "templates" +PARTIALS = SOURCE / "partials" CONFIG_PATH = SOURCE / "site.json" PROJECT_PATH = ROOT / "ArIED61850Tester.csproj" APP_ICON_SOURCE = ROOT / "Assets" / "app-icon-256.png" - -REMOTE_SCREENSHOTS = { - "https://raw.githubusercontent.com/masarray/arsas/main/Assets/screenshot/arsas%20%281%29.webp": "assets/screenshots/arsas-first-launch.webp", - "https://raw.githubusercontent.com/masarray/arsas/main/Assets/screenshot/arsas%20%282%29.webp": "assets/screenshots/arsas-multi-ied.webp", - "https://raw.githubusercontent.com/masarray/arsas/main/Assets/screenshot/arsas%20%283%29.webp": "assets/screenshots/arsas-live-values.webp", - "https://raw.githubusercontent.com/masarray/arsas/main/Assets/screenshot/arsas%20%284%29.webp": "assets/screenshots/arsas-event-log.webp", - "https://raw.githubusercontent.com/masarray/arsas/main/Assets/screenshot/arsas%20%285%29.webp": "assets/screenshots/arsas-goose.webp", - "https://raw.githubusercontent.com/masarray/arsas/main/Assets/screenshot/arsas%20%286%29.webp": "assets/screenshots/arsas-diagnostics.webp", -} +INCLUDE_PATTERN = re.compile(r"\{\{>\s*([a-z0-9-]+)\s*\}\}", re.IGNORECASE) +TOKEN_PATTERN = re.compile(r"\{\{([A-Z0-9_]+)\}\}") +VERIFICATION_FILE_PATTERN = re.compile(r"google[a-z0-9]+\.html", re.IGNORECASE) def read_version() -> str: @@ -48,6 +44,7 @@ def read_config() -> dict[str, object]: "product.name", "product.canonicalRoot", "product.repository", + "product.engineRepository", "author.name", "author.linkedin", "author.github", @@ -63,6 +60,10 @@ def read_config() -> dict[str, object]: value = value[key] if not isinstance(value, str) or not value.strip(): raise SystemExit(f"landing/site.json has invalid {dotted}") + + pages = config.get("pages") + if not isinstance(pages, list) or not pages: + raise SystemExit("landing/site.json must define a non-empty pages registry") return config @@ -85,44 +86,62 @@ def token_values(config: dict[str, object], version: str) -> dict[str, str]: } +def expand_partials(text: str, stack: tuple[str, ...] = ()) -> str: + def replace(match: re.Match[str]) -> str: + name = match.group(1).lower() + if name in stack: + raise SystemExit("Circular landing partial include: " + " -> ".join((*stack, name))) + path = PARTIALS / f"{name}.html" + if not path.exists(): + raise SystemExit(f"Missing landing partial: {path.relative_to(ROOT)}") + return expand_partials(path.read_text(encoding="utf-8"), (*stack, name)) + + previous = None + while previous != text: + previous = text + text = INCLUDE_PATTERN.sub(replace, text) + return text + + def render(text: str, values: dict[str, str]) -> str: + text = expand_partials(text) for key, value in values.items(): text = text.replace("{{" + key + "}}", value) - unresolved = sorted(set(re.findall(r"\{\{([A-Z0-9_]+)\}\}", text))) + unresolved = sorted(set(TOKEN_PATTERN.findall(text))) if unresolved: raise SystemExit("Unresolved landing template tokens: " + ", ".join(unresolved)) + if INCLUDE_PATTERN.search(text): + raise SystemExit("Unresolved landing partial include remains") return text -def normalize_legacy_page(text: str, version: str) -> str: - """Only normalize assets and version on pages not migrated to templates yet.""" - for remote, local in REMOTE_SCREENSHOTS.items(): - text = text.replace(remote, local) - text = text.replace( - "https://masarray.github.io/arsas/assets/social-card.svg", - "https://masarray.github.io/arsas/assets/social-card.png", - ) - text = text.replace( - '', - "", - ) - text = re.sub( - r'', - '', - text, - flags=re.IGNORECASE, - ) - text = re.sub( - r'', - '\n ', - text, - flags=re.IGNORECASE, - ) - return re.sub( - r'("softwareVersion"\s*:\s*")\d+\.\d+\.\d+(\")', - rf"\g<1>{version}\g<2>", - text, - ) +def page_registry(config: dict[str, object]) -> list[dict[str, object]]: + pages = config.get("pages") + if not isinstance(pages, list): + raise SystemExit("landing/site.json pages registry is invalid") + + normalized: list[dict[str, object]] = [] + paths: set[str] = set() + templates: set[str] = set() + for entry in pages: + if not isinstance(entry, dict): + raise SystemExit("Every landing page registry entry must be an object") + path = entry.get("path") + template = entry.get("template") + if not isinstance(path, str) or not isinstance(template, str): + raise SystemExit("Every landing page registry entry needs string path and template") + if path in paths or template in templates: + raise SystemExit(f"Duplicate landing page registry entry: {path or template}") + if path not in ("", "404.html") and not path.endswith(".html"): + raise SystemExit(f"Invalid landing page path: {path}") + if not template.endswith(".html"): + raise SystemExit(f"Invalid landing template name: {template}") + if not (TEMPLATES / template).exists(): + raise SystemExit(f"Registered landing template is missing: {template}") + paths.add(path) + templates.add(template) + normalized.append(entry) + return normalized def install_icon(output: Path) -> None: @@ -146,14 +165,35 @@ def install_icon(output: Path) -> None: ) -def write_build_info(output: Path, config: dict[str, object], version: str) -> None: +def write_sitemap(output: Path, config: dict[str, object], pages: list[dict[str, object]]) -> None: + root = str(config["product"]["canonicalRoot"]) + lines = ['', ''] + for entry in pages: + if entry.get("index", True) is False: + continue + path = str(entry["path"]) + loc = root if path == "" else root + path + lines.extend([ + " ", + f" {escape(loc)}", + f" {escape(str(entry.get('lastmod', '2026-07-20')))}", + f" {escape(str(entry.get('changefreq', 'monthly')))}", + f" {escape(str(entry.get('priority', '0.7')))}", + " ", + ]) + lines.append("") + (output / "sitemap.xml").write_text("\n".join(lines) + "\n", encoding="utf-8") + + +def write_build_info(output: Path, config: dict[str, object], version: str, pages: list[dict[str, object]]) -> None: payload = { - "schemaVersion": 1, + "schemaVersion": 2, "product": config["product"]["name"], "version": version, "canonicalRoot": config["product"]["canonicalRoot"], "repository": config["product"]["repository"], "author": config["author"], + "pages": [entry["path"] or "index.html" for entry in pages], } (output / "build-info.json").write_text( json.dumps(payload, indent=2, ensure_ascii=False) + "\n", @@ -161,57 +201,77 @@ def write_build_info(output: Path, config: dict[str, object], version: str) -> N ) +def legacy_html_names() -> list[str]: + return sorted( + path.name + for path in SOURCE.glob("*.html") + if not VERIFICATION_FILE_PATTERN.fullmatch(path.name) + ) + + def build(output: Path) -> None: version = read_version() config = read_config() values = token_values(config, version) + pages = page_registry(config) if output.exists(): shutil.rmtree(output) shutil.copytree(SOURCE, output) shutil.rmtree(output / "templates", ignore_errors=True) - - migrated = {"index.html", "download.html"} - for template in TEMPLATES.glob("*.html"): - target = output / template.name - target.write_text(render(template.read_text(encoding="utf-8"), values), encoding="utf-8") - - for page in output.glob("*.html"): - if page.name in migrated: - continue - page.write_text(normalize_legacy_page(page.read_text(encoding="utf-8"), version), encoding="utf-8") + shutil.rmtree(output / "partials", ignore_errors=True) + + generated: set[str] = set() + for entry in pages: + template_name = str(entry["template"]) + target_name = "index.html" if str(entry["path"]) == "" else str(entry["path"]) + target = output / target_name + target.parent.mkdir(parents=True, exist_ok=True) + source_text = (TEMPLATES / template_name).read_text(encoding="utf-8") + target.write_text(render(source_text, values), encoding="utf-8") + generated.add(target_name) + + source_html = legacy_html_names() + if source_html: + raise SystemExit("Legacy landing HTML remains outside templates: " + ", ".join(source_html)) install_icon(output) - write_build_info(output, config, version) + write_sitemap(output, config, pages) + write_build_info(output, config, version, pages) - required = ( - "index.html", - "download.html", - "about.html", + required = { + *generated, "site.json", + "sitemap.xml", "build-info.json", "assets/app-icon.png", "assets/social-card.png", "assets/screenshots/arsas-first-launch.webp", + "assets/screenshots/arsas-multi-ied.webp", + "assets/screenshots/arsas-live-values.webp", + "assets/screenshots/arsas-event-log.webp", + "assets/screenshots/arsas-goose.webp", + "assets/screenshots/arsas-diagnostics.webp", "assets/screenshots/arsas-rcb-scl-export.webp", - ) - missing = [item for item in required if not (output / item).exists()] + } + missing = sorted(item for item in required if not (output / item).exists()) if missing: raise SystemExit("Missing product-site output: " + ", ".join(missing)) - combined = "\n".join(page.read_text(encoding="utf-8") for page in output.glob("*.html")) + combined = "\n".join((output / page).read_text(encoding="utf-8") for page in sorted(generated)) forbidden = ( "raw.githubusercontent.com/masarray/arsas/main/Assets/screenshot", "https://masarray.github.io/arsas/assets/social-card.svg", 'href="assets/favicon.svg"', - "{{ARSAS_", - "{{AUTHOR_", + "{{", + "github.com/masarray/arsas#quick-start", + ' int: diff --git a/scripts/validate-product-build.py b/scripts/validate-product-build.py index 111f9b8fc..c271af711 100644 --- a/scripts/validate-product-build.py +++ b/scripts/validate-product-build.py @@ -11,10 +11,6 @@ from pathlib import Path from urllib.parse import urlparse -EXPECTED_PAGES = ( - "index.html", "download.html", "about.html", "smart-reporting.html", - "features.html", "control.html", "architecture.html", "roadmap.html", "404.html", -) EXPECTED_MEDIA = ( "assets/app-icon.png", "assets/social-card.png", "assets/screenshots/arsas-first-launch.webp", @@ -43,6 +39,8 @@ def __init__(self) -> None: self.title = "" self.in_title = False self.description: str | None = None + self.body_page: str | None = None + self.nav_pages: set[str] = set() def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: values = dict(attrs) @@ -50,8 +48,12 @@ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None self.in_title = True elif tag == "h1": self.h1 += 1 + elif tag == "body": + self.body_page = values.get("data-page") elif tag == "meta" and values.get("name", "").lower() == "description": self.description = values.get("content") + if tag == "a" and values.get("data-nav-page"): + self.nav_pages.add(values["data-nav-page"] or "") for key in ("href", "src"): value = values.get(key) if value: @@ -106,13 +108,15 @@ def validate_latest(site: Path, errors: list[str]) -> None: errors.append("latest.json installer SHA-256 is invalid") -def validate_build_info(site: Path, errors: list[str]) -> str | None: +def validate_build_info(site: Path, errors: list[str]) -> tuple[str | None, list[str]]: path = site / "build-info.json" try: info = json.loads(path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError) as exc: errors.append(f"build-info.json: {exc}") - return None + return None, [] + if info.get("schemaVersion") != 2: + errors.append("build-info.json schemaVersion must be 2") version = str(info.get("version", "")) if not re.fullmatch(r"\d+\.\d+\.\d+", version): errors.append("build-info.json version is invalid") @@ -121,19 +125,44 @@ def validate_build_info(site: Path, errors: list[str]) -> str | None: author = info.get("author") if not isinstance(author, dict) or author.get("name") != "Ari Sulistiono": errors.append("build-info.json author is invalid") - return version or None + pages = info.get("pages") + if not isinstance(pages, list) or not pages or not all(isinstance(page, str) for page in pages): + errors.append("build-info.json pages registry is invalid") + return version or None, [] + if len(pages) != len(set(pages)): + errors.append("build-info.json pages registry contains duplicates") + return version or None, list(pages) + + +def validate_sitemap(site: Path, pages: list[str], errors: list[str]) -> None: + path = site / "sitemap.xml" + if not path.exists(): + errors.append("missing sitemap.xml") + return + text = path.read_text(encoding="utf-8") + root = "https://masarray.github.io/arsas/" + for page in pages: + if page == "404.html": + if root + page in text: + errors.append("sitemap.xml must not index 404.html") + continue + url = root if page == "index.html" else root + page + if url not in text: + errors.append(f"sitemap.xml missing {page}") def main() -> int: site = Path(sys.argv[1] if len(sys.argv) > 1 else "_site").resolve() errors: list[str] = [] - for relative in EXPECTED_PAGES + EXPECTED_MEDIA + ("site.json", "build-info.json"): + version, pages = validate_build_info(site, errors) + for relative in tuple(pages) + EXPECTED_MEDIA + ("site.json", "build-info.json", "sitemap.xml"): if not (site / relative).exists(): errors.append(f"missing deployable file: {relative}") combined = "" - for name in EXPECTED_PAGES: + expected_nav = {"overview", "capabilities", "reporting", "control", "architecture", "roadmap", "about", "download"} + for name in pages: page = site / name if not page.exists(): continue @@ -141,11 +170,14 @@ def main() -> int: combined += text parser = Parser() parser.feed(text) - if name != "404.html": - if parser.h1 != 1: - errors.append(f"{name}: expected one h1") - if not parser.title.strip() or not parser.description: - errors.append(f"{name}: title or description is missing") + if parser.h1 != 1: + errors.append(f"{name}: expected one h1") + if not parser.title.strip() or not parser.description: + errors.append(f"{name}: title or description is missing") + if not parser.body_page: + errors.append(f"{name}: body data-page is missing") + if parser.nav_pages != expected_nav: + errors.append(f"{name}: shared navigation is incomplete") for reference in parser.refs: target = local_ref(site, page, reference) if target is not None: @@ -163,12 +195,16 @@ def main() -> int: touch = [icon for icon in parser.icons if (icon.get("rel") or "").lower() == "apple-touch-icon"] if len(touch) != 1 or touch[0].get("href") != APP_ICON: errors.append(f"{name}: apple-touch-icon must use {APP_ICON}") + if name != "404.html": + for value in (LINKEDIN, REPOSITORY, 'href="download.html"'): + if value not in text: + errors.append(f"{name}: shared product footer or download route missing {value}") for forbidden in ( "raw.githubusercontent.com/masarray/arsas/main/Assets/screenshot", "https://masarray.github.io/arsas/assets/social-card.svg", 'href="assets/favicon.svg"', - "{{ARSAS_", "{{AUTHOR_", "{{INSTALLER_", + "{{", "github.com/masarray/arsas#quick-start", ' int: for value in (LINKEDIN, AUTHOR_GITHUB, REPOSITORY): if value not in about + home: errors.append(f"author or open-source identity missing {value}") - if "github.com/masarray/arsas#quick-start" in home + download: - errors.append("primary product pages route ordinary users to README quick-start") - - version = validate_build_info(site, errors) if version and f'"softwareVersion": "{version}"' not in home: errors.append("homepage softwareVersion does not match build-info.json") + + validate_sitemap(site, pages, errors) validate_latest(site, errors) icon = site / APP_ICON @@ -210,7 +244,7 @@ def main() -> int: for error in errors: print(f"- {error}", file=sys.stderr) return 1 - print("ARSAS product-build validation passed: official downloads, author identity, screenshots, metadata and local assets are consistent.") + print(f"ARSAS product-build validation passed: {len(pages)} pages share product navigation, author identity, downloads and local assets.") return 0 diff --git a/scripts/validate-product-source.py b/scripts/validate-product-source.py index 171807e10..b9404e6f0 100644 --- a/scripts/validate-product-source.py +++ b/scripts/validate-product-source.py @@ -1,18 +1,20 @@ #!/usr/bin/env python3 -"""Validate product templates, identity and distribution contracts before build.""" +"""Validate ARSAS product templates, partials, identity and page registry before build.""" from __future__ import annotations import json import re import sys -import xml.etree.ElementTree as ET from html.parser import HTMLParser from pathlib import Path ROOT = Path(__file__).resolve().parents[1] LANDING = ROOT / "landing" -TEMPLATES = (LANDING / "templates" / "index.html", LANDING / "templates" / "download.html") +TEMPLATES = LANDING / "templates" +PARTIALS = LANDING / "partials" +INCLUDE_PATTERN = re.compile(r"\{\{>\s*([a-z0-9-]+)\s*\}\}", re.IGNORECASE) +VERIFICATION_FILE_PATTERN = re.compile(r"google[a-z0-9]+\.html", re.IGNORECASE) KNOWN_TOKENS = { "ARSAS_VERSION", "PRODUCT_NAME", "CANONICAL_ROOT", "REPOSITORY_URL", "ENGINE_REPOSITORY_URL", "AUTHOR_NAME", "AUTHOR_LINKEDIN", "AUTHOR_GITHUB", @@ -29,6 +31,7 @@ def __init__(self) -> None: self.description: str | None = None self.meta: dict[str, str] = {} self.images: list[dict[str, str | None]] = [] + self.body_page: str | None = None def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: values = dict(attrs) @@ -36,6 +39,8 @@ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None self.in_title = True elif tag == "h1": self.h1 += 1 + elif tag == "body": + self.body_page = values.get("data-page") elif tag == "meta": key = values.get("name") or values.get("property") value = values.get("content") @@ -55,11 +60,31 @@ def handle_data(self, data: str) -> None: self.title += data +def expand_partials(text: str, errors: list[str], stack: tuple[str, ...] = ()) -> str: + def replace(match: re.Match[str]) -> str: + name = match.group(1).lower() + if name in stack: + errors.append("circular partial include: " + " -> ".join((*stack, name))) + return "" + path = PARTIALS / f"{name}.html" + if not path.exists(): + errors.append(f"missing partial: {path.relative_to(ROOT)}") + return "" + return expand_partials(path.read_text(encoding="utf-8"), errors, (*stack, name)) + + previous = None + while previous != text: + previous = text + text = INCLUDE_PATTERN.sub(replace, text) + return text + + def validate_template(path: Path, errors: list[str]) -> None: if not path.exists(): errors.append(f"missing template: {path.relative_to(ROOT)}") return - text = path.read_text(encoding="utf-8") + raw = path.read_text(encoding="utf-8") + text = expand_partials(raw, errors) parser = Parser() parser.feed(text) label = path.relative_to(ROOT) @@ -70,6 +95,8 @@ def validate_template(path: Path, errors: list[str]) -> None: errors.append(f"{label}: expected one h1, found {parser.h1}") if not parser.description or not 70 <= len(parser.description) <= 220: errors.append(f"{label}: invalid meta description") + if not parser.body_page: + errors.append(f"{label}: missing body data-page") for key in ("og:title", "og:description", "og:url", "og:image", "og:image:width", "og:image:height"): if not parser.meta.get(key): errors.append(f"{label}: missing {key}") @@ -83,14 +110,26 @@ def validate_template(path: Path, errors: list[str]) -> None: unknown = set(re.findall(r"\{\{([A-Z0-9_]+)\}\}", text)) - KNOWN_TOKENS if unknown: errors.append(f"{label}: unknown tokens {sorted(unknown)}") + if INCLUDE_PATTERN.search(text): + errors.append(f"{label}: unresolved partial include") + if ' header}}", "{{> footer}}"): + if include not in raw: + errors.append(f"{label}: missing shared include {include}") + if path.name not in ("index.html", "download.html", "404.html") and "{{> download-cta}}" not in raw: + errors.append(f"{label}: missing shared download CTA") -def validate_config(errors: list[str]) -> None: +def read_config(errors: list[str]) -> dict[str, object] | None: try: config = json.loads((LANDING / "site.json").read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError) as exc: errors.append(f"landing/site.json: {exc}") - return + return None checks = { ("product", "name"): "ARSAS", @@ -110,31 +149,98 @@ def validate_config(errors: list[str]) -> None: value = config.get(group, {}).get(key) if isinstance(config.get(group), dict) else None if not isinstance(value, str) or not value.startswith("https://github.com/masarray/arsas/releases/latest/download/"): errors.append(f"landing/site.json: invalid {group}.{key}") + return config -def validate_contract(errors: list[str]) -> None: - home = TEMPLATES[0].read_text(encoding="utf-8") if TEMPLATES[0].exists() else "" - download = TEMPLATES[1].read_text(encoding="utf-8") if TEMPLATES[1].exists() else "" - about_path = LANDING / "about.html" - about = about_path.read_text(encoding="utf-8") if about_path.exists() else "" +def validate_registry(config: dict[str, object], errors: list[str]) -> list[Path]: + pages = config.get("pages") + if not isinstance(pages, list) or not pages: + errors.append("landing/site.json: pages registry must be a non-empty list") + return [] + + paths: set[str] = set() + template_names: set[str] = set() + templates: list[Path] = [] + for entry in pages: + if not isinstance(entry, dict): + errors.append("landing/site.json: every page entry must be an object") + continue + path = entry.get("path") + template = entry.get("template") + if not isinstance(path, str) or not isinstance(template, str): + errors.append("landing/site.json: every page entry needs string path and template") + continue + if path in paths: + errors.append(f"landing/site.json: duplicate page path {path}") + if template in template_names: + errors.append(f"landing/site.json: duplicate template {template}") + paths.add(path) + template_names.add(template) + template_path = TEMPLATES / template + templates.append(template_path) + if not template_path.exists(): + errors.append(f"landing/site.json: missing registered template {template}") + if path not in ("", "404.html") and not path.endswith(".html"): + errors.append(f"landing/site.json: invalid page path {path}") + if path == "404.html" and entry.get("index", True) is not False: + errors.append("landing/site.json: 404.html must be excluded from sitemap") + + actual = {path.name for path in TEMPLATES.glob("*.html")} + missing_from_registry = sorted(actual - template_names) + missing_from_templates = sorted(template_names - actual) + if missing_from_registry: + errors.append("templates missing from registry: " + ", ".join(missing_from_registry)) + if missing_from_templates: + errors.append("registry templates missing from disk: " + ", ".join(missing_from_templates)) + return templates + + +def validate_partials(errors: list[str]) -> None: + header = (PARTIALS / "header.html").read_text(encoding="utf-8") if (PARTIALS / "header.html").exists() else "" + footer = (PARTIALS / "footer.html").read_text(encoding="utf-8") if (PARTIALS / "footer.html").exists() else "" + cta = (PARTIALS / "download-cta.html").read_text(encoding="utf-8") if (PARTIALS / "download-cta.html").exists() else "" + for page in ("overview", "capabilities", "reporting", "control", "architecture", "roadmap", "about", "download"): + if f'data-nav-page="{page}"' not in header: + errors.append(f"shared header missing navigation key {page}") + for value in ("{{AUTHOR_NAME}}", "{{AUTHOR_LINKEDIN}}", "{{REPOSITORY_URL}}"): + if value not in footer: + errors.append(f"shared footer missing {value}") + for value in ("{{ARSAS_VERSION}}", "{{INSTALLER_URL}}", 'href="download.html"'): + if value not in cta: + errors.append(f"shared download CTA missing {value}") + +def validate_contract(errors: list[str]) -> None: + home = (TEMPLATES / "index.html").read_text(encoding="utf-8") if (TEMPLATES / "index.html").exists() else "" + download = (TEMPLATES / "download.html").read_text(encoding="utf-8") if (TEMPLATES / "download.html").exists() else "" + about = (TEMPLATES / "about.html").read_text(encoding="utf-8") if (TEMPLATES / "about.html").exists() else "" for value in ("{{INSTALLER_URL}}", 'href="download.html"', "arsas-rcb-scl-export.webp", "{{AUTHOR_LINKEDIN}}", '"codeRepository"'): if value not in home: errors.append(f"homepage template missing {value}") for value in ("{{INSTALLER_URL}}", "{{PORTABLE_URL}}", "{{CHECKSUMS_URL}}", "{{ARSAS_VERSION}}"): if value not in download: errors.append(f"download template missing {value}") - for value in ("https://www.linkedin.com/in/ari-sulistiono", "https://github.com/masarray"): + for value in ("{{AUTHOR_LINKEDIN}}", "{{AUTHOR_GITHUB}}", "{{REPOSITORY_URL}}"): if value not in about: - errors.append(f"about page missing {value}") - if "github.com/masarray/arsas#quick-start" in home + download: - errors.append("primary product templates route users to README quick-start") + errors.append(f"about template missing {value}") + + root_html = sorted( + path.name + for path in LANDING.glob("*.html") + if not VERIFICATION_FILE_PATTERN.fullmatch(path.name) + ) + if root_html: + errors.append("legacy landing HTML remains outside templates: " + ", ".join(root_html)) + verification_files = [path.name for path in LANDING.glob("google*.html") if VERIFICATION_FILE_PATTERN.fullmatch(path.name)] + if len(verification_files) > 1: + errors.append("multiple Google verification HTML files are present") + if (LANDING / "sitemap.xml").exists(): + errors.append("landing/sitemap.xml must be generated from site.json, not stored as a second source") required_files = ( "assets/screenshots/arsas-first-launch.webp", "assets/screenshots/arsas-rcb-scl-export.webp", "assets/social-card.png", - "about.html", "site.webmanifest", "robots.txt", ) @@ -143,31 +249,21 @@ def validate_contract(errors: list[str]) -> None: errors.append(f"missing landing source file: {relative}") -def validate_sitemap(errors: list[str]) -> None: - try: - ET.parse(LANDING / "sitemap.xml") - except (OSError, ET.ParseError) as exc: - errors.append(f"landing/sitemap.xml: {exc}") - return - sitemap = (LANDING / "sitemap.xml").read_text(encoding="utf-8") - if "https://masarray.github.io/arsas/about.html" not in sitemap: - errors.append("landing/sitemap.xml missing about.html") - - def main() -> int: errors: list[str] = [] - validate_config(errors) - for template in TEMPLATES: + config = read_config(errors) + templates = validate_registry(config, errors) if config else [] + validate_partials(errors) + for template in templates: validate_template(template, errors) validate_contract(errors) - validate_sitemap(errors) errors = list(dict.fromkeys(errors)) if errors: print("ARSAS product-source validation failed:", file=sys.stderr) for error in errors: print(f"- {error}", file=sys.stderr) return 1 - print("ARSAS product-source validation passed.") + print(f"ARSAS product-source validation passed: {len(templates)} registered templates use shared product chrome.") return 0