From 2f12189eef684aca27be16ba6541b1fcae60191a Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Tue, 22 Apr 2025 01:53:03 +0300 Subject: [PATCH] feat: add device name field to DeviceEntity and update related DTOs and services --- .../modules/device/entities/device.entity.ts | 5 +- src/device/dtos/add.device.dto.ts | 8 ++++ src/device/services/device.service.ts | 38 ++++++++------- src/group/group.module.ts | 22 +++++++++ src/group/services/group.service.ts | 46 +++---------------- src/space/services/space-device.service.ts | 32 ++----------- .../subspace/subspace-device.service.ts | 44 +++--------------- 7 files changed, 69 insertions(+), 126 deletions(-) diff --git a/libs/common/src/modules/device/entities/device.entity.ts b/libs/common/src/modules/device/entities/device.entity.ts index 89c8f23..68b3777 100644 --- a/libs/common/src/modules/device/entities/device.entity.ts +++ b/libs/common/src/modules/device/entities/device.entity.ts @@ -32,7 +32,10 @@ export class DeviceEntity extends AbstractEntity { type: 'boolean', }) isActive: boolean; - + @Column({ + nullable: true, + }) + name: string; @OneToMany( () => DeviceUserPermissionEntity, (permission) => permission.device, diff --git a/src/device/dtos/add.device.dto.ts b/src/device/dtos/add.device.dto.ts index 4801c6a..564dc78 100644 --- a/src/device/dtos/add.device.dto.ts +++ b/src/device/dtos/add.device.dto.ts @@ -17,6 +17,14 @@ export class AddDeviceDto { @IsString() @IsNotEmpty() public spaceUuid: string; + + @ApiProperty({ + description: 'deviceName', + required: true, + }) + @IsString() + @IsNotEmpty() + public deviceName: string; } export class AssignDeviceToSpaceDto { @ApiProperty({ diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index 4729901..827523d 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -159,6 +159,7 @@ export class DeviceService { deviceTuyaUuid: addDeviceDto.deviceTuyaUuid, productDevice: { uuid: device.productUuid }, spaceDevice: { uuid: addDeviceDto.spaceUuid }, + name: addDeviceDto.deviceName, }); if (deviceSaved.uuid) { const deviceStatus: BaseResponseDto = @@ -299,22 +300,15 @@ export class DeviceService { ); } } - async updateDeviceNameTuya( - deviceId: string, - deviceName: string, - ): Promise { + async updateDeviceName(deviceUuid: string, deviceName: string) { try { - const path = `/v2.0/cloud/thing/${deviceId}/attribute`; - const response = await this.tuya.request({ - method: 'POST', - path, - body: { type: 1, data: deviceName }, - }); - - return response as controlDeviceInterface; + await this.deviceRepository.update( + { uuid: deviceUuid }, + { name: deviceName }, + ); } catch (error) { throw new HttpException( - 'Error updating device name from Tuya', + 'Error updating device name', HttpStatus.INTERNAL_SERVER_ERROR, ); } @@ -643,11 +637,8 @@ export class DeviceService { true, projectUuid, ); - if (device.deviceTuyaUuid) { - await this.updateDeviceNameTuya( - device.deviceTuyaUuid, - updateDeviceDto.deviceName, - ); + if (device.uuid) { + await this.updateDeviceName(deviceUuid, updateDeviceDto.deviceName); } return new SuccessResponseDto({ @@ -682,15 +673,22 @@ export class DeviceService { prodId: camelCaseResponse.result.productId, }, }); - + const deviceDetails = await this.deviceRepository.findOne({ + where: { + deviceTuyaUuid: deviceId, + }, + }); // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { productId, id, ...rest } = camelCaseResponse.result; + const { productId, id, name, ...rest } = camelCaseResponse.result; return { ...rest, productUuid: product.uuid, + name: deviceDetails.name, } as GetDeviceDetailsInterface; } catch (error) { + console.log('error', error); + throw new HttpException( 'Error fetching device details from Tuya', HttpStatus.INTERNAL_SERVER_ERROR, diff --git a/src/group/group.module.ts b/src/group/group.module.ts index b5ade2d..6b3f0b0 100644 --- a/src/group/group.module.ts +++ b/src/group/group.module.ts @@ -6,6 +6,18 @@ import { ConfigModule } from '@nestjs/config'; import { DeviceRepositoryModule } from '@app/common/modules/device'; import { SpaceRepository } from '@app/common/modules/space/repositories'; import { ProductRepository } from '@app/common/modules/product/repositories'; +import { DeviceService } from 'src/device/services'; +import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; +import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service'; +import { SceneService } from 'src/scene/services'; +import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; +import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories'; +import { + SceneIconRepository, + SceneRepository, +} from '@app/common/modules/scene/repositories'; +import { AutomationRepository } from '@app/common/modules/automation/repositories'; @Module({ imports: [ConfigModule, DeviceRepositoryModule], controllers: [GroupController], @@ -15,6 +27,16 @@ import { ProductRepository } from '@app/common/modules/product/repositories'; SpaceRepository, DeviceRepository, ProductRepository, + DeviceService, + SceneDeviceRepository, + DeviceStatusFirebaseService, + SceneService, + TuyaService, + ProjectRepository, + DeviceStatusLogRepository, + SceneIconRepository, + SceneRepository, + AutomationRepository, ], exports: [GroupService], }) diff --git a/src/group/services/group.service.ts b/src/group/services/group.service.ts index 049e82d..25f37d5 100644 --- a/src/group/services/group.service.ts +++ b/src/group/services/group.service.ts @@ -2,19 +2,17 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { TuyaContext } from '@tuya/tuya-connector-nodejs'; import { ConfigService } from '@nestjs/config'; import { SpaceRepository } from '@app/common/modules/space/repositories'; -import { GetDeviceDetailsInterface } from 'src/device/interfaces/get.device.interface'; -import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; -import { ProductRepository } from '@app/common/modules/product/repositories'; import { PermissionType } from '@app/common/constants/permission-type.enum'; import { In } from 'typeorm'; import { ProductType } from '@app/common/constants/product-type.enum'; +import { DeviceService } from 'src/device/services'; @Injectable() export class GroupService { private tuya: TuyaContext; constructor( private readonly configService: ConfigService, - private readonly productRepository: ProductRepository, + private readonly deviceService: DeviceService, private readonly spaceRepository: SpaceRepository, ) { const accessKey = this.configService.get('auth-config.ACCESS_KEY'); @@ -101,9 +99,10 @@ export class GroupService { spaces.flatMap(async (space) => { return await Promise.all( space.devices.map(async (device) => { - const deviceDetails = await this.getDeviceDetailsByDeviceIdTuya( - device.deviceTuyaUuid, - ); + const deviceDetails = + await this.deviceService.getDeviceDetailsByDeviceIdTuya( + device.deviceTuyaUuid, + ); return { haveRoom: !!device.spaceDevice, productUuid: device.productDevice.uuid, @@ -126,37 +125,4 @@ export class GroupService { ); } } - - async getDeviceDetailsByDeviceIdTuya( - deviceId: string, - ): Promise { - try { - const path = `/v1.1/iot-03/devices/${deviceId}`; - const response = await this.tuya.request({ - method: 'GET', - path, - }); - - // Convert keys to camel case - const camelCaseResponse = convertKeysToCamelCase(response); - const product = await this.productRepository.findOne({ - where: { - prodId: camelCaseResponse.result.productId, - }, - }); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { productName, productId, ...rest } = camelCaseResponse.result; - - return { - ...rest, - productUuid: product.uuid, - } as GetDeviceDetailsInterface; - } catch (error) { - throw new HttpException( - 'Error fetching device details from Tuya', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } } diff --git a/src/space/services/space-device.service.ts b/src/space/services/space-device.service.ts index df9597b..891df3e 100644 --- a/src/space/services/space-device.service.ts +++ b/src/space/services/space-device.service.ts @@ -1,21 +1,21 @@ import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { GetDeviceDetailsInterface } from 'src/device/interfaces/get.device.interface'; import { GetSpaceParam } from '../dtos'; import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; -import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; import { ValidationService } from './space-validation.service'; import { ProductType } from '@app/common/constants/product-type.enum'; import { BatteryStatus } from '@app/common/constants/battery-status.enum'; +import { DeviceService } from 'src/device/services'; @Injectable() export class SpaceDeviceService { constructor( private readonly tuyaService: TuyaService, private readonly validationService: ValidationService, + private readonly deviceService: DeviceService, ) {} async listDevicesInSpace(params: GetSpaceParam): Promise { @@ -60,7 +60,9 @@ export class SpaceDeviceService { try { // Fetch Tuya details in parallel const [tuyaDetails, tuyaDeviceStatusResponse] = await Promise.all([ - this.getDeviceDetailsByDeviceIdTuya(device.deviceTuyaUuid), + this.deviceService.getDeviceDetailsByDeviceIdTuya( + device.deviceTuyaUuid, + ), this.tuyaService.getDevicesInstructionStatusTuya(device.deviceTuyaUuid), ]); @@ -119,28 +121,4 @@ export class SpaceDeviceService { ); return batteryStatus ? batteryStatus.value : null; } - - private async getDeviceDetailsByDeviceIdTuya( - deviceId: string, - ): Promise { - try { - const tuyaDeviceDetails = - await this.tuyaService.getDeviceDetails(deviceId); - - // Convert keys to camel case - const camelCaseResponse = convertKeysToCamelCase(tuyaDeviceDetails); - - // Exclude specific keys and add `productUuid` - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { uuid, ...rest } = camelCaseResponse; - return { - ...rest, - } as GetDeviceDetailsInterface; - } catch (error) { - throw new HttpException( - `Error fetching device details from Tuya for device id ${deviceId}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } } diff --git a/src/space/services/subspace/subspace-device.service.ts b/src/space/services/subspace/subspace-device.service.ts index 66553b0..5a572e5 100644 --- a/src/space/services/subspace/subspace-device.service.ts +++ b/src/space/services/subspace/subspace-device.service.ts @@ -3,23 +3,19 @@ import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { DeviceRepository } from '@app/common/modules/device/repositories'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { DeviceSubSpaceParam, GetSubSpaceParam } from '../../dtos'; -import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; -import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; -import { ProductRepository } from '@app/common/modules/product/repositories'; -import { GetDeviceDetailsInterface } from '../../../device/interfaces/get.device.interface'; import { ValidationService } from '../space-validation.service'; import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository'; import { In, QueryRunner } from 'typeorm'; import { DeviceEntity } from '@app/common/modules/device/entities'; import { TagRepository } from '@app/common/modules/space'; +import { DeviceService } from 'src/device/services'; @Injectable() export class SubspaceDeviceService { constructor( private readonly subspaceRepository: SubspaceRepository, private readonly deviceRepository: DeviceRepository, - private readonly tuyaService: TuyaService, - private readonly productRepository: ProductRepository, + private readonly deviceService: DeviceService, private readonly validationService: ValidationService, private readonly tagRepository: TagRepository, ) {} @@ -39,9 +35,10 @@ export class SubspaceDeviceService { const safeFetch = async (device: any) => { try { - const tuyaDetails = await this.getDeviceDetailsByDeviceIdTuya( - device.deviceTuyaUuid, - ); + const tuyaDetails = + await this.deviceService.getDeviceDetailsByDeviceIdTuya( + device.deviceTuyaUuid, + ); return { uuid: device.uuid, @@ -205,35 +202,6 @@ export class SubspaceDeviceService { ); } - private async getDeviceDetailsByDeviceIdTuya( - deviceId: string, - ): Promise { - try { - const tuyaDeviceDetails = - await this.tuyaService.getDeviceDetails(deviceId); - - const camelCaseResponse = convertKeysToCamelCase(tuyaDeviceDetails); - - const product = await this.productRepository.findOne({ - where: { - prodId: camelCaseResponse.productId, - }, - }); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { uuid, ...rest } = camelCaseResponse; - return { - ...rest, - productUuid: product?.uuid, - } as GetDeviceDetailsInterface; - } catch (error) { - throw new HttpException( - `Error fetching device details from Tuya for device uuid ${deviceId}.`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - async findNextTag(): Promise { const tags = await this.tagRepository.find({ select: ['tag'] });