From cd40dc897be123305049d155b03c2de97b3fbf28 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Sat, 18 May 2024 20:23:17 +0300 Subject: [PATCH] Add endpoint to update device firmware --- ...type.enum copy.ts => product-type.enum.ts} | 0 src/device/controllers/device.controller.ts | 19 ++++++ src/device/interfaces/get.device.interface.ts | 5 ++ src/device/services/device.service.ts | 58 +++++++++++++++++-- 4 files changed, 78 insertions(+), 4 deletions(-) rename libs/common/src/constants/{permission-type.enum copy.ts => product-type.enum.ts} (100%) diff --git a/libs/common/src/constants/permission-type.enum copy.ts b/libs/common/src/constants/product-type.enum.ts similarity index 100% rename from libs/common/src/constants/permission-type.enum copy.ts rename to libs/common/src/constants/product-type.enum.ts diff --git a/src/device/controllers/device.controller.ts b/src/device/controllers/device.controller.ts index 986f23a..e5ac98c 100644 --- a/src/device/controllers/device.controller.ts +++ b/src/device/controllers/device.controller.ts @@ -152,6 +152,25 @@ export class DeviceController { } @ApiBearerAuth() @UseGuards(JwtAuthGuard) + @Post(':deviceUuid/firmware/:firmwareVersion') + async updateDeviceFirmware( + @Param('deviceUuid') deviceUuid: string, + @Param('firmwareVersion') firmwareVersion: number, + ) { + try { + return await this.deviceService.updateDeviceFirmware( + deviceUuid, + firmwareVersion, + ); + } catch (error) { + throw new HttpException( + error.message || 'Internal server error', + error.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + @ApiBearerAuth() + @UseGuards(JwtAuthGuard) @Get('getaway/:gatewayUuid/devices') async getDevicesInGetaway(@Param('gatewayUuid') gatewayUuid: string) { try { diff --git a/src/device/interfaces/get.device.interface.ts b/src/device/interfaces/get.device.interface.ts index f7012f7..526c199 100644 --- a/src/device/interfaces/get.device.interface.ts +++ b/src/device/interfaces/get.device.interface.ts @@ -59,3 +59,8 @@ export interface DeviceInstructionResponse { dataType: string; }[]; } +export interface updateDeviceFirmwareInterface { + success: boolean; + result: boolean; + msg: string; +} diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index 310c2e6..7302250 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -4,6 +4,7 @@ import { HttpException, HttpStatus, NotFoundException, + BadRequestException, } from '@nestjs/common'; import { TuyaContext } from '@tuya/tuya-connector-nodejs'; import { ConfigService } from '@nestjs/config'; @@ -17,6 +18,7 @@ import { GetDeviceDetailsFunctionsStatusInterface, GetDeviceDetailsInterface, controlDeviceInterface, + updateDeviceFirmwareInterface, } from '../interfaces/get.device.interface'; import { GetDeviceByGroupIdDto, @@ -26,7 +28,7 @@ import { ControlDeviceDto } from '../dtos/control.device.dto'; import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; import { DeviceRepository } from '@app/common/modules/device/repositories'; import { GroupDeviceRepository } from '@app/common/modules/group-device/repositories'; -import { ProductType } from '@app/common/constants/permission-type.enum copy'; +import { ProductType } from '@app/common/constants/product-type.enum'; @Injectable() export class DeviceService { @@ -163,6 +165,7 @@ export class DeviceService { try { const deviceDetails = await this.getDeviceByDeviceUuid( controlDeviceDto.deviceUuid, + false, ); if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { @@ -362,7 +365,7 @@ export class DeviceService { if (!deviceDetails) { throw new NotFoundException('Device Not Found'); } else if (deviceDetails.productDevice.prodType !== ProductType.GW) { - throw new NotFoundException('This is not a gateway device'); + throw new BadRequestException('This is not a gateway device'); } const response = await this.getDevicesInGetawayTuya( @@ -407,12 +410,59 @@ export class DeviceService { } } - private async getDeviceByDeviceUuid(deviceUuid: string) { + private async getDeviceByDeviceUuid( + deviceUuid: string, + withProductDevice: boolean = true, + ) { return await this.deviceRepository.findOne({ where: { uuid: deviceUuid, }, - relations: ['productDevice'], + ...(withProductDevice && { relations: ['productDevice'] }), }); } + + async updateDeviceFirmware(deviceUuid: string, firmwareVersion: number) { + try { + const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid, false); + + if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { + throw new NotFoundException('Device Not Found'); + } + const response = await this.updateDeviceFirmwareTuya( + deviceDetails.deviceTuyaUuid, + firmwareVersion, + ); + + 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 updateDeviceFirmwareTuya( + deviceUuid: string, + firmwareVersion: number, + ): Promise { + try { + const path = `/v2.0/cloud/thing/${deviceUuid}/firmware/${firmwareVersion}`; + const response = await this.tuya.request({ + method: 'POST', + path, + }); + + return response as updateDeviceFirmwareInterface; + } catch (error) { + throw new HttpException( + 'Error updating device firmware from Tuya', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } }