Refactoring API's for Customer Dashboard

This commit is contained in:
Nikhil Kadam
2025-04-30 19:40:01 +05:30
parent c0a92d9edd
commit 0b9c8c9660
11 changed files with 882 additions and 8 deletions

View File

@@ -6,6 +6,7 @@ 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;
@@ -13,12 +14,14 @@ 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
{
@@ -33,7 +36,6 @@ class TelemetryController extends Controller
$this->customerInfoService = $customerInfoService;
$this->alarmService = $alarmService;
$this->adminService = $adminService;
}
@@ -837,4 +839,501 @@ class TelemetryController extends Controller
// 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' => $this->getAssetHealth($deviceHealthStatuses),
'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) {
$transformedTelemetry[] = [
'display_name' => $displayNameMap[$key] ?? $key,
'value' => $item['value']
];
}
}
}
return [
'deviceId' => $device->id,
'deviceName' => $device->name,
'deviceType' => $deviceProfileName,
'indicator' => $transformedTelemetry
];
})->values();
return [
'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(
[
'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(
[
'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);
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
function parameters()
{
$keys = [
"4e989080-04ad-11f0-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'PowerLoss_value,ChannelSpeed',
"keyNameList2" => 'MechanicalHealth_valueInHealth,ChannelSpeed',
],
"88986090-16b3-11f0-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'PowerLoss_value,ChannelSpeed',
"keyNameList2" => 'MechanicalHealth_valueInHealth,ChannelSpeed',
],
"a7802800-f34d-11ef-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'PowerLoss_value,ChannelSpeed',
"keyNameList2" => 'MechanicalHealth_valueInHealth,ChannelSpeed',
],
"b82d42a0-f34d-11ef-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'GlobalMixed_valueInPercent,ChannelSpeed',
"keyNameList2" => 'BearingGlobal_valueInPercent,ChannelSpeed',
],
"b60d08f0-16b3-11f0-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'GlobalMixed_valueInPercent,ChannelSpeed',
"keyNameList2" => 'BearingGlobal_valueInPercent,ChannelSpeed',
],
"b13497a0-f34d-11ef-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'RegularityDeviation_valueInPercent,BladeStatus_valueInPercent,ChannelSpeed',
"keyNameList2" => 'BearingStatus_valueInPercent,TurbineCoupling_valueInPercent,ChannelSpeed',
],
"72907b10-04ad-11f0-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'RegularityDeviation_valueInPercent,BladeStatus_valueInPercent,ChannelSpeed',
"keyNameList2" => 'BearingStatus_valueInPercent,TurbineCoupling_valueInPercent,ChannelSpeed',
],
"bfbd2490-f34d-11ef-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'StaticTorque_value,ChannelSpeed',
"keyNameList2" => 'StaticPower_value,ChannelSpeed',
]
];
return $keys;
}

View File

@@ -369,4 +369,48 @@ if (!function_exists('getTokenFromHeader')) {
}
}
}
}
}
if (!function_exists('parameters')) {
function parameters()
{
$keys = [
"4e989080-04ad-11f0-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'PowerLoss_value,ChannelSpeed',
"keyNameList2" => 'MechanicalHealth_valueInHealth,ChannelSpeed',
],
"88986090-16b3-11f0-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'PowerLoss_value,ChannelSpeed',
"keyNameList2" => 'MechanicalHealth_valueInHealth,ChannelSpeed',
],
"a7802800-f34d-11ef-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'PowerLoss_value,ChannelSpeed',
"keyNameList2" => 'MechanicalHealth_valueInHealth,ChannelSpeed',
],
"b82d42a0-f34d-11ef-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'GlobalMixed_valueInPercent,ChannelSpeed',
"keyNameList2" => 'BearingGlobal_valueInPercent,ChannelSpeed',
],
"b60d08f0-16b3-11f0-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'GlobalMixed_valueInPercent,ChannelSpeed',
"keyNameList2" => 'BearingGlobal_valueInPercent,ChannelSpeed',
],
"b13497a0-f34d-11ef-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'RegularityDeviation_valueInPercent,BladeStatus_valueInPercent,ChannelSpeed',
"keyNameList2" => 'BearingStatus_valueInPercent,TurbineCoupling_valueInPercent,ChannelSpeed',
],
"72907b10-04ad-11f0-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'RegularityDeviation_valueInPercent,BladeStatus_valueInPercent,ChannelSpeed',
"keyNameList2" => 'BearingStatus_valueInPercent,TurbineCoupling_valueInPercent,ChannelSpeed',
],
"bfbd2490-f34d-11ef-a9dc-45dd276e4cd5" => [
"keyNameList1" => 'StaticTorque_value,ChannelSpeed',
"keyNameList2" => 'StaticPower_value,ChannelSpeed',
]
];
return $keys;
}
}

View File

@@ -53,6 +53,11 @@ class Asset extends Model
return $this->belongsTo(Customer::class, 'customer_xid', 'id');
}
public function userLinks()
{
return $this->hasMany(UserAssetLink::class, 'asset_id', 'id');
}
public function devices()
{
return $this->hasMany(Device::class, 'asset_id', 'id');

View File

@@ -33,12 +33,11 @@ class AdminService
// 'accept' => 'application/json',
'Content-Type' => 'application/json',
])
->post("{$this->baseUrl}/api/auth/login", [
->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));

View File

@@ -364,7 +364,6 @@ class CustomerInfoService
$username = env('THINGSBOARD_USERNAME', 'tenant1@thingsboard.org');
$password = env('THINGSBOARD_PASSWORD', 'tenant1');
if (Cache::has('thingsboard_token')) {
return Cache::get('thingsboard_token');
}
@@ -381,7 +380,7 @@ class CustomerInfoService
if ($response->successful()) {
$token = $response->json('token');
Cache::put('thingsboard_token', $token, now()->addMinutes(15));
Cache::put('thingsboard_token', $token, now()->addMinutes(1440));
return $token;
} else {
Log::error("ThingsBoard Authentication Failed: " . $response->body());
@@ -389,4 +388,222 @@ class CustomerInfoService
}
}
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)
{
try {
$token = $this->adminService->getToken();
if (!$token) {
throw new \Exception("Failed to authenticate with ThingsBoard");
}
$url = env('THINGSBOARD_URL') . 'api/alarmsQuery/find';
// Timestamp range (modify as needed)
$startTs = now()->subDays(30)->timestamp * 1000;
$endTs = now()->timestamp * 1000;
$payload = [
"entityFilter" => [
"type" => "entityList",
"entityType" => "DEVICE",
"entityList" => $deviceIds
],
"pageLink" => [
"startTs" => $startTs,
"endTs" => $endTs,
"pageSize" => 100,
"page" => 0,
"textSearch" => "",
"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);
}
}
}

View File

@@ -98,7 +98,7 @@ return [
'users' => [
'provider' => 'users',
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
'expire' => 60,
'expire' => 1440,
'throttle' => 60,
],
],

View File

@@ -101,7 +101,7 @@ return [
|
*/
'ttl' => env('JWT_TTL', 60),
'ttl' => env('JWT_TTL', 1440),
/*
|--------------------------------------------------------------------------

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('timeseries_key_master', function (Blueprint $table) {
$table->tinyInteger('display_on_health_condition')->default(0)->after('display_on_popup');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('timeseries_key_master', function (Blueprint $table) {
$table->dropColumn('display_on_health_condition');
});
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('timeseries_key_master', function (Blueprint $table) {
$table->tinyInteger('display_on_alerts')->default(0)->after('display_on_health_condition');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('timeseries_key_master', function (Blueprint $table) {
$table->dropColumn('display_on_alerts');
});
}
};

View File

@@ -44,4 +44,15 @@ Route::middleware(['customerApiBasicAuth'])->group(function () {
Route::post('/alarm/filter', [AlarmControllerCommon::class, 'filterAlarm'])->name('alarm.filter');
Route::post('/alarm', [AlarmControllerCommon::class, 'getDeviceAlarms'])->name('alarm.device');
// ***************************************** Based on Documentation ***********************************************
Route::get('/entity-query', [TelemetryController::class, 'entityQuery']);
Route::get('/user-assets-new', [TelemetryController::class, 'userAssetsNew']);
Route::get('/customer-device-info-new', [TelemetryController::class, 'customerDeviceInfoNew']);
Route::get('/get-device-indicators/{assetId}', [TelemetryController::class, 'getDeviceIndicators']);
Route::get('/get-alerts/{deviceId}', [TelemetryController::class, 'getAlerts']);
Route::get('/get-global-indicators/{deviceId}', [TelemetryController::class, 'getGlobalIndicators']);
Route::get('/get-trends/{deviceId}', [TelemetryController::class, 'getTrends']);
});