/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ import { mqtt, mqtt5, iot, iotshadow } from 'aws-iot-device-sdk-v2'; import {once} from "events"; const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); type Args = { [index: string]: any }; const yargs = require('yargs'); yargs.command('*', false, (yargs: any) => { yargs.option('endpoint', { alias: 'e', description: 'Your AWS IoT custom endpoint, not including a port.', type: 'string', required: true }) .option('cert', { alias: 'c', description: ': File path to a PEM encoded certificate to use with mTLS.', type: 'string', required: false }) .option('key', { alias: 'k', description: ': File path to a PEM encoded private key that matches cert.', type: 'string', required: false }) .option('region', { alias: 'r', description: 'AWS region to establish a websocket connection to.', type: 'string', required: false }) .option('client_id', { alias: 'C', description: 'Client ID for MQTT connection.', type: 'string', required: false }) .option('shadow_property', { alias: 'p', description: 'Name of property in shadow to keep in sync', type: 'string', default: 'color' }) .option('shadow_value', { alias: 'u', description: 'Value for shadow property', type: 'string', default: 'on' }) .option('shadow_name', { alias: 'N', description: 'Use named shadow with specified name', type: 'string' }) .option('thing_name', { alias: 'n', description: 'The name assigned to your IoT Thing', type: 'string', default: 'name' }) .option('mqtt_version', { description: 'MQTT version to use (3 or 5). Default is 5.', type: 'number', required: false, default: 5 }) }, main).parse(); function change_shadow_value(shadow: iotshadow.IotShadowClient, argv: Args, new_value?: object) { return new Promise(async (resolve, reject) => { try { if (typeof new_value !== 'undefined') { var updateShadow: iotshadow.model.UpdateShadowRequest = { state: { desired: new_value, reported: new_value }, thingName: argv.thing_name }; await shadow.publishUpdateShadow( updateShadow, mqtt.QoS.AtLeastOnce) console.log("Update request published."); } } catch (error) { console.log("Failed to publish update request.") reject(error); } resolve(true) }); } function change_named_shadow_value(shadow: iotshadow.IotShadowClient, argv: Args, new_value?: object) { return new Promise(async (resolve, reject) => { try { if (typeof new_value !== 'undefined') { var updateNamedShadow: iotshadow.model.UpdateNamedShadowRequest = { state: { desired: new_value, reported: new_value }, thingName: argv.thing_name, shadowName: argv.shadow_name }; await shadow.publishUpdateNamedShadow( updateNamedShadow, mqtt.QoS.AtLeastOnce) console.log("Update request published."); } } catch (error) { console.log("Failed to publish update request.") reject(error); } resolve(true) }); } function createConnection(args: any): mqtt.MqttClientConnection { let config_builder = iot.AwsIotMqttConnectionConfigBuilder.new_mtls_builder_from_path( args.cert, args.key ); config_builder.with_clean_session(false); config_builder.with_client_id(args.client_id || "test-" + Math.floor(Math.random() * 100000000)); config_builder.with_endpoint(args.endpoint); const config = config_builder.build(); const client = new mqtt.MqttClient(); return client.new_connection(config); } function createMqtt5Client(args: any): mqtt5.Mqtt5Client { let builder: iot.AwsIotMqtt5ClientConfigBuilder; if (args.key && args.cert) { builder = iot.AwsIotMqtt5ClientConfigBuilder.newDirectMqttBuilderWithMtlsFromPath( args.endpoint, args.cert, args.key ); } else { builder = iot.AwsIotMqtt5ClientConfigBuilder.newWebsocketMqttBuilderWithSigv4Auth( args.endpoint, { region: args.region || 'us-east-1' } ); } builder.withConnectProperties({ clientId: args.client_id || "test-" + Math.floor(Math.random() * 100000000), keepAliveIntervalSeconds: 1200 }); return new mqtt5.Mqtt5Client(builder.build()); } async function main(argv: Args) { let connection: mqtt.MqttClientConnection | undefined; let client5: mqtt5.Mqtt5Client | undefined; let shadow: iotshadow.IotShadowClient; console.log("Connecting..."); if (argv.mqtt_version == 5) { client5 = createMqtt5Client(argv); shadow = iotshadow.IotShadowClient.newFromMqtt5Client(client5); const connectionSuccess = once(client5, "connectionSuccess"); client5.start(); await connectionSuccess; console.log("Connected with Mqtt5 Client..."); } else { connection = createConnection(argv); shadow = new iotshadow.IotShadowClient(connection); await connection.connect(); console.log("Connected with Mqtt3 Client..."); } try { let data_to_send: any = {} data_to_send[argv.shadow_property] = argv.shadow_value if (argv.shadow_name) { console.log("Use named shadow") await change_named_shadow_value(shadow, argv, data_to_send); } else { console.log("Use classic shadow") await change_shadow_value(shadow, argv, data_to_send); } } catch (error) { console.log(error); } console.log("Disconnecting.."); if (connection) { await connection.disconnect(); } else if (client5) { let stopped = once(client5, "stopped"); client5.stop(); await stopped; client5.close(); } // force node to wait a second before quitting to finish any promises await sleep(1000); console.log("Disconnected"); // Quit NodeJS process.exit(0); }