diff --git a/.doc_gen/metadata/iot-data_metadata.yaml b/.doc_gen/metadata/iot-data_metadata.yaml index 45159359f4b..ae7f1739d01 100644 --- a/.doc_gen/metadata/iot-data_metadata.yaml +++ b/.doc_gen/metadata/iot-data_metadata.yaml @@ -5,6 +5,15 @@ iot-data-plane_GetThingShadow: synopsis: get the shadow for an &IoT; thing. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.get.shadow.writer.main Java: versions: - sdk_version: 2 @@ -21,6 +30,15 @@ iot-data-plane_UpdateThingShadow: synopsis: update the shadow for an &IoT; thing. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.update.shadow.thing.main Java: versions: - sdk_version: 2 diff --git a/.doc_gen/metadata/iot_metadata.yaml b/.doc_gen/metadata/iot_metadata.yaml index 74f78b08b95..23a5db80e8e 100644 --- a/.doc_gen/metadata/iot_metadata.yaml +++ b/.doc_gen/metadata/iot_metadata.yaml @@ -5,6 +5,15 @@ iot_Hello: synopsis: get started using &IoT;. category: Hello languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.hello_iot.main Java: versions: - sdk_version: 2 @@ -22,6 +31,15 @@ iot_DescribeEndpoint: synopsis: get &IoT; endpoint information. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.describe.endpoint.main Java: versions: - sdk_version: 2 @@ -62,6 +80,15 @@ iot_ListCertificates: synopsis: list your &IoT; certificates. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.list.certs.main Java: versions: - sdk_version: 2 @@ -78,6 +105,15 @@ iot_CreateCertificate: synopsis: create an &IoT; certificate. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.java2.create.cert.main Java: versions: - sdk_version: 2 @@ -94,6 +130,15 @@ iot_DeleteCertificate: synopsis: delete an &IoT; certificate. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.delete.cert.main Java: versions: - sdk_version: 2 @@ -110,6 +155,15 @@ iot_SearchIndex: synopsis: query the &IoT; search index. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.search.thing.main Java: versions: - sdk_version: 2 @@ -126,6 +180,15 @@ iot_DeleteThing: synopsis: delete an &IoT; thing. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.delete.thing.main Java: versions: - sdk_version: 2 @@ -142,6 +205,15 @@ iot_DescribeThing: synopsis: describe an &IoT; thing. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.describe.thing.main Java: versions: - sdk_version: 2 @@ -158,6 +230,15 @@ iot_AttachThingPrincipal: synopsis: attach an &IoT; certificate. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.attach.thing.main Java: versions: - sdk_version: 2 @@ -174,6 +255,15 @@ iot_DetachThingPrincipal: synopsis: detach an &IoT; certificate. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.detach.thing.main Java: versions: - sdk_version: 2 @@ -190,6 +280,15 @@ iot_UpdateThing: synopsis: update an &IoT; thing. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.update.thing.main Java: versions: - sdk_version: 2 @@ -206,6 +305,15 @@ iot_CreateRule: synopsis: create an &IoT; rule. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.create.rule.main Java: versions: - sdk_version: 2 @@ -222,6 +330,15 @@ iot_CreateThing: synopsis: create an &IoT; thing. category: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.create.thing.main Java: versions: - sdk_version: 2 @@ -238,6 +355,15 @@ iot_Scenario: synopsis: working with &IoT; device management use cases using &IoT; SDK category: Scenarios languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/iot + sdkguide: + excerpts: + - description: + snippet_tags: + - iot.kotlin.scenario.main Java: versions: - sdk_version: 2 diff --git a/kotlin/services/iot/Readme.md b/kotlin/services/iot/Readme.md new file mode 100644 index 00000000000..55a06dfd243 --- /dev/null +++ b/kotlin/services/iot/Readme.md @@ -0,0 +1,81 @@ +# AWS IoT Core code examples for the SDK for Kotlin + +## Overview +This README discusses how to run and test the AWS SDK for Kotlin examples for AWS IoT Core. + +AWS IoT Core enables secure two-way communication between internet-connected devices and AWS services with device gateway and device SDK capabilities. + +## ⚠️ Important +* The SDK for Kotlin examples perform AWS operations for the account and AWS Region for which you've specified credentials. Running these examples might incur charges on your account. For details about the charges you can expect for a given service and API operation, see [AWS Pricing](https://aws.amazon.com/pricing/). +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + +## Code examples + +The credential provider used in all code examples is the default credential provider. For more information, see [Using credentials](https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/credential-providers.html). + +### Get started + +- [Hello AWS IoT Core](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/HelloIoT.kt) (`ListThings`) + + +### Single action + +The following examples use the **IotClient** object: + +- [Attach a certificate to an AWS IoT thing](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`AttachThingPrincipal`) +- [Create an AWS IoT thing](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`CreateThing`) +- [Create an AWS IoT certificate](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`CreateKeysAndCertificate`) +- [Create an AWS IoT rule](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`CreateTopicRule`) +- [Delete an AWS IoT certificate](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`DeleteCertificate`) +- [Delete an AWS IoT thing](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`DeleteThing`) +- [Detach a certificate from an AWS IoT thing](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`DetachThingPrincipal`) +- [Get information about an endpoint](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`DescribeEndpoint`) +- [List your AWS IoT certificates](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`ListCertificates`) +- [Query the AWS IoT search index.](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`SearchIndex`) +- [Update an AWS IoT thing](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`UpdateThing`) + +The following examples use the **IotDataPlaneClient** object: + +- [Get the shadow for the specified thing](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`GetThingShadow`) +- [Update the shadow for the specified thing](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) (`UpdateThingShadow`) + +### Scenarios + +Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. + +* [Perform device management use cases ](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt) + +## Running the AWS IoT Kotlin files + +Some of these examples perform *destructive* operations on AWS resources, such as deleting an AWS IoT Thing. **Be very careful** when running an operation that deletes or modifies AWS resources in your account. We recommend creating separate test-only resources when experimenting with these examples. + +To run these examples, set up your development environment. For more information, +see [Get started with the SDK for Kotlin](https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/get-started.html). + + + ## Testing the AWS IoT Kotlin files + +You can test the Kotlin code examples for AWS IoT by running a test file named **IoTTests**. This file uses JUnit 5 to run the JUnit tests and is located in the **src/test/kotlin** folder. For more information, see [https://junit.org/junit5/](https://junit.org/junit5/). + +You can run the JUnit tests from an IDE, such as IntelliJ, or from the command line. As each test runs, you can view messages that inform you if the various tests succeed or fail. For example, the following message informs you that the Test passed. + + Test 2 passed + +**WARNING**: _Running these JUnit tests manipulates real Amazon resources and might incur charges on your account._ + + ### Properties file +Before running the JUnit tests, you must define values in the **config.properties** file located in the **resources** folder. This file contains values that are required to run the JUnit tests. For example, you define a tableId used in the tests. If you do not define all values, the JUnit tests fail. + +Define these values to successfully run the JUnit tests: + +- **roleARN** - The ARN of an IAM role that has permission to work with AWS IOT. +- **snsAction** - An ARN of an SNS topic. + +## Additional resources +* [Developer Guide - AWS SDK for Koltin](https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/home.html). +* [Developer Guide - AWS IoT Core](https://docs.aws.amazon.com/iot/latest/developerguide/iot-gs.html). +* [Interface IotClient](https://sdk.amazonaws.com/kotlin/api/latest/iot/aws.sdk.kotlin.services.iot/-iot-client/index.html). + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 \ No newline at end of file diff --git a/kotlin/services/iot/build.gradle.kts b/kotlin/services/iot/build.gradle.kts new file mode 100644 index 00000000000..9e5cacd5ca0 --- /dev/null +++ b/kotlin/services/iot/build.gradle.kts @@ -0,0 +1,52 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.9.0" + application +} + +group = "me.scmacdon" +version = "1.0-SNAPSHOT" + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +buildscript { + repositories { + maven("https://plugins.gradle.org/m2/") + } + dependencies { + classpath("org.jlleitschuh.gradle:ktlint-gradle:10.3.0") + } +} + +repositories { + mavenCentral() +} +apply(plugin = "org.jlleitschuh.gradle.ktlint") +dependencies { + implementation("aws.sdk.kotlin:iot:1.0.30") + implementation("aws.sdk.kotlin:iotdataplane:1.0.30") + implementation("aws.sdk.kotlin:secretsmanager:1.0.30") + implementation("aws.smithy.kotlin:http-client-engine-okhttp:0.30.0") + implementation("aws.smithy.kotlin:http-client-engine-crt:0.30.0") + implementation("com.google.code.gson:gson:2.10") + testImplementation("org.junit.jupiter:junit-jupiter:5.9.2") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") +} +tasks.withType() { + kotlinOptions.jvmTarget = "17" +} + +tasks.test { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") + } + + // Define the test source set + testClassesDirs += files("build/classes/kotlin/test") + classpath += files("build/classes/kotlin/main", "build/resources/main") +} diff --git a/kotlin/services/iot/src/main/kotlin/com/example/iot/HelloIoT.kt b/kotlin/services/iot/src/main/kotlin/com/example/iot/HelloIoT.kt new file mode 100644 index 00000000000..c3407392e28 --- /dev/null +++ b/kotlin/services/iot/src/main/kotlin/com/example/iot/HelloIoT.kt @@ -0,0 +1,31 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.iot + +// snippet-start:[iot.kotlin.hello_iot.main] +import aws.sdk.kotlin.services.iot.IotClient +import aws.sdk.kotlin.services.iot.model.ListThingsRequest + +suspend fun main() { + println("A listing of your AWS IoT Things:") + listAllThings() +} + +suspend fun listAllThings() { + val thingsRequest = ListThingsRequest { + maxResults = 10 + } + + IotClient { region = "us-east-1" }.use { iotClient -> + val response = iotClient.listThings(thingsRequest) + val thingList = response.things + if (thingList != null) { + for (attribute in thingList) { + println("Thing name ${attribute.thingName}") + println("Thing ARN: ${attribute.thingArn}") + } + } + } +} +// snippet-end:[iot.kotlin.hello_iot.main] diff --git a/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt b/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt new file mode 100644 index 00000000000..113ac89c54b --- /dev/null +++ b/kotlin/services/iot/src/main/kotlin/com/example/iot/IotScenario.kt @@ -0,0 +1,515 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.iot + +// snippet-start:[iot.kotlin.scenario.main] +import aws.sdk.kotlin.services.iot.IotClient +import aws.sdk.kotlin.services.iot.model.Action +import aws.sdk.kotlin.services.iot.model.AttachThingPrincipalRequest +import aws.sdk.kotlin.services.iot.model.AttributePayload +import aws.sdk.kotlin.services.iot.model.CreateThingRequest +import aws.sdk.kotlin.services.iot.model.CreateTopicRuleRequest +import aws.sdk.kotlin.services.iot.model.DeleteCertificateRequest +import aws.sdk.kotlin.services.iot.model.DeleteThingRequest +import aws.sdk.kotlin.services.iot.model.DescribeEndpointRequest +import aws.sdk.kotlin.services.iot.model.DescribeThingRequest +import aws.sdk.kotlin.services.iot.model.DetachThingPrincipalRequest +import aws.sdk.kotlin.services.iot.model.ListTopicRulesRequest +import aws.sdk.kotlin.services.iot.model.SearchIndexRequest +import aws.sdk.kotlin.services.iot.model.SnsAction +import aws.sdk.kotlin.services.iot.model.TopicRulePayload +import aws.sdk.kotlin.services.iot.model.UpdateThingRequest +import aws.sdk.kotlin.services.iotdataplane.IotDataPlaneClient +import aws.sdk.kotlin.services.iotdataplane.model.GetThingShadowRequest +import aws.sdk.kotlin.services.iotdataplane.model.UpdateThingShadowRequest +import aws.smithy.kotlin.runtime.content.ByteStream +import aws.smithy.kotlin.runtime.content.toByteArray +import java.util.Scanner +import java.util.regex.Pattern +import kotlin.system.exitProcess + +/** + * Before running this Kotlin code example, ensure that your development environment + * is set up, including configuring your credentials. + * + * For detailed instructions, refer to the following documentation topic: + * [Setting Up Your Development Environment](https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/setup.html) + * + * This code example requires an SNS topic and an IAM Role. + * Follow the steps in the documentation to set up these resources: + * + * - [Creating an SNS Topic](https://docs.aws.amazon.com/sns/latest/dg/sns-getting-started.html#step-create-topic) + * - [Creating an IAM Role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create.html) + */ + +val DASHES = String(CharArray(80)).replace("\u0000", "-") +val TOPIC = "your-iot-topic" +suspend fun main(args: Array) { + val usage = """ + Usage: + + + Where: + roleARN - The ARN of an IAM role that has permission to work with AWS IOT. + snsAction - An ARN of an SNS topic. + + """.trimIndent() + + if (args.size != 2) { + println(usage) + exitProcess(1) + } + + var thingName: String + val roleARN = args[0] + val snsAction = args[1] + val scanner = Scanner(System.`in`) + + println(DASHES) + println("Welcome to the AWS IoT example scenario.") + println( + """ + This example program demonstrates various interactions with the AWS Internet of Things (IoT) Core service. + The program guides you through a series of steps, including creating an IoT thing, generating a device certificate, + updating the thing with attributes, and so on. + + It utilizes the AWS SDK for Kotlin and incorporates functionality for creating and managing IoT things, certificates, rules, + shadows, and performing searches. The program aims to showcase AWS IoT capabilities and provides a comprehensive example for + developers working with AWS IoT in a Kotlin environment. + """.trimIndent() + ) + + print("Press Enter to continue...") + scanner.nextLine() + println(DASHES) + + println(DASHES) + println("1. Create an AWS IoT thing.") + println( + """ + An AWS IoT thing represents a virtual entity in the AWS IoT service that can be associated with a physical device. + """.trimIndent() + ) + // Prompt the user for input. + print("Enter thing name: ") + thingName = scanner.nextLine() + createIoTThing(thingName) + describeThing(thingName) + println(DASHES) + + println(DASHES) + println("2. Generate a device certificate.") + println( + """ + A device certificate performs a role in securing the communication between devices (things) and the AWS IoT platform. + """.trimIndent() + ) + + print("Do you want to create a certificate for $thingName? (y/n)") + val certAns = scanner.nextLine() + var certificateArn: String? = "" + if (certAns != null && certAns.trim { it <= ' ' }.equals("y", ignoreCase = true)) { + certificateArn = createCertificate() + println("Attach the certificate to the AWS IoT thing.") + attachCertificateToThing(thingName, certificateArn) + } else { + println("A device certificate was not created.") + } + println(DASHES) + + println(DASHES) + println("3. Update an AWS IoT thing with Attributes.") + println( + """ + IoT thing attributes, represented as key-value pairs, offer a pivotal advantage in facilitating efficient data + management and retrieval within the AWS IoT ecosystem. + """.trimIndent() + ) + print("Press Enter to continue...") + scanner.nextLine() + updateThing(thingName) + println(DASHES) + + println(DASHES) + println("4. Return a unique endpoint specific to the Amazon Web Services account.") + println( + """ + An IoT Endpoint refers to a specific URL or Uniform Resource Locator that serves as the entry point for communication between IoT devices and the AWS IoT service. + """.trimIndent() + ) + print("Press Enter to continue...") + scanner.nextLine() + val endpointUrl = describeEndpoint() + println(DASHES) + + println(DASHES) + println("5. List your AWS IoT certificates") + print("Press Enter to continue...") + scanner.nextLine() + if (certificateArn!!.isNotEmpty()) { + listCertificates() + } else { + println("You did not create a certificates. Skipping this step.") + } + println(DASHES) + + println(DASHES) + println("6. Create an IoT shadow that refers to a digital representation or virtual twin of a physical IoT device") + println( + """ + A thing shadow refers to a feature that enables you to create a virtual representation, or "shadow," + of a physical device or thing. The thing shadow allows you to synchronize and control the state of a device between + the cloud and the device itself. and the AWS IoT service. For example, you can write and retrieve JSON data from a thing shadow. + + """.trimIndent() + ) + print("Press Enter to continue...") + scanner.nextLine() + updateShawdowThing(thingName) + println(DASHES) + + println(DASHES) + println("7. Write out the state information, in JSON format.") + print("Press Enter to continue...") + scanner.nextLine() + getPayload(thingName) + println(DASHES) + + println(DASHES) + println("8. Creates a rule") + println( + """ + Creates a rule that is an administrator-level action. + Any user who has permission to create rules will be able to access data processed by the rule. + """.trimIndent() + ) + print("Enter Rule name: ") + val ruleName = scanner.nextLine() + createIoTRule(roleARN, ruleName, snsAction) + println(DASHES) + + println(DASHES) + println("9. List your rules.") + print("Press Enter to continue...") + scanner.nextLine() + listIoTRules() + println(DASHES) + + println(DASHES) + println("10. Search things using the name.") + print("Press Enter to continue...") + scanner.nextLine() + val queryString = "thingName:$thingName" + searchThings(queryString) + println(DASHES) + + println(DASHES) + if (certificateArn.length > 0) { + print("Do you want to detach and delete the certificate for $thingName? (y/n)") + val delAns = scanner.nextLine() + if (delAns != null && delAns.trim { it <= ' ' }.equals("y", ignoreCase = true)) { + println("11. You selected to detach amd delete the certificate.") + print("Press Enter to continue...") + scanner.nextLine() + detachThingPrincipal(thingName, certificateArn) + deleteCertificate(certificateArn) + } else { + println("11. You selected not to delete the certificate.") + } + } else { + println("11. You did not create a certificate so there is nothing to delete.") + } + println(DASHES) + + println(DASHES) + println("12. Delete the AWS IoT thing.") + print("Do you want to delete the IoT thing? (y/n)") + val delAns = scanner.nextLine() + if (delAns != null && delAns.trim { it <= ' ' }.equals("y", ignoreCase = true)) { + deleteIoTThing(thingName) + } else { + println("The IoT thing was not deleted.") + } + println(DASHES) + + println(DASHES) + println("The AWS IoT workflow has successfully completed.") + println(DASHES) +} + +// snippet-start:[iot.kotlin.delete.thing.main] +suspend fun deleteIoTThing(thingNameVal: String) { + val deleteThingRequest = DeleteThingRequest { + thingName = thingNameVal + } + + IotClient { region = "us-east-1" }.use { iotClient -> + iotClient.deleteThing(deleteThingRequest) + println("Deleted $thingNameVal") + } +} +// snippet-end:[iot.kotlin.delete.thing.main] + +// snippet-start:[iot.kotlin.delete.cert.main] +suspend fun deleteCertificate(certificateArn: String) { + val certificateProviderRequest = DeleteCertificateRequest { + certificateId = extractCertificateId(certificateArn) + } + IotClient { region = "us-east-1" }.use { iotClient -> + iotClient.deleteCertificate(certificateProviderRequest) + println("$certificateArn was successfully deleted.") + } +} +// snippet-end:[iot.kotlin.delete.cert.main] + +private fun extractCertificateId(certificateArn: String): String? { + // Example ARN: arn:aws:iot:region:account-id:cert/certificate-id. + val arnParts = certificateArn.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + val certificateIdPart = arnParts[arnParts.size - 1] + return certificateIdPart.substring(certificateIdPart.lastIndexOf("/") + 1) +} + +// snippet-start:[iot.kotlin.detach.thing.main] +suspend fun detachThingPrincipal(thingNameVal: String, certificateArn: String) { + val thingPrincipalRequest = DetachThingPrincipalRequest { + principal = certificateArn + thingName = thingNameVal + } + + IotClient { region = "us-east-1" }.use { iotClient -> + iotClient.detachThingPrincipal(thingPrincipalRequest) + println("$certificateArn was successfully removed from $thingNameVal") + } +} +// snippet-end:[iot.kotlin.detach.thing.main] + +// snippet-start:[iot.kotlin.search.thing.main] +suspend fun searchThings(queryStringVal: String?) { + val searchIndexRequest = SearchIndexRequest { + queryString = queryStringVal + } + + IotClient { region = "us-east-1" }.use { iotClient -> + val searchIndexResponse = iotClient.searchIndex(searchIndexRequest) + if (searchIndexResponse.things?.isEmpty() == true) { + println("No things found.") + } else { + searchIndexResponse.things + ?.forEach { thing -> println("Thing id found using search is ${thing.thingId}") } + } + } +} +// snippet-end:[iot.kotlin.search.thing.main] + +// snippet-start:[iot.kotlin.list.rules.main] +suspend fun listIoTRules() { + val listTopicRulesRequest = ListTopicRulesRequest {} + + IotClient { region = "us-east-1" }.use { iotClient -> + val listTopicRulesResponse = iotClient.listTopicRules(listTopicRulesRequest) + println("List of IoT rules:") + val ruleList = listTopicRulesResponse.rules + ruleList?.forEach { rule -> + println("Rule name: ${rule.ruleName}") + println("Rule ARN: ${rule.ruleArn}") + println("--------------") + } + } +} +// snippet-end:[iot.kotlin.list.rules.main] + +// snippet-start:[iot.kotlin.create.rule.main] +suspend fun createIoTRule(roleARNVal: String?, ruleNameVal: String?, action: String?) { + val sqlVal = "SELECT * FROM '$TOPIC '" + val action1 = SnsAction { + targetArn = action + roleArn = roleARNVal + } + + val myAction = Action { + sns = action1 + } + + val topicRulePayloadVal = TopicRulePayload { + sql = sqlVal + actions = listOf(myAction) + } + + val topicRuleRequest = CreateTopicRuleRequest { + ruleName = ruleNameVal + topicRulePayload = topicRulePayloadVal + } + + IotClient { region = "us-east-1" }.use { iotClient -> + iotClient.createTopicRule(topicRuleRequest) + println("IoT rule created successfully.") + } +} +// snippet-end:[iot.kotlin.create.rule.main] + +// snippet-start:[iot.kotlin.get.shadow.writer.main] +suspend fun getPayload(thingNameVal: String?) { + val getThingShadowRequest = GetThingShadowRequest { + thingName = thingNameVal + } + + IotDataPlaneClient { region = "us-east-1" }.use { iotPlaneClient -> + val getThingShadowResponse = iotPlaneClient.getThingShadow(getThingShadowRequest) + val payload = getThingShadowResponse.payload + val payloadString = payload?.let { java.lang.String(it, Charsets.UTF_8) } + println("Received shadow data: $payloadString") + } +} +// snippet-end:[iot.kotlin.get.shadow.writer.main] + +// snippet-start:[iot.kotlin.list.certs.main] +suspend fun listCertificates() { + IotClient { region = "us-east-1" }.use { iotClient -> + val response = iotClient.listCertificates() + val certList = response.certificates + certList?.forEach { cert -> + println("Cert id: ${cert.certificateId}") + println("Cert Arn: ${cert.certificateArn}") + } + } +} +// snippet-end:[iot.kotlin.list.certs.main] + +// snippet-start:[iot.kotlin.describe.endpoint.main] +suspend fun describeEndpoint(): String? { + val request = DescribeEndpointRequest {} + + IotClient { region = "us-east-1" }.use { iotClient -> + val endpointResponse = iotClient.describeEndpoint(request) + val endpointUrl: String? = endpointResponse.endpointAddress + val exString: String = getValue(endpointUrl) + val fullEndpoint = "https://$exString-ats.iot.us-east-1.amazonaws.com" + println("Full endpoint URL: $fullEndpoint") + return fullEndpoint + } +} +// snippet-end:[iot.kotlin.describe.endpoint.main] + +private fun getValue(input: String?): String { + // Define a regular expression pattern for extracting the subdomain. + val pattern = Pattern.compile("^(.*?)\\.iot\\.us-east-1\\.amazonaws\\.com") + + // Match the pattern against the input string. + val matcher = pattern.matcher(input) + + // Check if a match is found. + if (matcher.find()) { + val subdomain = matcher.group(1) + println("Extracted subdomain: $subdomain") + return subdomain + } else { + println("No match found") + } + return "" +} + +// snippet-start:[iot.kotlin.update.thing.main] +suspend fun updateThing(thingNameVal: String?) { + val newLocation = "Office" + val newFirmwareVersion = "v2.0" + val attMap: MutableMap = HashMap() + attMap["location"] = newLocation + attMap["firmwareVersion"] = newFirmwareVersion + + val attributePayloadVal = AttributePayload { + attributes = attMap + } + + val updateThingRequest = UpdateThingRequest { + thingName = thingNameVal + attributePayload = attributePayloadVal + } + + IotClient { region = "us-east-1" }.use { iotClient -> + // Update the IoT thing attributes. + iotClient.updateThing(updateThingRequest) + println("$thingNameVal attributes updated successfully.") + } +} +// snippet-end:[iot.kotlin.update.thing.main] + +// snippet-start:[iot.kotlin.update.shadow.thing.main] +suspend fun updateShawdowThing(thingNameVal: String?) { + // Create the thing shadow state document. + val stateDocument = "{\"state\":{\"reported\":{\"temperature\":25, \"humidity\":50}}}" + val byteStream: ByteStream = ByteStream.fromString(stateDocument) + val byteArray: ByteArray = byteStream.toByteArray() + + val updateThingShadowRequest = UpdateThingShadowRequest { + thingName = thingNameVal + payload = byteArray + } + + IotDataPlaneClient { region = "us-east-1" }.use { iotPlaneClient -> + iotPlaneClient.updateThingShadow(updateThingShadowRequest) + println("The thing shadow was updated successfully.") + } +} +// snippet-end:[iot.kotlin.update.shadow.thing.main] + +// snippet-start:[iot.kotlin.attach.thing.main] +suspend fun attachCertificateToThing(thingNameVal: String?, certificateArn: String?) { + val principalRequest = AttachThingPrincipalRequest { + thingName = thingNameVal + principal = certificateArn + } + + IotClient { region = "us-east-1" }.use { iotClient -> + iotClient.attachThingPrincipal(principalRequest) + println("Certificate attached to $thingNameVal successfully.") + } +} +// snippet-end:[iot.kotlin.attach.thing.main] + +// snippet-start:[iot.kotlin.describe.thing.main] +suspend fun describeThing(thingNameVal: String) { + val thingRequest = DescribeThingRequest { + thingName = thingNameVal + } + + // Print Thing details. + IotClient { region = "us-east-1" }.use { iotClient -> + val describeResponse = iotClient.describeThing(thingRequest) + println("Thing details:") + println("Thing name: ${describeResponse.thingName}") + println("Thing ARN: ${describeResponse.thingArn}") + } +} +// snippet-end:[iot.kotlin.describe.thing.main] + +// snippet-start:[iot.kotlin.create.cert.main] +suspend fun createCertificate(): String? { + IotClient { region = "us-east-1" }.use { iotClient -> + val response = iotClient.createKeysAndCertificate() + val certificatePem = response.certificatePem + val certificateArn = response.certificateArn + + // Print the details. + println("\nCertificate:") + println(certificatePem) + println("\nCertificate ARN:") + println(certificateArn) + return certificateArn + } +} +// snippet-end:[iot.kotlin.create.cert.main] + +// snippet-start:[iot.kotlin.create.thing.main] +suspend fun createIoTThing(thingNameVal: String) { + val createThingRequest = CreateThingRequest { + thingName = thingNameVal + } + + IotClient { region = "us-east-1" }.use { iotClient -> + iotClient.createThing(createThingRequest) + println("Created $thingNameVal}") + } +} +// snippet-end:[iot.kotlin.create.thing.main] +// snippet-end:[iot.kotlin.scenario.main] diff --git a/kotlin/services/iot/src/test/kotlin/IoTTest.kt b/kotlin/services/iot/src/test/kotlin/IoTTest.kt new file mode 100644 index 00000000000..c0080a75055 --- /dev/null +++ b/kotlin/services/iot/src/test/kotlin/IoTTest.kt @@ -0,0 +1,111 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import aws.sdk.kotlin.runtime.auth.credentials.EnvironmentCredentialsProvider +import aws.sdk.kotlin.services.secretsmanager.SecretsManagerClient +import aws.sdk.kotlin.services.secretsmanager.model.GetSecretValueRequest +import com.example.iot.attachCertificateToThing +import com.example.iot.createCertificate +import com.example.iot.createIoTRule +import com.example.iot.createIoTThing +import com.example.iot.deleteCertificate +import com.example.iot.deleteIoTThing +import com.example.iot.describeEndpoint +import com.example.iot.describeThing +import com.example.iot.detachThingPrincipal +import com.example.iot.getPayload +import com.example.iot.listAllThings +import com.example.iot.listCertificates +import com.example.iot.listIoTRules +import com.example.iot.searchThings +import com.example.iot.updateShawdowThing +import com.example.iot.updateThing +import com.google.gson.Gson +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.MethodOrderer +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Order +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestMethodOrder +import java.util.Random + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestMethodOrder(MethodOrderer.OrderAnnotation::class) +class IoTTest { + private var roleARN = "" + private var snsAction = "" + private var thingName = "foo" + private var queryString = "thingName:" + private var ruleName = "rule" + + @BeforeAll + fun setup() = runBlocking { + val random = Random() + val randomNumber = random.nextInt(1001) + thingName = thingName + randomNumber + queryString = queryString + thingName + ruleName = ruleName + randomNumber + + // Get the values from AWS Secrets Manager. + val gson = Gson() + val json: String = getSecretValues() + val values = gson.fromJson(json, SecretValues::class.java) + roleARN = values.roleARN.toString() + snsAction = values.snsAction.toString() + } + + @Test + @Order(1) + fun helloIoTTest() = runBlocking { + listAllThings() + println("Test 1 passed") + } + + @Test + @Order(2) + fun testScenario() = runBlocking { + createIoTThing(thingName) + describeThing(thingName) + val certificateArn = createCertificate() + attachCertificateToThing(thingName, certificateArn) + updateThing(thingName) + describeEndpoint() + listCertificates() + updateShawdowThing(thingName) + getPayload(thingName) + createIoTRule(roleARN, ruleName, snsAction) + listIoTRules() + searchThings(queryString) + if (certificateArn != null) { + detachThingPrincipal(thingName, certificateArn) + } + if (certificateArn != null) { + deleteCertificate(certificateArn) + } + deleteIoTThing(thingName) + println("Test 2 passed") + } + + private suspend fun getSecretValues(): String { + val secretClient = SecretsManagerClient { + region = "us-east-1" + credentialsProvider = EnvironmentCredentialsProvider() + } + val secretName = "test/iot" + val valueRequest = GetSecretValueRequest { + secretId = secretName + } + val valueResponse = secretClient.getSecretValue(valueRequest) + return valueResponse.secretString.toString() + } + + @Nested + @DisplayName("A class used to get test values from test/iot (an AWS Secrets Manager secret)") + internal class SecretValues { + val roleARN: String? = null + val snsAction: String? = null + } +}