Quick start
A real Laravel controller reading a PLC tag in three lines. Plus the canonical Tinker session, a console command, and a queued job — the four shapes you'll write 90% of the time.
Four shapes cover almost every use of laravel-opcua in a real
Laravel application. This page walks through each.
Prerequisite: package installed (see Installation)
and .env pointing at a reachable OPC UA server.
1 — In a controller
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use PhpOpcua\LaravelOpcua\Facades\Opcua;
use PhpOpcua\Client\Types\StatusCode;
class DashboardController extends Controller
{
public function speed(): JsonResponse
{
$dataValue = Opcua::read('ns=2;s=PLC/Speed');
if (! StatusCode::isGood($dataValue->statusCode)) {
return response()->json([
'error' => 'Read failed: ' . StatusCode::getName($dataValue->statusCode),
], 503);
}
return response()->json([
'speed_rpm' => $dataValue->getValue(),
'as_of' => $dataValue->sourceTimestamp?->format('c'),
]);
}
}
Route it like any other:
use App\Http\Controllers\DashboardController;
Route::get('/api/speed', [DashboardController::class, 'speed']);
Opcua::read() opens (or reuses) a session, issues a single OPC
UA Read request, returns a DataValue. The facade points at the
default connection from config/opcua.php.
2 — In a Tinker session
php artisan tinker
>>> use PhpOpcua\LaravelOpcua\Facades\Opcua;
>>> Opcua::read('i=2261')->getValue();
=> "open62541 OPC UA Server"
>>> $refs = Opcua::browse('i=85');
>>> count($refs);
=> 4
>>> Opcua::write('ns=2;s=PLC/Setpoint', 42.5);
=> 0 // 0 = Good status
>>> $eps = Opcua::getEndpoints('opc.tcp://plc.local:4840');
>>> collect($eps)->pluck('securityPolicyUri')->unique()->values()->all();
=> ["http://opcfoundation.org/UA/SecurityPolicy#None", "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"]
Tinker is the fastest exploration loop — no controller, no test,
no route. The Opcua facade works exactly as in production.
3 — In a console command
php artisan make:command CapturePlcSpeed
namespace App\Console\Commands;
use App\Models\PlcReading;
use Illuminate\Console\Command;
use PhpOpcua\LaravelOpcua\Facades\Opcua;
class CapturePlcSpeed extends Command
{
protected $signature = 'plc:capture-speed
{connection=default : The opcua connection name}';
protected $description = 'Capture the current PLC speed reading';
public function handle(): int
{
$value = Opcua::connection($this->argument('connection'))
->read('ns=2;s=PLC/Speed')
->getValue();
PlcReading::create([
'tag' => 'PLC/Speed',
'value' => $value,
]);
$this->info("Captured: {$value}");
return Command::SUCCESS;
}
}
Schedule it in routes/console.php:
use Illuminate\Support\Facades\Schedule;
Schedule::command('plc:capture-speed')->everyMinute();
The kernel's schedule:run (typically wired into cron at 1-minute
granularity) fires it. One PLC read per tick — durable, in the
database, queryable later.
4 — In a queued job
For more involved work — fetch many tags, transform, persist, notify — wrap it in a Job:
php artisan make:job SamplePlc
namespace App\Jobs;
use App\Models\PlcReading;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use PhpOpcua\LaravelOpcua\Facades\Opcua;
class SamplePlc implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public function handle(): void
{
$values = Opcua::readMulti([
['nodeId' => 'ns=2;s=PLC/Speed'],
['nodeId' => 'ns=2;s=PLC/Mode'],
['nodeId' => 'ns=2;s=PLC/Health'],
]);
PlcReading::create([
'speed' => $values[0]->getValue(),
'mode' => $values[1]->getValue(),
'health' => $values[2]->getValue(),
]);
}
}
Dispatch from anywhere:
\App\Jobs\SamplePlc::dispatch();
The queue worker picks it up. With Horizon, watch it through the dashboard — see Integrations · Horizon and queues.
With the session-manager daemon
For request-driven workloads (HTTP controllers, queue workers that hit OPC UA per job), start the daemon in a separate terminal:
php artisan opcua:session
The Laravel app autodetects the daemon and routes through it. The OPC UA session is opened once on the daemon side and reused across every request — no per-request handshake.
In production, supervise the daemon; see Session manager · Production supervisor.
What just happened, in one line each
| Step | Mechanism |
|---|---|
composer require ... |
Auto-discovery wires the service provider + facade |
php artisan vendor:publish ... |
Drops config/opcua.php into the application |
Opcua::read(...) |
Facade → OpcuaManager::__call() → default connection → Client::read() |
php artisan opcua:session |
Boots the SessionManagerDaemon configured from config/opcua.php |
Worker calling Opcua::read(...) |
ManagedClient → IPC → daemon-held session → server |
Every layer is documented in detail in the rest of the docs. This page is the first turn.
Where to go next
- How laravel-opcua fits — the mental model behind the facade, the manager, and the daemon.
- Using the client · Facade vs injection — when to pick one over the other.
- Recipes · Persistent tag history — the controller + schedule + Eloquent walkthrough, end to end.