mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-15 02:15:21 +00:00
feat: add device name field to DeviceEntity and update related DTOs and services
This commit is contained in:
@ -32,7 +32,10 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
})
|
})
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
@Column({
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
name: string;
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
() => DeviceUserPermissionEntity,
|
() => DeviceUserPermissionEntity,
|
||||||
(permission) => permission.device,
|
(permission) => permission.device,
|
||||||
|
@ -17,6 +17,14 @@ export class AddDeviceDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public spaceUuid: string;
|
public spaceUuid: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'deviceName',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public deviceName: string;
|
||||||
}
|
}
|
||||||
export class AssignDeviceToSpaceDto {
|
export class AssignDeviceToSpaceDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
|
@ -159,6 +159,7 @@ export class DeviceService {
|
|||||||
deviceTuyaUuid: addDeviceDto.deviceTuyaUuid,
|
deviceTuyaUuid: addDeviceDto.deviceTuyaUuid,
|
||||||
productDevice: { uuid: device.productUuid },
|
productDevice: { uuid: device.productUuid },
|
||||||
spaceDevice: { uuid: addDeviceDto.spaceUuid },
|
spaceDevice: { uuid: addDeviceDto.spaceUuid },
|
||||||
|
name: addDeviceDto.deviceName,
|
||||||
});
|
});
|
||||||
if (deviceSaved.uuid) {
|
if (deviceSaved.uuid) {
|
||||||
const deviceStatus: BaseResponseDto =
|
const deviceStatus: BaseResponseDto =
|
||||||
@ -299,22 +300,15 @@ export class DeviceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async updateDeviceNameTuya(
|
async updateDeviceName(deviceUuid: string, deviceName: string) {
|
||||||
deviceId: string,
|
|
||||||
deviceName: string,
|
|
||||||
): Promise<controlDeviceInterface> {
|
|
||||||
try {
|
try {
|
||||||
const path = `/v2.0/cloud/thing/${deviceId}/attribute`;
|
await this.deviceRepository.update(
|
||||||
const response = await this.tuya.request({
|
{ uuid: deviceUuid },
|
||||||
method: 'POST',
|
{ name: deviceName },
|
||||||
path,
|
);
|
||||||
body: { type: 1, data: deviceName },
|
|
||||||
});
|
|
||||||
|
|
||||||
return response as controlDeviceInterface;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'Error updating device name from Tuya',
|
'Error updating device name',
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -643,11 +637,8 @@ export class DeviceService {
|
|||||||
true,
|
true,
|
||||||
projectUuid,
|
projectUuid,
|
||||||
);
|
);
|
||||||
if (device.deviceTuyaUuid) {
|
if (device.uuid) {
|
||||||
await this.updateDeviceNameTuya(
|
await this.updateDeviceName(deviceUuid, updateDeviceDto.deviceName);
|
||||||
device.deviceTuyaUuid,
|
|
||||||
updateDeviceDto.deviceName,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SuccessResponseDto({
|
return new SuccessResponseDto({
|
||||||
@ -682,15 +673,22 @@ export class DeviceService {
|
|||||||
prodId: camelCaseResponse.result.productId,
|
prodId: camelCaseResponse.result.productId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const deviceDetails = await this.deviceRepository.findOne({
|
||||||
|
where: {
|
||||||
|
deviceTuyaUuid: deviceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { productId, id, ...rest } = camelCaseResponse.result;
|
const { productId, id, name, ...rest } = camelCaseResponse.result;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
productUuid: product.uuid,
|
productUuid: product.uuid,
|
||||||
|
name: deviceDetails.name,
|
||||||
} as GetDeviceDetailsInterface;
|
} as GetDeviceDetailsInterface;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log('error', error);
|
||||||
|
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'Error fetching device details from Tuya',
|
'Error fetching device details from Tuya',
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
@ -6,6 +6,18 @@ import { ConfigModule } from '@nestjs/config';
|
|||||||
import { DeviceRepositoryModule } from '@app/common/modules/device';
|
import { DeviceRepositoryModule } from '@app/common/modules/device';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { ProductRepository } from '@app/common/modules/product/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({
|
@Module({
|
||||||
imports: [ConfigModule, DeviceRepositoryModule],
|
imports: [ConfigModule, DeviceRepositoryModule],
|
||||||
controllers: [GroupController],
|
controllers: [GroupController],
|
||||||
@ -15,6 +27,16 @@ import { ProductRepository } from '@app/common/modules/product/repositories';
|
|||||||
SpaceRepository,
|
SpaceRepository,
|
||||||
DeviceRepository,
|
DeviceRepository,
|
||||||
ProductRepository,
|
ProductRepository,
|
||||||
|
DeviceService,
|
||||||
|
SceneDeviceRepository,
|
||||||
|
DeviceStatusFirebaseService,
|
||||||
|
SceneService,
|
||||||
|
TuyaService,
|
||||||
|
ProjectRepository,
|
||||||
|
DeviceStatusLogRepository,
|
||||||
|
SceneIconRepository,
|
||||||
|
SceneRepository,
|
||||||
|
AutomationRepository,
|
||||||
],
|
],
|
||||||
exports: [GroupService],
|
exports: [GroupService],
|
||||||
})
|
})
|
||||||
|
@ -2,19 +2,17 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|||||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
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 { PermissionType } from '@app/common/constants/permission-type.enum';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GroupService {
|
export class GroupService {
|
||||||
private tuya: TuyaContext;
|
private tuya: TuyaContext;
|
||||||
constructor(
|
constructor(
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly productRepository: ProductRepository,
|
private readonly deviceService: DeviceService,
|
||||||
private readonly spaceRepository: SpaceRepository,
|
private readonly spaceRepository: SpaceRepository,
|
||||||
) {
|
) {
|
||||||
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
||||||
@ -101,7 +99,8 @@ export class GroupService {
|
|||||||
spaces.flatMap(async (space) => {
|
spaces.flatMap(async (space) => {
|
||||||
return await Promise.all(
|
return await Promise.all(
|
||||||
space.devices.map(async (device) => {
|
space.devices.map(async (device) => {
|
||||||
const deviceDetails = await this.getDeviceDetailsByDeviceIdTuya(
|
const deviceDetails =
|
||||||
|
await this.deviceService.getDeviceDetailsByDeviceIdTuya(
|
||||||
device.deviceTuyaUuid,
|
device.deviceTuyaUuid,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
@ -126,37 +125,4 @@ export class GroupService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDeviceDetailsByDeviceIdTuya(
|
|
||||||
deviceId: string,
|
|
||||||
): Promise<GetDeviceDetailsInterface> {
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
|
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { GetDeviceDetailsInterface } from 'src/device/interfaces/get.device.interface';
|
|
||||||
import { GetSpaceParam } from '../dtos';
|
import { GetSpaceParam } from '../dtos';
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.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 { ValidationService } from './space-validation.service';
|
||||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||||
import { BatteryStatus } from '@app/common/constants/battery-status.enum';
|
import { BatteryStatus } from '@app/common/constants/battery-status.enum';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SpaceDeviceService {
|
export class SpaceDeviceService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly tuyaService: TuyaService,
|
private readonly tuyaService: TuyaService,
|
||||||
private readonly validationService: ValidationService,
|
private readonly validationService: ValidationService,
|
||||||
|
private readonly deviceService: DeviceService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async listDevicesInSpace(params: GetSpaceParam): Promise<BaseResponseDto> {
|
async listDevicesInSpace(params: GetSpaceParam): Promise<BaseResponseDto> {
|
||||||
@ -60,7 +60,9 @@ export class SpaceDeviceService {
|
|||||||
try {
|
try {
|
||||||
// Fetch Tuya details in parallel
|
// Fetch Tuya details in parallel
|
||||||
const [tuyaDetails, tuyaDeviceStatusResponse] = await Promise.all([
|
const [tuyaDetails, tuyaDeviceStatusResponse] = await Promise.all([
|
||||||
this.getDeviceDetailsByDeviceIdTuya(device.deviceTuyaUuid),
|
this.deviceService.getDeviceDetailsByDeviceIdTuya(
|
||||||
|
device.deviceTuyaUuid,
|
||||||
|
),
|
||||||
this.tuyaService.getDevicesInstructionStatusTuya(device.deviceTuyaUuid),
|
this.tuyaService.getDevicesInstructionStatusTuya(device.deviceTuyaUuid),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -119,28 +121,4 @@ export class SpaceDeviceService {
|
|||||||
);
|
);
|
||||||
return batteryStatus ? batteryStatus.value : null;
|
return batteryStatus ? batteryStatus.value : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getDeviceDetailsByDeviceIdTuya(
|
|
||||||
deviceId: string,
|
|
||||||
): Promise<GetDeviceDetailsInterface> {
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,19 @@ import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { DeviceSubSpaceParam, GetSubSpaceParam } from '../../dtos';
|
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 { ValidationService } from '../space-validation.service';
|
||||||
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
import { In, QueryRunner } from 'typeorm';
|
import { In, QueryRunner } from 'typeorm';
|
||||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
import { DeviceEntity } from '@app/common/modules/device/entities';
|
||||||
import { TagRepository } from '@app/common/modules/space';
|
import { TagRepository } from '@app/common/modules/space';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SubspaceDeviceService {
|
export class SubspaceDeviceService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly subspaceRepository: SubspaceRepository,
|
private readonly subspaceRepository: SubspaceRepository,
|
||||||
private readonly deviceRepository: DeviceRepository,
|
private readonly deviceRepository: DeviceRepository,
|
||||||
private readonly tuyaService: TuyaService,
|
private readonly deviceService: DeviceService,
|
||||||
private readonly productRepository: ProductRepository,
|
|
||||||
private readonly validationService: ValidationService,
|
private readonly validationService: ValidationService,
|
||||||
private readonly tagRepository: TagRepository,
|
private readonly tagRepository: TagRepository,
|
||||||
) {}
|
) {}
|
||||||
@ -39,7 +35,8 @@ export class SubspaceDeviceService {
|
|||||||
|
|
||||||
const safeFetch = async (device: any) => {
|
const safeFetch = async (device: any) => {
|
||||||
try {
|
try {
|
||||||
const tuyaDetails = await this.getDeviceDetailsByDeviceIdTuya(
|
const tuyaDetails =
|
||||||
|
await this.deviceService.getDeviceDetailsByDeviceIdTuya(
|
||||||
device.deviceTuyaUuid,
|
device.deviceTuyaUuid,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -205,35 +202,6 @@ export class SubspaceDeviceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getDeviceDetailsByDeviceIdTuya(
|
|
||||||
deviceId: string,
|
|
||||||
): Promise<GetDeviceDetailsInterface> {
|
|
||||||
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<number> {
|
async findNextTag(): Promise<number> {
|
||||||
const tags = await this.tagRepository.find({ select: ['tag'] });
|
const tags = await this.tagRepository.find({ select: ['tag'] });
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user