diff --git a/app/Http/Controllers/APIS/CustomerApi/TelemetryController.php b/app/Http/Controllers/APIS/CustomerApi/TelemetryController.php index e12617d..d2ab681 100644 --- a/app/Http/Controllers/APIS/CustomerApi/TelemetryController.php +++ b/app/Http/Controllers/APIS/CustomerApi/TelemetryController.php @@ -6,6 +6,7 @@ use App\Http\Controllers\Controller; use App\Models\Asset; use App\Models\Device; use App\Models\TimeseriesKeyMaster; +use App\Services\AlarmService; use App\Services\CustomerInfoService; use Illuminate\Container\Attributes\DB; use Illuminate\Http\Request; @@ -16,17 +17,354 @@ use Illuminate\Support\Facades\Validator; class TelemetryController extends Controller { - protected $customerInfoService; + protected $customerInfoService, $alarmService; - public function __construct(CustomerInfoService $customerInfoService) + // public function __construct(CustomerInfoService $customerInfoService) + // { + // $this->customerInfoService = $customerInfoService; + // } + public function __construct(CustomerInfoService $customerInfoService, AlarmService $alarmService) { $this->customerInfoService = $customerInfoService; + $this->alarmService = $alarmService; // 💡 Add AlarmService } + + + + + + + // public function telemetryDataAsset(Request $request) + // { + // $validator = Validator::make($request->all(), [ + // 'asset_id' => 'required|string', + // 'startTs' => 'nullable|string', + // 'endTs' => 'nullable|string', + // ]); + + // if ($validator->fails()) { + // return jsonResponseWithErrorMessage($validator->errors()->first(), 400); + // } + + // $assetId = $request->input('asset_id'); + // $startTs = $request->input('startTs') ?: now()->subHours(24)->timestamp * 1000; // Default: last 24 hrs + // $endTs = $request->input('endTs') ?: now()->timestamp * 1000; + + // $devices = Device::with('deviceProfile') + // ->where('asset_id', $assetId) + // ->get(); + + // if ($devices->isEmpty()) { + // return response()->json(['error' => 'No devices found for the asset'], 404); + // } + + // $response = []; + + // foreach ($devices as $device) { + // $filteredTelemetry = []; + + // // Fetch telemetry data + // $keysData = TimeseriesKeyMaster::where('device_profile_xid', $device->device_profile_id) + // ->where('display_on_dashboard', 1) + // ->get(['key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']); + + // $keyNames = $keysData->pluck('key_name')->toArray(); + + // // Retrieve telemetry data + // $telemetryResponse = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTs, $endTs); + + // foreach ($keysData as $keyData) { + // $keyName = $keyData->key_name; + + // if (isset($telemetryResponse[$keyName])) { + // foreach ($telemetryResponse[$keyName] as $item) { + // // 💡 Check alert status for each telemetry key + // $alert = $this->checkTelemetryKeyAlert($device->id, $keyName); + + // $filteredTelemetry[] = [ + // 'key_name' => $keyName, + // 'display_name' => $keyData->display_name, + // 'display_on_dashboard' => $keyData->display_on_dashboard, + // 'display_on_popup' => $keyData->display_on_popup, + // 'timestamp' => $item['ts'] ?? null, + // 'value' => $item['value'] ?? null, + // 'alert' => $alert // ✅ Add alert status for each key + // ]; + // } + // } + // } + + // $response[] = [ + // 'device_id' => (string) $device->id, + // 'device_profile_name' => (string) $device->deviceProfile->name, + // 'asset_id' => (string) $device->asset_id, + // 'device_profile_id' => (string) $device->device_profile_id, + // 'telemetry' => $filteredTelemetry, + // ]; + // } + + // return response()->json(['telemetry' => $response]); + // } + + + // public function telemetryDataAsset(Request $request) + // { + // $validator = Validator::make($request->all(), [ + // 'asset_id' => 'required|string', + // 'startTs' => 'nullable|string', + // 'endTs' => 'nullable|string', + // ]); + + // if ($validator->fails()) { + // return jsonResponseWithErrorMessage($validator->errors()->first(), 400); + // } + + // $assetId = $request->input('asset_id'); + // $startTs = $request->input('startTs') ?: null; + // $endTs = $request->input('endTs') ?: null; + + // // Fetch devices associated with the asset + // $devices = Device::with('deviceProfile') + // ->where('asset_id', $assetId) + // ->get(); + + // if ($devices->isEmpty()) { + // return response()->json(['error' => 'No devices found for the asset'], 404); + // } + + // $response = []; + + // foreach ($devices as $device) { + // $telemetry = []; + + // $keysData = TimeseriesKeyMaster::where('device_profile_xid', $device->device_profile_id) + // ->where(function ($query) { + // $query->where('display_on_dashboard', true) + // ->orWhere('display_on_popup', true); + // }) + // ->get(['key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']); + + // $keyNames = $keysData->pluck('key_name')->toArray(); + + // // Log key names for debugging + // // Log::info('Key Names for Device', ['device_id' => $device->id, 'key_names' => $keyNames]); + + // // Fetch telemetry data + // $telemetryResponse = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTs, $endTs); + + // foreach ($keysData as $keyData) { + // $keyName = $keyData->key_name; + + // if (isset($telemetryResponse[$keyName])) { + // foreach ($telemetryResponse[$keyName] as $item) { + // $telemetry[] = [ + // 'key_name' => $keyName, + // 'display_name' => $keyData->display_name, + // 'display_on_dashboard' => $keyData->display_on_dashboard, + // 'display_on_popup' => $keyData->display_on_popup, + // 'timestamp' => $item['ts'] ?? null, + // 'value' => $item['value'] ?? null, + // ]; + // } + // } + // } + + // $response[] = [ + // 'device_id' => (string) $device->id, + // 'device_profile_name' => (string) $device->deviceProfile->name, + // 'asset_id' => (string) $device->asset_id, + // 'device_profile_id' => (string) $device->device_profile_id, + // 'telemetry' => $telemetry, + // ]; + // } + + // return response()->json(['telemetry' => $response]); + // } + + + // public function telemetryDataAsset(Request $request) + // { + // $validator = Validator::make($request->all(), [ + // 'asset_id' => 'required|string', + // 'startTs' => 'nullable|string', + // 'endTs' => 'nullable|string', + // ]); + + // if ($validator->fails()) { + // return jsonResponseWithErrorMessage($validator->errors()->first(), 400); + // } + + // $assetId = $request->input('asset_id'); + // $startTs = $request->input('startTs') ?: now()->subHours(24)->timestamp * 1000; // Default: last 24 hrs + // $endTs = $request->input('endTs') ?: now()->timestamp * 1000; + + // $devices = Device::with('deviceProfile') + // ->where('asset_id', $assetId) + // ->get(); + + // if ($devices->isEmpty()) { + // return response()->json(['error' => 'No devices found for the asset'], 404); + // } + + // $response = []; + + // foreach ($devices as $device) { + // $telemetry = []; + + // // Fetch telemetry keys + // $keysData = TimeseriesKeyMaster::where('device_profile_xid', $device->device_profile_id) + // ->where(function ($query) { + // $query->where('display_on_dashboard', true) + // ->orWhere('display_on_popup', true); + // }) + // ->get(['key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']); + + // $keyNames = $keysData->pluck('key_name')->toArray(); + + // // Fetch telemetry data + // $telemetryResponse = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTs, $endTs); + + // // Fetch alarms for the device and map by telemetry key + // $alarmMap = $this->getDeviceAlarmsForTelemetry($device->id); + + // foreach ($keysData as $keyData) { + // $keyName = $keyData->key_name; + + // if (isset($telemetryResponse[$keyName])) { + // foreach ($telemetryResponse[$keyName] as $item) { + // // Check if the telemetry key has an alarm + // $alert = isset($alarmMap[$keyName]); + + // $telemetry[] = [ + // 'key_name' => $keyName, + // 'display_name' => $keyData->display_name, + // 'display_on_dashboard' => $keyData->display_on_dashboard, + // 'display_on_popup' => $keyData->display_on_popup, + // 'timestamp' => $item['ts'] ?? null, + // 'value' => $item['value'] ?? null, + // 'alert' => $alert // ✅ Display alert status + // ]; + // } + // } + // } + + // $response[] = [ + // 'device_id' => (string) $device->id, + // 'device_profile_name' => (string) $device->deviceProfile->name, + // 'asset_id' => (string) $device->asset_id, + // 'device_profile_id' => (string) $device->device_profile_id, + // 'telemetry' => $telemetry, + // ]; + // } + + // return response()->json(['telemetry' => $response]); + // } + + // public function telemetryDataAsset(Request $request) + // { + // Log::info("Received telemetryDataAsset request.", $request->all()); + + // $validator = Validator::make($request->all(), [ + // 'asset_id' => 'required|string', + // 'startTs' => 'nullable|string', + // 'endTs' => 'nullable|string', + // ]); + + // if ($validator->fails()) { + // Log::error("Validation failed: " . $validator->errors()->first()); + // return jsonResponseWithErrorMessage($validator->errors()->first(), 400); + // } + + // $assetId = $request->input('asset_id'); + // $startTs = $request->input('startTs') ?: now()->subHours(24)->timestamp * 1000; // Default: last 24 hrs + // $endTs = $request->input('endTs') ?: now()->timestamp * 1000; + + // Log::info("Telemetry time range: Start => {$startTs}, End => {$endTs}"); + + // // Fetch devices associated with the asset + // $devices = Device::with('deviceProfile') + // ->where('asset_id', $assetId) + // ->get(); + + // if ($devices->isEmpty()) { + // Log::warning("No devices found for asset ID: {$assetId}"); + // return response()->json(['error' => 'No devices found for the asset'], 404); + // } + + // Log::info("Found " . $devices->count() . " devices for asset ID: {$assetId}"); + + // $response = []; + + // foreach ($devices as $device) { + // $telemetry = []; + + // Log::info("Processing device ID: {$device->id}"); + + // // Fetch telemetry keys + // $keysData = TimeseriesKeyMaster::where('device_profile_xid', $device->device_profile_id) + // ->where(function ($query) { + // $query->where('display_on_dashboard', true) + // ->orWhere('display_on_popup', true); + // }) + // ->get(['key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']); + + // Log::info("Fetched " . $keysData->count() . " telemetry keys for device ID: {$device->id}"); + + // $keyNames = $keysData->pluck('key_name')->toArray(); + + // // Fetch telemetry data + // $telemetryResponse = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTs, $endTs); + + // Log::info("Fetched telemetry data for device ID: {$device->id}"); + + // // Fetch alarms for the device and map by telemetry key + // $alarmMap = $this->getDeviceAlarmsForTelemetry($device->id); + // Log::info("Fetched alarms for device ID: {$device->id}", $alarmMap); + + // foreach ($keysData as $keyData) { + // $keyName = $keyData->key_name; + + // if (isset($telemetryResponse[$keyName])) { + // foreach ($telemetryResponse[$keyName] as $item) { + // // Check if the telemetry key has an alarm + // $alert = isset($alarmMap[$keyName]); + + // $telemetry[] = [ + // 'key_name' => $keyName, + // 'display_name' => $keyData->display_name, + // 'display_on_dashboard' => $keyData->display_on_dashboard, + // 'display_on_popup' => $keyData->display_on_popup, + // 'timestamp' => $item['ts'] ?? null, + // 'value' => $item['value'] ?? null, + // 'alert' => $alert // ✅ Display alert status + // ]; + // } + // } + // } + + // $response[] = [ + // 'device_id' => (string) $device->id, + // 'device_profile_name' => (string) $device->deviceProfile->name, + // 'asset_id' => (string) $device->asset_id, + // 'device_profile_id' => (string) $device->device_profile_id, + // 'telemetry' => $telemetry, + // ]; + + // Log::info("Processed telemetry for device ID: {$device->id}"); + // } + + // Log::info("Telemetry data successfully generated for asset ID: {$assetId}"); + + // return response()->json(['telemetry' => $response]); + // } + public function telemetryDataAsset(Request $request) { + Log::info("Received telemetryDataAsset request.", $request->all()); + $validator = Validator::make($request->all(), [ 'asset_id' => 'required|string', 'startTs' => 'nullable|string', @@ -34,12 +372,15 @@ class TelemetryController extends Controller ]); if ($validator->fails()) { + Log::error("Validation failed: " . $validator->errors()->first()); return jsonResponseWithErrorMessage($validator->errors()->first(), 400); } $assetId = $request->input('asset_id'); - $startTs = $request->input('startTs') ?: null; - $endTs = $request->input('endTs') ?: null; + $startTs = $request->input('startTs') ?: now()->subHours(24)->timestamp * 1000; // Default: last 24 hrs + $endTs = $request->input('endTs') ?: now()->timestamp * 1000; + + Log::info("Telemetry time range: Start => {$startTs}, End => {$endTs}"); // Fetch devices associated with the asset $devices = Device::with('deviceProfile') @@ -47,34 +388,45 @@ class TelemetryController extends Controller ->get(); if ($devices->isEmpty()) { + Log::warning("No devices found for asset ID: {$assetId}"); return response()->json(['error' => 'No devices found for the asset'], 404); } + Log::info("Found " . $devices->count() . " devices for asset ID: {$assetId}"); + $response = []; foreach ($devices as $device) { $telemetry = []; + Log::info("Processing device ID: {$device->id}"); + + // Fetch telemetry keys where display_on_dashboard is true $keysData = TimeseriesKeyMaster::where('device_profile_xid', $device->device_profile_id) - ->where(function ($query) { - $query->where('display_on_dashboard', true) - ->orWhere('display_on_popup', true); - }) + ->where('display_on_dashboard', true) // ✅ Only fetch keys where display_on_dashboard is true ->get(['key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']); + Log::info("Fetched " . $keysData->count() . " telemetry keys for device ID: {$device->id}"); + $keyNames = $keysData->pluck('key_name')->toArray(); - // Log key names for debugging - // Log::info('Key Names for Device', ['device_id' => $device->id, 'key_names' => $keyNames]); - // Fetch telemetry data $telemetryResponse = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTs, $endTs); + Log::info("Fetched telemetry data for device ID: {$device->id}"); + + // Fetch alarms for the device and map by telemetry key + $alarmMap = $this->getDeviceAlarmsForTelemetry($device->id); + Log::info("Fetched alarms for device ID: {$device->id}", $alarmMap); + foreach ($keysData as $keyData) { $keyName = $keyData->key_name; if (isset($telemetryResponse[$keyName])) { foreach ($telemetryResponse[$keyName] as $item) { + // Check if the telemetry key has an alarm + $alert = isset($alarmMap[$keyName]); + $telemetry[] = [ 'key_name' => $keyName, 'display_name' => $keyData->display_name, @@ -82,6 +434,7 @@ class TelemetryController extends Controller 'display_on_popup' => $keyData->display_on_popup, 'timestamp' => $item['ts'] ?? null, 'value' => $item['value'] ?? null, + 'alert' => $alert // ✅ Display alert status ]; } } @@ -92,14 +445,91 @@ class TelemetryController extends Controller 'device_profile_name' => (string) $device->deviceProfile->name, 'asset_id' => (string) $device->asset_id, 'device_profile_id' => (string) $device->device_profile_id, - 'telemetry' => $telemetry, + 'telemetry' => array_values($telemetry), // Reset array index ]; + + Log::info("Processed telemetry for device ID: {$device->id}"); } + Log::info("Telemetry data successfully generated for asset ID: {$assetId}"); + return response()->json(['telemetry' => $response]); } + + + + private function getDeviceAlarmsForTelemetry($deviceId) + { + Log::info("Fetching alarms for device: {$deviceId}"); + + $pageSize = 1000; + $page = 0; + + // Fetch ThingsBoard token + $token = $this->alarmService->getToken(); + if (!$token) { + Log::error("Failed to fetch ThingsBoard token."); + return []; + } + Log::info("Token fetched successfully."); + + $baseUrl = env('THINGSBOARD_URL'); + + $endTime = now()->timestamp * 1000; // Current time in ms + $startTime = now()->subHours(24)->timestamp * 1000; // 24 hours ago in ms + + Log::info("Time range: Start => {$startTime}, End => {$endTime}"); + + // Fetch alarms from ThingsBoard API + try { + $response = Http::withHeaders([ + 'Authorization' => "Bearer $token", + 'Accept' => 'application/json', + ])->get("$baseUrl/api/v2/alarms", [ + 'statusList' => 'ACTIVE', + 'severityList' => 'CRITICAL,MAJOR,MINOR,WARNING', + 'pageSize' => $pageSize, + 'page' => $page, + 'startTime' => $startTime, + 'endTime' => $endTime, + 'sortProperty' => 'createdTime', + 'sortOrder' => 'DESC', + 'originator' => $deviceId // Filter by device ID + ]); + + if (!$response->successful()) { + Log::error("Failed to fetch alarms. Status: " . $response->status()); + return []; + } + + // Parse the response + $alarms = $response->json()['data'] ?? []; + Log::info("Fetched " . count($alarms) . " alarms for device ID: {$deviceId}"); + + // Map alarms by `type` field + $alarmMap = []; + foreach ($alarms as $alarm) { + if (isset($alarm['type'])) { + $alarmMap[$alarm['type']] = true; + } + } + + Log::info("Mapped alarm types: ", $alarmMap); + + return $alarmMap; + } catch (\Exception $e) { + Log::error("Error fetching alarms: " . $e->getMessage()); + return []; + } + } + + + + + + // public function telemetryDataDevice(Request $request) // { // try { @@ -265,6 +695,8 @@ class TelemetryController extends Controller $token ); + + if (!is_array($telemetryResponse)) { throw new \Exception("Invalid telemetry data format received from service"); } diff --git a/app/Http/Controllers/AlarmControllerCommon.php b/app/Http/Controllers/AlarmControllerCommon.php index 5c3d43d..53320bb 100644 --- a/app/Http/Controllers/AlarmControllerCommon.php +++ b/app/Http/Controllers/AlarmControllerCommon.php @@ -6,9 +6,13 @@ use App\Services\AlarmService; use Carbon\Carbon; use Illuminate\Support\Facades\Log; use Exception; +use App\Models\Device; use Illuminate\Support\Facades\Http; - +use Illuminate\Support\Facades\Validator; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use App\Models\User; +use Tymon\JWTAuth\Facades\JWTAuth; class AlarmControllerCommon extends Controller { @@ -182,4 +186,125 @@ class AlarmControllerCommon extends Controller return jsonResponseWithErrorMessage($e->getMessage(), 500); } } + + + + + public function getDeviceAlarms(Request $request) + { + $validator = Validator::make($request->all(), [ + 'device_id' => 'required|string', + 'pageSize' => 'nullable|integer', + 'page' => 'nullable|integer', + ]); + + // Handle validation failure + if ($validator->fails()) { + return response()->json(['error' => $validator->errors()->first()], 400); + } + + // Get the device ID from the request + $deviceId = $request->input('device_id'); + $pageSize = $request->input('pageSize', 1000); + $page = $request->input('page', 0); + + // Fetch ThingsBoard token + $token = $this->alarmService->getToken(); + + if (!$token) { + return response()->json(['error' => 'Failed to fetch ThingsBoard token'], 401); + } + + $baseUrl = env('THINGSBOARD_URL'); + + // Get timestamps for the past 24 hours + $endTime = now()->timestamp * 1000; // Current time in ms + $startTime = now()->subHours(24)->timestamp * 1000; // 24 hours ago in ms + + // Fetch alarms from ThingsBoard API + $response = Http::withHeaders([ + 'Authorization' => "Bearer $token", + 'Accept' => 'application/json', + ])->get("$baseUrl/api/v2/alarms", [ + 'statusList' => 'ACTIVE', + 'severityList' => 'CRITICAL,MAJOR,MINOR,WARNING', + 'pageSize' => $pageSize, + 'page' => $page, + 'startTime' => $startTime, + 'endTime' => $endTime, + 'sortProperty' => 'createdTime', + 'sortOrder' => 'DESC' + ]); + + // If the request fails, return an error + if (!$response->successful()) { + return response()->json(['error' => 'Failed to fetch alarms'], $response->status()); + } + + $alarms = $response->json()['data'] ?? []; + + // Get the token from the Authorization header + $token = $request->header('Authorization'); + if ($token) { + $token = str_replace('Bearer ', '', $token); + + // Decode the token + try { + $user = JWTAuth::toUser($token); + } catch (\Exception $e) { + return response()->json(['error' => 'Invalid token'], 401); + } + + if (!$user) { + return response()->json(['error' => 'User not found in the token'], 401); + } + + // Retrieve the customer_id from the decoded user + $customerId = $user->customer_id; + } else { + return response()->json(['error' => 'Token not provided'], 400); + } + + // Alert initialization + $alert = false; + + // Retrieve the device data to check if it belongs to the logged-in user's customer_id + $device = Device::find($deviceId); + if (!$device) { + return response()->json(['error' => 'Device not found'], 404); + } + + // Check if the device's customer_id matches the logged-in user's customer_id + if ($device->customer_id !== $customerId) { + return response()->json(['error' => 'Device does not belong to the logged-in user\'s customer'], 403); + } + + // Get device display name + $deviceDisplayName = $device->display_name; + + // Iterate through the alarms to check if any match the criteria + foreach ($alarms as $alarm) { + // Match the device ID with the alarm's originator + $isDeviceMatch = isset($alarm['originator']['id']) && $alarm['originator']['id'] === $deviceId; + + // Match the assignee user ID with the logged-in user + $isUserMatch = isset($alarm['assignee']['id']['id']) && $alarm['assignee']['id']['id'] === $user->id; + + // Match the alarm type with the device's display name + $isTypeMatch = isset($alarm['type']) && $alarm['type'] === $deviceDisplayName; + + // Check if the device, user, and alarm type conditions are met + if ($isDeviceMatch && $isUserMatch && $isTypeMatch) { + $alert = true; + break; + } + } + + return response()->json([ + 'alert' => $alert, + 'alarms' => $alarms, + 'message' => $alert ? 'Alarm conditions met!' : 'No matching alarms found.' + ]); + } + } diff --git a/app/Services/CustomerInfoService.php b/app/Services/CustomerInfoService.php index a70e59d..bd40b46 100644 --- a/app/Services/CustomerInfoService.php +++ b/app/Services/CustomerInfoService.php @@ -121,6 +121,8 @@ class CustomerInfoService return $telemetry; } + + public function getTelemetryDataDevice($device, $keyNames, $startTs, $endTs) { @@ -354,8 +356,7 @@ class CustomerInfoService } } -<<<<<<< HEAD -======= + public function getToken() { @@ -387,5 +388,5 @@ class CustomerInfoService throw new Exception('Unable to authenticate with ThingsBoard: ' . $response->body()); } } ->>>>>>> 7c6c6a5243ba835684e8006b373cce70f901415f + } diff --git a/routes/customer_api.php b/routes/customer_api.php index b78f70a..c011629 100644 --- a/routes/customer_api.php +++ b/routes/customer_api.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use App\Http\Controllers\APIS\CustomerApi\UserAssetLinkController; use Tymon\JWTAuth\Facades\JWTAuth; +use App\Http\Controllers\AlarmControllerCommon; use App\Http\Controllers\APIS\CustomerApi\AuthController; use App\Http\Controllers\APIS\CustomerApi\CustomerDeviceInfoController; @@ -34,4 +35,7 @@ Route::post('/telemetry-data-device',[TelemetryController::class,'telemetryDataD Route::post('/store/report', [CustomerApiDownloadsController::class, 'storePdfData'])->name('store-report'); Route::post('/fetch/report', [CustomerApiDownloadsController::class, 'fetchReport'])->name('fetch-report'); Route::post('/destroy/report', [CustomerApiDownloadsController::class, 'destroyReport'])->name('destroy-report'); + + Route::post('/alarm', [AlarmControllerCommon::class, 'getDeviceAlarms'])->name('alarm.device'); + });