Files
pand03-CEOandClaude Sonnet 5 2a9b28581c Rapihin setup/member/lot-parking + fitur intercom, exclude WIP controller & file sampah dari git
Kumpulan perubahan yang udah numpuk di working tree: refactor Setup
(Gate/Vehicle/Member), rapihin memberin & stiker, service parking baru
(ParkingUtilsServices, NetworkService), model/migration lot-parking &
DHCP reservation, dan fitur baru Intercom (controller/model/migration/
view).

ReportTransaksiController versi lokal ini WIP (~90%, masih didebug) -
versi yang bener ada di server, jadi dikeluarin dari git (ditambahin
ke .gitignore) biar gak numpuk nindihin punya server pas git pull di
sana. Sekalian keluarin dump mentah tabel softseting (1.8MB, nyasar
ke-commit), file .bak, dan arsip ad-hoc (api.tgz, c.zip) yang emang
bukan source code.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EAJc2mrpj2cSTe4oowLPzQ
2026-10-04 07:15:54 +07:00

129 lines
4.6 KiB
PHP

<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Models\IntercomCall;
use App\Models\IntercomDevice;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Modul Intercom: reuse pola ParkingOperationController.
* Laravel HANYA urus signaling + log, BUKAN relay audio.
* Audio diurus Go relay (UDP), Laravel cuma simpan metadata + path rekaman.
*/
class IntercomController extends Controller
{
public function devices()
{
return IntercomDevice::orderBy('device_id')->get();
}
public function queue()
{
return IntercomCall::whereIn('status', ['waiting', 'active'])
->orderBy('requested_at')
->limit(20)->get();
}
public function history(Request $request)
{
return IntercomCall::orderByDesc('id')->limit($request->input('limit', 50))->get();
}
// Dipanggil Go relay saat ESP32 kirim MQTT intercom/request
public function request(Request $request)
{
$data = $request->validate([
'device_id' => 'required|string|max:20',
'arah' => 'sometimes|string|in:in,out',
]);
$deviceId = strtoupper($data['device_id']);
$device = IntercomDevice::firstOrCreate(
['device_id' => $deviceId],
['nama' => $deviceId, 'status' => 'idle']
);
// Kalau device lagi active, tetap masuk antrean (tidak ditolak)
$call = IntercomCall::create([
'device_id' => $deviceId,
'arah' => $data['arah'] ?? 'in',
'status' => 'waiting',
'requested_at' => now(),
]);
$device->update(['status' => 'calling', 'last_seen_at' => now()]);
Log::info("Intercom request {$deviceId} call_id={$call->id}");
return response()->json(['status' => true, 'call_id' => $call->id, 'device_id' => $deviceId]);
}
// Admin klik [Terima] di dashboard
public function accept(Request $request)
{
$data = $request->validate(['call_id' => 'required|integer']);
$call = IntercomCall::findOrFail($data['call_id']);
// Tutup sesi active lain di device yang sama (single private session)
IntercomCall::where('device_id', $call->device_id)
->where('status', 'active')->update(['status' => 'ended', 'ended_at' => now(), 'ended_by' => 'admin-switch']);
$call->update(['status' => 'active', 'started_at' => now()]);
IntercomDevice::where('device_id', $call->device_id)->update(['status' => 'active']);
// Go relay yang bertugas publish MQTT intercom/invite/{DEVICE} + buka UDP port.
// Laravel cuma ubah status, tidak publish MQTT langsung.
return response()->json(['status' => true, 'call' => $call]);
}
public function end(Request $request)
{
$data = $request->validate([
'call_id' => 'required|integer',
'ended_by' => 'sometimes|string|max:20',
'recording_path' => 'sometimes|string|max:255',
]);
$call = IntercomCall::findOrFail($data['call_id']);
$now = now();
$durasi = $call->started_at ? $now->diffInSeconds($call->started_at) : ($call->requested_at ? $now->diffInSeconds($call->requested_at) : 0);
$call->update([
'status' => $call->status === 'waiting' && ($data['ended_by'] ?? '') === 'timeout' ? 'missed' : 'ended',
'ended_at' => $now,
'durasi_detik' => $durasi,
'ended_by' => $data['ended_by'] ?? 'admin',
'recording_path' => $data['recording_path'] ?? $call->recording_path,
]);
// Balikin status device ke idle kalau tidak ada sesi lain
$masihAktif = IntercomCall::where('device_id', $call->device_id)->whereIn('status', ['waiting', 'active'])->exists();
if (!$masihAktif) {
IntercomDevice::where('device_id', $call->device_id)->update(['status' => 'idle']);
}
return response()->json(['status' => true, 'call' => $call]);
}
// Heartbeat / LWT dari Go relay: ESP32 online/offline
public function heartbeat(Request $request)
{
$data = $request->validate([
'device_id' => 'required|string|max:20',
'status' => 'sometimes|string|max:20',
'ip_address' => 'sometimes|string|max:45',
]);
IntercomDevice::updateOrCreate(
['device_id' => strtoupper($data['device_id'])],
['status' => $data['status'] ?? 'idle', 'ip_address' => $data['ip_address'] ?? null, 'last_seen_at' => now()]
);
return response()->json(['status' => true]);
}
}