Files
backend_vib360_laravel/app/Http/Controllers/APIS/CustomerApi/TelemetryController.php
Nikhil Kadam 5b4eeff6d4 Error handling
2025-05-02 19:31:02 +05:30

1357 lines
57 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 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;
class TelemetryController extends Controller
{
protected $customerInfoService, $alarmService, $adminService;
// public function __construct(CustomerInfoService $customerInfoService)
// {
// $this->customerInfoService = $customerInfoService;
// }
public function __construct(CustomerInfoService $customerInfoService, AlarmService $alarmService, AdminService $adminService)
{
$this->customerInfoService = $customerInfoService;
$this->alarmService = $alarmService;
$this->adminService = $adminService;
}
// 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');
// 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;
$startTsMs = $endTsMs - (30 * 60 * 1000);
// Get devices with their telemetry keys
$devices = 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();
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) {
// Check device active status directly
$deviceInfoToken = $this->adminService->getToken();
$isActive = false;
if ($deviceInfoToken) {
$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();
$isActive = $deviceInfo['active'] ?? false;
} else {
Log::error("Failed to fetch device info for device ID: {$device->id}");
}
}
$keysData = $device->timeseriesKeys;
$keyNames = $keysData->pluck('key_name')->toArray();
// Only fetch telemetry if device is active
$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 = 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, $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);
// Determine trend only if device is active
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 = 'grey';
if ($isActive) {
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;
}
}
} else {
$colorCode = 'green';
}
}
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();
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,
];
});
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 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()]);
$token = readHeaderToken();
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;
try {
Log::info('Fetching device telemetry', ['device_id' => $deviceId]);
$deviceWithTelemetry = 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();
$displayKeys = $deviceWithTelemetry->timeseriesKeys->pluck('key_name')->toArray();
$deviceProfileName = strtolower($deviceWithTelemetry->deviceProfile->name ?? '');
Log::info('Device profile and keys retrieved', [
'device_profile' => $deviceProfileName,
'display_keys' => $displayKeys
]);
// Pressure key condition
$pressureKey = 'Pressure_value';
$pressureActive = false;
$telemetryResponse = $this->customerInfoService->getTelemetryDataDevice(
$deviceWithTelemetry,
$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");
}
// 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)
&& isset($telemetryResponse[$pressureKey])
&& is_array($telemetryResponse[$pressureKey])
) {
foreach ($telemetryResponse[$pressureKey] as $pressureData) {
if (!empty($pressureData['value']) && floatval($pressureData['value']) > 0) {
$pressureActive = true;
break;
}
}
}
Log::info('Telemetry data processed', [
'pressure_value' => $pressureActive,
'telemetry_keys' => array_keys($telemetryResponse)
]);
// Filter telemetry data based on display keys
$filteredResponse = array_intersect_key($telemetryResponse, array_flip($displayKeys));
// Add Pressure key if condition is met
if (isset($telemetryResponse[$pressureKey])) {
$filteredResponse[$pressureKey] = $telemetryResponse[$pressureKey];
}
$telemetry = collect($filteredResponse)
->flatMap(function ($items, $keyName) use ($deviceWithTelemetry) {
$keyData = $deviceWithTelemetry->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();
Log::info('Telemetry response successfully generated', ['device_id' => $deviceId]);
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,
'pressure_value' => $pressureActive, // Updated response
'telemetry_data' => $telemetry,
]
], 200);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
Log::error('Device not found', ['device_id' => $deviceId]);
return response()->json([
'success' => false,
'error' => 'Device not found'
], 404);
} catch (\Exception $e) {
Log::error('Failed to fetch telemetry data', [
'device_id' => $deviceId,
'error' => $e->getMessage()
]);
return response()->json([
'success' => false,
'error' => 'Failed to fetch telemetry data',
'details' => config('app.debug') ? $e->getMessage() : null
], 503);
}
} 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);
}
}
// public function telemetryDataDeviceDiagnostic(Request $request, $deviceId)
// {
// $devices = Device::with('deviceProfile')
// ->where('id', $deviceId)
// ->get();
// if ($devices->isEmpty()) {
// return response()->json(['error' => 'No devices found'], 404);
// }
// $startTs = $request->has('start_date') ? strtotime($request->start_date) * 1000 : null;
// $endTs = $request->has('end_date') ? strtotime($request->end_date) * 1000 : null;
// $response = [];
// foreach ($devices as $device) {
// $telemetry = [];
// $keyNames = TimeseriesKeyMaster::where('device_profile_xid', $device->device_profile_id)
// ->pluck('key_name', 'display_name')
// ->toArray();
// $telemetryResponse = $this->customerInfoService->getTelemetryDataDeviceDiagonostic($device, $keyNames, $startTs, $endTs);
// foreach ($keyNames as $keyName) {
// if (isset($telemetryResponse[$keyName])) {
// foreach ($telemetryResponse[$keyName] as $item) {
// $timestamp = $item['ts'] ?? null;
// // ✅ Filter telemetry by timestamp range
// if ($timestamp && $timestamp >= $startTs && $timestamp <= $endTs) {
// $telemetry[] = [
// 'key_name' => $keyName,
// 'timestamp' => $timestamp,
// 'start_date' => $startTs,
// 'end_date' => $endTs,
// 'value' => $item['value'] ?? null,
// 'display_name' => $keyName,
// ];
// }
// }
// }
// }
// if (!empty($telemetry)) {
// $response[] = [
// 'device_id' => (string) $device->id,
// 'device_name' => $device->name,
// 'device_profile_name' => (string) $device->deviceProfile->name,
// 'device_profile_id' => (string) $device->device_profile_id,
// 'telemetry' => $telemetry,
// ];
// }
// }
// return response()->json(['telemetry' => $response]);
// }
// public function telemetryDataDeviceDiagnostic(Request $request, $deviceId)
// {
// // Fetch devices
// $devices = Device::with('deviceProfile')
// ->where('id', $deviceId)
// ->get();
// if ($devices->isEmpty()) {
// return response()->json(['error' => 'No devices found'], 404);
// }
// // Get start and end timestamps from request parameters
// $startTs = $request->has('start_date') ? strtotime($request->start_date) * 1000 : null;
// $endTs = $request->has('end_date') ? strtotime($request->end_date) * 1000 : null;
// if (!$startTs || !$endTs) {
// return response()->json(['error' => 'Start date and end date are required'], 400);
// }
// $response = [];
// foreach ($devices as $device) {
// $telemetry = [];
// $keyNames = TimeseriesKeyMaster::where('device_profile_xid', $device->device_profile_id)
// ->pluck('key_name', 'display_name')
// ->toArray();
// $telemetryResponse = $this->customerInfoService->getTelemetryDataDeviceDiagonostic($device, $keyNames, $startTs, $endTs);
// foreach ($keyNames as $displayName => $keyName) {
// if (isset($telemetryResponse[$keyName])) {
// foreach ($telemetryResponse[$keyName] as $item) {
// $itemTs = $item['timestamp'] ?? null;
// // ✅ Filter only telemetry within the date range
// if ($itemTs >= $startTs && $itemTs <= $endTs) {
// $telemetry[] = [
// 'key_name' => $keyName,
// 'value' => $item['value'] ?? null,
// 'display_name' => $displayName,
// 'timestamp' => $itemTs,
// 'start_date' => $startTs,
// 'end_date' => $endTs
// ];
// }
// }
// }
// }
// if (!empty($telemetry)) {
// $response[] = [
// 'device_id' => (string) $device->id,
// 'device_name' => $device->name,
// 'device_profile_name' => (string) $device->deviceProfile->name,
// 'device_profile_id' => (string) $device->device_profile_id,
// 'telemetry' => $telemetry,
// ];
// }
// }
// return response()->json(['telemetry' => $response]);
// }
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 = UserAssetLink::with('asset.devices')
->where('user_id', $token['sub'])
->get()
->pluck('asset.devices')
->flatten()
->pluck('id')
->toArray();
// Retrieve required timeseries of devices
$timeseriesKeys = TimeseriesKeyMaster::where('display_on_dashboard', 1)
->orWhere('display_on_popup',1)
->get()
->pluck('key_name')
->flatten()
->toArray();
$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 = 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();
});
// 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);
}
}
public function getDeviceHealth(array $values): string
{
$hasRed = false;
$hasOrange = false;
foreach ($values as $value) {
if($value['key_name'] == 'PowerLoss_value'){
if ($value['value'] > 5 && $value['value'] < 10) {
$hasRed = true;
break; // Red is highest priority, no need to continue
} elseif ($value['value'] > 2.5 && $value['value'] < 5) {
$hasOrange = true;
}
} else {
if ($value['value'] > 0 && $value['value'] < 31) {
$hasRed = true;
break; // Red is highest priority, no need to continue
} elseif ($value['value'] < 71) {
$hasOrange = true;
}
}
}
if ($hasRed) {
return 'red';
} elseif ($hasOrange) {
return 'orange';
}
return 'green';
}
public function getAssetHealth($deviceHealthStatuses) {
if (in_array('red', $deviceHealthStatuses)) {
return 'red';
} elseif (in_array('orange', $deviceHealthStatuses)) {
return 'orange';
}
return 'green';
}
public function userAssetsNew(){
try {
$token = readHeaderToken();
// Retrieve devices of user
$assetDeviceListing = UserAssetLink::with('asset.devices')
->where('user_id', $token['sub'])
->get();
$formattedData = $assetDeviceListing->map(function ($link) {
$asset = $link->asset;
$deviceHealthStatuses = [];
$devicesData = $asset->devices->map(function ($device) use (&$deviceHealthStatuses) {
$timeseriesKeys = TimeseriesKeyMaster::where('display_on_health_condition', 1)
->where('device_profile_xid', $device->device_profile_id)
->pluck('key_name')
->implode(',');
// \Log::info("Keys for device {$device->name}", [$timeseriesKeys]);
$telemetryValue = $this->customerInfoService->fetchTelemetryData($device->id, $timeseriesKeys);
$data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;
// \Log::info("Telemetry data for device {$device->name}", $data);
$transformedTelemetry = [];
// dd($data);
if (!empty($data) && is_array($data)) {
foreach ($data as $key => $items) {
foreach ($items as $item) {
$transformedTelemetry[] = [
'key_name' => $key,
'value' => $item['value']
];
}
}
}
// \Log::info("Transformed data for device {$device->name}", $transformedTelemetry);
$deviceHealth = $this->getDeviceHealth($transformedTelemetry);
$deviceHealthStatuses[] = $deviceHealth;
return [
'deviceName' => $device->name,
'deviceHealth' => $deviceHealth
];
})->values();
return [
'assetName' => $asset->name,
'assetHealth' => $deviceHealthStatuses ? $this->getAssetHealth($deviceHealthStatuses) : null,
'devices' => $devicesData
];
});
return response()->json(['success' => true,'data' => $formattedData]);
} catch(Exception $e){
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}
}
public function customerDeviceInfoNew(){
try {
$token = readHeaderToken();
// Fetch all devices linked to user in one go
$devices = UserAssetLink::with('asset.devices')
->where('user_id', $token['sub'])
->get()
->pluck('asset.devices')
->flatten()
->unique('id'); // Ensure no duplicate devices
$good = $moderate = $bad = 0;
$deviceIds = $devices->pluck('id')->toArray();
foreach ($deviceIds as $deviceId) {
$device = Device::find($deviceId); // get the device row first
if ($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']
];
}
}
}
// \Log::info("Transformed data for device {$device->name}", $transformedTelemetry);
$deviceHealth = $this->getDeviceHealth($transformedTelemetry);
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'],
'active' => $deviceCount['activeDevices'],
'alarm' => $alarms['count']
];
return response()->json($response);
} catch(Exception $e){
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}
}
public function getDeviceIndicators($assetId){
try{
$token = readHeaderToken();
$assetDeviceListing = UserAssetLink::with('asset.devices')
->where(['user_id' => $token['sub'], 'asset_id' => $assetId])
->get();
$assetLink = $assetDeviceListing->map(function($link){
$asset = $link->asset;
$deviceData = $asset->devices->map(function($device){
$deviceProfile = Device::with('deviceProfile')
->where('id', $device->id)
->first();
$deviceProfileId = $deviceProfile?->deviceProfile?->id;
$deviceProfileName = $deviceProfile?->deviceProfile?->name;
$timeseriesList = TimeseriesKeyMaster::where('display_on_dashboard', 1)
->where('device_profile_xid', $deviceProfileId)
->get(['key_name', 'display_name']);
$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 = [];
if (!empty($data) && is_array($data)) {
foreach ($data as $key => $items) {
foreach ($items as $item) {
$ts['startTs'] = Carbon::now()->subHours(6)->timestamp * 1000;
$ts['endTs'] = Carbon::now()->timestamp * 1000;
$pastValues = $this->customerInfoService->fetchTelemetryData($device->id, $key, $ts);
$pastValTotal = 1;
// $itemTotal
foreach($pastValues as $past){
// $pastValTotal
}
// echo "$i -".count($pastValues)."\n";
$transformedTelemetry[] = [
'display_name' => $displayNameMap[$key] ?? $key,
'value' => $item['value'],
'pastValue' => $pastValues ? $pastValues[$key] : []
];
}
// exit;
}
}
return [
'deviceId' => $device->id,
'deviceName' => $device->name,
'deviceType' => $deviceProfileName,
'deviceSensor' => $device->sensor,
'indicator' => $transformedTelemetry
];
})->values();
return [
'success' => true,
'data' => $deviceData
];
});
return response()->json($assetLink);
} catch(Exception $e){
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}
}
public function getAlerts($deviceId){
try{
$token = readHeaderToken();
$deviceParams = TimeseriesKeyMaster::select('key_name', 'display_name')
->where('display_on_alerts', 1)
->whereHas('device', function ($query) use ($deviceId) {
$query->where('id', $deviceId);
})
->get();
$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 = [];
if (!empty($data) && is_array($data)) {
foreach ($data as $key => $items) {
foreach ($items as $item) {
$timeseriesId = TimeseriesKeyMaster::where('display_name', $displayNameMap[$key])->first('id');
$fetchMsg = TimeseriesAlertMessage::where('timeseries_key_master_xid', $timeseriesId['id'])
->where('min_value', '<=', $item['value'])
->where('max_value', '>=', $item['value'])
->first(['alert_msg']);
$alertPoints = [];
if (!empty($fetchMsg?->alert_msg)) {
$alertPoints = explode("\n", trim($fetchMsg->alert_msg));
}
$dateTime = Carbon::createFromTimestamp($item['ts'] / 1000)->format('d-M-Y H:i:s');
$transformedTelemetry[] = [
'display_name' => $displayNameMap[$key] ?? $key,
'alert_msg' => $alertPoints ?: ["No Alerts & Instructions"]
];
}
}
}
return response()->json(
[
'success' => true,
'updated_time' => $this->convertToUserTimezone($dateTime),
'data' => $transformedTelemetry
]
);
} catch(Exception $e){
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}
}
public function getGlobalIndicators($deviceId){
try{
$token = readHeaderToken();
$deviceParams = TimeseriesKeyMaster::select('key_name', 'display_name')
->where('display_on_popup', 1)
->whereHas('device', function ($query) use ($deviceId) {
$query->where('id', $deviceId);
})
->get();
$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 = [];
if (!empty($data) && is_array($data)) {
foreach ($data as $key => $items) {
foreach ($items as $item) {
$dateTime = Carbon::createFromTimestamp($item['ts'] / 1000)->format('d-M-Y H:i:s');
switch (true) {
case $item['value'] > 70:
$status = 'Stable';
break;
case $item['value'] > 30:
$status = 'Attention';
break;
default:
$status = 'Alert';
}
$transformedTelemetry[] = [
'display_name' => $displayNameMap[$key] ?? $key,
'value' => $item['value'],
'health_status' => $status
];
}
}
}
return response()->json(
[
'success' => true,
'updated_time' => $this->convertToUserTimezone($dateTime),
'data' => $transformedTelemetry
]
);
} catch(Exception $e){
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}
}
public function getTrends($deviceId){
try {
$token = readHeaderToken();
$dates = collect(range(0, 6))->map(function ($i) {
return Carbon::now()->subDays($i)->format('M d, Y');
})->reverse()->values()->toArray();
foreach($dates as $date){
$dateTs[] = (Carbon::createFromFormat('M d, Y', $date)->timestamp)*1000;
// Start timestamp (beginning of the day)
$ts['startTs'] = Carbon::createFromFormat('M d, Y', $date)->startOfDay()->timestamp * 1000;
// End timestamp (end of the day)
$ts['endTs'] = Carbon::createFromFormat('M d, Y', $date)->endOfDay()->timestamp * 1000;
$deviceProfile = Device::with('deviceProfile')
->where('id', $deviceId)
->first();
$deviceProfileId = $deviceProfile?->deviceProfile?->id;
$parameters = parameters();
$value1 = $value2 = [];
$telemetryValue1 = $this->customerInfoService->fetchTelemetryData($deviceId, $parameters[$deviceProfileId]['keyNameList1'], $ts);
$trendsData1 = $telemetryValue1 instanceof \Illuminate\Http\JsonResponse ? $telemetryValue1->getData(true) : $telemetryValue1;
$telemetryValue2 = $this->customerInfoService->fetchTelemetryData($deviceId, $parameters[$deviceProfileId]['keyNameList2'], $ts);
$trendsData2 = $telemetryValue2 instanceof \Illuminate\Http\JsonResponse ? $telemetryValue2->getData(true) : $telemetryValue2;
foreach ($trendsData1 as $key => $trend) {
$displayName = TimeseriesKeyMaster::where('key_name',$key)->first('display_name');
foreach ($trend as $val) {
$value1[0][$displayName['display_name']][] = $val['value'];
}
}
foreach ($trendsData2 as $key => $trend) {
$displayName = TimeseriesKeyMaster::where('key_name',$key)->first('display_name');
foreach ($trend as $val) {
$value2[0][$displayName['display_name']][] = $val['value'];
}
}
$graph1[$date] = $value1;
$graph2[$date] = $value2;
}
return [
'success' => true,
'graph1' => $graph1,
'graph2' => $graph2,
];
} catch(Exception $e){
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}
}
}