1780 lines
72 KiB
PHP
1780 lines
72 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\APIS\CustomerApi;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Asset;
|
|
use App\Models\Customer;
|
|
use App\Models\Device;
|
|
use App\Models\DeviceProfileMaster;
|
|
use App\Models\TimeseriesAlertMessage;
|
|
use App\Models\TimeseriesKeyMaster;
|
|
use App\Models\User;
|
|
use App\Models\UserAssetLink;
|
|
use App\Services\AdminService;
|
|
use App\Services\AlarmService;
|
|
use App\Services\CustomerInfoService;
|
|
use App\Services\TelemetryService;
|
|
use Exception;
|
|
use Illuminate\Container\Attributes\DB;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB as FacadesDB;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
class TelemetryController extends Controller
|
|
{
|
|
protected $customerInfoService, $alarmService, $adminService, $telemetryService;
|
|
|
|
// public function __construct(CustomerInfoService $customerInfoService)
|
|
// {
|
|
// $this->customerInfoService = $customerInfoService;
|
|
// }
|
|
public function __construct(CustomerInfoService $customerInfoService, AlarmService $alarmService, AdminService $adminService, TelemetryService $telemetryService)
|
|
{
|
|
$this->customerInfoService = $customerInfoService;
|
|
$this->alarmService = $alarmService;
|
|
$this->adminService = $adminService;
|
|
$this->telemetryService = $telemetryService;
|
|
}
|
|
|
|
|
|
|
|
// public function telemetryDataAsset(Request $request)
|
|
// {
|
|
// try {
|
|
// $token = readHeaderToken();
|
|
// $userId = $token['sub'];
|
|
// $customerId = User::where('id', $userId)->value('customer_id');
|
|
|
|
// // Validate request
|
|
// $validator = Validator::make($request->all(), [
|
|
// 'asset_id' => 'required|string',
|
|
// ]);
|
|
|
|
// if ($validator->fails()) {
|
|
// return jsonResponseWithErrorMessage($validator->errors()->first(), 400);
|
|
// }
|
|
|
|
// $assetId = $request->input('asset_id');
|
|
|
|
// // Verify asset ownership
|
|
// $assetLinkExists = UserAssetLink::where('user_id', $userId)
|
|
// ->where('asset_id', $assetId)
|
|
// ->exists();
|
|
|
|
// if (!$assetLinkExists) {
|
|
// return response()->json([
|
|
// 'error' => 'You are not authorized to access this asset',
|
|
// 'code' => 'UNAUTHORIZED_ACCESS'
|
|
// ], 403);
|
|
// }
|
|
|
|
// // Set timestamps in milliseconds for database query
|
|
// $endTsMs = now()->timestamp * 1000; // Current time in milliseconds
|
|
// $startTsMs = $endTsMs - (30 * 60 * 1000); // 30 minutes ago in milliseconds
|
|
|
|
// // Get devices with their telemetry keys
|
|
// $devices = Device::with([
|
|
// 'deviceProfile' => function($query) {
|
|
// $query->select(['id', 'name']); // Only select needed fields
|
|
// },
|
|
// 'timeseriesKeys' => function ($query) {
|
|
// $query->where('display_on_dashboard', true)
|
|
// ->orWhere('display_on_popup', true)
|
|
// ->select(['id', 'device_profile_xid', 'key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']);
|
|
// }
|
|
// ])->where('asset_id', $assetId)
|
|
// ->where('customer_id', $customerId)
|
|
// ->get();
|
|
|
|
// if ($devices->isEmpty()) {
|
|
// return response()->json([
|
|
// 'error' => 'No devices found for the specified asset',
|
|
// 'code' => 'DEVICES_NOT_FOUND'
|
|
// ], 404);
|
|
// }
|
|
|
|
// // Process telemetry data for each device
|
|
// $response = $devices->map(function ($device) use ($startTsMs, $endTsMs) {
|
|
// $keysData = $device->timeseriesKeys;
|
|
// $keyNames = $keysData->pluck('key_name')->toArray();
|
|
|
|
// // Get telemetry data for start and end times
|
|
// $startTelemetry = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTsMs, $startTsMs);
|
|
// $endTelemetry = $this->customerInfoService->getTelemetryData($device, $keyNames, $endTsMs, $endTsMs);
|
|
|
|
// $alarmMap = $this->getDeviceAlarmsForTelemetry($device->id);
|
|
// $alertMessages = TimeseriesAlertMessage::whereIn('timeseries_key_master_xid', $keysData->pluck('id'))
|
|
// ->orderBy('min_value', 'asc')
|
|
// ->get()
|
|
// ->groupBy('timeseries_key_master_xid');
|
|
|
|
// $telemetry = $keysData->map(function ($keyData) use ($startTelemetry, $endTelemetry, $alarmMap, $alertMessages) {
|
|
// $startData = collect($startTelemetry[$keyData->key_name] ?? [])->last();
|
|
// $endData = collect($endTelemetry[$keyData->key_name] ?? [])->last();
|
|
|
|
// $startValue = floatval($startData['value'] ?? 0);
|
|
// $endValue = floatval($endData['value'] ?? 0);
|
|
|
|
// // Determine trend
|
|
// $trend = null;
|
|
// if ($startValue > 0) {
|
|
// if ($endValue > $startValue) {
|
|
// $trend = 'upward';
|
|
// } elseif ($endValue < $startValue) {
|
|
// $trend = 'downward';
|
|
// } else {
|
|
// $trend = 'stable';
|
|
// }
|
|
// }
|
|
|
|
// // Format timestamp
|
|
// $currentData = $endData ?? $startData ?? ['ts' => now()->timestamp * 1000];
|
|
// $timestamp = is_float($currentData['ts']) || $currentData['ts'] > 9999999999
|
|
// ? intval($currentData['ts'] / 1000)
|
|
// : $currentData['ts'];
|
|
|
|
// // Color code logic
|
|
// $colorCode = null;
|
|
// if ($endValue == 0) {
|
|
// $colorCode = "grey";
|
|
// } elseif (isset($alertMessages[$keyData->id])) {
|
|
// foreach ($alertMessages[$keyData->id] as $alertMsg) {
|
|
// if ((is_null($alertMsg->min_value) || $endValue >= floatval($alertMsg->min_value)) &&
|
|
// (is_null($alertMsg->max_value) || $endValue <= floatval($alertMsg->max_value))) {
|
|
// $colorCode = $alertMsg->color_code;
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// return [
|
|
// 'key_name' => $keyData->key_name,
|
|
// 'display_name' => $keyData->display_name,
|
|
// 'display_on_dashboard' => $keyData->display_on_dashboard,
|
|
// 'display_on_popup' => $keyData->display_on_popup,
|
|
// 'timestamp' => $timestamp,
|
|
// 'value' => $endValue,
|
|
// 'start_value' => $startValue > 0 ? $startValue : null,
|
|
// 'trend' => $trend,
|
|
// 'alert' => isset($alarmMap[$keyData->key_name]),
|
|
// 'color_code' => $colorCode ?: 'green', // Default to green if no alerts match
|
|
// ];
|
|
// })->filter()->values();
|
|
|
|
// return [
|
|
// '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,
|
|
// 'time_range' => [
|
|
// 'startTs' => intval($startTsMs / 1000),
|
|
// 'endTs' => intval($endTsMs / 1000),
|
|
// ]
|
|
// ]);
|
|
|
|
// } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
// return response()->json([
|
|
// 'error' => 'User not found',
|
|
// 'code' => 'USER_NOT_FOUND'
|
|
// ], 404);
|
|
// } catch (\Exception $e) {
|
|
// Log::error('Telemetry data fetch failed: ' . $e->getMessage(), [
|
|
// 'exception' => $e,
|
|
// 'user_id' => $userId ?? null,
|
|
// 'asset_id' => $assetId ?? null
|
|
// ]);
|
|
|
|
// return response()->json([
|
|
// 'error' => 'Failed to fetch telemetry data',
|
|
// 'code' => 'SERVER_ERROR'
|
|
// ], 500);
|
|
// }
|
|
// }
|
|
|
|
public function telemetryDataAsset(Request $request)
|
|
{
|
|
try {
|
|
$token = readHeaderToken();
|
|
$userId = $token['sub'];
|
|
$customerId = User::where('id', $userId)->value('customer_id');
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
'asset_id' => 'required|string',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return jsonResponseWithErrorMessage($validator->errors()->first(), 400);
|
|
}
|
|
|
|
$assetId = $request->input('asset_id');
|
|
|
|
if (!$this->validateAssetAccess($userId, $assetId)) {
|
|
return response()->json([
|
|
'error' => 'You are not authorized to access this asset',
|
|
'code' => 'UNAUTHORIZED_ACCESS'
|
|
], 403);
|
|
}
|
|
|
|
$endTsMs = now()->timestamp * 1000;
|
|
$startTsMs = $endTsMs - (30 * 60 * 1000);
|
|
|
|
$devices = $this->getDevicesForAsset($assetId, $customerId);
|
|
|
|
if ($devices->isEmpty()) {
|
|
return response()->json([
|
|
'error' => 'No devices found for the specified asset',
|
|
'code' => 'DEVICES_NOT_FOUND'
|
|
], 404);
|
|
}
|
|
|
|
$response = $this->processDevicesTelemetry($devices, $startTsMs, $endTsMs);
|
|
|
|
return response()->json([
|
|
'telemetry' => $response,
|
|
'time_range' => [
|
|
'startTs' => intval($startTsMs / 1000),
|
|
'endTs' => intval($endTsMs / 1000),
|
|
]
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('Telemetry data fetch failed: ' . $e->getMessage());
|
|
return response()->json([
|
|
'error' => 'Failed to fetch telemetry data',
|
|
'code' => 'SERVER_ERROR'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
private function validateAssetAccess($userId, $assetId): bool
|
|
{
|
|
return UserAssetLink::where('user_id', $userId)
|
|
->where('asset_id', $assetId)
|
|
->exists();
|
|
}
|
|
|
|
private function getDevicesForAsset($assetId, $customerId)
|
|
{
|
|
return Device::with([
|
|
'deviceProfile:id,name',
|
|
'timeseriesKeys' => function ($query) {
|
|
$query->where('display_on_dashboard', true)
|
|
->orWhere('display_on_popup', true)
|
|
->select(['id', 'device_profile_xid', 'key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']);
|
|
}
|
|
])->where('asset_id', $assetId)
|
|
->where('customer_id', $customerId)
|
|
->get();
|
|
}
|
|
|
|
private function processDevicesTelemetry($devices, $startTsMs, $endTsMs)
|
|
{
|
|
return $devices->map(function ($device) use ($startTsMs, $endTsMs) {
|
|
$isActive = $this->checkDeviceActiveStatus($device);
|
|
$keysData = $device->timeseriesKeys;
|
|
$keyNames = $keysData->pluck('key_name')->toArray();
|
|
|
|
$startTelemetry = [];
|
|
$endTelemetry = [];
|
|
|
|
if ($isActive) {
|
|
$startTelemetry = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTsMs, $startTsMs);
|
|
$endTelemetry = $this->customerInfoService->getTelemetryData($device, $keyNames, $endTsMs, $endTsMs);
|
|
}
|
|
|
|
$alarmMap = $this->getDeviceAlarmsForTelemetry($device->id);
|
|
$alertMessages = $this->getAlertMessages($keysData);
|
|
|
|
$telemetry = $this->processTelemetryData($keysData, $startTelemetry, $endTelemetry, $alarmMap, $alertMessages, $isActive);
|
|
|
|
return [
|
|
'device_id' => (string) $device->id,
|
|
'device_name' => (string) $device->deviceProfile->name,
|
|
'device_profile_name' => (string) $device->deviceProfile->name,
|
|
'asset_id' => (string) $device->asset_id,
|
|
'device_profile_id' => (string) $device->device_profile_id,
|
|
'is_active' => $isActive,
|
|
'telemetry' => $telemetry,
|
|
];
|
|
});
|
|
}
|
|
|
|
private function checkDeviceActiveStatus($device): bool
|
|
{
|
|
$deviceInfoToken = $this->adminService->getToken();
|
|
if (!$deviceInfoToken) {
|
|
return false;
|
|
}
|
|
|
|
$baseUrl = env('THINGSBOARD_URL');
|
|
$deviceInfoResponse = Http::withHeaders([
|
|
'Authorization' => "Bearer $deviceInfoToken",
|
|
'Accept' => 'application/json',
|
|
])->get("{$baseUrl}api/device/info/{$device->id}");
|
|
|
|
if ($deviceInfoResponse->successful()) {
|
|
$deviceInfo = $deviceInfoResponse->json();
|
|
return $deviceInfo['active'] ?? false;
|
|
}
|
|
|
|
Log::error("Failed to fetch device info for device ID: {$device->id}");
|
|
return false;
|
|
}
|
|
|
|
private function getAlertMessages($keysData)
|
|
{
|
|
return TimeseriesAlertMessage::whereIn('timeseries_key_master_xid', $keysData->pluck('id'))
|
|
->orderBy('min_value', 'asc')
|
|
->get()
|
|
->groupBy('timeseries_key_master_xid');
|
|
}
|
|
|
|
private function processTelemetryData($keysData, $startTelemetry, $endTelemetry, $alarmMap, $alertMessages, $isActive)
|
|
{
|
|
return $keysData->map(function ($keyData) use ($startTelemetry, $endTelemetry, $alarmMap, $alertMessages, $isActive) {
|
|
$startValue = 0;
|
|
$endValue = 0;
|
|
$timestamp = now()->timestamp;
|
|
$trend = null;
|
|
|
|
if ($isActive) {
|
|
$startData = collect($startTelemetry[$keyData->key_name] ?? [])->last();
|
|
$endData = collect($endTelemetry[$keyData->key_name] ?? [])->last();
|
|
|
|
$startValue = floatval($startData['value'] ?? 0);
|
|
$endValue = floatval($endData['value'] ?? 0);
|
|
|
|
if ($startValue > 0) {
|
|
$trend = $this->determineTrend($endValue, $startValue);
|
|
}
|
|
|
|
$currentData = $endData ?? $startData ?? ['ts' => now()->timestamp * 1000];
|
|
$timestamp = $this->formatTimestamp($currentData['ts']);
|
|
}
|
|
|
|
$colorCode = $this->determineColorCode($endValue, $alertMessages, $keyData->id, $isActive);
|
|
|
|
return [
|
|
'key_name' => $keyData->key_name,
|
|
'display_name' => $keyData->display_name,
|
|
'display_on_dashboard' => $keyData->display_on_dashboard,
|
|
'display_on_popup' => $keyData->display_on_popup,
|
|
'timestamp' => $timestamp,
|
|
'value' => $isActive ? $endValue : 0,
|
|
'start_value' => $isActive && $startValue > 0 ? $startValue : null,
|
|
'trend' => $trend,
|
|
'alert' => isset($alarmMap[$keyData->key_name]),
|
|
'color_code' => $colorCode,
|
|
];
|
|
})->filter()->values();
|
|
}
|
|
|
|
private function determineTrend($endValue, $startValue): ?string
|
|
{
|
|
if ($endValue > $startValue) {
|
|
return 'upward';
|
|
} elseif ($endValue < $startValue) {
|
|
return 'downward';
|
|
}
|
|
return 'stable';
|
|
}
|
|
|
|
private function formatTimestamp($ts): int
|
|
{
|
|
return is_float($ts) || $ts > 9999999999
|
|
? intval($ts / 1000)
|
|
: $ts;
|
|
}
|
|
|
|
private function determineColorCode($endValue, $alertMessages, $keyId, $isActive): string
|
|
{
|
|
if (!$isActive) {
|
|
return 'grey';
|
|
}
|
|
|
|
if ($endValue == 0) {
|
|
return 'grey';
|
|
}
|
|
|
|
if (isset($alertMessages[$keyId])) {
|
|
foreach ($alertMessages[$keyId] as $alertMsg) {
|
|
if ((is_null($alertMsg->min_value) || $endValue >= floatval($alertMsg->min_value)) &&
|
|
(is_null($alertMsg->max_value) || $endValue <= floatval($alertMsg->max_value))) {
|
|
return $alertMsg->color_code;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 'green';
|
|
}
|
|
|
|
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 {
|
|
|
|
// $token = readHeaderToken();
|
|
// if (!$token) {
|
|
// return response()->json([
|
|
// 'success' => false,
|
|
// 'error' => 'Authorization token required'
|
|
// ], 401);
|
|
// }
|
|
|
|
// $validator = Validator::make($request->all(), [
|
|
// 'device_id' => 'required|string',
|
|
// 'startTs' => 'nullable|string',
|
|
// 'endTs' => 'nullable|string',
|
|
// ]);
|
|
|
|
// if ($validator->fails()) {
|
|
// return response()->json([
|
|
// 'success' => false,
|
|
// 'error' => $validator->errors()->first()
|
|
// ], 400);
|
|
// }
|
|
|
|
// $deviceId = $request->input('device_id');
|
|
// $startTs = $request->input('startTs') ?: null;
|
|
// $endTs = $request->input('endTs') ?: null;
|
|
|
|
// try {
|
|
// $deviceWithTelemetry = Device::with([
|
|
// 'deviceProfile',
|
|
// 'timeseriesKeys' => function ($query) {
|
|
// $query->select('key_name', 'display_name', 'device_profile_xid', 'display_on_dashboard','display_on_dashboard');
|
|
// }
|
|
// ])
|
|
// ->where('id', $deviceId)
|
|
// ->firstOrFail();
|
|
|
|
// $telemetryResponse = $this->customerInfoService->getTelemetryDataDevice(
|
|
// $deviceWithTelemetry,
|
|
// $deviceWithTelemetry->timeseriesKeys->pluck('key_name')->toArray(),
|
|
// $startTs,
|
|
// $endTs,
|
|
// $token
|
|
// );
|
|
|
|
// if (!is_array($telemetryResponse)) {
|
|
// throw new \Exception("Invalid telemetry data format received from service");
|
|
// }
|
|
|
|
// $telemetry = collect($telemetryResponse)
|
|
// ->flatMap(function ($items, $keyName) use ($deviceWithTelemetry) {
|
|
// $displayName = $deviceWithTelemetry->timeseriesKeys
|
|
// ->firstWhere('key_name', $keyName)?->display_name ?? $keyName;
|
|
|
|
// return collect($items)->map(function ($item) use ($keyName, $displayName) {
|
|
// return [
|
|
// 'key_name' => $keyName,
|
|
// 'timestamp' => $item['ts'] ?? null,
|
|
// 'value' => $item['value'] ?? null,
|
|
// 'display_name' => $displayName,
|
|
// 'display_on_dashboard'
|
|
// ];
|
|
// });
|
|
// })
|
|
// ->values()
|
|
// ->all();
|
|
|
|
// return response()->json([
|
|
// 'success' => true,
|
|
// 'telemetry' => [
|
|
// 'device_id' => (string) $deviceWithTelemetry->id,
|
|
// 'device_name' => $deviceWithTelemetry->name,
|
|
// 'device_profile_name' => $deviceWithTelemetry->deviceProfile->name,
|
|
// 'device_profile_id' => (string) $deviceWithTelemetry->device_profile_id,
|
|
// 'telemetry_data' => $telemetry,
|
|
// ]
|
|
// ], 200);
|
|
// } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
// return response()->json([
|
|
// 'success' => false,
|
|
// 'error' => 'Device not found'
|
|
// ], 404);
|
|
// } catch (\Exception $e) {
|
|
// return response()->json([
|
|
// 'success' => false,
|
|
// 'error' => 'Failed to fetch telemetry data',
|
|
// 'details' => config('app.debug') ? $e->getMessage() : null
|
|
// ], 503);
|
|
// }
|
|
// } catch (\Exception $e) {
|
|
// return response()->json([
|
|
// 'success' => false,
|
|
// 'error' => 'Internal server error',
|
|
// 'details' => config('app.debug') ? $e->getMessage() : null
|
|
// ], 500);
|
|
// }
|
|
// }
|
|
|
|
public function telemetryDataDevice(Request $request)
|
|
{
|
|
try {
|
|
$token = readHeaderToken();
|
|
$customerId = User::where('id', $token['sub'])->value('customer_id');
|
|
|
|
Log::info('Telemetry request received', ['request_data' => $request->all()]);
|
|
|
|
if (!$token) {
|
|
Log::warning('Unauthorized access attempt: Missing token');
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => 'Authorization token required'
|
|
], 401);
|
|
}
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
'device_id' => 'required|string',
|
|
'startTs' => 'nullable|string',
|
|
'endTs' => 'nullable|string',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
Log::error('Validation failed', ['errors' => $validator->errors()]);
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => $validator->errors()->first()
|
|
], 400);
|
|
}
|
|
|
|
$deviceId = $request->input('device_id');
|
|
$startTs = $request->input('startTs') ?: null;
|
|
$endTs = $request->input('endTs') ?: null;
|
|
|
|
$device = $this->getDeviceWithTelemetryKeys($deviceId, $customerId);
|
|
$displayKeys = $device->timeseriesKeys->pluck('key_name')->toArray();
|
|
$deviceProfileName = strtolower($device->deviceProfile->name ?? '');
|
|
|
|
Log::info('Device profile and keys retrieved', [
|
|
'device_profile' => $deviceProfileName,
|
|
'display_keys' => $displayKeys
|
|
]);
|
|
|
|
// Check pressure value for specific device profiles
|
|
$pressureActive = $this->checkPressureValue(
|
|
$device,
|
|
$deviceProfileName,
|
|
$displayKeys,
|
|
$startTs,
|
|
$endTs
|
|
);
|
|
|
|
$telemetryResponse = $this->customerInfoService->getTelemetryDataDevice(
|
|
$device,
|
|
$displayKeys,
|
|
$startTs,
|
|
$endTs,
|
|
$token
|
|
);
|
|
|
|
if (!is_array($telemetryResponse)) {
|
|
Log::error('Invalid telemetry data format received');
|
|
throw new \Exception("Invalid telemetry data format received from service");
|
|
}
|
|
|
|
$filteredResponse = $this->filterTelemetryResponse($telemetryResponse, $displayKeys, $pressureActive);
|
|
$telemetry = $this->formatDeviceTelemetry($filteredResponse, $device);
|
|
|
|
Log::info('Telemetry response successfully generated', ['device_id' => $deviceId]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'telemetry' => [
|
|
'device_id' => (string) $device->id,
|
|
'device_name' => $device->name,
|
|
'device_profile_name' => $device->deviceProfile->name,
|
|
'device_profile_id' => (string) $device->device_profile_id,
|
|
'pressure_value' => $pressureActive,
|
|
'telemetry_data' => $telemetry,
|
|
]
|
|
], 200);
|
|
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
|
|
Log::error('Device not found', ['device_id' => $deviceId ?? null]);
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => 'Device not found'
|
|
], 404);
|
|
} catch (\Exception $e) {
|
|
Log::critical('Internal server error', ['error' => $e->getMessage()]);
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => 'Internal server error',
|
|
'details' => config('app.debug') ? $e->getMessage() : null
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
private function getDeviceWithTelemetryKeys($deviceId, $customerId)
|
|
{
|
|
return Device::with([
|
|
'deviceProfile',
|
|
'timeseriesKeys' => function ($query) {
|
|
$query->where(function ($q) {
|
|
$q->where('display_on_dashboard', true)
|
|
->orWhere('display_on_popup', true);
|
|
})
|
|
->select('key_name', 'display_name', 'device_profile_xid', 'display_on_dashboard', 'display_on_popup');
|
|
}
|
|
])
|
|
->where('id', $deviceId)
|
|
->where('customer_id', $customerId)
|
|
->firstOrFail();
|
|
}
|
|
|
|
private function checkPressureValue($device, $deviceProfileName, $displayKeys, $startTs, $endTs)
|
|
{
|
|
$pressureKey = 'Pressure_value';
|
|
$pressureActive = false;
|
|
|
|
// Check if the device has "Gas Engine Profile" or "Engine Profile" in its profile name
|
|
if (strpos($deviceProfileName, 'gas engine profile') !== false ||
|
|
strpos($deviceProfileName, 'engine profile') !== false) {
|
|
|
|
$token = readHeaderToken();
|
|
$pressureResponse = $this->customerInfoService->getTelemetryDataDevice(
|
|
$device,
|
|
[$pressureKey],
|
|
$startTs,
|
|
$endTs,
|
|
$token
|
|
);
|
|
|
|
if (isset($pressureResponse[$pressureKey]) && is_array($pressureResponse[$pressureKey])) {
|
|
foreach ($pressureResponse[$pressureKey] as $pressureData) {
|
|
if (!empty($pressureData['value']) && floatval($pressureData['value']) > 0) {
|
|
$pressureActive = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $pressureActive;
|
|
}
|
|
|
|
private function filterTelemetryResponse($telemetryResponse, $displayKeys, $pressureActive)
|
|
{
|
|
// Filter telemetry data based on display keys
|
|
$filteredResponse = array_intersect_key($telemetryResponse, array_flip($displayKeys));
|
|
|
|
// Add Pressure key if condition is met
|
|
$pressureKey = 'Pressure_value';
|
|
if ($pressureActive && isset($telemetryResponse[$pressureKey])) {
|
|
$filteredResponse[$pressureKey] = $telemetryResponse[$pressureKey];
|
|
}
|
|
|
|
return $filteredResponse;
|
|
}
|
|
|
|
private function formatDeviceTelemetry($filteredResponse, $device)
|
|
{
|
|
return collect($filteredResponse)
|
|
->flatMap(function ($items, $keyName) use ($device) {
|
|
$keyData = $device->timeseriesKeys->firstWhere('key_name', $keyName);
|
|
|
|
return collect($items)->map(function ($item) use ($keyName, $keyData) {
|
|
return [
|
|
'key_name' => $keyName,
|
|
'timestamp' => $item['ts'] ?? null,
|
|
'value' => $item['value'] ?? null,
|
|
'display_name' => $keyData->display_name ?? $keyName,
|
|
'display_on_dashboard' => $keyData->display_on_dashboard ?? false,
|
|
'display_on_popup' => $keyData->display_on_popup ?? false
|
|
];
|
|
});
|
|
})
|
|
->values()
|
|
->all();
|
|
}
|
|
|
|
public function convertToUserTimezone($utcDatetime, $userTimezone = 'Asia/Kolkata', $format = 'd-M-Y H:i:s')
|
|
{
|
|
return Carbon::parse($utcDatetime, 'UTC')
|
|
->setTimezone($userTimezone)
|
|
->format($format);
|
|
}
|
|
|
|
public function entityQuery(){
|
|
try {
|
|
$token = readHeaderToken();
|
|
|
|
// Retrieve devices of user
|
|
$deviceIds = $this->getUserDeviceIds($token['sub']);
|
|
|
|
// Retrieve required timeseries of devices
|
|
$timeseriesKeys = $this->getAllDashboardTimeseriesKeys();
|
|
|
|
$entityQuery = $this->customerInfoService->fetchEntityQuery($deviceIds, $timeseriesKeys);
|
|
|
|
// Ensure the response is converted to an array if it's a JsonResponse
|
|
$data = $entityQuery instanceof \Illuminate\Http\JsonResponse ? $entityQuery->getData(true) : $entityQuery;
|
|
|
|
$timeseriesKeyMap = $this->getTimeseriesKeysByProfile();
|
|
|
|
// Process the array and format the output
|
|
$formatted = [
|
|
'success' => true,
|
|
'data' => collect($data['data'])->map(function ($device) use ($timeseriesKeyMap) {
|
|
$deviceType = $device['latest']['ENTITY_FIELD']['type']['value'] ?? null;
|
|
$deviceProfileId = DeviceProfileMaster::where('name', $deviceType)->select('id')->first();
|
|
$allTimeseries = $device['latest']['TIME_SERIES'] ?? [];
|
|
|
|
// Step 2: Get allowed keys for this device type
|
|
$allowedKeys = $timeseriesKeyMap[$deviceProfileId['id']] ?? [];
|
|
|
|
// Step 3: Filter timeseries to only include allowed keys
|
|
$filteredTimeseries = collect($allTimeseries)
|
|
->only($allowedKeys)
|
|
->toArray();
|
|
|
|
return [
|
|
'deviceId' => $device['entityId']['id'] ?? null,
|
|
'deviceName' => $device['latest']['ENTITY_FIELD']['name']['value'] ?? null,
|
|
'deviceProfileId' => $deviceProfileId['id'] ?? null,
|
|
'deviceType' => $deviceType,
|
|
'timeseries' => $filteredTimeseries,
|
|
];
|
|
})->toArray()
|
|
];
|
|
|
|
return response()->json($formatted);
|
|
|
|
} catch(Exception $e){
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
private function getUserDeviceIds($userId)
|
|
{
|
|
return UserAssetLink::with('asset.devices')
|
|
->where('user_id', $userId)
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->pluck('id')
|
|
->toArray();
|
|
}
|
|
|
|
private function getAllDashboardTimeseriesKeys()
|
|
{
|
|
return TimeseriesKeyMaster::where('display_on_dashboard', 1)
|
|
->orWhere('display_on_popup', 1)
|
|
->get()
|
|
->pluck('key_name')
|
|
->flatten()
|
|
->toArray();
|
|
}
|
|
|
|
private function getTimeseriesKeysByProfile()
|
|
{
|
|
return TimeseriesKeyMaster::where('display_on_dashboard', 1)
|
|
->orWhere('display_on_popup', 1)
|
|
->get()
|
|
->groupBy('device_profile_xid')
|
|
->map(function ($group) {
|
|
return $group->pluck('key_name')->toArray();
|
|
});
|
|
}
|
|
|
|
public function userAssetsNew(){
|
|
try {
|
|
$token = readHeaderToken();
|
|
$userId = $token['sub'];
|
|
|
|
// Set cache key per user
|
|
$cacheKey = "user_assets_health_{$userId}";
|
|
|
|
// Cache the response for 60 seconds
|
|
$formattedData = Cache::remember($cacheKey, now()->addSeconds(value: 60), function () use ($userId) {
|
|
$assetDeviceListing = UserAssetLink::with('asset.devices')
|
|
->where(['user_id' => $userId, 'active' => 1])
|
|
->get();
|
|
|
|
return $assetDeviceListing->map(function ($link) {
|
|
$asset = $link->asset;
|
|
$deviceHealthStatuses = [];
|
|
|
|
$devicesData = $asset->devices->map(function ($device) use (&$deviceHealthStatuses) {
|
|
$deviceType = $device->type;
|
|
$telemetryValues = $this->getHealthConditionTelemetry($device);
|
|
$deviceHealth = $deviceType == 'Torque' ? 'green' : $this->telemetryService->getDeviceHealth($telemetryValues);
|
|
$deviceHealthStatuses[] = $deviceHealth;
|
|
|
|
return [
|
|
'deviceId' => $device->id,
|
|
'deviceName' => $device->label,
|
|
'deviceHealth' => $deviceHealth
|
|
];
|
|
})->values();
|
|
|
|
return [
|
|
'assetId' => $asset->id,
|
|
'assetName' => $asset->name,
|
|
'assetHealth' => $deviceHealthStatuses ? $this->telemetryService->getAssetHealth($deviceHealthStatuses) : null,
|
|
'devices' => $devicesData
|
|
];
|
|
});
|
|
});
|
|
|
|
return response()->json(['success' => true, 'data' => $formattedData]);
|
|
|
|
} catch(Exception $e){
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
private function getHealthConditionTelemetry($device)
|
|
{
|
|
$timeseriesKeys = TimeseriesKeyMaster::where('display_on_health_condition', 1)
|
|
->where('device_profile_xid', $device->device_profile_id)
|
|
->pluck('key_name')
|
|
->implode(',');
|
|
|
|
$telemetryValue = $this->customerInfoService->fetchTelemetryData($device->id, $timeseriesKeys);
|
|
$data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;
|
|
|
|
$transformedTelemetry = [];
|
|
if (!empty($data) && is_array($data)) {
|
|
foreach ($data as $key => $items) {
|
|
foreach ($items as $item) {
|
|
$transformedTelemetry[] = [
|
|
'key_name' => $key,
|
|
'value' => $item['value']
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $transformedTelemetry;
|
|
}
|
|
|
|
public function customerDeviceInfoNew()
|
|
{
|
|
try {
|
|
$token = readHeaderToken();
|
|
$cacheKey = 'device_info_' . $token['sub'];
|
|
|
|
// Cache the entire response for 15 minutes
|
|
// $response = Cache::remember($cacheKey, now()->addMinutes(value: 15), function () use ($token) {
|
|
$devices = UserAssetLink::with('asset.devices')
|
|
->where(['user_id' => $token['sub'], 'active' => 1])
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->unique('id');
|
|
|
|
$good = $moderate = $bad = 0;
|
|
$deviceIds = $devices->pluck('id')->toArray();
|
|
|
|
if (!empty($deviceIds)) {
|
|
foreach ($deviceIds as $deviceId) {
|
|
$device = Device::find($deviceId);
|
|
if ($device) {
|
|
$deviceType = $device->type;
|
|
$telemetryValues = $this->getHealthConditionTelemetry($device);
|
|
$deviceHealth = $deviceType == 'Torque' ? 'green' : $this->telemetryService->getDeviceHealth($telemetryValues);
|
|
|
|
match ($deviceHealth) {
|
|
'green' => $good++,
|
|
'orange' => $moderate++,
|
|
default => $bad++
|
|
};
|
|
}
|
|
}
|
|
|
|
$deviceCount = $this->customerInfoService->getDevicesCount($deviceIds);
|
|
$alarms = $this->customerInfoService->fetchDeviceAlarms($deviceIds);
|
|
}
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'good' => $good,
|
|
'moderate' => $moderate,
|
|
'bad' => $bad,
|
|
'total' => $deviceCount['totalDevices'] ?? 0,
|
|
'active' => $deviceCount['activeDevices'] ?? 0,
|
|
'alarm' => $alarms['count'] ?? 0
|
|
];
|
|
// });
|
|
|
|
return response()->json($response);
|
|
|
|
} catch (Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function getActiveDevicesList() {
|
|
try {
|
|
$token = readHeaderToken();
|
|
$userId = $token['sub'];
|
|
|
|
$assetDeviceLinks = UserAssetLink::with('asset.devices')
|
|
->where(['user_id' => $userId, 'active' => 1])
|
|
->get();
|
|
|
|
// Maintain order as per userAssetsNew
|
|
$orderedDeviceIds = [];
|
|
|
|
foreach ($assetDeviceLinks as $link) {
|
|
foreach ($link->asset->devices as $device) {
|
|
$orderedDeviceIds[] = $device->id;
|
|
}
|
|
}
|
|
|
|
// Remove duplicates while keeping order
|
|
$orderedDeviceIds = array_values(array_unique($orderedDeviceIds));
|
|
|
|
// Fetch only active devices
|
|
$activeDevices = $this->customerInfoService->getActiveDevicesList($orderedDeviceIds);
|
|
$activeDeviceIds = collect($activeDevices['activeDevices'])->pluck('entityId')->pluck('id')->toArray();
|
|
|
|
// Intersect ordered list with active IDs while preserving order
|
|
$orderedActiveDeviceIds = array_values(array_filter($orderedDeviceIds, function ($id) use ($activeDeviceIds) {
|
|
return in_array($id, $activeDeviceIds);
|
|
}));
|
|
|
|
// Fetch device details
|
|
$getDevices = Device::with(['asset', 'customer'])
|
|
->whereIn('id', $orderedActiveDeviceIds)
|
|
->get(['id', 'name', 'label', 'asset_id', 'customer_id', 'type', 'created_at']);
|
|
|
|
// Maintain order
|
|
$deviceMap = $getDevices->keyBy('id');
|
|
$liveDevices = collect($orderedActiveDeviceIds)->map(function ($id) use ($deviceMap) {
|
|
$device = $deviceMap[$id] ?? null;
|
|
if (!$device) return null;
|
|
|
|
return [
|
|
'deviceId' => $device->id,
|
|
'assetName' => $device->asset->name ?? 'N/A',
|
|
'deviceName' => $device->label,
|
|
'deviceType' => $device->type,
|
|
'deviceCustomer' => $device->customer->title ?? 'N/A',
|
|
'deviceCreatedAt' => $device->created_at ?? 'N/A'
|
|
];
|
|
})->filter(); // remove nulls
|
|
|
|
// Count
|
|
$deviceCount = $this->customerInfoService->getDevicesCount($orderedDeviceIds);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'totalDevices' => $deviceCount['totalDevices'] ?? 0,
|
|
'activeDevices' => $deviceCount['activeDevices'] ?? 0,
|
|
'data' => $liveDevices
|
|
]);
|
|
} catch (Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public function getDeviceIndicators($assetId){
|
|
try {
|
|
$token = readHeaderToken();
|
|
$cacheKey = "device_indicators_{$token['sub']}_asset_{$assetId}";
|
|
|
|
// Cache the response for 60 seconds
|
|
$cachedData = Cache::remember($cacheKey, now()->addSeconds(value: 60), function () use ($token, $assetId) {
|
|
$assetDeviceListing = $this->getUserAssetLinkWithDevices($token['sub'], $assetId);
|
|
|
|
return $assetDeviceListing->map(function($link){
|
|
$asset = $link->asset;
|
|
$deviceData = $asset->devices->map(function($device){
|
|
$deviceProfile = $this->getDeviceWithProfile($device->id);
|
|
$deviceProfileId = $deviceProfile?->deviceProfile?->id;
|
|
$deviceProfileName = $deviceProfile?->deviceProfile?->name;
|
|
|
|
$timeseriesList = $this->getDashboardTimeseriesKeysForProfile($deviceProfileId);
|
|
$keyNameList = $timeseriesList->pluck('key_name')->implode(',');
|
|
$displayNameMap = $timeseriesList->pluck('display_name', 'key_name')->toArray();
|
|
|
|
$telemetryValue = $this->customerInfoService->fetchTelemetryData($device->id, $keyNameList);
|
|
$data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;
|
|
|
|
$transformedTelemetry = $this->processDeviceIndicators($data, $device->id, $device->type, $displayNameMap);
|
|
|
|
return [
|
|
'deviceId' => $device->id,
|
|
'deviceName' => $device->label,
|
|
'deviceType' => $deviceProfileName,
|
|
'deviceSensor' => $device->sensor,
|
|
'indicator' => $transformedTelemetry
|
|
];
|
|
})->values();
|
|
|
|
return [
|
|
'success' => true,
|
|
'data' => $deviceData
|
|
];
|
|
});
|
|
|
|
// return $assetLink;
|
|
});
|
|
|
|
return response()->json($cachedData);
|
|
|
|
} catch(Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
private function getUserAssetLinkWithDevices($userId = null, $assetId = null)
|
|
{
|
|
$query = UserAssetLink::with('asset.devices')
|
|
->where('user_id', $userId);
|
|
|
|
if ($assetId) {
|
|
$query->where('asset_id', $assetId);
|
|
}
|
|
|
|
return $query->get();
|
|
}
|
|
|
|
private function getDeviceWithProfile($deviceId)
|
|
{
|
|
return Device::with('deviceProfile')->find($deviceId);
|
|
}
|
|
|
|
private function getDashboardTimeseriesKeysForProfile($deviceProfileId)
|
|
{
|
|
return TimeseriesKeyMaster::where('display_on_dashboard', true)
|
|
->where('device_profile_xid', $deviceProfileId)
|
|
->orderBy('display_on_popup_sequence','asc')
|
|
->get(['key_name', 'display_name']);
|
|
}
|
|
|
|
private function processDeviceIndicators($data, $deviceId, $deviceType, $displayNameMap)
|
|
{
|
|
$transformedTelemetry = [];
|
|
|
|
if (!empty($data) && is_array($data)) {
|
|
foreach ($data as $key => $items) {
|
|
foreach ($items as $item) {
|
|
$color = $deviceType == 'Torque' ? 'green' : $this->determineIndicatorColor($key, $item['value']);
|
|
|
|
// Calculate average over past 6 hours
|
|
$averageVal = $this->calculateAverageOverPastHours($deviceId, $key, 6);
|
|
|
|
$transformedTelemetry[] = [
|
|
'display_name' => $displayNameMap[$key] ?? $key,
|
|
'value' => $this->telemetryService->getTypeWiseValue($key, $item['value']),
|
|
'averageVal' => $this->telemetryService->getTypeWiseValue($key, $averageVal),
|
|
'color' => $color
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $transformedTelemetry;
|
|
}
|
|
|
|
private function determineIndicatorColor($key, $value)
|
|
{
|
|
if ($key == "PowerLoss_value") {
|
|
if ($value > 5) {
|
|
return 'red';
|
|
} elseif ($value > 30) {
|
|
return 'orange';
|
|
}
|
|
return 'green';
|
|
}
|
|
|
|
if ($key == "GlobalLevel_value") {
|
|
if ($value > 7) {
|
|
return 'red';
|
|
} elseif ($value > 4) {
|
|
return 'orange';
|
|
}
|
|
return 'green';
|
|
}
|
|
|
|
if ($value > 70) {
|
|
return 'green';
|
|
} elseif ($value > 30) {
|
|
return 'orange';
|
|
}
|
|
return 'red';
|
|
}
|
|
|
|
private function calculateAverageOverPastHours($deviceId, $key, $hours = 6)
|
|
{
|
|
$ts['startTs'] = Carbon::now()->subHours($hours)->timestamp * 1000;
|
|
$ts['endTs'] = Carbon::now()->timestamp * 1000;
|
|
|
|
$pastValues = $this->customerInfoService->fetchTelemetryData($deviceId, $key, $ts);
|
|
|
|
$pastValTotal = 0;
|
|
$pastValTotalCount = 0;
|
|
|
|
if (!empty($pastValues)) {
|
|
foreach ($pastValues as $past) {
|
|
foreach ($past as $value) {
|
|
$pastValTotal += $value['value'];
|
|
$pastValTotalCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $pastValTotalCount > 0 ? round($pastValTotal / $pastValTotalCount, 2) : 0;
|
|
}
|
|
|
|
public function getAlerts($deviceId){
|
|
try {
|
|
$token = readHeaderToken();
|
|
$cacheKey = "device_alerts_{$token['sub']}_device_{$deviceId}";
|
|
|
|
if (!$this->validateUserHasAccessToDevice($token['sub'], $deviceId)) {
|
|
return response()->json(['success' => true, 'message' => 'Device not found'], 404);
|
|
}
|
|
|
|
// $cachedData = Cache::remember($cacheKey, now()->addHours(value: 1), function () use ($deviceId) {
|
|
$deviceParams = $this->getDeviceAlertParameters($deviceId);
|
|
|
|
$keyNameList = $deviceParams->pluck('key_name')->implode(',');
|
|
$displayNameMap = $deviceParams->pluck('display_name', 'key_name')->toArray();
|
|
|
|
$telemetryValue = $this->customerInfoService->fetchTelemetryData($deviceId, $keyNameList);
|
|
$data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;
|
|
|
|
$transformedTelemetry = [];
|
|
$dateTime = null;
|
|
|
|
if (!empty($data) && is_array($data)) {
|
|
foreach ($data as $key => $items) {
|
|
foreach ($items as $item) {
|
|
$alertPoints = $this->getAlertPointsForKey($key, $item['value'], $displayNameMap);
|
|
$dateTime = Carbon::createFromTimestamp($item['ts'] / 1000)->format('d-M-Y H:i:s');
|
|
|
|
if($alertPoints){
|
|
$transformedTelemetry[] = [
|
|
'display_name' => $displayNameMap[$key] ?? $key,
|
|
'alert_msg' => $alertPoints ?: ["No Alerts & Instructions"]
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'updated_time' => $this->telemetryService->convertToUserTimezone($dateTime),
|
|
'data' => $transformedTelemetry
|
|
];
|
|
// });
|
|
|
|
return response()->json($response);
|
|
|
|
} catch(Exception $e){
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
private function validateUserHasAccessToDevice($userId, $deviceId)
|
|
{
|
|
$userDevices = UserAssetLink::with('asset.devices')
|
|
->where('user_id', $userId)
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->unique('id');
|
|
|
|
$deviceIds = $userDevices->pluck('id')->toArray();
|
|
|
|
return in_array($deviceId, $deviceIds);
|
|
}
|
|
|
|
private function getDeviceAlertParameters($deviceId)
|
|
{
|
|
return TimeseriesKeyMaster::select('key_name', 'display_name')
|
|
->where('display_on_alerts', 1)
|
|
->whereHas('device', function ($query) use ($deviceId) {
|
|
$query->where('id', $deviceId);
|
|
})
|
|
->get();
|
|
}
|
|
|
|
private function getAlertPointsForKey($key, $value, $displayNameMap)
|
|
{
|
|
$displayName = $displayNameMap[$key] ?? $key;
|
|
$timeseriesId = TimeseriesKeyMaster::where('display_name', $displayName)->first('id');
|
|
|
|
if (!$timeseriesId) {
|
|
return [];
|
|
}
|
|
|
|
$fetchMsg = TimeseriesAlertMessage::where('timeseries_key_master_xid', $timeseriesId['id'])
|
|
->where('min_value', '<=', $value)
|
|
->where('max_value', '>=', $value)
|
|
->first(['alert_msg']);
|
|
|
|
return !empty($fetchMsg?->alert_msg) ? explode("\n", trim($fetchMsg->alert_msg)) : [];
|
|
}
|
|
|
|
public function getLiveDevice($deviceId){
|
|
try {
|
|
if (!$this->validateUserHasAccessToDevice(readHeaderToken()['sub'], $deviceId)) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => 'You are not authorized to access this device'
|
|
], 403);
|
|
}
|
|
|
|
$deviceType = Device::where('id', $deviceId)->first('type');
|
|
$deviceCount = $this->customerInfoService->getDevicesCount(["$deviceId"]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'active' => $deviceCount['activeDevices'] ? true : false,
|
|
'deviceType' => $deviceType->type
|
|
]);
|
|
|
|
} catch(Exception $e){
|
|
Log::error("Error checking device status: " . $e->getMessage(), ['device_id' => $deviceId]);
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function getGlobalIndicators($deviceId){
|
|
try {
|
|
$token = readHeaderToken();
|
|
$cacheKey = "global_indicators_{$token['sub']}_device_{$deviceId}";
|
|
|
|
if (!$this->validateUserHasAccessToDevice($token['sub'], $deviceId)) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => 'Device not found or you do not have access to it'
|
|
], 404);
|
|
}
|
|
|
|
// Cache the response for 60 seconds
|
|
$cachedData = Cache::remember($cacheKey, now()->addSeconds(value: 60), function () use ($deviceId) {
|
|
$deviceParams = $this->getPopupTimeseriesKeys($deviceId);
|
|
|
|
$keyNameList = $deviceParams->pluck('key_name')->implode(',');
|
|
$displayNameMap = $deviceParams->pluck('display_name', 'key_name')->toArray();
|
|
|
|
$telemetryValue = $this->customerInfoService->fetchTelemetryData($deviceId, $keyNameList);
|
|
$data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;
|
|
$deviceLiveStatus = $this->getLiveDevice($deviceId);
|
|
$deviceLiveStatus = $deviceLiveStatus instanceof \Illuminate\Http\JsonResponse ? $deviceLiveStatus->getData(true) : $deviceLiveStatus;
|
|
|
|
// Transform the data using our TelemetryService
|
|
$transformed = $this->telemetryService->transformTelemetryData($deviceId, $data, $displayNameMap, $deviceLiveStatus['active']);
|
|
|
|
return [
|
|
'success' => true,
|
|
'updated_time' => $transformed['dateTime'] ? $this->telemetryService->convertToUserTimezone($transformed['dateTime']) : null,
|
|
'data' => $transformed['telemetry']
|
|
];
|
|
});
|
|
|
|
return response()->json($cachedData);
|
|
|
|
} catch(Exception $e){
|
|
Log::error("Error fetching global indicators: " . $e->getMessage(), ['device_id' => $deviceId]);
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
private function getPopupTimeseriesKeys($deviceId)
|
|
{
|
|
return TimeseriesKeyMaster::select('key_name', 'display_name', 'display_on_popup_sequence')
|
|
->where('display_on_popup', 1)
|
|
->whereHas('device', function ($query) use ($deviceId) {
|
|
$query->where('id', $deviceId);
|
|
})
|
|
->orderBy('display_on_popup_sequence')
|
|
->get();
|
|
}
|
|
|
|
public function getTrends($deviceId)
|
|
{
|
|
try {
|
|
$token = readHeaderToken();
|
|
$cacheKey = "trends_{$token['sub']}_device_{$deviceId}";
|
|
|
|
$userDevices = UserAssetLink::with('asset.devices')
|
|
->where('user_id', $token['sub'])
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->unique('id');
|
|
$deviceIds = $userDevices->pluck('id')->toArray();
|
|
|
|
if (!in_array($deviceId, $deviceIds)) {
|
|
return response()->json(['success' => true, 'message' => 'Device not found'], 404);
|
|
}
|
|
|
|
// Cache the response for 60 seconds
|
|
$cachedData = Cache::remember($cacheKey, now()->addSeconds(value: 60), function () use ($deviceId) {
|
|
$dates = collect(range(0, 6))->map(function ($i) {
|
|
return Carbon::now()->subDays($i)->format('M d, Y');
|
|
})->reverse()->values()->toArray();
|
|
|
|
$graph1 = $graph2 = [];
|
|
foreach ($dates as $date) {
|
|
$dateTs[] = Carbon::createFromFormat('M d, Y', $date)->timestamp * 1000;
|
|
$ts['startTs'] = Carbon::createFromFormat('M d, Y', $date)->startOfDay()->timestamp * 1000;
|
|
$ts['endTs'] = Carbon::createFromFormat('M d, Y', $date)->endOfDay()->timestamp * 1000;
|
|
|
|
$deviceProfile = Device::with('deviceProfile')->find($deviceId);
|
|
$deviceProfileId = $deviceProfile?->deviceProfile?->id;
|
|
|
|
$parameters = parameters();
|
|
|
|
$value1 = $value2 = [];
|
|
$key1 = explode(',', $parameters[$deviceProfileId]['keyNameList1']);
|
|
$key2 = explode(',', $parameters[$deviceProfileId]['keyNameList2']);
|
|
|
|
// For $key1 array
|
|
if (count($key1) === 3) {
|
|
$x1[0] = TimeseriesKeyMaster::where('key_name', $key1[0])->first('display_name');
|
|
$x1[1] = TimeseriesKeyMaster::where('key_name', $key1[1])->first('display_name');
|
|
$x2 = array_key_exists(1, $key1) ? TimeseriesKeyMaster::where('key_name', $key1[2])->first('display_name') : null;
|
|
} else {
|
|
$x1 = TimeseriesKeyMaster::where('key_name', $key1[0])->first('display_name');
|
|
$x2 = array_key_exists(1, $key1) ? TimeseriesKeyMaster::where('key_name', $key1[1])->first('display_name') : null;
|
|
}
|
|
|
|
|
|
// For $key2 array
|
|
if (count($key2) === 3) {
|
|
$y1[0] = TimeseriesKeyMaster::where('key_name', $key2[0])->first('display_name');
|
|
$y1[1] = TimeseriesKeyMaster::where('key_name', $key2[1])->first('display_name');
|
|
$y2 = array_key_exists(1, $key2) ? TimeseriesKeyMaster::where('key_name', $key2[2])->first('display_name') : null;
|
|
} else {
|
|
$y1 = TimeseriesKeyMaster::where('key_name', $key2[0])->first('display_name');
|
|
$y2 = array_key_exists(1, $key2) ? TimeseriesKeyMaster::where('key_name', $key2[1])->first('display_name') : null;
|
|
}
|
|
|
|
if($key1[0] === 'PowerLoss_value' || $key1[0] === 'GlobalLevel_value'){
|
|
$min1 = 0;
|
|
$max1 = 10;
|
|
} else if($key1[0] === 'StaticTorque_value'){
|
|
$min1 = 0;
|
|
$max1 = 500000;
|
|
} else {
|
|
$min1 = 0;
|
|
$max1 = 100;
|
|
}
|
|
|
|
if($key2[0] === 'StaticPower_value'){
|
|
$min2 = 0;
|
|
$max2 = 500000;
|
|
} else if($key2[0] === 'TDN'){
|
|
$min2 = 0;
|
|
$max2 = 1500;
|
|
} else {
|
|
$min2 = 0;
|
|
$max2 = 100;
|
|
}
|
|
|
|
|
|
// $min1 = $key1[0] === 'PowerLoss_value' ? 0 : 0;
|
|
// $max1 = $key1[0] === 'PowerLoss_value' ? 10 : 100;
|
|
|
|
$telemetryValue1 = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, $parameters[$deviceProfileId]['keyNameList1'], $ts);
|
|
$trendsData1 = $telemetryValue1 instanceof \Illuminate\Http\JsonResponse ? $telemetryValue1->getData(true) : $telemetryValue1;
|
|
|
|
$telemetryValue2 = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, $parameters[$deviceProfileId]['keyNameList2'], $ts);
|
|
$trendsData2 = $telemetryValue2 instanceof \Illuminate\Http\JsonResponse ? $telemetryValue2->getData(true) : $telemetryValue2;
|
|
|
|
if($trendsData1){
|
|
foreach ($trendsData1 as $key => $trend) {
|
|
$displayName = TimeseriesKeyMaster::where('key_name', $key)->first('display_name');
|
|
foreach ($trend as $val) {
|
|
$value1[0][$displayName['display_name']][] = $this->telemetryService->getTypeWiseValue($key, $val['value']);
|
|
}
|
|
}
|
|
}
|
|
|
|
if($trendsData2){
|
|
foreach ($trendsData2 as $key => $trend) {
|
|
$displayName = TimeseriesKeyMaster::where('key_name', $key)->first('display_name');
|
|
foreach ($trend as $val) {
|
|
$value2[0][$displayName['display_name']][] = $this->telemetryService->getTypeWiseValue($key, $val['value']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$getLimit = Device::where('id', $deviceId)->select('speed_limit','torque_limit','power_limit')->first();
|
|
|
|
$graph1['y1'] = count($key1) === 3 ? ['name' => [$x1[0]['display_name'], $x1[1]['display_name']], 'min' => $min1, 'max' => $getLimit['torque_limit'] ?? 50000] : ['name' => [$x1['display_name']], 'min' => $min1, 'max' => $max1 ];
|
|
$graph1['y2'] = $x2 ? ['name' => [$x2['display_name']], 'min' => 0, 'max' => ($key1[0] === 'StaticTorque_value') ? ($getLimit['speed_limit'] ?? $max1) : $max1] : null;
|
|
$graph1[$date] = $value1;
|
|
|
|
$graph2['y1'] = count($key2) === 3 ? ['name' => [$y1[0]['display_name'], $y1[1]['display_name']], 'min' => $min2, 'max' => $getLimit['power_limit'] ?? 500000] : ['name' => [$y1['display_name']], 'min' => $min2, 'max' => $max2 ];
|
|
$graph2['y2'] = $y2 ? ['name' => [$y2['display_name']], 'min' => 0, 'max' => ($key2[0] === 'StaticPower_value') ? ($getLimit['speed_limit'] ?? $max2) : $max2] : null;
|
|
$graph2[$date] = $value2;
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'graph1' => $graph1,
|
|
'graph2' => $graph2,
|
|
];
|
|
});
|
|
|
|
return response()->json($cachedData);
|
|
|
|
} catch (Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function getCylinderSpecificIndicators($deviceId) {
|
|
try {
|
|
$token = readHeaderToken();
|
|
$cacheKey = "cylinder_specific_indicators_device_{$deviceId}";
|
|
|
|
$userDevices = UserAssetLink::with('asset.devices')
|
|
->where('user_id', $token['sub'])
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->unique('id');
|
|
$deviceIds = $userDevices->pluck('id')->toArray();
|
|
|
|
if (!in_array($deviceId, $deviceIds)) {
|
|
return response()->json(['success' => true, 'message' => 'Device not found'], 404);
|
|
}
|
|
|
|
// $data = Cache::remember($cacheKey, now()->addHours(value: 1), function () use ($deviceId) {
|
|
$device = Device::find($deviceId, ['device_profile_id', 'type']);
|
|
$profileId = $device->device_profile_id;
|
|
$isGasEngine = $device->type === 'Gas Engine';
|
|
|
|
$cylindersToShow = ['Compression Condition','Injection Condition','Bearing Condition','Condition of Cyl Moving Parts'];
|
|
if ($isGasEngine) {
|
|
$cylindersToShow[] = 'Misfiring';
|
|
}
|
|
|
|
$global = [
|
|
0 => 'Compression_valueInPercent',
|
|
1 => 'InjectionCondition_valueInPercent',
|
|
2 => 'Bearing_valueInPercent',
|
|
3 => 'BearingBis_valueInPercent',
|
|
4 => 'Misfiring_valueInPercent'
|
|
];
|
|
|
|
$firingOrderKeys = TimeseriesKeyMaster::where('display_firing_order', 1)
|
|
->where('device_profile_xid', $profileId)
|
|
->pluck('key_name')
|
|
->toArray();
|
|
|
|
$firingOrderData = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, implode(',', $firingOrderKeys));
|
|
$data = [];
|
|
|
|
foreach ($cylindersToShow as $index => $title) {
|
|
$cylinderKeys = TimeseriesKeyMaster::where('display_cylinder_specific', $index + 1)
|
|
->where('device_profile_xid', $profileId)
|
|
->pluck('key_name')
|
|
->toArray();
|
|
|
|
$globalKey = $global[$index];
|
|
$colorData = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, implode(',', $cylinderKeys));
|
|
$globalValue = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, $globalKey);
|
|
|
|
$globalRaw = $globalValue[$globalKey][0]['value'] ?? 0;
|
|
$globalValueColor = $globalRaw > 70 ? 'green' : ($globalRaw > 30 ? 'orange' : 'red');
|
|
|
|
$response = [];
|
|
$i = 1;
|
|
foreach ($firingOrderData as $orderKey => $values) {
|
|
$cylinderNum = $values[0]['value'] ?? 0;
|
|
$name = 'Cyl' . $cylinderNum;
|
|
|
|
$prefixMap = [
|
|
0 => 'Compression',
|
|
1 => 'InjectionCondition',
|
|
2 => 'Bearing',
|
|
3 => 'BearingBis',
|
|
4 => 'Misfiring'
|
|
];
|
|
|
|
$prefix = $prefixMap[$index];
|
|
$colorKey = "{$prefix}_cylinderValues_" . $i++;
|
|
|
|
$val = $colorData[$colorKey][0]['value'] ?? null;
|
|
$color = is_null($val) ? 'grey' : ($val > 70 ? 'green' : ($val > 30 ? 'orange' : 'red'));
|
|
|
|
$response[] = [
|
|
'name' => $name,
|
|
'value' => $val,
|
|
'color' => $color,
|
|
];
|
|
}
|
|
|
|
$data[] = [
|
|
'title' => $title,
|
|
'global' => [
|
|
'value' => $globalRaw,
|
|
'color' => $globalValueColor,
|
|
],
|
|
'data' => $response
|
|
];
|
|
}
|
|
|
|
$response = ['success' => true, 'data' => $data];
|
|
// });
|
|
|
|
return response()->json($response);
|
|
|
|
} catch (Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function getPeakPressure($deviceId) {
|
|
try {
|
|
$token = readHeaderToken();
|
|
$cacheKey = "peak_pressure_device_{$deviceId}";
|
|
|
|
$userDevices = UserAssetLink::with('asset.devices')
|
|
->where('user_id', $token['sub'])
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->unique('id');
|
|
$deviceIds = $userDevices->pluck('id')->toArray();
|
|
|
|
if (!in_array($deviceId, $deviceIds)) {
|
|
return response()->json(['success' => true, 'message' => 'Device not found'], 404);
|
|
}
|
|
|
|
// $data = Cache::remember($cacheKey, now()->addHours(value: 1), function () use ($deviceId) {
|
|
$device = Device::find($deviceId, ['device_profile_id', 'type']);
|
|
$profileId = $device->device_profile_id;
|
|
$pressureValKey = 'Pressure_value';
|
|
|
|
$pressureVal = $this->customerInfoService->fetchTelemetryData($deviceId, $pressureValKey);
|
|
if ($pressureVal[$pressureValKey][0]['value'] == 0) {
|
|
return ['success' => false, 'message' => 'No data available'];
|
|
}
|
|
|
|
$firingOrderKeys = TimeseriesKeyMaster::where('display_firing_order', 1)
|
|
->where('device_profile_xid', $profileId)
|
|
->pluck('key_name')
|
|
->toArray();
|
|
|
|
$cylinderKeys = TimeseriesKeyMaster::where('display_cylinder_specific', 6)
|
|
->where('device_profile_xid', $profileId)
|
|
->pluck('key_name')
|
|
->toArray();
|
|
|
|
$firingOrderData = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, implode(',', $firingOrderKeys));
|
|
$valData = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, implode(',', $cylinderKeys));
|
|
|
|
$i = 1;
|
|
$response = [];
|
|
|
|
foreach ($firingOrderData as $orderKey => $values) {
|
|
$cylinderNum = $values[0]['value'] ?? 0;
|
|
$name = 'Cyl' . $cylinderNum;
|
|
|
|
$valKey = "Pressure_cylinderHealth_" . $i++;
|
|
$val = $valData[$valKey][0]['value'] ?? null;
|
|
|
|
$response[] = [
|
|
'name' => $name,
|
|
'value' => $val,
|
|
];
|
|
}
|
|
|
|
$response = ['success' => true, 'data' => $response];
|
|
// });
|
|
|
|
return response()->json($response);
|
|
|
|
} catch (Exception $e) {
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function getDeviceByAsset($assetId){
|
|
$deviceList = Device::where('asset_id', $assetId)->select('id','name')->get()->toArray();
|
|
return response()->json($deviceList);
|
|
}
|
|
|
|
public function getAdminAlarms(Request $request){
|
|
try {
|
|
if($request->assetIds){
|
|
$getDeviceByAsset = Device::whereIn('asset_id', $request->assetIds)->pluck('id')->toArray();
|
|
}else{
|
|
$getDeviceByAsset = $request->deviceIds;
|
|
}
|
|
|
|
$data = [
|
|
'statusList' => $request->statusList ?? ['ACTIVE'],
|
|
'severityList' => $request->severityList,
|
|
'startTs' => $request->startTs,
|
|
'endTs' => $request->endTs,
|
|
'deviceIds' => $request->deviceIds ?? $getDeviceByAsset,
|
|
];
|
|
|
|
$allDevices = Device::pluck('id')->toArray();
|
|
|
|
$alarms = $this->customerInfoService->fetchDeviceAlarms($allDevices, $data);
|
|
|
|
return response()->json(['success' => true, 'data' => $alarms]);
|
|
} catch(Exception $e){
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function getUserAssets(){
|
|
$token = readHeaderToken();
|
|
$userId = $token['sub'];
|
|
|
|
$userAssets = UserAssetLink::with('asset:id,name')
|
|
->where(['user_id' => $userId, 'active' => 1])
|
|
->get()
|
|
->map(function($link) {
|
|
return [
|
|
'id' => $link->asset->id,
|
|
'name' => $link->asset->name
|
|
];
|
|
});
|
|
return response()->json($userAssets);
|
|
}
|
|
|
|
public function getUserDeviceByAsset($assetId){
|
|
$token = readHeaderToken();
|
|
$userDevices = UserAssetLink::with('asset.devices')
|
|
->where(['user_id' => $token['sub'], 'active' => 1, 'asset_id' => $assetId])
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->select('id','name');
|
|
|
|
return response()->json($userDevices);
|
|
}
|
|
|
|
public function getUserAlarms(Request $request){
|
|
try {
|
|
$token = readHeaderToken();
|
|
|
|
if($request->assetIds) {
|
|
$userDevices = UserAssetLink::with('asset.devices')
|
|
->where(['user_id' => $token['sub'], 'active' => 1])
|
|
->whereIn('asset_id', $request->assetIds)
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->unique('id');
|
|
$getDeviceByAsset = $userDevices->pluck('id')->toArray();
|
|
} else {
|
|
$getDeviceByAsset = $request->deviceIds;
|
|
}
|
|
|
|
$data = [
|
|
'statusList' => $request->statusList ?? ['ACTIVE'],
|
|
'severityList' => $request->severityList,
|
|
'startTs' => $request->startTs,
|
|
'endTs' => $request->endTs,
|
|
'deviceIds' => $request->deviceIds ?? $getDeviceByAsset,
|
|
];
|
|
|
|
$userDevices = UserAssetLink::with('asset.devices')
|
|
->where(['user_id' => $token['sub'], 'active' => 1])
|
|
->get()
|
|
->pluck('asset.devices')
|
|
->flatten()
|
|
->unique('id');
|
|
$allDevices = $userDevices->pluck('id')->toArray();
|
|
|
|
$alarms = $this->customerInfoService->fetchDeviceAlarms($allDevices, $data);
|
|
|
|
return response()->json(['success' => true, 'data' => $alarms]);
|
|
} catch(Exception $e){
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
}
|