diff --git a/example/main.ts b/example/main.ts index 6a8b3d4..cb21f91 100644 --- a/example/main.ts +++ b/example/main.ts @@ -88,6 +88,9 @@ async function main() { }); for (const device of Object.entries(devices.DevicesObj)) { + const serial = await client.getDeviceSerialNumber(device[0]); + rootLogger.info(`Serial number for device '${device[0]}' (${device[1].Name}): ${serial}`); + await client.startRealtimeUpdates(device[0]); } } diff --git a/package-lock.json b/package-lock.json index a2d5e70..9e01f2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "license": "MIT", "dependencies": { + "@aws-sdk/client-iot": "3.825.0", "@aws-sdk/credential-providers": "3.825.0", "amazon-cognito-identity-js": "6.3.15", "aws-iot-device-sdk-v2": "1.21.5", @@ -276,6 +277,121 @@ "node": ">=14.0.0" } }, + "node_modules/@aws-sdk/client-iot": { + "version": "3.825.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-iot/-/client-iot-3.825.0.tgz", + "integrity": "sha512-q2CcipEBhmLIaIr1NXL7ijYgQ5I4dKCMoeu/XdJNkPYE5ceONI+I+76CPlvqgFdG+/T2IrOsfpAGD8rtLTETzw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.825.0", + "@aws-sdk/credential-provider-node": "3.825.0", + "@aws-sdk/middleware-host-header": "3.821.0", + "@aws-sdk/middleware-logger": "3.821.0", + "@aws-sdk/middleware-recursion-detection": "3.821.0", + "@aws-sdk/middleware-user-agent": "3.825.0", + "@aws-sdk/region-config-resolver": "3.821.0", + "@aws-sdk/types": "3.821.0", + "@aws-sdk/util-endpoints": "3.821.0", + "@aws-sdk/util-user-agent-browser": "3.821.0", + "@aws-sdk/util-user-agent-node": "3.825.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.5.2", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.10", + "@smithy/middleware-retry": "^4.1.11", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.2", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.18", + "@smithy/util-defaults-mode-node": "^4.0.18", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.5", + "@smithy/util-utf8": "^4.0.0", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-iot/node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-iot/node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-iot/node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-iot/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-iot/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@aws-sdk/client-sso": { "version": "3.825.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.825.0.tgz", @@ -3131,6 +3247,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", diff --git a/package.json b/package.json index 54fa9f3..c9059f6 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "build:docs": "typedoc" }, "dependencies": { + "@aws-sdk/client-iot": "3.825.0", "@aws-sdk/credential-providers": "3.825.0", "amazon-cognito-identity-js": "6.3.15", "aws-iot-device-sdk-v2": "1.21.5", diff --git a/src/api/MysaApiClient.ts b/src/api/MysaApiClient.ts index fa656d8..41b4b92 100644 --- a/src/api/MysaApiClient.ts +++ b/src/api/MysaApiClient.ts @@ -7,6 +7,7 @@ import { InMessageType } from '@/types/mqtt/in/InMessageType'; import { StartPublishingDeviceStatus } from '@/types/mqtt/in/StartPublishingDeviceStatus'; import { OutMessageType } from '@/types/mqtt/out/OutMessageType'; import { Devices, DeviceStates, Firmwares } from '@/types/rest'; +import { DescribeThingCommand, IoTClient } from '@aws-sdk/client-iot'; import { fromCognitoIdentityPool } from '@aws-sdk/credential-providers'; import { AuthenticationDetails, @@ -195,6 +196,48 @@ export class MysaApiClient { return response.json(); } + /** + * Retrieves the serial number for a specific device. + * + * @param deviceId - The ID of the device to get the serial number for. + * @returns A promise that resolves to the serial number, or undefined if not found. + */ + async getDeviceSerialNumber(deviceId: string): Promise { + this._logger.debug(`Fetching serial number for device ${deviceId}...`); + + const session = await this.getFreshSession(); + + // Get AWS credentials for IoT client + const credentialsProvider = fromCognitoIdentityPool({ + clientConfig: { + region: AwsRegion + }, + identityPoolId: CognitoIdentityPoolId, + logins: { + [CognitoLoginKey]: session.getIdToken().getJwtToken() + } + }); + + const credentials = await credentialsProvider(); + const iotClient = new IoTClient({ + region: AwsRegion, + credentials: { + accessKeyId: credentials.accessKeyId, + secretAccessKey: credentials.secretAccessKey, + sessionToken: credentials.sessionToken + } + }); + + try { + const command = new DescribeThingCommand({ thingName: deviceId }); + const response = await iotClient.send(command); + return response.attributes?.['Serial']; + } catch (error) { + this._logger.warn(`Could not get serial number for device ${deviceId}:`, error); + return undefined; + } + } + async getDeviceFirmwares(): Promise { this._logger.debug(`Fetching device firmwares...`);