sayliR #48

Merged
Sayli.Raut merged 3 commits from sayliR into main 2025-03-28 08:23:42 +00:00
5 changed files with 217 additions and 120 deletions

View File

@@ -11,6 +11,7 @@ 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;
class TelemetryController extends Controller
@@ -26,119 +27,80 @@ class TelemetryController extends Controller
public function telemetryDataAsset(Request $request)
{
try {
// Read and validate token first
$token = readHeaderToken();
if (!$token) {
return response()->json([
'success' => false,
'error' => 'Authorization token required'
], 401);
}
$validator = Validator::make($request->all(), [
'asset_id' => 'required|string',
'startTs' => 'nullable|string',
'endTs' => 'nullable|string',
]);
$validator = Validator::make($request->all(), [
'asset_id' => 'required|string',
'startTs' => 'nullable|string',
'endTs' => 'nullable|string',
]);
if ($validator->fails()) {
return jsonResponseWithErrorMessage($validator->errors()->first(), 400);
}
if ($validator->fails()) {
return response()->json([
'success' => false,
'error' => $validator->errors()->first()
], 400);
}
$assetId = $request->input('asset_id');
$startTs = $request->input('startTs') ?: null;
$endTs = $request->input('endTs') ?: null;
$assetId = $request->input('asset_id');
$startTs = $request->input('startTs');
$endTs = $request->input('endTs');
// Get devices with their profiles and timeseries keys
$devices = Device::with(['deviceProfile', 'timeseriesKeys' => function($query) {
$query->where('display_on_dashboard', true)
->orWhere('display_on_popup', true)
->select(['key_name', 'display_name', 'display_on_dashboard', 'display_on_popup', 'device_profile_xid']);
}])
// Fetch devices associated with the asset
$devices = Device::with('deviceProfile')
->where('asset_id', $assetId)
->get();
if ($devices->isEmpty()) {
return response()->json([
'success' => false,
'error' => 'No devices found for the asset'
], 404);
}
if ($devices->isEmpty()) {
return response()->json(['error' => 'No devices found for the asset'], 404);
}
// Prepare data for bulk telemetry request
$deviceIds = $devices->pluck('id');
$allKeyNames = TimeseriesKeyMaster::whereIn('device_profile_xid', $devices->pluck('device_profile_id'))
->where(function($query) {
$response = [];
foreach ($devices as $device) {
$telemetry = [];
// Fetch key names and additional columns from TimeseriesKeyMaster
$keysData = TimeseriesKeyMaster::where('device_profile_xid', $device->device_profile_id)
->where(function ($query) {
$query->where('display_on_dashboard', true)
->orWhere('display_on_popup', true);
->orWhere('display_on_popup', true);
})
->pluck('key_name')
->unique()
->toArray();
->get(['key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']);
// Get telemetry data with token
$bulkTelemetry = $this->customerInfoService->getTelemetryData(
$deviceIds,
$allKeyNames,
$startTs,
$endTs,
$token // Pass the token to the service
);
$keyNames = $keysData->pluck('key_name')->toArray();
if (!is_array($bulkTelemetry)) {
throw new \Exception("Invalid telemetry data format received from service");
}
// Log key names for debugging
// Log::info('Key Names for Device', ['device_id' => $device->id, 'key_names' => $keyNames]);
// Format the response
$response = $devices->map(function($device) use ($bulkTelemetry) {
$telemetry = collect();
// Fetch telemetry data
$telemetryResponse = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTs, $endTs);
foreach ($device->timeseriesKeys as $keyData) {
$keyName = $keyData->key_name;
foreach ($keysData as $keyData) {
$keyName = $keyData->key_name;
if (isset($bulkTelemetry[$device->id][$keyName])) {
$telemetry = $telemetry->merge(
collect($bulkTelemetry[$device->id][$keyName])->map(function($item) use ($keyData) {
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' => $item['ts'] ?? null,
'value' => $item['value'] ?? null,
];
})
);
if (isset($telemetryResponse[$keyName])) {
foreach ($telemetryResponse[$keyName] as $item) {
$telemetry[] = [
'key_name' => $keyName,
'display_name' => $keyData->display_name,
'display_on_dashboard' => $keyData->display_on_dashboard,
'display_on_popup' => $keyData->display_on_popup,
'timestamp' => $item['ts'] ?? null,
'value' => $item['value'] ?? null,
];
}
}
}
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->values()->all(),
];
});
return response()->json([
'success' => true,
'telemetry' => $response
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'error' => 'Failed to fetch telemetry data',
'details' => config('app.debug') ? $e->getMessage() : null
], 500);
$response[] = [
'device_id' => (string) $device->id,
'device_profile_name' => (string) $device->deviceProfile->name,
'asset_id' => (string) $device->asset_id,
'device_profile_id' => (string) $device->device_profile_id,
'telemetry' => $telemetry,
];
}
return response()->json(['telemetry' => $response]);
}
public function telemetryDataDevice(Request $request)
{
try {
@@ -165,14 +127,16 @@ class TelemetryController extends Controller
}
$deviceId = $request->input('device_id');
$startTs = $request->input('startTs');
$endTs = $request->input('endTs');
$startTs = $request->input('startTs') ?: null;
$endTs = $request->input('endTs') ?: null;
try {
$deviceWithTelemetry = Device::with(['deviceProfile',
'timeseriesKeys' => function($query) {
$deviceWithTelemetry = Device::with([
'deviceProfile',
'timeseriesKeys' => function ($query) {
$query->select('key_name', 'display_name', 'device_profile_xid');
}])
}
])
->where('id', $deviceId)
->firstOrFail();
@@ -216,13 +180,11 @@ class TelemetryController extends Controller
'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,
@@ -230,7 +192,6 @@ class TelemetryController extends Controller
'details' => config('app.debug') ? $e->getMessage() : null
], 503);
}
} catch (\Exception $e) {
return response()->json([
'success' => false,
@@ -361,4 +322,4 @@ class TelemetryController extends Controller
// return response()->json(['telemetry' => $response]);
// }
}
}

View File

@@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Http;
use Illuminate\Http\Request;
class AlarmController extends Controller
class AlarmControllerCommon extends Controller
{
protected $alarmService;
@@ -151,4 +151,35 @@ class AlarmController extends Controller
}
public function filterAlarm(Request $request)
{
try {
$alarmData = $request->only([
// 'statusList',
'severity',
// 'type',
// 'assigneeId',
'pageSize',
'page',
// 'textSearch',
// 'sortProperty',
// 'sortOrder',
'startTs',
'endTs'
]);
$apiResponse = $this->alarmService->filterAlarm($alarmData);
return jsonResponseWithSuccessMessage('Alarm data retrieved successfully', ['api_response' => $apiResponse]);
} catch (Exception $e) {
Log::error("Error: " . $e->getMessage());
$errorResponse = json_decode($e->getMessage(), true);
if (json_last_error() === JSON_ERROR_NONE) {
return jsonResponseWithErrorMessage($errorResponse['message'] ?? 'Something went wrong', 400, $errorResponse);
}
return jsonResponseWithErrorMessage($e->getMessage(), 500);
}
}
}

View File

@@ -8,6 +8,9 @@ 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
{
@@ -16,8 +19,44 @@ class AlarmService
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 {
@@ -214,6 +253,8 @@ class AlarmService
public function getTelemetryData($device, $keyNames, $startTs, $endTs)
{
$token = $this->adminService->getToken();
@@ -307,6 +348,62 @@ class AlarmService
return $response->json();
}
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,
'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)
// {

View File

@@ -54,7 +54,7 @@ class CustomerInfoService
public function getTelemetryData($device, $keyNames, $startTs, $endTs)
public function getTelemetryData($device, $keyNames, $startTs , $endTs )
{
$token = $this->adminService->getToken();
@@ -68,15 +68,16 @@ public function getTelemetryData($device, $keyNames, $startTs, $endTs)
$keys = implode(',', $keyNames);
// Build query parameters dynamically
$queryParams = [
'keys' => $keys,
];
if (!empty($startTs)) {
if ($startTs) {
$queryParams['startTs'] = $startTs;
}
if (!empty($endTs)) {
if ($endTs) {
$queryParams['interval'] = $endTs;
}
@@ -99,7 +100,7 @@ public function getTelemetryData($device, $keyNames, $startTs, $endTs)
// Decode the telemetry response
$telemetry = $response->json();
// Log::info("Telemetry Data", $telemetry);
Log::info("Telemetry Data", $telemetry);
if (json_last_error() !== JSON_ERROR_NONE) {
Log::error("Failed to decode telemetry response for device: {$device->name}", [
@@ -128,19 +129,23 @@ public function getTelemetryData($device, $keyNames, $startTs, $endTs)
$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/58bf81a0-0619-11f0-a9dc-45dd276e4cd5/values/timeseries", [
])->get("$baseUrl/api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries", [
'Accept' => 'application/json',
])->get("$baseUrl/api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries", $queryParams);
'keys' => $keys,
'startTs' => $startTs,
'interval' => $endTs,
'limit' => 100,
'useStrictDataTypes' => false
]);

View File

@@ -3,7 +3,8 @@
// use App\Http\Controllers\AssetController;
use App\Http\Controllers\APIS\AdminApi\AlarmController;
use App\Http\Controllers\APIS\CustomerApi\CustomerController;
use App\Http\Controllers\AlarmControllerCommon;
use App\Http\Controllers\APIS\AdminApi\CustomerController;
use App\Http\Controllers\APIS\AdminApi\UsersController;
use App\Http\Controllers\APIS\AdminApi\DeviceController;
use Illuminate\Http\Request;
@@ -48,6 +49,7 @@ Route::post('/users-customer-list', [UsersController::class, 'userlistCustomer']
//******************************************************* Device API********************************************************
Route::post('/device/create-or-update', [DeviceController::class, 'createOrUpdateDevice'])->name('device.create-or-update');
Route::get('/device/list', [DeviceController::class, 'listDevices'])->name('device.list');
@@ -61,6 +63,7 @@ Route::post('/update-device-profile-master/{deviceId}', [DeviceProfileMasterCont
//******************************************************* Alarm API ********************************************************
Route::post('/alarm/create-or-update', [AlarmController::class, 'createOrUpdateAlarm'])->name('alarm.create-or-update');
Route::get('/alarm/{id}', [AlarmController::class, 'getAlarmById'])->name('get.alarm');
Route::post('/alarm/ack/{id}', [AlarmController::class, 'acknowledgeAlarmById'])->name('ack.alarm');
Route::post('/alarm/create-or-update', [AlarmControllerCommon::class, 'createOrUpdateAlarm'])->name('alarm.create-or-update');
Route::get('/alarm/{id}', [AlarmControllerCommon::class, 'getAlarmById'])->name('get.alarm');
Route::post('/alarm/ack/{id}', [AlarmControllerCommon::class, 'acknowledgeAlarmById'])->name('ack.alarm');
Route::post('/alarm/filter', [AlarmControllerCommon::class, 'filterAlarm'])->name('alarm.filter');