mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-27 23:04:53 +00:00
288 lines
6.8 KiB
TypeScript
288 lines
6.8 KiB
TypeScript
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
|
import {
|
|
AddTuyaResponseInterface,
|
|
ConvertedAction,
|
|
TuyaResponseInterface,
|
|
} from '../interfaces';
|
|
|
|
@Injectable()
|
|
export class TuyaService {
|
|
private tuya: TuyaContext;
|
|
|
|
constructor(private readonly configService: ConfigService) {
|
|
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
|
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
|
|
const tuyaEuUrl = this.configService.get<string>('tuya-config.TUYA_EU_URL');
|
|
this.tuya = new TuyaContext({
|
|
baseUrl: tuyaEuUrl,
|
|
accessKey,
|
|
secretKey,
|
|
});
|
|
}
|
|
async createSpace({ name }: { name: string }) {
|
|
const path = '/v2.0/cloud/space/creation';
|
|
const body = { name };
|
|
|
|
const response = await this.tuya.request({
|
|
method: 'POST',
|
|
path,
|
|
body,
|
|
});
|
|
|
|
if (response.success) {
|
|
return response.result as string;
|
|
} else {
|
|
throw new HttpException(
|
|
'Error creating space in Tuya',
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async getDeviceDetails(deviceId: string) {
|
|
const path = `/v1.1/iot-03/devices/${deviceId}`;
|
|
const response = await this.tuya.request({
|
|
method: 'GET',
|
|
path,
|
|
});
|
|
|
|
if (!response.success) {
|
|
throw new HttpException(
|
|
`Error fetching device details: ${response.msg}`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
|
|
return response.result;
|
|
}
|
|
|
|
async deleteSceneRule(sceneId: string, spaceId: string) {
|
|
const path = `/v2.0/cloud/scene/rule?ids=${sceneId}&space_id=${spaceId}`;
|
|
const response = await this.tuya.request({
|
|
method: 'DELETE',
|
|
path,
|
|
});
|
|
|
|
if (response.success) {
|
|
return response;
|
|
} else {
|
|
throw new HttpException(
|
|
`Error deleting scene rule: ${response.msg}`,
|
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
|
|
async getSceneRule(sceneId: string) {
|
|
const path = `/v2.0/cloud/scene/rule/${sceneId}`;
|
|
const response = await this.tuya.request({
|
|
method: 'GET',
|
|
path,
|
|
});
|
|
|
|
if (response.success) {
|
|
return response;
|
|
} else {
|
|
throw new HttpException(
|
|
`Error fetching scene rule: ${response.msg}`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
}
|
|
|
|
async addTapToRunScene(
|
|
spaceId: string,
|
|
sceneName: string,
|
|
actions: ConvertedAction[],
|
|
decisionExpr: string,
|
|
) {
|
|
const path = `/v2.0/cloud/scene/rule`;
|
|
const response = await this.tuya.request({
|
|
method: 'POST',
|
|
path,
|
|
body: {
|
|
space_id: spaceId,
|
|
name: sceneName,
|
|
type: 'scene',
|
|
decision_expr: decisionExpr,
|
|
actions: actions,
|
|
},
|
|
});
|
|
|
|
if (response.success) {
|
|
return response;
|
|
} else {
|
|
throw new HttpException(
|
|
`Error fetching scene rule: ${response.msg}`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
}
|
|
async updateTapToRunScene(
|
|
sceneTuyaUuid: string,
|
|
spaceId: string,
|
|
sceneName: string,
|
|
actions: ConvertedAction[],
|
|
decisionExpr: string,
|
|
) {
|
|
const path = `/v2.0/cloud/scene/rule/${sceneTuyaUuid}`;
|
|
const response = await this.tuya.request({
|
|
method: 'PUT',
|
|
path,
|
|
body: {
|
|
space_id: spaceId,
|
|
name: sceneName,
|
|
type: 'scene',
|
|
decision_expr: decisionExpr,
|
|
conditions: [],
|
|
actions: actions,
|
|
},
|
|
});
|
|
|
|
if (response.success) {
|
|
return response;
|
|
} else {
|
|
throw new HttpException(
|
|
`Error fetching scene rule: ${response.msg}`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
}
|
|
|
|
async triggerScene(sceneId: string): Promise<TuyaResponseInterface> {
|
|
const path = `/v2.0/cloud/scene/rule/${sceneId}/actions/trigger`;
|
|
const response: TuyaResponseInterface = await this.tuya.request({
|
|
method: 'POST',
|
|
path,
|
|
});
|
|
|
|
if (!response.success) {
|
|
throw new HttpException(
|
|
response.msg || 'Error triggering scene',
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
async createAutomation(
|
|
spaceId: string,
|
|
automationName: string,
|
|
effectiveTime: any,
|
|
decisionExpr: string,
|
|
conditions: any[],
|
|
actions: any[],
|
|
) {
|
|
const path = `/v2.0/cloud/scene/rule`;
|
|
|
|
const response: AddTuyaResponseInterface = await this.tuya.request({
|
|
method: 'POST',
|
|
path,
|
|
body: {
|
|
space_id: spaceId,
|
|
name: automationName,
|
|
effective_time: {
|
|
...effectiveTime,
|
|
timezone_id: 'Asia/Dubai',
|
|
},
|
|
type: 'automation',
|
|
decision_expr: decisionExpr,
|
|
conditions: conditions,
|
|
actions: actions,
|
|
},
|
|
});
|
|
|
|
if (!response.success) {
|
|
throw new HttpException(response.msg, HttpStatus.BAD_REQUEST);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
async deleteAutomation(spaceId: string, automationUuid: string) {
|
|
const path = `/v2.0/cloud/scene/rule?ids=${automationUuid}&space_id=${spaceId}`;
|
|
const response = await this.tuya.request({
|
|
method: 'DELETE',
|
|
path,
|
|
});
|
|
|
|
if (!response.success) {
|
|
throw new HttpException(
|
|
'Failed to delete automation',
|
|
HttpStatus.NOT_FOUND,
|
|
);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
async updateAutomation(
|
|
automationUuid: string,
|
|
spaceId: string,
|
|
automationName: string,
|
|
actions: ConvertedAction[],
|
|
conditions: any[],
|
|
decisionExpr: string,
|
|
effectiveTime: any,
|
|
) {
|
|
const path = `/v2.0/cloud/scene/rule/${automationUuid}`;
|
|
const response = await this.tuya.request({
|
|
method: 'PUT',
|
|
path,
|
|
body: {
|
|
space_id: spaceId,
|
|
name: automationName,
|
|
effective_time: {
|
|
...effectiveTime,
|
|
timezone_id: 'Asia/Dubai',
|
|
},
|
|
type: 'automation',
|
|
decision_expr: decisionExpr,
|
|
conditions: conditions,
|
|
actions: actions,
|
|
},
|
|
});
|
|
|
|
if (response.success) {
|
|
return response;
|
|
} else {
|
|
throw new HttpException(
|
|
`Error fetching automation rule: ${response.msg}`,
|
|
HttpStatus.BAD_REQUEST,
|
|
);
|
|
}
|
|
}
|
|
|
|
async updateAutomationState(
|
|
spaceId: string,
|
|
automationUuid: string,
|
|
isEnable: boolean,
|
|
) {
|
|
const path = `/v2.0/cloud/scene/rule/state?space_id=${spaceId}`;
|
|
|
|
try {
|
|
const response: TuyaResponseInterface = await this.tuya.request({
|
|
method: 'PUT',
|
|
path,
|
|
body: {
|
|
ids: automationUuid,
|
|
is_enable: isEnable,
|
|
},
|
|
});
|
|
|
|
if (!response.success) {
|
|
throw new HttpException('Automation not found', HttpStatus.NOT_FOUND);
|
|
}
|
|
|
|
return response;
|
|
} catch (error) {
|
|
throw new HttpException(
|
|
error.message || 'Failed to update automation state',
|
|
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
);
|
|
}
|
|
}
|
|
}
|