Files
backend_vib360_laravel/app/Services/CustomerInfoService.php
2025-05-15 11:55:51 +05:30

621 lines
20 KiB
PHP

<?php
namespace App\Services;
use App\Models\TimeseriesKeyMaster;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use App\Services\AdminService;
use Exception;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Cache;
class CustomerInfoService
{
protected $adminService;
public function __construct(AdminService $adminService)
{
$this->adminService = $adminService;
}
// public function getThingsBoardDevices($customerId)
// {
// try {
// $token = $this->adminService->getToken();
// if (!$token) {
// Log::error("Failed to authenticate with ThingsBoard.");
// return response()->json([
// 'error' => 'thingsboard_auth_failed',
// 'message' => 'Failed to authenticate with ThingsBoard'
// ], 401);
// }
// $response = Http::withHeaders([
// 'Authorization' => "Bearer $token",
// 'Accept' => 'application/json',
// ])->get("http://65.0.131.117:8080/api/customer/{$customerId}/deviceInfos?pageSize=100&page=0");
// if (!$response->successful()) {
// Log::error("Failed to fetch ThingsBoard devices: " . $response->body());
// return response()->json([
// 'error' => 'thingsboard_fetch_failed',
// 'message' => 'Failed to fetch devices from ThingsBoard',
// 'details' => $response->body()
// ], $response->status());
// }
// $data = $response->json();
// return $data['data'] ?? [];
// } catch (\Exception $e) {
// Log::error("Error fetching ThingsBoard devices: " . $e->getMessage());
// return response()->json([
// 'error' => 'thingsboard_error',
// 'message' => 'Error fetching devices from ThingsBoard',
// 'details' => $e->getMessage()
// ], 500);
// }
// }
public function getTelemetryData($device, $keyNames, $startTs, $endTs)
{
$token = $this->adminService->getToken();
if (!$token) {
return ['error' => 'Failed to fetch ThingsBoard token'];
}
$baseUrl = env('THINGSBOARD_URL');
$deviceId = $device->id;
$keys = implode(',', $keyNames);
// Build query parameters dynamically
$queryParams = [
'keys' => $keys,
];
if ($startTs) {
$queryParams['startTs'] = $startTs;
}
if ($endTs) {
$queryParams['interval'] = $endTs;
}
// Make the HTTP request
$response = Http::withHeaders([
'Authorization' => "Bearer $token",
'Accept' => 'application/json',
])->get("{$baseUrl}api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries", $queryParams);
// Check if the response was successful
if (!$response->successful()) {
Log::error("Failed to fetch telemetry for device: {$device->name} (ID: {$deviceId})", [
'http_code' => $response->status(),
'url' => $response->effectiveUri(),
'response' => $response->body(),
]);
return ['error' => "Failed to fetch telemetry. HTTP Code: " . $response->status()];
}
// Decode the telemetry response
$telemetry = $response->json();
Log::info("Telemetry Data", $telemetry);
if (json_last_error() !== JSON_ERROR_NONE) {
Log::error("Failed to decode telemetry response for device: {$device->name}", [
'response' => $response->body(),
]);
return ['error' => 'Invalid telemetry response format'];
}
return $telemetry;
}
public function getTelemetryDataDevice($device, $keyNames, $startTs, $endTs)
{
$token = $this->adminService->getToken();
if (!$token) {
Log::error('Failed to fetch ThingsBoard token');
return ['error' => 'Failed to fetch ThingsBoard token'];
}
$baseUrl = env('THINGSBOARD_URL');
$deviceId = $device->id;
$keys = implode(',', $keyNames);
$queryParams = [
'keys' => $keys,
];
if ($startTs) {
$queryParams['startTs'] = $startTs;
}
if ($endTs) {
$queryParams['endTs'] = $endTs;
}
$response = Http::withHeaders([
'Authorization' => "Bearer $token",
'Accept' => 'application/json',
])->get("{$baseUrl}api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries", $queryParams);
// Check if the response was successful
if (!$response->successful()) {
Log::error("Failed to fetch telemetry for device: {$device->name} (ID: {$deviceId})", [
'http_code' => $response->status(),
'url' => $response->effectiveUri(),
'response' => $response->body()
]);
return ['error' => "Failed to fetch telemetry. HTTP Code: " . $response->status()];
}
// Decode the telemetry response
$telemetry = $response->json();
if (json_last_error() !== JSON_ERROR_NONE) {
Log::error("Failed to decode telemetry response for device: {$device->name}", [
'response' => $response->body()
]);
return ['error' => 'Invalid telemetry response format'];
}
return $telemetry;
}
public function getTelemetryDataDeviceDiagonostic($device, $keyNames, $startTs, $endTs)
{
$token = $this->adminService->getToken();
if (!$token) {
Log::error('Failed to fetch ThingsBoard token');
return ['error' => 'Failed to fetch ThingsBoard token'];
}
$baseUrl = env('THINGSBOARD_URL');
$deviceId = $device->id;
$keys = implode(',', $keyNames);
$response = Http::withHeaders([
'Authorization' => "Bearer $token",
'Accept' => 'application/json'
// ])->get("$baseUrl/api/plugins/telemetry/DEVICE/58bf81a0-0619-11f0-a9dc-45dd276e4cd5/values/timeseries", [
])->get("$baseUrl/api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries", [
'keys' => $keys,
// 'keys' => 'MechanicalHealth_valueInPercent',
'startTs' => $startTs,
'interval' => $endTs,
'limit' => 100,
'useStrictDataTypes' => false
]);
// Check if the response was successful
if (!$response->successful()) {
Log::error("Failed to fetch telemetry for device: {$device->name} (ID: {$deviceId})", [
'http_code' => $response->status(),
'url' => $response->effectiveUri(),
'response' => $response->body()
]);
return ['error' => "Failed to fetch telemetry. HTTP Code: " . $response->status()];
}
// Decode the telemetry response
$telemetry = $response->json();
if (json_last_error() !== JSON_ERROR_NONE) {
Log::error("Failed to decode telemetry response for device: {$device->name}", [
'response' => $response->body()
]);
return ['error' => 'Invalid telemetry response format'];
}
return $telemetry;
}
public function getCustomerDevicesAndAlarms($customerId)
{
$result = [
'devices' => [],
'alarms' => [],
'errors' => []
];
try {
// Step 1: Get devices
$devicesResponse = $this->getThingsBoardDevices($customerId);
if (isset($devicesResponse['error'])) {
$result['errors']['devices'] = $devicesResponse;
} else {
$result['devices'] = $devicesResponse;
// Step 2: Get alarms if devices were fetched successfully
$deviceIds = array_column($devicesResponse, 'id.id');
if (!empty($deviceIds)) {
$alarmsResponse = $this->getDeviceAlarms($deviceIds);
if (isset($alarmsResponse['error'])) {
$result['errors']['alarms'] = $alarmsResponse;
} else {
$result['alarms'] = $alarmsResponse['data'] ?? [];
}
}
}
return $result;
} catch (\Exception $e) {
Log::error("ThingsBoard service error: " . $e->getMessage());
return [
'error' => 'service_error',
'message' => 'Failed to complete ThingsBoard operation',
'details' => $e->getMessage()
];
}
}
/**
* Get devices for a customer
*/
private function getThingsBoardDevices($customerId)
{
try {
$token = $this->adminService->getToken();
if (!$token) {
throw new \Exception("Failed to authenticate with ThingsBoard");
}
$response = Http::withHeaders([
'Authorization' => "Bearer $token",
'Accept' => 'application/json',
])->get("http://65.0.131.117:8080/api/customer/{$customerId}/deviceInfos?pageSize=100&page=0");
if (!$response->successful()) {
throw new \Exception("Failed to fetch devices: " . $response->body());
}
$data = $response->json();
return $data['data'] ?? [];
} catch (\Exception $e) {
Log::error("Device fetch error: " . $e->getMessage());
return [
'error' => 'device_fetch_failed',
'message' => 'Failed to fetch devices',
'details' => $e->getMessage()
];
}
}
/**
* Get alarms for specific devices (last 24 hours)
*/
private function getDeviceAlarms(array $deviceIds)
{
try {
$token = $this->adminService->getToken();
if (!$token) {
throw new \Exception("Failed to authenticate with ThingsBoard");
}
$startTime = (time() - 86400) * 1000; // 24 hours ago in milliseconds
$deviceIdsParam = implode(',', $deviceIds);
$response = Http::withHeaders([
'Authorization' => "Bearer $token",
'Accept' => 'application/json',
])->get("http://65.0.131.117:8080/api/v2/alarms", [
'pageSize' => 100,
'page' => 0,
'startTime' => $startTime,
'deviceIds' => $deviceIdsParam
]);
if (!$response->successful()) {
throw new \Exception("Failed to fetch alarms: " . $response->body());
}
return $response->json();
} catch (\Exception $e) {
Log::error("Alarm fetch error: " . $e->getMessage());
return [
'error' => 'alarm_fetch_failed',
'message' => 'Failed to fetch alarms',
'details' => $e->getMessage()
];
}
}
public function getToken()
{
$baseUrl = env('THINGSBOARD_URL', 'http://65.0.131.117:8080');
$username = env('THINGSBOARD_USERNAME', 'tenant1@thingsboard.org');
$password = env('THINGSBOARD_PASSWORD', 'tenant1');
if (Cache::has('thingsboard_token')) {
return Cache::get('thingsboard_token');
}
$response = Http::withHeaders([
// 'accept' => 'application/json',
'Content-Type' => 'application/json',
])
->post("{$baseUrl}api/auth/login", [
'username' => $username,
'password' => $password,
]);
if ($response->successful()) {
$token = $response->json('token');
Cache::put('thingsboard_token', $token, now()->addMinutes(1440));
return $token;
} else {
Log::error("ThingsBoard Authentication Failed: " . $response->body());
throw new Exception('Unable to authenticate with ThingsBoard: ' . $response->body());
}
}
public function fetchEntityQuery($deviceIds, $timeseriesKeys){
try{
$token = $this->adminService->getToken();
if (!$token) {
throw new \Exception("Failed to authenticate with ThingsBoard");
}
$url = env('THINGSBOARD_URL').'api/entitiesQuery/find';
$timeSeries = array_map(function($key) {
return [
'type' => 'TIME_SERIES',
'key' => $key
];
}, $timeseriesKeys);
$payload = [
"entityFilter" => [
"type" => "entityList",
"entityType" => "DEVICE",
"entityList" => $deviceIds
],
"pageLink" => [
"pageSize" => 100,
"page" => 0,
"textSearch" => "",
"dynamic" => true
],
"entityFields" => [
["type" => "ENTITY_FIELD", "key" => "name"],
["type" => "ENTITY_FIELD", "key" => "type"],
],
"latestValues" => $timeSeries
];
$response = Http::withHeaders([
'accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Authorization' => 'Bearer ' . $token,
])->post($url, $payload);
// Return JSON response
return response()->json($response->json(), $response->status());
} catch(Exception $e){
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}
}
public function fetchTelemetryData($deviceId,$keys,$ts=[])
{
$url = env('THINGSBOARD_URL') ."api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries?useStrictDataTypes=false";
$token = $this->adminService->getToken();
if (!$token) {
throw new \Exception("Failed to authenticate with ThingsBoard");
}
try {
$response = Http::withToken($token)->asForm()->get($url, [
'keys' => $keys,
'startTs' => $ts['startTs'] ?? null,
'endTs' => $ts['endTs'] ?? null,
'limit' => $ts ? 25000 : null
]);
if ($response->successful()) {
return $response->json();
} else {
return response()->json([
'success' => false,
'message' => 'Failed to fetch data',
'status' => $response->status(),
], $response->status());
}
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'An error occurred: ' . $e->getMessage(),
], 500);
}
}
public function getDevicesCount($deviceIds){
try {
$token = $this->adminService->getToken();
if (!$token) {
throw new \Exception("Failed to authenticate with ThingsBoard");
}
$url = env('THINGSBOARD_URL') . 'api/entitiesQuery/count';
// ---------- 1. Total count ----------
$totalPayload = [
"entityFilter" => [
"type" => "entityList",
"entityType" => "DEVICE",
"entityList" => $deviceIds
]
];
$totalResponse = Http::withHeaders([
'accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Authorization' => 'Bearer ' . $token,
])->post($url, $totalPayload);
$totalCount = $totalResponse->json() ?? 0;
// ---------- 2. active count (active = false) ----------
$activePayload = [
"entityFilter" => [
"type" => "entityList",
"entityType" => "DEVICE",
"entityList" => $deviceIds
],
"keyFilters" => [
[
"key" => [
"type" => "ATTRIBUTE",
"key" => "active"
],
"valueType" => "BOOLEAN",
"predicate" => [
"operation" => "EQUAL",
"value" => [
"defaultValue" => true,
"dynamicValue" => null
],
"type" => "BOOLEAN"
]
]
]
];
$activeResponse = Http::withHeaders([
'accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Authorization' => 'Bearer ' . $token,
])->post($url, $activePayload);
$activeCount = $activeResponse->json() ?? 0;
// ---------- Return both counts ----------
return [
'totalDevices' => $totalCount,
'activeDevices' => $activeCount
];
} catch(Exception $e){
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}
}
public function fetchDeviceAlarms(array $deviceIds, $data=[])
{
try {
$token = $this->adminService->getToken();
if (!$token) {
throw new \Exception("Failed to authenticate with ThingsBoard");
}
$url = env('THINGSBOARD_URL') . 'api/alarmsQuery/find';
if (isset($data['startTs']) && isset($data['endTs'])) {
$startDate = \DateTime::createFromFormat('d/m/Y', $data['startTs']);
$endDate = \DateTime::createFromFormat('d/m/Y', $data['endTs']);
if ($startDate && $endDate) {
$startTimestamp = $startDate->getTimestamp() * 1000;
$endTimestamp = $endDate->getTimestamp() * 1000;
}
}
// Timestamp range (modify as needed)
$startTs = $startTimestamp ?? now()->subHours(24)->timestamp * 1000;
$endTs = $endTimestamp ?? now()->timestamp * 1000;
$entityList = $data['deviceIds'] ?? $deviceIds;
$payload = [
"entityFilter" => [
"type" => "entityList",
"entityType" => "DEVICE",
"entityList" => $entityList
],
"pageLink" => [
"startTs" => $startTs,
"endTs" => $endTs,
"pageSize" => 100,
"page" => 0,
"textSearch" => "",
"statusList" => $data['statusList'] ?? [],
"severityList" => $data['severityList'] ?? [],
"sortOrder" => [
"key" => [
"type" => "ALARM_FIELD",
"key" => "createdTime"
],
"direction" => "DESC"
]
],
"alarmFields" => []
];
$response = Http::withHeaders([
'accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Authorization' => 'Bearer ' . $token,
])->post($url, $payload);
if (!$response->successful()) {
throw new \Exception("Failed to fetch alarms: " . $response->body());
}
$alarmData = $response->json();
return [
'data' => $alarmData['data'] ?? [],
'count' => $alarmData['totalElements'] ?? 0
];
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Error: ' . $e->getMessage()
], 500);
}
}
}