finished 4scene configration endpoints

This commit is contained in:
faris Aljohari
2024-11-16 23:05:06 -06:00
parent 4bb598d8b0
commit eb916b79b4
25 changed files with 429 additions and 15 deletions

View File

@ -8,8 +8,15 @@ import config from './config';
import { EmailService } from './util/email.service'; import { EmailService } from './util/email.service';
import { ErrorMessageService } from 'src/error-message/error-message.service'; import { ErrorMessageService } from 'src/error-message/error-message.service';
import { TuyaService } from './integrations/tuya/services/tuya.service'; import { TuyaService } from './integrations/tuya/services/tuya.service';
import { SceneDeviceRepository } from './modules/scene-device/repositories';
@Module({ @Module({
providers: [CommonService, EmailService, ErrorMessageService, TuyaService], providers: [
CommonService,
EmailService,
ErrorMessageService,
TuyaService,
SceneDeviceRepository,
],
exports: [ exports: [
CommonService, CommonService,
TuyaService, TuyaService,
@ -17,6 +24,7 @@ import { TuyaService } from './integrations/tuya/services/tuya.service';
AuthModule, AuthModule,
EmailService, EmailService,
ErrorMessageService, ErrorMessageService,
SceneDeviceRepository,
], ],
imports: [ imports: [
ConfigModule.forRoot({ ConfigModule.forRoot({

View File

@ -0,0 +1,6 @@
export enum FourSceneSwitchesEnum {
Scene_1 = 'scene_1',
Scene_2 = 'scene_2',
Scene_3 = 'scene_3',
Scene_4 = 'scene_4',
}

View File

@ -22,6 +22,7 @@ import { VisitorPasswordEntity } from '../modules/visitor-password/entities';
import { CommunityEntity } from '../modules/community/entities'; import { CommunityEntity } from '../modules/community/entities';
import { DeviceStatusLogEntity } from '../modules/device-status-log/entities'; import { DeviceStatusLogEntity } from '../modules/device-status-log/entities';
import { SceneEntity, SceneIconEntity } from '../modules/scene/entities'; import { SceneEntity, SceneIconEntity } from '../modules/scene/entities';
import { SceneDeviceEntity } from '../modules/scene-device/entities';
@Module({ @Module({
imports: [ imports: [
@ -60,6 +61,7 @@ import { SceneEntity, SceneIconEntity } from '../modules/scene/entities';
DeviceStatusLogEntity, DeviceStatusLogEntity,
SceneEntity, SceneEntity,
SceneIconEntity, SceneIconEntity,
SceneDeviceEntity,
], ],
namingStrategy: new SnakeNamingStrategy(), namingStrategy: new SnakeNamingStrategy(),
synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))), synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))),

View File

@ -1,4 +1,12 @@
import { Column, Entity, ManyToOne, OneToMany, Unique, Index, JoinColumn } from 'typeorm'; import {
Column,
Entity,
ManyToOne,
OneToMany,
Unique,
Index,
JoinColumn,
} from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { DeviceDto, DeviceUserPermissionDto } from '../dtos/device.dto'; import { DeviceDto, DeviceUserPermissionDto } from '../dtos/device.dto';
import { SpaceEntity, SubspaceEntity } from '../../space/entities'; import { SpaceEntity, SubspaceEntity } from '../../space/entities';
@ -6,6 +14,7 @@ import { ProductEntity } from '../../product/entities';
import { UserEntity } from '../../user/entities'; import { UserEntity } from '../../user/entities';
import { DeviceNotificationDto } from '../dtos'; import { DeviceNotificationDto } from '../dtos';
import { PermissionTypeEntity } from '../../permission/entities'; import { PermissionTypeEntity } from '../../permission/entities';
import { SceneDeviceEntity } from '../../scene-device/entities';
@Entity({ name: 'device' }) @Entity({ name: 'device' })
@Unique(['deviceTuyaUuid']) @Unique(['deviceTuyaUuid'])
@ -62,6 +71,9 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
@Column({ nullable: false }) @Column({ nullable: false })
uuid: string; uuid: string;
@OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.device, {})
sceneDevices: SceneDeviceEntity[];
constructor(partial: Partial<DeviceEntity>) { constructor(partial: Partial<DeviceEntity>) {
super(); super();
Object.assign(this, partial); Object.assign(this, partial);

View File

@ -0,0 +1 @@
export * from './scene-device.dto';

View File

@ -0,0 +1,20 @@
import { IsNotEmpty, IsString } from 'class-validator';
export class SceneDeviceDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public deviceUuid: string;
@IsString()
@IsNotEmpty()
public sceneUuid: string;
@IsString()
@IsNotEmpty()
public switchName: string;
@IsString()
@IsNotEmpty()
public automationTuyaUuid: string;
}

View File

@ -0,0 +1 @@
export * from './scene-device.entity';

View File

@ -0,0 +1,50 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { SceneDeviceDto } from '../dtos';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { FourSceneSwitchesEnum } from '@app/common/constants/four-scene.enum';
import { DeviceEntity } from '../../device/entities';
import { SceneEntity } from '../../scene/entities';
@Entity({ name: 'scene-device' })
export class SceneDeviceEntity extends AbstractEntity<SceneDeviceDto> {
@Column({
type: 'uuid',
default: () => 'gen_random_uuid()',
nullable: false,
})
public uuid: string;
@ManyToOne(() => DeviceEntity, (device) => device.sceneDevices, {
nullable: false,
})
@JoinColumn({ name: 'device_uuid' })
device: DeviceEntity;
@Column({
nullable: false,
})
sceneUuid: string;
@Column({
nullable: false,
type: 'enum',
enum: FourSceneSwitchesEnum,
})
switchName: FourSceneSwitchesEnum;
@Column({
nullable: false,
})
automationTuyaUuid: string;
@ManyToOne(() => SceneEntity, (scene) => scene.sceneDevices, {
nullable: false,
})
@JoinColumn({ name: 'scene_uuid' })
scene: SceneEntity;
constructor(partial: Partial<SceneDeviceEntity>) {
super();
Object.assign(this, partial);
}
}

View File

@ -0,0 +1 @@
export * from './scene-device.repository';

View File

@ -0,0 +1,10 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { SceneDeviceEntity } from '../entities';
@Injectable()
export class SceneDeviceRepository extends Repository<SceneDeviceEntity> {
constructor(private dataSource: DataSource) {
super(SceneDeviceEntity, dataSource.createEntityManager());
}
}

View File

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { SceneDeviceEntity } from './entities';
@Module({
providers: [],
exports: [],
controllers: [],
imports: [TypeOrmModule.forFeature([SceneDeviceEntity])],
})
export class SceneDeviceRepositoryModule {}

View File

@ -2,6 +2,7 @@ import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
import { SceneDto, SceneIconDto } from '../dtos'; import { SceneDto, SceneIconDto } from '../dtos';
import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { SceneIconType } from '@app/common/constants/secne-icon-type.enum'; import { SceneIconType } from '@app/common/constants/secne-icon-type.enum';
import { SceneDeviceEntity } from '../../scene-device/entities';
// Define SceneIconEntity before SceneEntity // Define SceneIconEntity before SceneEntity
@Entity({ name: 'scene-icon' }) @Entity({ name: 'scene-icon' })
@ -59,6 +60,9 @@ export class SceneEntity extends AbstractEntity<SceneDto> {
}) })
sceneIcon: SceneIconEntity; sceneIcon: SceneIconEntity;
@OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.scene)
sceneDevices: SceneDeviceEntity[];
constructor(partial: Partial<SceneEntity>) { constructor(partial: Partial<SceneEntity>) {
super(); super();
Object.assign(this, partial); Object.assign(this, partial);

View File

@ -9,6 +9,12 @@ import { DeviceRepository } from '@app/common/modules/device/repositories';
import { ProductRepository } from '@app/common/modules/product/repositories'; import { ProductRepository } from '@app/common/modules/product/repositories';
import { DeviceStatusFirebaseModule } from '@app/common/firebase/devices-status/devices-status.module'; import { DeviceStatusFirebaseModule } from '@app/common/firebase/devices-status/devices-status.module';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { SceneService } from 'src/scene/services';
import {
SceneIconRepository,
SceneRepository,
} from '@app/common/modules/scene/repositories';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
@Module({ @Module({
imports: [ConfigModule, SpaceRepositoryModule, DeviceStatusFirebaseModule], imports: [ConfigModule, SpaceRepositoryModule, DeviceStatusFirebaseModule],
@ -20,6 +26,10 @@ import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service
DeviceService, DeviceService,
DeviceRepository, DeviceRepository,
ProductRepository, ProductRepository,
SceneService,
SceneIconRepository,
SceneRepository,
SceneDeviceRepository,
], ],
exports: [AutomationService], exports: [AutomationService],
}) })

View File

@ -30,6 +30,7 @@ import {
} from '@app/common/constants/automation.enum'; } from '@app/common/constants/automation.enum';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { ConvertedAction } from '@app/common/integrations/tuya/interfaces'; import { ConvertedAction } from '@app/common/integrations/tuya/interfaces';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
@Injectable() @Injectable()
export class AutomationService { export class AutomationService {
@ -39,6 +40,7 @@ export class AutomationService {
private readonly spaceRepository: SpaceRepository, private readonly spaceRepository: SpaceRepository,
private readonly deviceService: DeviceService, private readonly deviceService: DeviceService,
private readonly tuyaService: TuyaService, private readonly tuyaService: TuyaService,
private readonly sceneDeviceRepository: SceneDeviceRepository,
) { ) {
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY'); const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY'); const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
@ -304,6 +306,16 @@ export class AutomationService {
HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST,
); );
} }
const existingSceneDevice = await this.sceneDeviceRepository.findOne({
where: { automationTuyaUuid: automationUuid },
});
if (existingSceneDevice) {
await this.sceneDeviceRepository.delete({
automationTuyaUuid: automationUuid,
});
}
const response = this.tuyaService.deleteAutomation( const response = this.tuyaService.deleteAutomation(
automation.spaceId, automation.spaceId,
automationUuid, automationUuid,
@ -323,6 +335,15 @@ export class AutomationService {
async delete(tuyaSpaceId: string, automationUuid: string) { async delete(tuyaSpaceId: string, automationUuid: string) {
try { try {
const existingSceneDevice = await this.sceneDeviceRepository.findOne({
where: { automationTuyaUuid: automationUuid },
});
if (existingSceneDevice) {
await this.sceneDeviceRepository.delete({
automationTuyaUuid: automationUuid,
});
}
const response = await this.tuyaService.deleteAutomation( const response = await this.tuyaService.deleteAutomation(
tuyaSpaceId, tuyaSpaceId,
automationUuid, automationUuid,

View File

@ -12,13 +12,18 @@ import {
Put, Put,
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
import { AddDeviceDto, UpdateDeviceInSpaceDto } from '../dtos/add.device.dto'; import {
AddDeviceDto,
AddSceneToFourSceneDeviceDto,
UpdateDeviceInSpaceDto,
} from '../dtos/add.device.dto';
import { GetDeviceLogsDto } from '../dtos/get.device.dto'; import { GetDeviceLogsDto } from '../dtos/get.device.dto';
import { import {
ControlDeviceDto, ControlDeviceDto,
BatchControlDevicesDto, BatchControlDevicesDto,
BatchStatusDevicesDto, BatchStatusDevicesDto,
BatchFactoryResetDevicesDto, BatchFactoryResetDevicesDto,
GetSceneFourSceneDeviceDto,
} from '../dtos/control.device.dto'; } from '../dtos/control.device.dto';
import { CheckRoomGuard } from 'src/guards/room.guard'; import { CheckRoomGuard } from 'src/guards/room.guard';
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
@ -184,4 +189,35 @@ export class DeviceController {
powerClampUuid, powerClampUuid,
); );
} }
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Post('four-scene/:deviceUuid')
async addSceneToFourSceneDevice(
@Param('deviceUuid') deviceUuid: string,
@Body() addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto,
) {
const device = await this.deviceService.addSceneToFourSceneDevice(
deviceUuid,
addSceneToFourSceneDeviceDto,
);
return {
statusCode: HttpStatus.CREATED,
success: true,
message: `scene added successfully to device ${deviceUuid}`,
data: device,
};
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('four-scene/:deviceUuid')
async getSceneFourSceneDevice(
@Param('deviceUuid') deviceUuid: string,
@Query() getSceneFourSceneDeviceDto: GetSceneFourSceneDeviceDto,
) {
return await this.deviceService.getSceneFourSceneDevice(
deviceUuid,
getSceneFourSceneDeviceDto,
);
}
} }

View File

@ -11,9 +11,18 @@ import { SpaceRepository } from '@app/common/modules/space/repositories';
import { DeviceUserPermissionRepository } from '@app/common/modules/device/repositories'; import { DeviceUserPermissionRepository } from '@app/common/modules/device/repositories';
import { UserRepository } from '@app/common/modules/user/repositories'; import { UserRepository } from '@app/common/modules/user/repositories';
import { DeviceStatusFirebaseModule } from '@app/common/firebase/devices-status/devices-status.module'; import { DeviceStatusFirebaseModule } from '@app/common/firebase/devices-status/devices-status.module';
import { SpaceModule } from 'src/space/space.module';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { SceneService } from 'src/scene/services';
import {
SceneIconRepository,
SceneRepository,
} from '@app/common/modules/scene/repositories';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
@Module({ @Module({
imports: [ imports: [
ConfigModule, ConfigModule,
SpaceModule,
ProductRepositoryModule, ProductRepositoryModule,
DeviceRepositoryModule, DeviceRepositoryModule,
DeviceStatusFirebaseModule, DeviceStatusFirebaseModule,
@ -27,6 +36,11 @@ import { DeviceStatusFirebaseModule } from '@app/common/firebase/devices-status/
SpaceRepository, SpaceRepository,
DeviceRepository, DeviceRepository,
UserRepository, UserRepository,
TuyaService,
SceneService,
SceneIconRepository,
SceneRepository,
SceneDeviceRepository,
], ],
exports: [DeviceService], exports: [DeviceService],
}) })

View File

@ -1,5 +1,6 @@
import { FourSceneSwitchesEnum } from '@app/common/constants/four-scene.enum';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString } from 'class-validator'; import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
export class AddDeviceDto { export class AddDeviceDto {
@ApiProperty({ @ApiProperty({
@ -35,3 +36,27 @@ export class UpdateDeviceInSpaceDto {
@IsNotEmpty() @IsNotEmpty()
public spaceUuid: string; public spaceUuid: string;
} }
export class AddSceneToFourSceneDeviceDto {
@ApiProperty({
description: 'switchName',
required: true,
})
@IsEnum(FourSceneSwitchesEnum)
@IsNotEmpty()
switchName: FourSceneSwitchesEnum;
@ApiProperty({
description: 'sceneUuid',
required: true,
})
@IsString()
@IsNotEmpty()
public sceneUuid: string;
@ApiProperty({
description: 'spaceUuid',
required: true,
})
@IsString()
@IsNotEmpty()
public spaceUuid: string;
}

View File

@ -54,3 +54,12 @@ export class BatchFactoryResetDevicesDto {
@IsNotEmpty() @IsNotEmpty()
public devicesUuid: [string]; public devicesUuid: [string];
} }
export class GetSceneFourSceneDeviceDto {
@ApiProperty({
description: 'switchName',
required: true,
})
@IsString()
@IsNotEmpty()
public switchName: string;
}

View File

@ -5,10 +5,16 @@ import {
HttpStatus, HttpStatus,
NotFoundException, NotFoundException,
BadRequestException, BadRequestException,
forwardRef,
Inject,
} from '@nestjs/common'; } 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 { AddDeviceDto, UpdateDeviceInSpaceDto } from '../dtos/add.device.dto'; import {
AddDeviceDto,
AddSceneToFourSceneDeviceDto,
UpdateDeviceInSpaceDto,
} from '../dtos/add.device.dto';
import { import {
DeviceInstructionResponse, DeviceInstructionResponse,
GetDeviceDetailsFunctionsInterface, GetDeviceDetailsFunctionsInterface,
@ -28,6 +34,7 @@ import {
BatchFactoryResetDevicesDto, BatchFactoryResetDevicesDto,
BatchStatusDevicesDto, BatchStatusDevicesDto,
ControlDeviceDto, ControlDeviceDto,
GetSceneFourSceneDeviceDto,
} from '../dtos/control.device.dto'; } from '../dtos/control.device.dto';
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
import { DeviceRepository } from '@app/common/modules/device/repositories'; import { DeviceRepository } from '@app/common/modules/device/repositories';
@ -40,6 +47,11 @@ import { DeviceStatuses } from '@app/common/constants/device-status.enum';
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum'; import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
import { BatteryStatus } from '@app/common/constants/battery-status.enum'; import { BatteryStatus } from '@app/common/constants/battery-status.enum';
import { SpaceEntity } from '@app/common/modules/space/entities'; import { SpaceEntity } from '@app/common/modules/space/entities';
import { SceneService } from 'src/scene/services';
import { AddAutomationDto } from 'src/automation/dtos';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
import { FourSceneSwitchesEnum } from '@app/common/constants/four-scene.enum';
@Injectable() @Injectable()
export class DeviceService { export class DeviceService {
@ -47,9 +59,13 @@ export class DeviceService {
constructor( constructor(
private readonly configService: ConfigService, private readonly configService: ConfigService,
private readonly deviceRepository: DeviceRepository, private readonly deviceRepository: DeviceRepository,
private readonly sceneDeviceRepository: SceneDeviceRepository,
private readonly productRepository: ProductRepository, private readonly productRepository: ProductRepository,
private readonly deviceStatusFirebaseService: DeviceStatusFirebaseService, private readonly deviceStatusFirebaseService: DeviceStatusFirebaseService,
private readonly spaceRepository: SpaceRepository, private readonly spaceRepository: SpaceRepository,
@Inject(forwardRef(() => SceneService))
private readonly sceneService: SceneService,
private readonly tuyaService: TuyaService,
) { ) {
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY'); const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY'); const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
@ -630,7 +646,6 @@ export class DeviceService {
status: deviceStatus.result[0].status, status: deviceStatus.result[0].status,
}; };
} catch (error) { } catch (error) {
console.log(error);
throw new HttpException( throw new HttpException(
'Error fetching device functions status', 'Error fetching device functions status',
HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.INTERNAL_SERVER_ERROR,
@ -1136,4 +1151,134 @@ export class DeviceService {
return descendants; return descendants;
} }
async addSceneToFourSceneDevice(
deviceUuid: string,
addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto,
) {
try {
const { spaceUuid, sceneUuid, switchName } = addSceneToFourSceneDeviceDto;
if (!spaceUuid || !sceneUuid || !switchName) {
throw new BadRequestException('Missing required fields in DTO');
}
const [sceneData, spaceData, deviceData] = await Promise.all([
this.sceneService.findScene(sceneUuid),
this.sceneService.getSpaceByUuid(spaceUuid),
this.getDeviceByDeviceUuid(deviceUuid),
]);
// Generate a shorter automation name (e.g., "Auto_ABC123_169")
const shortUuid = deviceUuid.slice(0, 6); // First 6 characters of the UUID
const timestamp = Math.floor(Date.now() / 1000); // Current timestamp in seconds
const automationName = `Auto_${shortUuid}_${timestamp}`;
const addAutomationData: AddAutomationDto = {
spaceUuid: spaceData.spaceTuyaUuid,
automationName,
decisionExpr: 'and',
effectiveTime: {
start: '00:00',
end: '23:59',
loops: '1111111',
},
conditions: [
{
code: 1,
entityId: deviceData.deviceTuyaUuid,
entityType: 'device_report',
expr: {
comparator: '==',
statusCode: switchName,
statusValue: 'scene',
},
},
],
actions: [
{
actionExecutor: 'rule_trigger',
entityId: sceneData.sceneTuyaUuid,
},
],
};
// Create automation
const automation = await this.tuyaService.createAutomation(
addAutomationData.spaceUuid,
addAutomationData.automationName,
addAutomationData.effectiveTime,
addAutomationData.decisionExpr,
addAutomationData.conditions,
addAutomationData.actions,
);
if (automation.success) {
const existingSceneDevice = await this.sceneDeviceRepository.findOne({
where: {
device: { uuid: deviceUuid },
scene: { uuid: sceneUuid },
switchName: switchName,
},
relations: ['scene', 'device'],
});
if (existingSceneDevice) {
await this.tuyaService.deleteAutomation(
spaceData.spaceTuyaUuid,
existingSceneDevice.automationTuyaUuid,
);
existingSceneDevice.automationTuyaUuid = automation.result.id;
existingSceneDevice.scene = sceneData;
existingSceneDevice.device = deviceData;
existingSceneDevice.switchName = switchName;
return await this.sceneDeviceRepository.save(existingSceneDevice);
} else {
const sceneDevice = await this.sceneDeviceRepository.save({
scene: sceneData,
device: deviceData,
automationTuyaUuid: automation.result.id,
switchName: switchName,
});
return sceneDevice;
}
}
} catch (err) {
const errorMessage = err.message || 'Error creating automation';
const errorStatus = err.status || HttpStatus.INTERNAL_SERVER_ERROR;
throw new HttpException(errorMessage, errorStatus);
}
}
async getSceneFourSceneDevice(
deviceUuid: string,
getSceneFourSceneDeviceDto: GetSceneFourSceneDeviceDto,
) {
try {
const sceneDevice = await this.sceneDeviceRepository.findOne({
where: {
device: { uuid: deviceUuid },
switchName:
getSceneFourSceneDeviceDto.switchName as FourSceneSwitchesEnum, // Cast the string to the enum
},
relations: ['device', 'scene'],
});
if (sceneDevice.uuid) {
const SceneDetails = await this.sceneService.getSceneByUuid(
sceneDevice.scene.uuid,
);
return {
switchName: sceneDevice.switchName,
createdAt: sceneDevice.createdAt,
updatedAt: sceneDevice.updatedAt,
deviceUuid: sceneDevice.device.uuid,
scene: {
...SceneDetails.data,
},
};
}
} catch (error) {
throw new HttpException('Scene device not found', HttpStatus.NOT_FOUND);
}
}
} }

View File

@ -11,6 +11,13 @@ import { ProductRepository } from '@app/common/modules/product/repositories';
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service'; import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
import { SpaceRepository } from '@app/common/modules/space/repositories'; import { SpaceRepository } from '@app/common/modules/space/repositories';
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories'; import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { SceneService } from 'src/scene/services';
import {
SceneIconRepository,
SceneRepository,
} from '@app/common/modules/scene/repositories';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
@Module({ @Module({
imports: [ConfigModule, DeviceRepositoryModule], imports: [ConfigModule, DeviceRepositoryModule],
controllers: [DoorLockController], controllers: [DoorLockController],
@ -24,6 +31,11 @@ import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log
DeviceStatusFirebaseService, DeviceStatusFirebaseService,
SpaceRepository, SpaceRepository,
DeviceStatusLogRepository, DeviceStatusLogRepository,
TuyaService,
SceneService,
SceneIconRepository,
SceneRepository,
SceneDeviceRepository,
], ],
exports: [DoorLockService], exports: [DoorLockService],
}) })

View File

@ -120,7 +120,6 @@ export class GroupService {
throw new HttpException('No devices found', HttpStatus.NOT_FOUND); throw new HttpException('No devices found', HttpStatus.NOT_FOUND);
return devices.flat(); // Flatten the array since flatMap was used return devices.flat(); // Flatten the array since flatMap was used
} catch (error) { } catch (error) {
console.log(error);
throw new HttpException( throw new HttpException(
'This space does not have any devices for the specified group name', 'This space does not have any devices for the specified group name',
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,

View File

@ -13,6 +13,7 @@ import {
SceneRepository, SceneRepository,
} from '@app/common/modules/scene/repositories'; } from '@app/common/modules/scene/repositories';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
@Module({ @Module({
imports: [ConfigModule, SpaceRepositoryModule, DeviceStatusFirebaseModule], imports: [ConfigModule, SpaceRepositoryModule, DeviceStatusFirebaseModule],
@ -26,6 +27,7 @@ import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service
ProductRepository, ProductRepository,
SceneIconRepository, SceneIconRepository,
SceneRepository, SceneRepository,
SceneDeviceRepository,
], ],
exports: [SceneService], exports: [SceneService],
}) })

View File

@ -3,6 +3,8 @@ import {
HttpException, HttpException,
HttpStatus, HttpStatus,
BadRequestException, BadRequestException,
forwardRef,
Inject,
} from '@nestjs/common'; } from '@nestjs/common';
import { SpaceRepository } from '@app/common/modules/space/repositories'; import { SpaceRepository } from '@app/common/modules/space/repositories';
import { import {
@ -14,7 +16,6 @@ import {
UpdateSceneTapToRunDto, UpdateSceneTapToRunDto,
} from '../dtos'; } from '../dtos';
import { convertKeysToSnakeCase } from '@app/common/helper/snakeCaseConverter'; import { convertKeysToSnakeCase } from '@app/common/helper/snakeCaseConverter';
import { DeviceService } from 'src/device/services';
import { import {
AddTapToRunSceneInterface, AddTapToRunSceneInterface,
DeleteTapToRunSceneInterface, DeleteTapToRunSceneInterface,
@ -37,6 +38,7 @@ 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 { HttpStatusCode } from 'axios'; import { HttpStatusCode } from 'axios';
import { ConvertedAction } from '@app/common/integrations/tuya/interfaces'; import { ConvertedAction } from '@app/common/integrations/tuya/interfaces';
import { DeviceService } from 'src/device/services';
@Injectable() @Injectable()
export class SceneService { export class SceneService {
@ -44,8 +46,9 @@ export class SceneService {
private readonly spaceRepository: SpaceRepository, private readonly spaceRepository: SpaceRepository,
private readonly sceneIconRepository: SceneIconRepository, private readonly sceneIconRepository: SceneIconRepository,
private readonly sceneRepository: SceneRepository, private readonly sceneRepository: SceneRepository,
private readonly deviceService: DeviceService,
private readonly tuyaService: TuyaService, private readonly tuyaService: TuyaService,
@Inject(forwardRef(() => DeviceService))
private readonly deviceService: DeviceService,
) {} ) {}
async createScene( async createScene(
@ -178,7 +181,10 @@ export class SceneService {
}); });
if (!scenesData.length) { if (!scenesData.length) {
return []; throw new HttpException(
`No scenes found for space UUID ${spaceUuid} with showInHomePage ${showInHomePage} `,
HttpStatus.NOT_FOUND,
);
} }
const scenes = await Promise.all( const scenes = await Promise.all(
@ -438,7 +444,6 @@ export class SceneService {
if (err instanceof BadRequestException) { if (err instanceof BadRequestException) {
throw err; throw err;
} else { } else {
console.log(err);
throw new HttpException( throw new HttpException(
`An error occurred while retrieving scene details for ${scene.uuid}`, `An error occurred while retrieving scene details for ${scene.uuid}`,
HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.INTERNAL_SERVER_ERROR,
@ -454,9 +459,6 @@ export class SceneService {
const space = await this.getSpaceByUuid(scene.spaceUuid); const space = await this.getSpaceByUuid(scene.spaceUuid);
await this.delete(scene.sceneTuyaUuid, space.spaceTuyaUuid); await this.delete(scene.sceneTuyaUuid, space.spaceTuyaUuid);
await this.sceneRepository.remove(scene);
return new SuccessResponseDto({ return new SuccessResponseDto({
message: `Scene with ID ${sceneUuid} deleted successfully`, message: `Scene with ID ${sceneUuid} deleted successfully`,
}); });
@ -564,7 +566,6 @@ export class SceneService {
}; };
} catch (err) { } catch (err) {
if (err instanceof BadRequestException) { if (err instanceof BadRequestException) {
console.log(err);
throw err; throw err;
} else { } else {
throw new HttpException( throw new HttpException(

View File

@ -37,6 +37,7 @@ import {
import { DeviceService } from 'src/device/services'; import { DeviceService } from 'src/device/services';
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service'; import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories'; import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
@Module({ @Module({
imports: [ConfigModule, SpaceRepositoryModule], imports: [ConfigModule, SpaceRepositoryModule],
@ -69,6 +70,7 @@ import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log
DeviceService, DeviceService,
DeviceStatusFirebaseService, DeviceStatusFirebaseService,
DeviceStatusLogRepository, DeviceStatusLogRepository,
SceneDeviceRepository,
], ],
exports: [SpaceService], exports: [SpaceService],
}) })

View File

@ -13,6 +13,13 @@ import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status
import { SpaceRepository } from '@app/common/modules/space/repositories'; import { SpaceRepository } from '@app/common/modules/space/repositories';
import { VisitorPasswordRepository } from '@app/common/modules/visitor-password/repositories'; import { VisitorPasswordRepository } from '@app/common/modules/visitor-password/repositories';
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories'; import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
import { SceneService } from 'src/scene/services';
import {
SceneIconRepository,
SceneRepository,
} from '@app/common/modules/scene/repositories';
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
@Module({ @Module({
imports: [ConfigModule, DeviceRepositoryModule, DoorLockModule], imports: [ConfigModule, DeviceRepositoryModule, DoorLockModule],
controllers: [VisitorPasswordController], controllers: [VisitorPasswordController],
@ -27,6 +34,11 @@ import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log
DeviceRepository, DeviceRepository,
VisitorPasswordRepository, VisitorPasswordRepository,
DeviceStatusLogRepository, DeviceStatusLogRepository,
TuyaService,
SceneService,
SceneIconRepository,
SceneRepository,
SceneDeviceRepository,
], ],
exports: [VisitorPasswordService], exports: [VisitorPasswordService],
}) })