gianfriaur / opcua-laravel-client
Laravel integration for OPC UA client with optional session manager support
Requires
- php: ^8.2
- illuminate/console: ^11.0|^12.0|^13.0
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- php-opcua/opcua-client: ^4.4.0
- php-opcua/opcua-session-manager: ^4.4.0
- psr/event-dispatcher: ^1.0
Requires (Dev)
- illuminate/config: ^11.0|^12.0|^13.0
- mockery/mockery: ^1.6
- pestphp/pest: ^3.0
- vlucas/phpdotenv: ^5.0
README
Laravel integration for OPC UA built on opcua-client and opcua-session-manager. Connect your Laravel app to PLCs, SCADA systems, sensors, and IoT devices with a familiar developer experience: a Facade, .env-based configuration, named connections (like config/database.php), and an Artisan command for the optional session manager daemon.
What you get:
- Facade —
Opcua::read('i=2259')with full IDE autocompletion - Named connections — define multiple OPC UA servers and switch between them, just like database connections
- Transparent session management — when the daemon is running, connections persist across HTTP requests; when it's not, direct per-request connections with zero code changes
- Laravel-native logging and caching — your log channel and cache store are automatically injected into every OPC UA client
- All OPC UA operations — browse, read, write, method calls, subscriptions, events, history, path resolution, type discovery
- PSR-14 events — 47 dispatched events covering every OPC UA operation for observability and extensibility
- Auto-publish — daemon monitors subscriptions automatically and dispatches PSR-14 events to your Laravel listeners — no manual publish loop
- Auto-connect — define subscriptions in
config/opcua.phpper connection and the daemon sets them up at startup - Trust store — certificate trust management with configurable policies and auto-accept modes
- Write auto-detection — omit the type parameter and let the client detect the correct OPC UA type automatically
Note: This package wraps the full opcua-client API with Laravel conventions. For the underlying protocol details, types, and advanced features, see the client documentation.
Tested against the OPC UA reference implementationThe underlying opcua-client is integration-tested against UA-.NETStandard — the reference implementation maintained by the OPC Foundation, the organization that defines the OPC UA specification. This Laravel package is additionally integration-tested via uanetstandard-test-suite in both direct and managed (daemon) modes, ensuring full compatibility across all connection strategies. Like opcua-client and opcua-session-manager, unit tests run cross-OS — Linux, macOS, and Windows across PHP 8.2–8.5 × Laravel 11/12/13 — on every push. Integration tests stay on Linux (Docker-hosted OPC UA servers). |
Quick Start
composer require php-opcua/laravel-opcua
# RSA security (or use ECC: ECC_nistP256, ECC_nistP384, ECC_brainpoolP256r1, ECC_brainpoolP384r1) OPCUA_ENDPOINT=opc.tcp://192.168.1.100:4840
use PhpOpcua\LaravelOpcua\Facades\Opcua; $client = Opcua::connect(); $value = $client->read('i=2259'); echo $value->getValue(); // 0 = Running $client->disconnect();
That's it. Facade, .env, connect, read. Everything else is optional.
See It in Action
Browse the address space
$client = Opcua::connect(); $refs = $client->browse('i=85'); // Objects folder foreach ($refs as $ref) { echo "{$ref->displayName} ({$ref->nodeId})\n"; } $client->disconnect();
Read multiple values with fluent builder
$client = Opcua::connect(); $results = $client->readMulti() ->node('i=2259')->value() ->node('ns=2;i=1001')->displayName() ->execute(); foreach ($results as $dv) { echo $dv->getValue() . "\n"; } $client->disconnect();
Write to a PLC
use PhpOpcua\Client\Types\BuiltinType; $client = Opcua::connect(); $client->write('ns=2;i=1001', 42, BuiltinType::Int32); // Or let the client auto-detect the type $client->write('ns=2;i=1001', 42); $client->disconnect();
Call a method on the server
use PhpOpcua\Client\Types\Variant; use PhpOpcua\Client\Types\BuiltinType; $client = Opcua::connect(); $result = $client->call( 'i=2253', // Server object 'i=11492', // Method [new Variant(BuiltinType::UInt32, 1)], ); echo $result->statusCode; // 0 echo $result->outputArguments[0]->value; // [1001, 1002, ...] $client->disconnect();
Subscribe to data changes
$client = Opcua::connect(); $sub = $client->createSubscription(publishingInterval: 500.0); $client->createMonitoredItems($sub->subscriptionId, [ ['nodeId' => 'ns=2;i=1001'], ]); $response = $client->publish(); foreach ($response->notifications as $notif) { echo $notif['dataValue']->getValue() . "\n"; } $client->deleteSubscription($sub->subscriptionId); $client->disconnect();
Auto-publish — no manual publish loop
With auto_publish enabled, the daemon handles subscriptions automatically. Just register Laravel event listeners:
// config/opcua.php 'session_manager' => ['auto_publish' => true], 'connections' => [ 'plc-1' => [ 'endpoint' => 'opc.tcp://192.168.1.10:4840', 'auto_connect' => true, 'subscriptions' => [ [ 'publishing_interval' => 500.0, 'monitored_items' => [ ['node_id' => 'ns=2;s=Temperature', 'client_handle' => 1], ], ], ], ], ],
// EventServiceProvider use PhpOpcua\Client\Event\DataChangeReceived; Event::listen(DataChangeReceived::class, function (DataChangeReceived $e) { DB::table('sensor_readings')->insert([ 'value' => $e->dataValue->getValue(), 'client_handle' => $e->clientHandle, ]); });
php artisan opcua:session # connects, subscribes, publishes — all automatic
React to events
47 PSR-14 events are dispatched automatically — connections, reads, writes, alarms, subscriptions, cache, retries. Just register listeners:
use Illuminate\Support\Facades\Event; use PhpOpcua\Client\Event\ClientConnected; use PhpOpcua\Client\Event\NodeValueWriteFailed; use PhpOpcua\Client\Event\AlarmActivated; // Log connections Event::listen(ClientConnected::class, function ($e) { logger()->info("Connected to {$e->endpointUrl}"); }); // Track write failures Event::listen(NodeValueWriteFailed::class, function ($e) { logger()->warning("Write failed on {$e->nodeId}: 0x" . dechex($e->statusCode)); }); // Alert operators on alarms Event::listen(AlarmActivated::class, function ($e) { Notification::send( User::role('operator')->get(), new AlarmTriggered($e->sourceName, $e->severity, $e->message), ); });
See Events documentation for the full reference of all 47 events.
Switch connections
// Named connection from config $client = Opcua::connect('plc-line-1'); $value = $client->read('ns=2;i=1001'); Opcua::disconnect('plc-line-1'); // Ad-hoc connection at runtime $client = Opcua::connectTo('opc.tcp://10.0.0.50:4840', [ 'username' => 'operator', 'password' => 'secret', ], as: 'temp-plc'); Opcua::disconnectAll();
Test without a real server
use PhpOpcua\Client\Testing\MockClient; use PhpOpcua\Client\Types\DataValue; $mock = MockClient::create() ->onRead('i=2259', fn() => DataValue::ofInt32(0)); // Inject into OpcuaManager via DI or reflection $value = $mock->read('i=2259'); echo $value->getValue(); // 0 echo $mock->callCount('read'); // 1
Features
| Feature | What it does |
|---|---|
| Facade | Opcua::read(), Opcua::browse(), etc. with full PHPDoc for IDE autocompletion |
| Named Connections | Define multiple servers in config/opcua.php, switch with Opcua::connection('plc-2') |
| Ad-hoc Connections | Opcua::connectTo('opc.tcp://...') for endpoints not in config |
| Session Manager | Artisan command php artisan opcua:session for daemon-based session persistence |
| Transparent Fallback | Daemon available? ManagedClient. Not available? Direct Client. Zero code changes |
| String NodeIds | 'i=2259', 'ns=2;s=MyNode' everywhere a NodeId is accepted |
| Fluent Builder API | readMulti(), writeMulti(), createMonitoredItems(), translateBrowsePaths() chain |
| PSR-3 Logging | Laravel's log channel injected automatically via config |
| PSR-14 Events | 47 dispatched events covering every OPC UA operation for observability and extensibility |
| PSR-16 Caching | Laravel's cache store injected automatically. Per-call useCache on browse ops |
| Write Auto-Detection | write('ns=2;i=1001', 42) — omit the type and the client detects it automatically |
| Read Metadata Cache | Cached node metadata avoids redundant reads; refresh on demand with read($nodeId, refresh: true) |
| Trust Store | FileTrustStore with configurable TrustPolicy, auto-accept modes, and certificate management |
| Type Discovery | discoverDataTypes() auto-detects custom server structures |
| Auto-Publish | Daemon auto-publishes for sessions with subscriptions, dispatches PSR-14 events to Laravel listeners |
| Auto-Connect | Per-connection auto_connect with declarative subscriptions config — daemon sets up monitoring on startup |
| Subscription Management | createMonitoredItems(), modifyMonitoredItems(), setTriggering(), transferSubscriptions() |
| MockClient | Test without a server — register handlers, assert calls |
| Timeout & Retry | Per-connection timeout, auto_retry via config or fluent API |
| Auto-Batching | readMulti/writeMulti transparently split when exceeding server limits |
| Recursive Browse | browseAll(), browseRecursive() with depth control and cycle detection |
| Path Resolution | resolveNodeId('/Objects/Server/ServerStatus') |
| Security | 10 policies (RSA + ECC), 3 auth modes, auto-generated certs, certificate trust management |
ECC disclaimer: ECC security policies (
ECC_nistP256,ECC_nistP384,ECC_brainpoolP256r1,ECC_brainpoolP384r1) are fully implemented and tested against the OPC Foundation's UA-.NETStandard reference stack. However, no commercial OPC UA vendor supports ECC endpoints yet. When using ECC, client certificates are auto-generated ifclient_certificate/client_keyare omitted, and username/password authentication uses theEccEncryptedSecretprotocol automatically. | History Read | Raw, processed, and at-time historical queries | | Typed Returns | All service responses returnpublic readonlyDTOs |
Documentation
Full documentation is available in docs/. Highlights:
| Section | Covers |
|---|---|
| Getting started — Overview · Installation · Quick start · How laravel-opcua fits · Upgrading | Concepts, install, first connection |
| Configuration — Config file · Connections · Environment variables · Security · Session manager · Publishing & overriding | .env, config file, named connections |
| Using the client — Facade vs injection · Named connections · Ad-hoc connections · Connection lifecycle · Using builders | Facade, DI, lifecycle |
| Operations — Reading · Writing · Browsing · Method calls · Subscriptions · History | Read/write, browse, subscribe, history |
| Session manager — Overview · Starting the daemon · Auto-publish · Production supervisor · Monitoring | Persistent sessions via daemon |
| Events — Overview · Connection events · Data events · Alarm events · Queued listeners | PSR-14 + Laravel listeners |
| Observability — Logging · Caching · Debugging · Telescope & Pulse | Logs, cache, dev tools |
| Security — Policies & modes · Credentials · Certificates · Trust store | Security policies, certs, trust |
| Testing — Pest setup · Mocking the facade · Using MockClient · Integration tests | Unit + integration tests |
| Integrations — Octane & FrankenPHP · Horizon & queues · Broadcasting · Livewire · Notifications · Filament | Laravel ecosystem |
| Reference — Facade methods · OpcuaManager API · Artisan commands · Exceptions | Public API |
| Recipes — Persistent tag history · Alarm routing · Livewire dashboard · Multi-plant tenant · Companion specs · Dev with Sail · Production deployment | Task-oriented walkthroughs |
Testing
146+ unit tests with 99%+ code coverage. Integration tests run against uanetstandard-test-suite — a Docker-based OPC UA environment built on the OPC Foundation's UA-.NETStandard reference implementation — in both direct and managed (daemon) modes.
./vendor/bin/pest tests/Unit/ # unit only ./vendor/bin/pest tests/Integration/ --group=integration # integration only ./vendor/bin/pest # everything
Ecosystem
| Package | Description |
|---|---|
| opcua-client | Pure PHP OPC UA client |
| opcua-cli | CLI tool — browse, read, write, watch, discover endpoints, manage certificates, generate code from NodeSet2.xml |
| opcua-session-manager | Daemon-based session persistence across PHP requests. Keeps OPC UA connections alive between short-lived PHP processes via a ReactPHP daemon and Unix sockets. Separate package by design — see ROADMAP.md for rationale. |
| opcua-client-nodeset | Pre-generated PHP types from 51 OPC Foundation companion specifications (DI, Robotics, Machinery, MachineTool, ISA-95, CNC, MTConnect, and more). 807 PHP files — NodeId constants, enums, typed DTOs, codecs, registrars with automatic dependency resolution. Just composer require and loadGeneratedTypes(). |
| laravel-opcua | Laravel integration — service provider, facade, config (this package) |
| uanetstandard-test-suite | Docker-based OPC UA test servers (UA-.NETStandard) for integration testing |
Community
Have questions, ideas, or want to share what you've built? Join the GitHub Discussions.
Connected a PLC, SCADA system, or OPC UA server? We're building a community-driven list of tested hardware and software. Share your experience in Tested Hardware & Software — even a one-liner like "Siemens S7-1500, works fine" helps other users know what to expect.
Contributing
Contributions welcome — see CONTRIBUTING.md.
AI-Ready
This package ships with machine-readable documentation designed for AI coding assistants (Claude, Cursor, Copilot, ChatGPT, and others). Feed these files to your AI so it knows how to use the library correctly:
| File | Purpose |
|---|---|
llms.txt |
Compact project summary — architecture, Facade, configuration, session manager. Optimized for LLM context windows with minimal token usage. |
llms-full.txt |
Comprehensive technical reference — every config key, method, DTO, event, trust store, managed client. For deep dives and complex questions. |
llms-skills.md |
Task-oriented recipes — step-by-step instructions for common tasks (install, read, write, browse, named connections, session manager, security, testing, events). Written so an AI can generate correct, production-ready code from a user's intent. |
How to use: copy the files you need into your project's AI configuration directory. The files are located in vendor/php-opcua/laravel-opcua/ after composer install.
- Claude Code: reference per-session with
--add-file vendor/php-opcua/laravel-opcua/llms-skills.md - Cursor: copy into your project's rules directory —
cp vendor/php-opcua/laravel-opcua/llms-skills.md .cursor/rules/laravel-opcua.md - GitHub Copilot: copy or append the content into your project's
.github/copilot-instructions.mdfile (create the file and directory if they don't exist). Copilot reads this file automatically for project-specific context - Other tools: paste the content into your system prompt, project knowledge base, or context configuration
Versioning
This package follows the same version numbering as php-opcua/opcua-client. Each release of laravel-opcua is aligned with the corresponding release of the client library to ensure full compatibility.
Changelog
See CHANGELOG.md.