mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-15 18:27:05 +00:00
Refactor Device Module
This commit is contained in:
@ -1,26 +1,19 @@
|
|||||||
import { Column, Entity, OneToMany } from 'typeorm';
|
import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
import { DeviceDto } from '../dtos/device.dto';
|
import { DeviceDto } from '../dtos/device.dto';
|
||||||
import { DeviceUserPermissionEntity } from './device-user-type.entity';
|
import { DeviceUserPermissionEntity } from './device-user-type.entity';
|
||||||
import { GroupDeviceEntity } from '../../group-device/entities';
|
import { GroupDeviceEntity } from '../../group-device/entities';
|
||||||
|
import { SpaceEntity } from '../../space/entities';
|
||||||
|
import { ProductEntity } from '../../product/entities';
|
||||||
|
|
||||||
@Entity({ name: 'device' })
|
@Entity({ name: 'device' })
|
||||||
|
@Unique(['spaceDevice', 'deviceTuyaUuid'])
|
||||||
export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
||||||
@Column({
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
public spaceUuid: string;
|
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
deviceTuyaUuid: string;
|
deviceTuyaUuid: string;
|
||||||
|
|
||||||
@Column({
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
public productUuid: string;
|
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: true,
|
nullable: true,
|
||||||
default: true,
|
default: true,
|
||||||
@ -44,6 +37,15 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
|||||||
)
|
)
|
||||||
userGroupDevices: GroupDeviceEntity[];
|
userGroupDevices: GroupDeviceEntity[];
|
||||||
|
|
||||||
|
@ManyToOne(() => SpaceEntity, (space) => space.devicesSpaceEntity, {
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
spaceDevice: SpaceEntity;
|
||||||
|
|
||||||
|
@ManyToOne(() => ProductEntity, (product) => product.devicesProductEntity, {
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
productDevice: ProductEntity;
|
||||||
constructor(partial: Partial<DeviceEntity>) {
|
constructor(partial: Partial<DeviceEntity>) {
|
||||||
super();
|
super();
|
||||||
Object.assign(this, partial);
|
Object.assign(this, partial);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Column, Entity } from 'typeorm';
|
import { Column, Entity, OneToMany } from 'typeorm';
|
||||||
import { ProductDto } from '../dtos';
|
import { ProductDto } from '../dtos';
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
|
import { DeviceEntity } from '../../device/entities';
|
||||||
|
|
||||||
@Entity({ name: 'product' })
|
@Entity({ name: 'product' })
|
||||||
export class ProductEntity extends AbstractEntity<ProductDto> {
|
export class ProductEntity extends AbstractEntity<ProductDto> {
|
||||||
@ -20,6 +21,11 @@ export class ProductEntity extends AbstractEntity<ProductDto> {
|
|||||||
})
|
})
|
||||||
public prodType: string;
|
public prodType: string;
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
() => DeviceEntity,
|
||||||
|
(devicesProductEntity) => devicesProductEntity.productDevice,
|
||||||
|
)
|
||||||
|
devicesProductEntity: DeviceEntity[];
|
||||||
constructor(partial: Partial<ProductEntity>) {
|
constructor(partial: Partial<ProductEntity>) {
|
||||||
super();
|
super();
|
||||||
Object.assign(this, partial);
|
Object.assign(this, partial);
|
||||||
|
@ -3,6 +3,7 @@ import { SpaceDto } from '../dtos';
|
|||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
import { SpaceTypeEntity } from '../../space-type/entities';
|
import { SpaceTypeEntity } from '../../space-type/entities';
|
||||||
import { UserSpaceEntity } from '../../user-space/entities';
|
import { UserSpaceEntity } from '../../user-space/entities';
|
||||||
|
import { DeviceEntity } from '../../device/entities';
|
||||||
|
|
||||||
@Entity({ name: 'space' })
|
@Entity({ name: 'space' })
|
||||||
export class SpaceEntity extends AbstractEntity<SpaceDto> {
|
export class SpaceEntity extends AbstractEntity<SpaceDto> {
|
||||||
@ -30,6 +31,12 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
|
|||||||
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.space)
|
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.space)
|
||||||
userSpaces: UserSpaceEntity[];
|
userSpaces: UserSpaceEntity[];
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
() => DeviceEntity,
|
||||||
|
(devicesSpaceEntity) => devicesSpaceEntity.spaceDevice,
|
||||||
|
)
|
||||||
|
devicesSpaceEntity: DeviceEntity[];
|
||||||
|
|
||||||
constructor(partial: Partial<SpaceEntity>) {
|
constructor(partial: Partial<SpaceEntity>) {
|
||||||
super();
|
super();
|
||||||
Object.assign(this, partial);
|
Object.assign(this, partial);
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
import { DeviceService } from '../services/device.service';
|
import { DeviceService } from '../services/device.service';
|
||||||
import { Body, Controller, Get, Post, Query, Param } from '@nestjs/common';
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Query,
|
||||||
|
Param,
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
|
UseGuards,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||||
import {
|
import {
|
||||||
AddDeviceInGroupDto,
|
AddDeviceInGroupDto,
|
||||||
@ -7,11 +17,12 @@ import {
|
|||||||
} from '../dtos/add.device.dto';
|
} from '../dtos/add.device.dto';
|
||||||
import {
|
import {
|
||||||
GetDeviceByGroupIdDto,
|
GetDeviceByGroupIdDto,
|
||||||
GetDeviceByRoomIdDto,
|
GetDeviceByRoomUuidDto,
|
||||||
} from '../dtos/get.device.dto';
|
} from '../dtos/get.device.dto';
|
||||||
import { ControlDeviceDto } from '../dtos/control.device.dto';
|
import { ControlDeviceDto } from '../dtos/control.device.dto';
|
||||||
import { AuthGuardWithRoles } from 'src/guards/device.permission.guard';
|
import { CheckRoomGuard } from 'src/guards/room.guard';
|
||||||
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
import { CheckGroupGuard } from 'src/guards/group.guard';
|
||||||
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
|
|
||||||
@ApiTags('Device Module')
|
@ApiTags('Device Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
@ -22,19 +33,38 @@ export class DeviceController {
|
|||||||
constructor(private readonly deviceService: DeviceService) {}
|
constructor(private readonly deviceService: DeviceService) {}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@AuthGuardWithRoles(PermissionType.READ)
|
@UseGuards(JwtAuthGuard, CheckRoomGuard)
|
||||||
@Get('room')
|
@Get('room')
|
||||||
async getDevicesByRoomId(
|
async getDevicesByRoomId(
|
||||||
@Query() getDeviceByRoomIdDto: GetDeviceByRoomIdDto,
|
@Query() getDeviceByRoomUuidDto: GetDeviceByRoomUuidDto,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
return await this.deviceService.getDevicesByRoomId(getDeviceByRoomIdDto);
|
return await this.deviceService.getDevicesByRoomId(
|
||||||
} catch (err) {
|
getDeviceByRoomUuidDto,
|
||||||
throw new Error(err);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
throw new HttpException(
|
||||||
|
error.message || 'Internal server error',
|
||||||
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard, CheckRoomGuard)
|
||||||
|
@Post('room')
|
||||||
|
async addDeviceInRoom(@Body() addDeviceInRoomDto: AddDeviceInRoomDto) {
|
||||||
|
try {
|
||||||
|
return await this.deviceService.addDeviceInRoom(addDeviceInRoomDto);
|
||||||
|
} catch (error) {
|
||||||
|
throw new HttpException(
|
||||||
|
error.message || 'Internal server error',
|
||||||
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@AuthGuardWithRoles(PermissionType.READ)
|
@UseGuards(JwtAuthGuard, CheckGroupGuard)
|
||||||
@Get('group')
|
@Get('group')
|
||||||
async getDevicesByGroupId(
|
async getDevicesByGroupId(
|
||||||
@Query() getDeviceByGroupIdDto: GetDeviceByGroupIdDto,
|
@Query() getDeviceByGroupIdDto: GetDeviceByGroupIdDto,
|
||||||
@ -43,68 +73,81 @@ export class DeviceController {
|
|||||||
return await this.deviceService.getDevicesByGroupId(
|
return await this.deviceService.getDevicesByGroupId(
|
||||||
getDeviceByGroupIdDto,
|
getDeviceByGroupIdDto,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
throw new Error(err);
|
throw new HttpException(
|
||||||
|
error.message || 'Internal server error',
|
||||||
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@AuthGuardWithRoles(PermissionType.READ)
|
@UseGuards(JwtAuthGuard, CheckGroupGuard)
|
||||||
@Get(':deviceId')
|
|
||||||
async getDeviceDetailsByDeviceId(@Param('deviceId') deviceId: string) {
|
|
||||||
try {
|
|
||||||
return await this.deviceService.getDeviceDetailsByDeviceId(deviceId);
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@AuthGuardWithRoles(PermissionType.READ)
|
|
||||||
@Get(':deviceId/functions')
|
|
||||||
async getDeviceInstructionByDeviceId(@Param('deviceId') deviceId: string) {
|
|
||||||
try {
|
|
||||||
return await this.deviceService.getDeviceInstructionByDeviceId(deviceId);
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@AuthGuardWithRoles(PermissionType.READ)
|
|
||||||
@Get(':deviceId/functions/status')
|
|
||||||
async getDevicesInstructionStatus(@Param('deviceId') deviceId: string) {
|
|
||||||
try {
|
|
||||||
return await this.deviceService.getDevicesInstructionStatus(deviceId);
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@AuthGuardWithRoles(PermissionType.CONTROLLABLE)
|
|
||||||
@Post('room')
|
|
||||||
async addDeviceInRoom(@Body() addDeviceInRoomDto: AddDeviceInRoomDto) {
|
|
||||||
try {
|
|
||||||
return await this.deviceService.addDeviceInRoom(addDeviceInRoomDto);
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@AuthGuardWithRoles(PermissionType.CONTROLLABLE)
|
|
||||||
@Post('group')
|
@Post('group')
|
||||||
async addDeviceInGroup(@Body() addDeviceInGroupDto: AddDeviceInGroupDto) {
|
async addDeviceInGroup(@Body() addDeviceInGroupDto: AddDeviceInGroupDto) {
|
||||||
try {
|
try {
|
||||||
return await this.deviceService.addDeviceInGroup(addDeviceInGroupDto);
|
return await this.deviceService.addDeviceInGroup(addDeviceInGroupDto);
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
throw new Error(err);
|
throw new HttpException(
|
||||||
|
error.message || 'Internal server error',
|
||||||
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@AuthGuardWithRoles(PermissionType.CONTROLLABLE)
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Get(':deviceUuid')
|
||||||
|
async getDeviceDetailsByDeviceId(@Param('deviceUuid') deviceUuid: string) {
|
||||||
|
try {
|
||||||
|
return await this.deviceService.getDeviceDetailsByDeviceId(deviceUuid);
|
||||||
|
} catch (error) {
|
||||||
|
throw new HttpException(
|
||||||
|
error.message || 'Internal server error',
|
||||||
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Get(':deviceUuid/functions')
|
||||||
|
async getDeviceInstructionByDeviceId(
|
||||||
|
@Param('deviceUuid') deviceUuid: string,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
return await this.deviceService.getDeviceInstructionByDeviceId(
|
||||||
|
deviceUuid,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
throw new HttpException(
|
||||||
|
error.message || 'Internal server error',
|
||||||
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Get(':deviceUuid/functions/status')
|
||||||
|
async getDevicesInstructionStatus(@Param('deviceUuid') deviceUuid: string) {
|
||||||
|
try {
|
||||||
|
return await this.deviceService.getDevicesInstructionStatus(deviceUuid);
|
||||||
|
} catch (error) {
|
||||||
|
throw new HttpException(
|
||||||
|
error.message || 'Internal server error',
|
||||||
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
@Post('control')
|
@Post('control')
|
||||||
async controlDevice(@Body() controlDeviceDto: ControlDeviceDto) {
|
async controlDevice(@Body() controlDeviceDto: ControlDeviceDto) {
|
||||||
try {
|
try {
|
||||||
return await this.deviceService.controlDevice(controlDeviceDto);
|
return await this.deviceService.controlDevice(controlDeviceDto);
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
throw new Error(err);
|
throw new HttpException(
|
||||||
|
error.message || 'Internal server error',
|
||||||
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,15 @@ import {
|
|||||||
import { PermissionTypeRepository } from '@app/common/modules/permission/repositories';
|
import { PermissionTypeRepository } from '@app/common/modules/permission/repositories';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { GroupDeviceRepository } from '@app/common/modules/group-device/repositories';
|
import { GroupDeviceRepository } from '@app/common/modules/group-device/repositories';
|
||||||
|
import { GroupRepository } from '@app/common/modules/group/repositories';
|
||||||
|
import { GroupRepositoryModule } from '@app/common/modules/group/group.repository.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, ProductRepositoryModule, DeviceRepositoryModule],
|
imports: [
|
||||||
|
ConfigModule,
|
||||||
|
ProductRepositoryModule,
|
||||||
|
DeviceRepositoryModule,
|
||||||
|
GroupRepositoryModule,
|
||||||
|
],
|
||||||
controllers: [DeviceController],
|
controllers: [DeviceController],
|
||||||
providers: [
|
providers: [
|
||||||
DeviceService,
|
DeviceService,
|
||||||
@ -23,6 +30,7 @@ import { GroupDeviceRepository } from '@app/common/modules/group-device/reposito
|
|||||||
SpaceRepository,
|
SpaceRepository,
|
||||||
DeviceRepository,
|
DeviceRepository,
|
||||||
GroupDeviceRepository,
|
GroupDeviceRepository,
|
||||||
|
GroupRepository,
|
||||||
],
|
],
|
||||||
exports: [DeviceService],
|
exports: [DeviceService],
|
||||||
})
|
})
|
||||||
|
@ -1,45 +1,37 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { IsNotEmpty, IsString, IsNumberString } from 'class-validator';
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class AddDeviceInRoomDto {
|
export class AddDeviceInRoomDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'deviceId',
|
description: 'deviceTuyaUuid',
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public deviceId: string;
|
public deviceTuyaUuid: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'roomId',
|
description: 'roomUuid',
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@IsNumberString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public roomId: string;
|
public roomUuid: string;
|
||||||
}
|
}
|
||||||
export class AddDeviceInGroupDto {
|
export class AddDeviceInGroupDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'deviceId',
|
description: 'deviceUuid',
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public deviceId: string;
|
public deviceUuid: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'homeId',
|
description: 'groupUuid',
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@IsNumberString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public homeId: string;
|
public groupUuid: string;
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'groupId',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
@IsNumberString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
public groupId: string;
|
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@ import { IsNotEmpty, IsString } from 'class-validator';
|
|||||||
|
|
||||||
export class ControlDeviceDto {
|
export class ControlDeviceDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'deviceId',
|
description: 'deviceUuid',
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public deviceId: string;
|
public deviceUuid: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'code',
|
description: 'code',
|
||||||
|
@ -1,44 +1,21 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { IsNotEmpty, IsNumberString } from 'class-validator';
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class GetDeviceByRoomIdDto {
|
export class GetDeviceByRoomUuidDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'roomId',
|
description: 'roomUuid',
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@IsNumberString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public roomId: string;
|
public roomUuid: string;
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'pageSize',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
@IsNumberString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
public pageSize: number;
|
|
||||||
}
|
}
|
||||||
export class GetDeviceByGroupIdDto {
|
export class GetDeviceByGroupIdDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'groupId',
|
description: 'groupUuid',
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
@IsNumberString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public groupId: string;
|
public groupUuid: string;
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'pageSize',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
@IsNumberString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
public pageSize: number;
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'pageNo',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
@IsNumberString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
public pageNo: number;
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
export interface GetDeviceDetailsInterface {
|
export interface GetDeviceDetailsInterface {
|
||||||
result: {
|
activeTime: number;
|
||||||
productId: string;
|
assetId: string;
|
||||||
};
|
category: string;
|
||||||
success: boolean;
|
categoryName: string;
|
||||||
msg: string;
|
createTime: number;
|
||||||
}
|
gatewayId: string;
|
||||||
export interface GetDevicesByRoomIdInterface {
|
icon: string;
|
||||||
success: boolean;
|
id: string;
|
||||||
msg: string;
|
ip: string;
|
||||||
result: any;
|
lat: string;
|
||||||
}
|
localKey: string;
|
||||||
|
lon: string;
|
||||||
export interface GetDevicesByGroupIdInterface {
|
model: string;
|
||||||
success: boolean;
|
name: string;
|
||||||
msg: string;
|
nodeId: string;
|
||||||
result: {
|
online: boolean;
|
||||||
count: number;
|
productId?: string;
|
||||||
data_list: [];
|
productName?: string;
|
||||||
};
|
sub: boolean;
|
||||||
|
timeZone: string;
|
||||||
|
updateTime: number;
|
||||||
|
uuid: string;
|
||||||
|
productType: string;
|
||||||
|
productUuid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface addDeviceInRoomInterface {
|
export interface addDeviceInRoomInterface {
|
||||||
@ -44,21 +49,13 @@ export interface GetDeviceDetailsFunctionsStatusInterface {
|
|||||||
success: boolean;
|
success: boolean;
|
||||||
msg: string;
|
msg: string;
|
||||||
}
|
}
|
||||||
export interface GetProductInterface {
|
|
||||||
productType: string;
|
|
||||||
productId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DeviceInstructionResponse {
|
export interface DeviceInstructionResponse {
|
||||||
success: boolean;
|
productUuid: string;
|
||||||
result: {
|
|
||||||
productId: string;
|
|
||||||
productType: string;
|
productType: string;
|
||||||
functions: {
|
functions: {
|
||||||
code: string;
|
code: string;
|
||||||
values: any[];
|
values: any[];
|
||||||
dataType: string;
|
dataType: string;
|
||||||
}[];
|
}[];
|
||||||
};
|
|
||||||
msg: string;
|
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,11 @@ import {
|
|||||||
GetDeviceDetailsFunctionsInterface,
|
GetDeviceDetailsFunctionsInterface,
|
||||||
GetDeviceDetailsFunctionsStatusInterface,
|
GetDeviceDetailsFunctionsStatusInterface,
|
||||||
GetDeviceDetailsInterface,
|
GetDeviceDetailsInterface,
|
||||||
GetDevicesByGroupIdInterface,
|
|
||||||
GetDevicesByRoomIdInterface,
|
|
||||||
GetProductInterface,
|
|
||||||
addDeviceInRoomInterface,
|
|
||||||
controlDeviceInterface,
|
controlDeviceInterface,
|
||||||
} from '../interfaces/get.device.interface';
|
} from '../interfaces/get.device.interface';
|
||||||
import {
|
import {
|
||||||
GetDeviceByGroupIdDto,
|
GetDeviceByGroupIdDto,
|
||||||
GetDeviceByRoomIdDto,
|
GetDeviceByRoomUuidDto,
|
||||||
} from '../dtos/get.device.dto';
|
} from '../dtos/get.device.dto';
|
||||||
import { ControlDeviceDto } from '../dtos/control.device.dto';
|
import { ControlDeviceDto } from '../dtos/control.device.dto';
|
||||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||||
@ -51,25 +47,31 @@ export class DeviceService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDevicesByRoomId(getDeviceByRoomIdDto: GetDeviceByRoomIdDto) {
|
async getDevicesByRoomId(
|
||||||
|
getDeviceByRoomUuidDto: GetDeviceByRoomUuidDto,
|
||||||
|
): Promise<GetDeviceDetailsInterface[]> {
|
||||||
try {
|
try {
|
||||||
const findRoom = await this.spaceRepository.findOne({
|
const devices = await this.deviceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
uuid: getDeviceByRoomIdDto.roomId,
|
spaceDevice: { uuid: getDeviceByRoomUuidDto.roomUuid },
|
||||||
},
|
},
|
||||||
|
relations: ['spaceDevice', 'productDevice'],
|
||||||
});
|
});
|
||||||
if (!findRoom) {
|
const devicesData = await Promise.all(
|
||||||
throw new NotFoundException('Room Details Not Found');
|
devices.map(async (device) => {
|
||||||
}
|
|
||||||
|
|
||||||
const response = await this.getDevicesByRoomIdTuya(getDeviceByRoomIdDto);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: response.success,
|
...(await this.getDeviceDetailsByDeviceIdTuya(
|
||||||
devices: response.result,
|
device.deviceTuyaUuid,
|
||||||
msg: response.msg,
|
)),
|
||||||
};
|
uuid: device.uuid,
|
||||||
|
productUuid: device.productDevice.uuid,
|
||||||
|
productType: device.productDevice.prodType,
|
||||||
|
} as GetDeviceDetailsInterface;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return devicesData;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// Handle the error here
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'Error fetching devices by room',
|
'Error fetching devices by room',
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
@ -77,68 +79,26 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDevicesByRoomIdTuya(
|
|
||||||
getDeviceByRoomIdDto: GetDeviceByRoomIdDto,
|
|
||||||
): Promise<GetDevicesByRoomIdInterface> {
|
|
||||||
try {
|
|
||||||
const path = `/v2.0/cloud/thing/space/device`;
|
|
||||||
const getDeviceByRoomId = await this.deviceRepository.find({
|
|
||||||
where: {
|
|
||||||
deviceTuyaUuid: getDeviceByRoomIdDto.roomId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const response: any = await this.tuya.request({
|
|
||||||
method: 'GET',
|
|
||||||
path,
|
|
||||||
query: {
|
|
||||||
space_ids: getDeviceByRoomIdDto.roomId,
|
|
||||||
page_size: getDeviceByRoomIdDto.pageSize,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!getDeviceByRoomId.length) {
|
|
||||||
throw new NotFoundException('Devices Not Found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const matchingRecords = [];
|
|
||||||
|
|
||||||
getDeviceByRoomId.forEach((item1) => {
|
|
||||||
const matchingItem = response.find(
|
|
||||||
(item2) => item1.deviceTuyaUuid === item2.uuid,
|
|
||||||
);
|
|
||||||
if (matchingItem) {
|
|
||||||
matchingRecords.push({ ...matchingItem });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
msg: 'Device Tuya Details Fetched successfully',
|
|
||||||
result: matchingRecords,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
'Error fetching devices by room from Tuya',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async getDevicesByGroupId(getDeviceByGroupIdDto: GetDeviceByGroupIdDto) {
|
async getDevicesByGroupId(getDeviceByGroupIdDto: GetDeviceByGroupIdDto) {
|
||||||
try {
|
try {
|
||||||
const devicesIds: GetDevicesByGroupIdInterface =
|
const groupDevices = await this.groupDeviceRepository.find({
|
||||||
await this.getDevicesByGroupIdTuya(getDeviceByGroupIdDto);
|
where: { group: { uuid: getDeviceByGroupIdDto.groupUuid } },
|
||||||
const devicesDetails = await Promise.all(
|
relations: ['device'],
|
||||||
devicesIds.result.data_list.map(async (device: any) => {
|
});
|
||||||
const deviceData = await this.getDeviceDetailsByDeviceId(
|
const devicesData = await Promise.all(
|
||||||
device.dev_id,
|
groupDevices.map(async (device) => {
|
||||||
);
|
return {
|
||||||
return deviceData.result;
|
...(await this.getDeviceDetailsByDeviceIdTuya(
|
||||||
|
device.device.deviceTuyaUuid,
|
||||||
|
)),
|
||||||
|
uuid: device.uuid,
|
||||||
|
productUuid: device.device.productDevice.uuid,
|
||||||
|
productType: device.device.productDevice.prodType,
|
||||||
|
} as GetDeviceDetailsInterface;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return {
|
|
||||||
success: devicesIds.success,
|
return devicesData;
|
||||||
devices: devicesDetails,
|
|
||||||
msg: devicesIds.msg,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'Error fetching devices by group',
|
'Error fetching devices by group',
|
||||||
@ -147,134 +107,62 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDevicesByGroupIdTuya(
|
|
||||||
getDeviceByGroupIdDto: GetDeviceByGroupIdDto,
|
|
||||||
): Promise<GetDevicesByGroupIdInterface> {
|
|
||||||
try {
|
|
||||||
const path = `/v2.0/cloud/thing/group/${getDeviceByGroupIdDto.groupId}/devices`;
|
|
||||||
const response = await this.tuya.request({
|
|
||||||
method: 'GET',
|
|
||||||
path,
|
|
||||||
query: {
|
|
||||||
page_size: getDeviceByGroupIdDto.pageSize,
|
|
||||||
page_no: getDeviceByGroupIdDto.pageNo,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return response as GetDevicesByGroupIdInterface;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
'Error fetching devices by group from Tuya',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async addDeviceInRoom(addDeviceInRoomDto: AddDeviceInRoomDto) {
|
async addDeviceInRoom(addDeviceInRoomDto: AddDeviceInRoomDto) {
|
||||||
const [deviceDetails, roomDetails] = await Promise.all([
|
|
||||||
this.deviceRepository.findOne({
|
|
||||||
where: {
|
|
||||||
uuid: addDeviceInRoomDto.deviceId,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
this.spaceRepository.findOne({
|
|
||||||
where: {
|
|
||||||
uuid: addDeviceInRoomDto.roomId,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!roomDetails) {
|
|
||||||
throw new NotFoundException('Room Details Not Found');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!deviceDetails) {
|
|
||||||
throw new NotFoundException('Device Details Not Found');
|
|
||||||
}
|
|
||||||
const response = await this.addDeviceInRooms(addDeviceInRoomDto);
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
return {
|
|
||||||
success: response.success,
|
|
||||||
result: response.result,
|
|
||||||
msg: response.msg,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
throw new HttpException(
|
|
||||||
response.msg || 'Unknown error',
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async addDeviceInRooms(
|
|
||||||
addDeviceInRoomDto: AddDeviceInRoomDto,
|
|
||||||
): Promise<addDeviceInRoomInterface> {
|
|
||||||
try {
|
try {
|
||||||
const path = `/v2.0/cloud/thing/${addDeviceInRoomDto.deviceId}/transfer`;
|
const device = await this.getDeviceDetailsByDeviceIdTuya(
|
||||||
const response = await this.tuya.request({
|
addDeviceInRoomDto.deviceTuyaUuid,
|
||||||
method: 'POST',
|
|
||||||
path,
|
|
||||||
body: {
|
|
||||||
space_id: addDeviceInRoomDto.roomId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return response as addDeviceInRoomInterface;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
'Error adding device in room from Tuya',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!device.productUuid) {
|
||||||
|
throw new Error('Product UUID is missing for the device.');
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.deviceRepository.save({
|
||||||
|
deviceTuyaUuid: addDeviceInRoomDto.deviceTuyaUuid,
|
||||||
|
spaceDevice: { uuid: addDeviceInRoomDto.roomUuid },
|
||||||
|
productDevice: { uuid: device.productUuid },
|
||||||
|
});
|
||||||
|
return { message: 'device added in room successfully' };
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === '23505') {
|
||||||
|
throw new Error('Device already exists in the room.');
|
||||||
|
} else {
|
||||||
|
throw new Error('Failed to add device in room');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async addDeviceInGroup(addDeviceInGroupDto: AddDeviceInGroupDto) {
|
async addDeviceInGroup(addDeviceInGroupDto: AddDeviceInGroupDto) {
|
||||||
const deviceDetails = this.deviceRepository.findOne({
|
|
||||||
where: {
|
|
||||||
uuid: addDeviceInGroupDto.deviceId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!deviceDetails) {
|
|
||||||
throw new NotFoundException('Device Details Not Found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await this.addDeviceInGroups(addDeviceInGroupDto);
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
return {
|
|
||||||
success: response.success,
|
|
||||||
result: response.result,
|
|
||||||
msg: response.msg,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
throw new HttpException(
|
|
||||||
response.msg || 'Unknown error',
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async addDeviceInGroups(
|
|
||||||
addDeviceInGroupDto: AddDeviceInGroupDto,
|
|
||||||
): Promise<addDeviceInRoomInterface> {
|
|
||||||
try {
|
try {
|
||||||
await this.groupDeviceRepository.create({
|
await this.groupDeviceRepository.save({
|
||||||
deviceUuid: addDeviceInGroupDto.deviceId,
|
device: { uuid: addDeviceInGroupDto.deviceUuid },
|
||||||
groupUuid: addDeviceInGroupDto.groupId,
|
group: { uuid: addDeviceInGroupDto.groupUuid },
|
||||||
});
|
});
|
||||||
|
return { message: 'device added in group successfully' };
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
msg: 'Group is Added to Specific Device',
|
|
||||||
result: true,
|
|
||||||
} as addDeviceInRoomInterface;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
if (error.code === '23505') {
|
||||||
'Error adding device in group from Tuya',
|
throw new Error('Device already exists in the group.');
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
} else {
|
||||||
);
|
throw new Error('Failed to add device in group');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async controlDevice(controlDeviceDto: ControlDeviceDto) {
|
async controlDevice(controlDeviceDto: ControlDeviceDto) {
|
||||||
const response = await this.controlDeviceTuya(controlDeviceDto);
|
try {
|
||||||
|
const deviceDetails = await this.deviceRepository.findOne({
|
||||||
|
where: {
|
||||||
|
uuid: controlDeviceDto.deviceUuid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
|
||||||
|
throw new NotFoundException('Device Not Found');
|
||||||
|
}
|
||||||
|
const response = await this.controlDeviceTuya(
|
||||||
|
deviceDetails.deviceTuyaUuid,
|
||||||
|
controlDeviceDto,
|
||||||
|
);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
return response;
|
return response;
|
||||||
@ -284,12 +172,16 @@ export class DeviceService {
|
|||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async controlDeviceTuya(
|
async controlDeviceTuya(
|
||||||
|
deviceUuid: string,
|
||||||
controlDeviceDto: ControlDeviceDto,
|
controlDeviceDto: ControlDeviceDto,
|
||||||
): Promise<controlDeviceInterface> {
|
): Promise<controlDeviceInterface> {
|
||||||
try {
|
try {
|
||||||
const path = `/v1.0/iot-03/devices/${controlDeviceDto.deviceId}/commands`;
|
const path = `/v1.0/iot-03/devices/${deviceUuid}/commands`;
|
||||||
const response = await this.tuya.request({
|
const response = await this.tuya.request({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
path,
|
path,
|
||||||
@ -309,29 +201,30 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDeviceDetailsByDeviceId(deviceId: string) {
|
async getDeviceDetailsByDeviceId(deviceUuid: string) {
|
||||||
try {
|
try {
|
||||||
const deviceDetails = await this.deviceRepository.findOne({
|
const deviceDetails = await this.deviceRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
uuid: deviceId,
|
uuid: deviceUuid,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!deviceDetails) {
|
if (!deviceDetails) {
|
||||||
throw new NotFoundException('Device Details Not Found');
|
throw new NotFoundException('Device Not Found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await this.getDeviceDetailsByDeviceIdTuya(deviceId);
|
const response = await this.getDeviceDetailsByDeviceIdTuya(
|
||||||
|
deviceDetails.deviceTuyaUuid,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: response.success,
|
...response,
|
||||||
result: response.result,
|
uuid: deviceDetails.uuid,
|
||||||
msg: response.msg,
|
productUuid: deviceDetails.productDevice.uuid,
|
||||||
|
productType: deviceDetails.productDevice.prodType,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||||
'Error fetching device details',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async getDeviceDetailsByDeviceIdTuya(
|
async getDeviceDetailsByDeviceIdTuya(
|
||||||
@ -343,19 +236,14 @@ export class DeviceService {
|
|||||||
method: 'GET',
|
method: 'GET',
|
||||||
path,
|
path,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Convert keys to camel case
|
// Convert keys to camel case
|
||||||
const camelCaseResponse = convertKeysToCamelCase(response);
|
const camelCaseResponse = convertKeysToCamelCase(response);
|
||||||
const productType: string = await this.getProductTypeByProductId(
|
|
||||||
camelCaseResponse.result.productId,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { productName, productId, ...rest } = camelCaseResponse.result;
|
||||||
return {
|
return {
|
||||||
result: {
|
...rest,
|
||||||
...camelCaseResponse.result,
|
|
||||||
productType: productType,
|
|
||||||
},
|
|
||||||
success: camelCaseResponse.success,
|
|
||||||
msg: camelCaseResponse.msg,
|
|
||||||
} as GetDeviceDetailsInterface;
|
} as GetDeviceDetailsInterface;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
@ -364,78 +252,29 @@ export class DeviceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async getProductIdByDeviceId(deviceId: string) {
|
|
||||||
try {
|
|
||||||
const deviceDetails: GetDeviceDetailsInterface =
|
|
||||||
await this.getDeviceDetailsByDeviceId(deviceId);
|
|
||||||
|
|
||||||
return deviceDetails.result.productId;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
'Error fetching product id by device id',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async getProductByProductId(productId: string): Promise<GetProductInterface> {
|
|
||||||
try {
|
|
||||||
const product = await this.productRepository
|
|
||||||
.createQueryBuilder('product')
|
|
||||||
.where('product.prodId = :productId', { productId })
|
|
||||||
.select(['product.prodId', 'product.prodType'])
|
|
||||||
.getOne();
|
|
||||||
|
|
||||||
if (product) {
|
|
||||||
return {
|
|
||||||
productType: product.prodType,
|
|
||||||
productId: product.prodId,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
throw new HttpException('Product not found', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
'Error fetching product by product id from db',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async getProductTypeByProductId(productId: string) {
|
|
||||||
try {
|
|
||||||
const product = await this.getProductByProductId(productId);
|
|
||||||
return product.productType;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
'Error getting product type by product id',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDeviceInstructionByDeviceId(
|
async getDeviceInstructionByDeviceId(
|
||||||
deviceId: string,
|
deviceUuid: string,
|
||||||
): Promise<DeviceInstructionResponse> {
|
): Promise<DeviceInstructionResponse> {
|
||||||
try {
|
try {
|
||||||
const deviceDetails = await this.deviceRepository.findOne({
|
const deviceDetails = await this.deviceRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
uuid: deviceId,
|
uuid: deviceUuid,
|
||||||
},
|
},
|
||||||
|
relations: ['productDevice'],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!deviceDetails) {
|
if (!deviceDetails) {
|
||||||
throw new NotFoundException('Device Details Not Found');
|
throw new NotFoundException('Device Not Found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await this.getDeviceInstructionByDeviceIdTuya(deviceId);
|
const response = await this.getDeviceInstructionByDeviceIdTuya(
|
||||||
|
deviceDetails.deviceTuyaUuid,
|
||||||
const productId: string = await this.getProductIdByDeviceId(deviceId);
|
);
|
||||||
const productType: string =
|
|
||||||
await this.getProductTypeByProductId(productId);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: response.success,
|
productUuid: deviceDetails.productDevice.uuid,
|
||||||
result: {
|
productType: deviceDetails.productDevice.prodType,
|
||||||
productId: productId,
|
|
||||||
productType: productType,
|
|
||||||
functions: response.result.functions.map((fun: any) => {
|
functions: response.result.functions.map((fun: any) => {
|
||||||
return {
|
return {
|
||||||
code: fun.code,
|
code: fun.code,
|
||||||
@ -443,14 +282,9 @@ export class DeviceService {
|
|||||||
dataType: fun.type,
|
dataType: fun.type,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
|
||||||
msg: response.msg,
|
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||||
'Error fetching device functions by device id',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,28 +305,26 @@ export class DeviceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async getDevicesInstructionStatus(deviceId: string) {
|
async getDevicesInstructionStatus(deviceUuid: string) {
|
||||||
try {
|
try {
|
||||||
const deviceDetails = await this.deviceRepository.findOne({
|
const deviceDetails = await this.deviceRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
uuid: deviceId,
|
uuid: deviceUuid,
|
||||||
},
|
},
|
||||||
|
relations: ['productDevice'],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!deviceDetails) {
|
if (!deviceDetails) {
|
||||||
throw new NotFoundException('Device Details Not Found');
|
throw new NotFoundException('Device Not Found');
|
||||||
}
|
}
|
||||||
const deviceStatus = await this.getDevicesInstructionStatusTuya(deviceId);
|
const deviceStatus = await this.getDevicesInstructionStatusTuya(
|
||||||
const productId: string = await this.getProductIdByDeviceId(deviceId);
|
deviceDetails.deviceTuyaUuid,
|
||||||
const productType: string =
|
);
|
||||||
await this.getProductTypeByProductId(productId);
|
|
||||||
return {
|
return {
|
||||||
result: {
|
productUuid: deviceDetails.productDevice.uuid,
|
||||||
productId: productId,
|
productType: deviceDetails.productDevice.prodType,
|
||||||
productType: productType,
|
|
||||||
status: deviceStatus.result[0].status,
|
status: deviceStatus.result[0].status,
|
||||||
},
|
|
||||||
success: deviceStatus.success,
|
|
||||||
msg: deviceStatus.msg,
|
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
@ -503,7 +335,7 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getDevicesInstructionStatusTuya(
|
async getDevicesInstructionStatusTuya(
|
||||||
deviceId: string,
|
deviceUuid: string,
|
||||||
): Promise<GetDeviceDetailsFunctionsStatusInterface> {
|
): Promise<GetDeviceDetailsFunctionsStatusInterface> {
|
||||||
try {
|
try {
|
||||||
const path = `/v1.0/iot-03/devices/status`;
|
const path = `/v1.0/iot-03/devices/status`;
|
||||||
@ -511,10 +343,10 @@ export class DeviceService {
|
|||||||
method: 'GET',
|
method: 'GET',
|
||||||
path,
|
path,
|
||||||
query: {
|
query: {
|
||||||
device_ids: deviceId,
|
device_ids: deviceUuid,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return response as unknown as GetDeviceDetailsFunctionsStatusInterface;
|
return response as GetDeviceDetailsFunctionsStatusInterface;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'Error fetching device functions status from Tuya',
|
'Error fetching device functions status from Tuya',
|
||||||
|
@ -43,7 +43,7 @@ export class GroupService {
|
|||||||
const groupDevices = await this.groupDeviceRepository.find({
|
const groupDevices = await this.groupDeviceRepository.find({
|
||||||
relations: ['group', 'device'],
|
relations: ['group', 'device'],
|
||||||
where: {
|
where: {
|
||||||
device: { spaceUuid },
|
device: { spaceDevice: { uuid: spaceUuid } },
|
||||||
isActive: true,
|
isActive: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -129,6 +129,7 @@ export class GroupService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async controlDevice(controlDeviceDto: ControlDeviceDto) {
|
async controlDevice(controlDeviceDto: ControlDeviceDto) {
|
||||||
|
try {
|
||||||
const response = await this.controlDeviceTuya(controlDeviceDto);
|
const response = await this.controlDeviceTuya(controlDeviceDto);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
@ -139,12 +140,15 @@ export class GroupService {
|
|||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async controlDeviceTuya(
|
async controlDeviceTuya(
|
||||||
controlDeviceDto: ControlDeviceDto,
|
controlDeviceDto: ControlDeviceDto,
|
||||||
): Promise<controlDeviceInterface> {
|
): Promise<controlDeviceInterface> {
|
||||||
try {
|
try {
|
||||||
const path = `/v1.0/iot-03/devices/${controlDeviceDto.deviceId}/commands`;
|
const path = `/v1.0/iot-03/devices/${controlDeviceDto.deviceUuid}/commands`;
|
||||||
const response = await this.tuya.request({
|
const response = await this.tuya.request({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
path,
|
path,
|
||||||
@ -170,7 +174,7 @@ export class GroupService {
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
devices.map(async (device) => {
|
devices.map(async (device) => {
|
||||||
return this.controlDevice({
|
return this.controlDevice({
|
||||||
deviceId: device.device.deviceTuyaUuid,
|
deviceUuid: device.device.deviceTuyaUuid,
|
||||||
code: controlGroupDto.code,
|
code: controlGroupDto.code,
|
||||||
value: controlGroupDto.value,
|
value: controlGroupDto.value,
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,7 @@ export class CheckProductUuidForAllDevicesGuard implements CanActivate {
|
|||||||
throw new BadRequestException('First device not found');
|
throw new BadRequestException('First device not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstProductUuid = firstDevice.productUuid;
|
const firstProductUuid = firstDevice.productDevice.uuid;
|
||||||
|
|
||||||
for (let i = 1; i < deviceUuids.length; i++) {
|
for (let i = 1; i < deviceUuids.length; i++) {
|
||||||
const device = await this.deviceRepository.findOne({
|
const device = await this.deviceRepository.findOne({
|
||||||
@ -47,7 +47,7 @@ export class CheckProductUuidForAllDevicesGuard implements CanActivate {
|
|||||||
throw new BadRequestException(`Device ${deviceUuids[i]} not found`);
|
throw new BadRequestException(`Device ${deviceUuids[i]} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.productUuid !== firstProductUuid) {
|
if (device.productDevice.uuid !== firstProductUuid) {
|
||||||
throw new BadRequestException(`Devices have different product UUIDs`);
|
throw new BadRequestException(`Devices have different product UUIDs`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
81
src/guards/group.guard.ts
Normal file
81
src/guards/group.guard.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import {
|
||||||
|
CanActivate,
|
||||||
|
ExecutionContext,
|
||||||
|
Injectable,
|
||||||
|
HttpStatus,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
|
||||||
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { GroupRepository } from '@app/common/modules/group/repositories';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CheckGroupGuard implements CanActivate {
|
||||||
|
constructor(
|
||||||
|
private readonly groupRepository: GroupRepository,
|
||||||
|
private readonly deviceRepository: DeviceRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const req = context.switchToHttp().getRequest();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (req.query && req.query.groupUuid) {
|
||||||
|
const { groupUuid } = req.query;
|
||||||
|
await this.checkGroupIsFound(groupUuid);
|
||||||
|
} else if (req.body && req.body.groupUuid && req.body.deviceUuid) {
|
||||||
|
const { groupUuid, deviceUuid } = req.body;
|
||||||
|
await this.checkGroupIsFound(groupUuid);
|
||||||
|
await this.checkDeviceIsFound(deviceUuid);
|
||||||
|
} else {
|
||||||
|
throw new BadRequestException('Invalid request parameters');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
this.handleGuardError(error, context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async checkGroupIsFound(groupUuid: string) {
|
||||||
|
const group = await this.groupRepository.findOne({
|
||||||
|
where: {
|
||||||
|
uuid: groupUuid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!group) {
|
||||||
|
throw new NotFoundException('Group not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async checkDeviceIsFound(deviceUuid: string) {
|
||||||
|
const device = await this.deviceRepository.findOne({
|
||||||
|
where: {
|
||||||
|
uuid: deviceUuid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!device) {
|
||||||
|
throw new NotFoundException('Device not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleGuardError(error: Error, context: ExecutionContext) {
|
||||||
|
const response = context.switchToHttp().getResponse();
|
||||||
|
if (error instanceof NotFoundException) {
|
||||||
|
response
|
||||||
|
.status(HttpStatus.NOT_FOUND)
|
||||||
|
.json({ statusCode: HttpStatus.NOT_FOUND, message: error.message });
|
||||||
|
} else if (error instanceof BadRequestException) {
|
||||||
|
response
|
||||||
|
.status(HttpStatus.BAD_REQUEST)
|
||||||
|
.json({ statusCode: HttpStatus.BAD_REQUEST, message: error.message });
|
||||||
|
} else {
|
||||||
|
response.status(HttpStatus.BAD_REQUEST).json({
|
||||||
|
statusCode: HttpStatus.BAD_REQUEST,
|
||||||
|
message: 'Invalid UUID',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
src/guards/room.guard.ts
Normal file
100
src/guards/room.guard.ts
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import {
|
||||||
|
CanActivate,
|
||||||
|
ExecutionContext,
|
||||||
|
Injectable,
|
||||||
|
HttpStatus,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||||
|
|
||||||
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CheckRoomGuard implements CanActivate {
|
||||||
|
private tuya: TuyaContext;
|
||||||
|
constructor(
|
||||||
|
private readonly configService: ConfigService,
|
||||||
|
private readonly spaceRepository: SpaceRepository,
|
||||||
|
private readonly deviceRepository: DeviceRepository,
|
||||||
|
) {
|
||||||
|
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
||||||
|
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
|
||||||
|
this.tuya = new TuyaContext({
|
||||||
|
baseUrl: 'https://openapi.tuyaeu.com',
|
||||||
|
accessKey,
|
||||||
|
secretKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const req = context.switchToHttp().getRequest();
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(req.body);
|
||||||
|
|
||||||
|
if (req.query && req.query.roomUuid) {
|
||||||
|
const { roomUuid } = req.query;
|
||||||
|
await this.checkRoomIsFound(roomUuid);
|
||||||
|
} else if (req.body && req.body.roomUuid && req.body.deviceTuyaUuid) {
|
||||||
|
const { roomUuid, deviceTuyaUuid } = req.body;
|
||||||
|
await this.checkRoomIsFound(roomUuid);
|
||||||
|
await this.checkDeviceIsFoundFromTuya(deviceTuyaUuid);
|
||||||
|
} else {
|
||||||
|
throw new BadRequestException('Invalid request parameters');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
this.handleGuardError(error, context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async checkRoomIsFound(roomUuid: string) {
|
||||||
|
const room = await this.spaceRepository.findOne({
|
||||||
|
where: {
|
||||||
|
uuid: roomUuid,
|
||||||
|
spaceType: {
|
||||||
|
type: 'room',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!room) {
|
||||||
|
throw new NotFoundException('Room not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async checkDeviceIsFoundFromTuya(deviceTuyaUuid: string) {
|
||||||
|
console.log('deviceTuyaUuid: ', deviceTuyaUuid);
|
||||||
|
|
||||||
|
const path = `/v1.1/iot-03/devices/${deviceTuyaUuid}`;
|
||||||
|
const response = await this.tuya.request({
|
||||||
|
method: 'GET',
|
||||||
|
path,
|
||||||
|
});
|
||||||
|
console.log('checkDeviceIsFoundFromTuya: ', response);
|
||||||
|
|
||||||
|
if (!response.success) {
|
||||||
|
throw new NotFoundException('Device not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleGuardError(error: Error, context: ExecutionContext) {
|
||||||
|
const response = context.switchToHttp().getResponse();
|
||||||
|
if (error instanceof NotFoundException) {
|
||||||
|
response
|
||||||
|
.status(HttpStatus.NOT_FOUND)
|
||||||
|
.json({ statusCode: HttpStatus.NOT_FOUND, message: error.message });
|
||||||
|
} else if (error instanceof BadRequestException) {
|
||||||
|
response
|
||||||
|
.status(HttpStatus.BAD_REQUEST)
|
||||||
|
.json({ statusCode: HttpStatus.BAD_REQUEST, message: error.message });
|
||||||
|
} else {
|
||||||
|
response.status(HttpStatus.BAD_REQUEST).json({
|
||||||
|
statusCode: HttpStatus.BAD_REQUEST,
|
||||||
|
message: 'Invalid UUID',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user