mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-26 20:04:54 +00:00
265 lines
7.2 KiB
TypeScript
265 lines
7.2 KiB
TypeScript
import {
|
|
Injectable,
|
|
HttpException,
|
|
HttpStatus,
|
|
BadRequestException,
|
|
} from '@nestjs/common';
|
|
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { AddGroupDto } from '../dtos/add.group.dto';
|
|
import {
|
|
GetGroupDetailsInterface,
|
|
GetGroupsBySpaceUuidInterface,
|
|
} from '../interfaces/get.group.interface';
|
|
import { ControlGroupDto } from '../dtos/control.group.dto';
|
|
import { RenameGroupDto } from '../dtos/rename.group.dto copy';
|
|
import { GroupRepository } from '@app/common/modules/group/repositories';
|
|
import { GroupDeviceRepository } from '@app/common/modules/group-device/repositories';
|
|
import { controlDeviceInterface } from 'src/device/interfaces/get.device.interface';
|
|
|
|
@Injectable()
|
|
export class GroupService {
|
|
private tuya: TuyaContext;
|
|
constructor(
|
|
private readonly configService: ConfigService,
|
|
private readonly groupRepository: GroupRepository,
|
|
private readonly groupDeviceRepository: GroupDeviceRepository,
|
|
) {
|
|
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
|
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
|
|
// const clientId = this.configService.get<string>('auth-config.CLIENT_ID');
|
|
this.tuya = new TuyaContext({
|
|
baseUrl: 'https://openapi.tuyaeu.com',
|
|
accessKey,
|
|
secretKey,
|
|
});
|
|
}
|
|
|
|
async getGroupsBySpaceUuid(
|
|
spaceUuid: string,
|
|
): Promise<GetGroupsBySpaceUuidInterface[]> {
|
|
try {
|
|
const groupDevices = await this.groupDeviceRepository.find({
|
|
relations: ['group', 'device'],
|
|
where: {
|
|
device: { spaceDevice: { uuid: spaceUuid } },
|
|
isActive: true,
|
|
},
|
|
});
|
|
|
|
// Extract and return only the group entities
|
|
const groups = groupDevices.map((groupDevice) => {
|
|
return {
|
|
groupUuid: groupDevice.uuid,
|
|
groupName: groupDevice.group.groupName,
|
|
};
|
|
});
|
|
if (groups.length > 0) {
|
|
return groups;
|
|
} else {
|
|
throw new HttpException(
|
|
'this space has no groups',
|
|
HttpStatus.NOT_FOUND,
|
|
);
|
|
}
|
|
} catch (error) {
|
|
throw new HttpException(
|
|
error.message || 'Error fetching groups',
|
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async addGroup(addGroupDto: AddGroupDto) {
|
|
try {
|
|
const group = await this.groupRepository.save({
|
|
groupName: addGroupDto.groupName,
|
|
});
|
|
|
|
const groupDevicePromises = addGroupDto.deviceUuids.map(
|
|
async (deviceUuid) => {
|
|
await this.saveGroupDevice(group.uuid, deviceUuid);
|
|
},
|
|
);
|
|
|
|
await Promise.all(groupDevicePromises);
|
|
return { message: 'Group added successfully' };
|
|
} catch (err) {
|
|
if (err.code === '23505') {
|
|
throw new HttpException(
|
|
'User already belongs to this group',
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
throw new HttpException(
|
|
err.message || 'Internal Server Error',
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
private async saveGroupDevice(groupUuid: string, deviceUuid: string) {
|
|
try {
|
|
await this.groupDeviceRepository.save({
|
|
group: {
|
|
uuid: groupUuid,
|
|
},
|
|
device: {
|
|
uuid: deviceUuid,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
async getDevicesByGroupUuid(groupUuid: string) {
|
|
try {
|
|
const devices = await this.groupDeviceRepository.find({
|
|
relations: ['device'],
|
|
where: {
|
|
group: {
|
|
uuid: groupUuid,
|
|
},
|
|
isActive: true,
|
|
},
|
|
});
|
|
return devices;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
async controlDevice(deviceUuid: string, code: string, value: any) {
|
|
try {
|
|
const response = await this.controlDeviceTuya(deviceUuid, code, value);
|
|
|
|
if (response.success) {
|
|
return response;
|
|
} else {
|
|
throw new HttpException(
|
|
response.msg || 'Unknown error',
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
} catch (error) {
|
|
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
|
}
|
|
}
|
|
async controlDeviceTuya(
|
|
deviceUuid: string,
|
|
code: string,
|
|
value: any,
|
|
): Promise<controlDeviceInterface> {
|
|
try {
|
|
const path = `/v1.0/iot-03/devices/${deviceUuid}/commands`;
|
|
const response = await this.tuya.request({
|
|
method: 'POST',
|
|
path,
|
|
body: {
|
|
commands: [{ code, value: value }],
|
|
},
|
|
});
|
|
|
|
return response as controlDeviceInterface;
|
|
} catch (error) {
|
|
throw new HttpException(
|
|
'Error control device from Tuya',
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
async controlGroup(controlGroupDto: ControlGroupDto) {
|
|
const devices = await this.getDevicesByGroupUuid(controlGroupDto.groupUuid);
|
|
|
|
try {
|
|
await Promise.all(
|
|
devices.map(async (device) => {
|
|
return this.controlDevice(
|
|
device.device.deviceTuyaUuid,
|
|
controlGroupDto.code,
|
|
controlGroupDto.value,
|
|
);
|
|
}),
|
|
);
|
|
return { message: 'Group controlled successfully', success: true };
|
|
} catch (error) {
|
|
throw new HttpException(
|
|
'Error controlling devices',
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async renameGroupByUuid(
|
|
groupUuid: string,
|
|
renameGroupDto: RenameGroupDto,
|
|
): Promise<GetGroupsBySpaceUuidInterface> {
|
|
try {
|
|
await this.groupRepository.update(
|
|
{ uuid: groupUuid },
|
|
{ groupName: renameGroupDto.groupName },
|
|
);
|
|
|
|
// Fetch the updated floor
|
|
const updatedGroup = await this.groupRepository.findOneOrFail({
|
|
where: { uuid: groupUuid },
|
|
});
|
|
return {
|
|
groupUuid: updatedGroup.uuid,
|
|
groupName: updatedGroup.groupName,
|
|
};
|
|
} catch (error) {
|
|
throw new HttpException('Group not found', HttpStatus.NOT_FOUND);
|
|
}
|
|
}
|
|
|
|
async deleteGroup(groupUuid: string) {
|
|
try {
|
|
const group = await this.getGroupsByGroupUuid(groupUuid);
|
|
|
|
if (!group) {
|
|
throw new HttpException('Group not found', HttpStatus.NOT_FOUND);
|
|
}
|
|
|
|
await this.groupRepository.update(
|
|
{ uuid: groupUuid },
|
|
{ isActive: false },
|
|
);
|
|
|
|
return { message: 'Group deleted successfully' };
|
|
} catch (error) {
|
|
throw new HttpException(
|
|
error.message || 'Error deleting group',
|
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async getGroupsByGroupUuid(
|
|
groupUuid: string,
|
|
): Promise<GetGroupDetailsInterface> {
|
|
try {
|
|
const group = await this.groupRepository.findOne({
|
|
where: {
|
|
uuid: groupUuid,
|
|
isActive: true,
|
|
},
|
|
});
|
|
if (!group) {
|
|
throw new BadRequestException('Invalid group UUID');
|
|
}
|
|
return {
|
|
groupUuid: group.uuid,
|
|
groupName: group.groupName,
|
|
createdAt: group.createdAt,
|
|
updatedAt: group.updatedAt,
|
|
};
|
|
} catch (err) {
|
|
if (err instanceof BadRequestException) {
|
|
throw err; // Re-throw BadRequestException
|
|
} else {
|
|
throw new HttpException('Group not found', HttpStatus.NOT_FOUND);
|
|
}
|
|
}
|
|
}
|
|
}
|