468 lines
15 KiB
PHP
468 lines
15 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Device;
|
|
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;
|
|
use Carbon\Carbon;
|
|
|
|
|
|
class AlarmService
|
|
{
|
|
protected $adminService;
|
|
|
|
public function __construct(AdminService $adminService)
|
|
{
|
|
$this->adminService = $adminService;
|
|
$this->baseUrl = env('THINGSBOARD_URL', 'http://65.0.131.117:8080');
|
|
$this->username = env('THINGSBOARD_USERNAME', 'tenant1@thingsboard.org');
|
|
$this->password = env('THINGSBOARD_PASSWORD', 'tenant1');
|
|
}
|
|
|
|
private $baseUrl;
|
|
private $username;
|
|
private $password;
|
|
|
|
|
|
|
|
public function getToken()
|
|
{
|
|
if (Cache::has('thingsboard_token')) {
|
|
return Cache::get('thingsboard_token');
|
|
}
|
|
|
|
$response = Http::withHeaders([
|
|
'accept' => 'application/json',
|
|
'Content-Type' => 'application/json',
|
|
])
|
|
->post("{$this->baseUrl}/api/auth/login", [
|
|
'username' => $this->username,
|
|
'password' => $this->password,
|
|
]);
|
|
|
|
|
|
if ($response->successful()) {
|
|
$token = $response->json('token');
|
|
Cache::put('thingsboard_token', $token, now()->addMinutes(15));
|
|
return $token;
|
|
} else {
|
|
Log::error("ThingsBoard Authentication Failed: " . $response->body());
|
|
throw new Exception('Unable to authenticate with ThingsBoard: ' . $response->body());
|
|
}
|
|
}
|
|
|
|
|
|
public function getAdminAlarm($data)
|
|
{
|
|
try {
|
|
|
|
$token = $this->adminService->getToken();
|
|
|
|
if (!$token) {
|
|
Log::error("Failed to authenticate with ThingsBoard.");
|
|
return [];
|
|
}
|
|
|
|
$response = Http::withHeaders([
|
|
'Authorization' => "Bearer $token",
|
|
'Accept' => 'application/json',
|
|
])->get("http://65.0.131.117:8080/api/v2/alarms?pageSize=10&page=0");
|
|
|
|
if (!$response->successful()) {
|
|
Log::error("Failed to fetch ThingsBoard devices: " . $response->body());
|
|
return [];
|
|
}
|
|
|
|
return $response->json()['data'] ?? [];
|
|
} catch (\Exception $e) {
|
|
Log::error("Error fetching ThingsBoard devices: " . $e->getMessage());
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// public function getTelemetryData($devices, $startTs, $endTs, $limit = 100)
|
|
// {
|
|
// try {
|
|
// // Get ThingsBoard token from AdminService
|
|
// $token = $this->adminService->getToken();
|
|
|
|
// if (!$token) {
|
|
// Log::error("Failed to authenticate with ThingsBoard.");
|
|
// return ['error' => 'Authentication failed'];
|
|
// }
|
|
|
|
// $baseUrl = env('THINGSBOARD_URL', 'http://65.0.131.117:8080');
|
|
// $telemetryData = [];
|
|
|
|
// foreach ($devices as $device) {
|
|
// $deviceToken = $device->token;
|
|
|
|
// // Include asset_id, device_profile_id, and device name
|
|
// $assetId = $device->asset_id;
|
|
// $deviceProfileId = $device->device_profile_id;
|
|
// $deviceName = $device->name;
|
|
|
|
// if (!$deviceToken) {
|
|
// Log::warning("Device token missing for device: {$deviceName} (ID: {$device->id})");
|
|
// continue;
|
|
// }
|
|
|
|
// $keys = $device->timeseriesKeys->pluck('key_name')->implode(',');
|
|
|
|
// if (empty($keys)) {
|
|
// Log::warning("No telemetry keys found for device: {$deviceName} (Token: {$deviceToken})");
|
|
// continue;
|
|
// }
|
|
|
|
// // Make the telemetry API call
|
|
// $response = Http::withHeaders([
|
|
// 'X-Authorization' => "Bearer $token",
|
|
// 'Accept' => 'application/json',
|
|
// ])->get("{$baseUrl}/api/plugins/telemetry/DEVICE/{$deviceToken}/values/timeseries", [
|
|
// 'keys' => $keys,
|
|
// 'startTs' => $startTs,
|
|
// 'endTs' => $endTs,
|
|
// 'limit' => $limit,
|
|
// 'useStrictDataTypes' => 'false',
|
|
// ]);
|
|
|
|
// if (!$response->successful()) {
|
|
// Log::error("Failed to fetch telemetry for device: {$deviceName} (Token: {$deviceToken})");
|
|
// continue;
|
|
// }
|
|
|
|
// $data = $response->json();
|
|
|
|
// // Format telemetry data with asset_id, device_profile_id, and name as key
|
|
// $formattedTelemetry = [];
|
|
|
|
// if (!empty($data)) {
|
|
// foreach ($data as $key => $values) {
|
|
// foreach ($values as $item) {
|
|
// $formattedTelemetry[] = [
|
|
// 'key' => $key,
|
|
// 'value' => $item['value'],
|
|
// 'ts' => $item['ts']
|
|
// ];
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// $telemetryData[] = [
|
|
// 'asset_id' => $assetId,
|
|
// 'device_profile_id' => $deviceProfileId,
|
|
// 'name' => $deviceName,
|
|
// 'telemetry' => $formattedTelemetry,
|
|
// ];
|
|
// }
|
|
|
|
// return $telemetryData;
|
|
|
|
// } catch (\Exception $e) {
|
|
// Log::error("Error fetching telemetry data: " . $e->getMessage());
|
|
// return ['error' => 'Failed to fetch telemetry data'];
|
|
// }
|
|
// }
|
|
|
|
// public function getTelemetryData($devices, $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');
|
|
|
|
// $headers = [
|
|
// 'Authorization: Bearer ' . $token,
|
|
// 'accept: application/json'
|
|
// ];
|
|
|
|
// $allTelemetry = [];
|
|
|
|
// foreach ($devices as $device) {
|
|
// $deviceId = $device->id;
|
|
// $keys = $device->timeseriesKeys->pluck('key_name')->filter()->implode(',');
|
|
|
|
// if (empty($keys)) {
|
|
// Log::warning("No telemetry keys found for device: {$device->name}");
|
|
// $allTelemetry[$deviceId] = [
|
|
// 'status' => 'error',
|
|
// 'message' => 'No telemetry keys found'
|
|
// ];
|
|
// continue;
|
|
// }
|
|
|
|
// $url = "$baseUrl/api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries"
|
|
// . "?keys={$keys}&startTs={$startTs}&endTs={$endTs}&limit=100";
|
|
|
|
// $ch = curl_init($url);
|
|
// curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
// curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
|
|
|
// $response = curl_exec($ch);
|
|
// $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
// $error = curl_error($ch);
|
|
// curl_close($ch);
|
|
|
|
// if ($error || $httpCode !== 200) {
|
|
// Log::error("Failed to fetch telemetry for device: {$device->name} (ID: {$deviceId})", [
|
|
// 'http_code' => $httpCode,
|
|
// 'error' => $error,
|
|
// 'url' => $url,
|
|
// 'response' => $response
|
|
// ]);
|
|
|
|
// $allTelemetry[$deviceId] = [
|
|
// 'status' => 'error',
|
|
// 'message' => "Failed to fetch telemetry. HTTP Code: $httpCode, Error: $error"
|
|
// ];
|
|
// continue;
|
|
// }
|
|
|
|
// $telemetry = json_decode($response, true);
|
|
|
|
// if (json_last_error() !== JSON_ERROR_NONE) {
|
|
// Log::error("Failed to decode telemetry response for device: {$device->name}", [
|
|
// 'response' => $response
|
|
// ]);
|
|
|
|
// $allTelemetry[$deviceId] = [
|
|
// 'status' => 'error',
|
|
// 'message' => 'Invalid telemetry response format'
|
|
// ];
|
|
// continue;
|
|
// }
|
|
|
|
// $allTelemetry[$deviceId] = [
|
|
// 'status' => 'success',
|
|
// 'telemetry' => $telemetry
|
|
// ];
|
|
// }
|
|
|
|
// return $allTelemetry; // Return telemetry data mapped by device_id
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
public function getTelemetryData($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
|
|
]);
|
|
|
|
// dd($response);
|
|
|
|
// 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 filterAlarm(array $data)
|
|
{
|
|
$token = $this->getToken();
|
|
$deviceId = null;
|
|
|
|
if (!empty($data['deviceId'])) {
|
|
$deviceId = $data['deviceId'];
|
|
} elseif (!empty($data['assetId'])) {
|
|
$deviceId = Device::where('asset_id', $data['assetId'])->value('id');
|
|
}
|
|
|
|
if (!empty($data['assetId']) && empty($deviceId)) {
|
|
return [
|
|
'data' => [],
|
|
'totalPages' => 0,
|
|
'totalElements' => 0,
|
|
'hasNext' => false,
|
|
];
|
|
}
|
|
|
|
$queryParams = array_filter([
|
|
'severityList' => $data['severity'] ?? null,
|
|
'assigneeId' => $data['assignId'] ?? null,
|
|
'pageSize' => $data['pageSize'] ?? 10,
|
|
'page' => $data['page'] ?? 0,
|
|
'startTime' => $data['startTs'] ?? null,
|
|
'endTime' => $data['endTs'] ?? null,
|
|
'deviceId' => $deviceId,
|
|
], function ($value) {
|
|
return $value !== null;
|
|
});
|
|
|
|
$url = "{$this->baseUrl}/api/v2/alarms" . (count($queryParams) ? '?' . http_build_query($queryParams) : '');
|
|
|
|
$response = Http::withHeaders([
|
|
'Authorization' => "Bearer $token",
|
|
'Accept' => 'application/json',
|
|
])->get($url);
|
|
|
|
if (!$response->successful()) {
|
|
Log::error("API Error Response:", ['body' => $response->body()]);
|
|
throw new Exception('API Error: ' . $response->body());
|
|
}
|
|
|
|
$responseData = $response->json();
|
|
|
|
// If device filtering was applied, refine the results manually
|
|
if (!empty($deviceId) && isset($responseData['data'])) {
|
|
$filteredData = array_values(array_filter(
|
|
$responseData['data'],
|
|
function ($alarm) use ($deviceId) {
|
|
return isset($alarm['originator']['id']) && $alarm['originator']['id'] === $deviceId;
|
|
}
|
|
));
|
|
|
|
// Update response with the filtered data
|
|
$responseData['data'] = $filteredData;
|
|
$responseData['totalElements'] = count($filteredData);
|
|
}
|
|
|
|
return $responseData;
|
|
}
|
|
|
|
|
|
|
|
public function createOrUpdateAlarm(array $data)
|
|
{
|
|
|
|
$token = $this->getToken();
|
|
|
|
$payload = [
|
|
'type' => $data['type'] ?? null,
|
|
'severity' => $data['severity'] ?? null,
|
|
'acknowledged' => $data['acknowledged'] ?? null,
|
|
'cleared' => $data['cleared'] ?? Carbon::now()->timestamp,
|
|
'startTs' => $data['startTs'] ?? Carbon::now()->timestamp,
|
|
'endTs' => $data['endTs'] ?? Carbon::now()->timestamp,
|
|
'originator' => [
|
|
'id' => $data['originator'] ?? null,
|
|
'entityType' => 'DEVICE'
|
|
],
|
|
// 'assigneeId' => [
|
|
// 'id' => $data['assigneeId'] ?? null,
|
|
// 'entityType' => 'USER'
|
|
// ],
|
|
'details' => $data['details'] ?? [],
|
|
'propagate' => $data['propagate'] ?? false,
|
|
'acknowledged' => false,
|
|
'propagateToOwner' => $data['propagateToOwner'] ?? false,
|
|
|
|
];
|
|
|
|
|
|
// Optional fields
|
|
if (!empty($data['id'])) {
|
|
$payload['id'] = [
|
|
'id' => $data['id'],
|
|
'entityType' => 'ALARM'
|
|
];
|
|
}
|
|
|
|
|
|
|
|
$url = "{$this->baseUrl}/api/alarm";
|
|
$method = 'post';
|
|
|
|
$response = Http::withHeaders([
|
|
'Authorization' => "Bearer $token",
|
|
'Accept' => 'application/json',
|
|
'Content-Type' => 'application/json',
|
|
])->post($url, $payload);
|
|
|
|
if (!$response->successful()) {
|
|
Log::error("API Error Response:", ['body' => $response->body()]);
|
|
throw new Exception('API Error: ' . $response->body());
|
|
}
|
|
|
|
$apiResponse = $response->json();
|
|
|
|
return $apiResponse;
|
|
}
|
|
|
|
|
|
// public function deleteDevice(array $data)
|
|
// {
|
|
// $token = $this->getToken();
|
|
|
|
|
|
// $url = "{$this->baseUrl}/api/device/{$data['deviceId']}";
|
|
|
|
// $response = Http::withHeaders([
|
|
// 'Authorization' => "Bearer $token",
|
|
// 'Accept' => 'application/json',
|
|
// ])->delete($url);
|
|
|
|
|
|
|
|
// // If response body is empty, assume success
|
|
// if ($response->status() === 200 && empty($response->body())) {
|
|
// return ['message' => 'Device deleted successfully'];
|
|
// }
|
|
|
|
// if ($response->successful()) {
|
|
// return $response->json();
|
|
// } else {
|
|
// throw new Exception('Failed to create Device: ' . $response->body());
|
|
// Log::info('API Response:', ['response' => $response]);
|
|
// }
|
|
|
|
// throw new Exception('Failed to create user: ' . $response->body());
|
|
// }
|
|
}
|