Interact with local shadows - Amazon IoT Greengrass
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

Interact with local shadows

Use the shadow IPC service to interact with local shadows on a device. The device you choose to interact with can be your core device or a connected client device.

To use these IPC operations, include the shadow manager component as a dependency in your custom component. You can then use IPC operations in your custom components to interact with local shadows on your device through the shadow manager. To enable custom components to react to changes in local shadow states, you can also use the publish/subscribe IPC service to subscribe to shadow events. For more information about using the publish/subscribe service, see the Publish/subscribe local messages.

Note

To enable a core device to interact with client device shadows, you must also configure and deploy the MQTT bridge component. For more information, see Enable shadow manager to communicate with client devices.

Minimum SDK versions

The following table lists the minimum versions of the Amazon IoT Device SDK that you must use to interact with local shadows.

Authorization

To use the shadow IPC service in a custom component, you must define authorization policies that allow your component to interact with shadows. For information about defining authorization policies, see Authorize components to perform IPC operations.

Authorization policies for shadow interaction have the following properties.

IPC service identifier: aws.greengrass.ShadowManager

Operation Description Resources

aws.greengrass#GetThingShadow

Allows a component to retrieve the shadow of a thing.

One of the following strings:

  • $aws/things/thingName/shadow/, to allow access to the classic device shadow.

  • $aws/things/thingName/shadow/name/shadowName, to allow access to a named shadow.

  • * to allow access to all shadows.

aws.greengrass#UpdateThingShadow

Allows a component to update the shadow of a thing.

One of the following strings:

  • $aws/things/thingName/shadow/, to allow access to the classic device shadow.

  • $aws/things/thingName/shadow/name/shadowName, to allow access to a named shadow.

  • * to allow access to all shadows.

aws.greengrass#DeleteThingShadow

Allows a component to delete the shadow of a thing.

One of the following strings:

  • $aws/things/thingName/shadow/, to allow access to the classic device shadow

  • $aws/things/thingName/shadow/name/shadowName, to allow access to a named shadow

  • *, to allow access to all shadows.

aws.greengrass#ListNamedShadowsForThing

Allows a component to retrieve the list of named shadows for a thing.

A thing name string that allows access to the thing to list its shadows.

Use * to allow access to all things.

IPC service identifier: aws.greengrass.ipc.pubsub

Operation Description Resources

aws.greengrass#SubscribeToTopic

Allows a component to subscribe to messages for the topics that you specify.

One of the following topic strings:

  • shadowTopicPrefix/get/accepted

  • shadowTopicPrefix/get/rejected

  • shadowTopicPrefix/delete/accepted

  • shadowTopicPrefix/delete/rejected

  • shadowTopicPrefix/update/accepted

  • shadowTopicPrefix/update/delta

  • shadowTopicPrefix/update/rejected

The value of the topic prefix shadowTopicPrefix depends on the type of shadow:

  • Classic shadow: $aws/things/thingName/shadow

  • Named shadow: $aws/things/thingName/shadow/name/shadowName

Use * to allow access to all topics.

In Greengrass nucleus v2.6.0 and later, you can subscribe to topics that contain MQTT topic wildcards (# and +). This topic string supports MQTT topic wildcards as literal characters. For example, if a component's authorization policy grants access to test/topic/#, the component can subscribe to test/topic/#, but it can't subscribe to test/topic/filter.

Recipe variables in local shadow authorization policies

If you use v2.6.0 or later of the Greengrass nucleus, and you set the Greengrass nucleus' interpolateComponentConfiguration configuration option to true, you can use the {iot:thingName} recipe variable in authorization policies. This feature enables you to configure a single authorization policy for a group of core devices, where each core device can access only its own shadow. For example, you can allow a component access to the following resource for shadow IPC operations.

$aws/things/{iot:thingName}/shadow/

Authorization policy examples

You can reference the following authorization policy examples to help you configure authorization policies for your components.

Example: Allow a group of core devices to interact with local shadows
Important

This example uses a feature that is available for v2.6.0 and later of the Greengrass nucleus component. Greengrass nucleus v2.6.0 adds support for most recipe variables, such as {iot:thingName}, in component configurations. To enable this feature, set the Greengrass nucleus' interpolateComponentConfiguration configuration option to true. For an example that works for all versions of the Greengrass nucleus, see the example authorization policy for a single core device.

The following example authorization policy allows the component com.example.MyShadowInteractionComponent to interact with the classic device shadow and the named shadow myNamedShadow for the core device that runs the component. This policy also allows this component to receive messages on local topics for these shadows.

JSON
{ "accessControl": { "aws.greengrass.ShadowManager": { "com.example.MyShadowInteractionComponent:shadow:1": { "policyDescription": "Allows access to shadows", "operations": [ "aws.greengrass#GetThingShadow", "aws.greengrass#UpdateThingShadow", "aws.greengrass#DeleteThingShadow" ], "resources": [ "$aws/things/{iot:thingName}/shadow", "$aws/things/{iot:thingName}/shadow/name/myNamedShadow" ] }, "com.example.MyShadowInteractionComponent:shadow:2": { "policyDescription": "Allows access to things with shadows", "operations": [ "aws.greengrass#ListNamedShadowsForThing" ], "resources": [ "{iot:thingName}" ] } }, "aws.greengrass.ipc.pubsub": { "com.example.MyShadowInteractionComponent:pubsub:1": { "policyDescription": "Allows access to shadow pubsub topics", "operations": [ "aws.greengrass#SubscribeToTopic" ], "resources": [ "$aws/things/{iot:thingName}/shadow/get/accepted", "$aws/things/{iot:thingName}/shadow/name/myNamedShadow/get/accepted" ] } } } }
YAML
accessControl: aws.greengrass.ShadowManager: 'com.example.MyShadowInteractionComponent:shadow:1': policyDescription: 'Allows access to shadows' operations: - 'aws.greengrass#GetThingShadow' - 'aws.greengrass#UpdateThingShadow' - 'aws.greengrass#DeleteThingShadow' resources: - $aws/things/{iot:thingName}/shadow - $aws/things/{iot:thingName}/shadow/name/myNamedShadow 'com.example.MyShadowInteractionComponent:shadow:2': policyDescription: 'Allows access to things with shadows' operations: - 'aws.greengrass#ListNamedShadowsForThing' resources: - '{iot:thingName}' aws.greengrass.ipc.pubsub: 'com.example.MyShadowInteractionComponent:pubsub:1': policyDescription: 'Allows access to shadow pubsub topics' operations: - 'aws.greengrass#SubscribeToTopic' resources: - $aws/things/{iot:thingName}/shadow/get/accepted - $aws/things/{iot:thingName}/shadow/name/myNamedShadow/get/accepted
Example: Allow a group of core devices to interact with client device shadows
Important

This feature requires Greengrass nucleus v2.6.0 or later, shadow manager v2.2.0 or later, and MQTT bridge v2.2.0 or later. You must configure MQTT bridge to enable shadow manager to communicate with client devices.

The following example authorization policy allows the component com.example.MyShadowInteractionComponent to interact with all device shadows for client devices whose names start with MyClientDevice.

Note

To enable a core device to interact with client device shadows, you must also configure and deploy the MQTT bridge component. For more information, see Enable shadow manager to communicate with client devices.

JSON
{ "accessControl": { "aws.greengrass.ShadowManager": { "com.example.MyShadowInteractionComponent:shadow:1": { "policyDescription": "Allows access to shadows", "operations": [ "aws.greengrass#GetThingShadow", "aws.greengrass#UpdateThingShadow", "aws.greengrass#DeleteThingShadow" ], "resources": [ "$aws/things/MyClientDevice*/shadow", "$aws/things/MyClientDevice*/shadow/name/*" ] }, "com.example.MyShadowInteractionComponent:shadow:2": { "policyDescription": "Allows access to things with shadows", "operations": [ "aws.greengrass#ListNamedShadowsForThing" ], "resources": [ "MyClientDevice*" ] } } } }
YAML
accessControl: aws.greengrass.ShadowManager: 'com.example.MyShadowInteractionComponent:shadow:1': policyDescription: 'Allows access to shadows' operations: - 'aws.greengrass#GetThingShadow' - 'aws.greengrass#UpdateThingShadow' - 'aws.greengrass#DeleteThingShadow' resources: - $aws/things/MyClientDevice*/shadow - $aws/things/MyClientDevice*/shadow/name/* 'com.example.MyShadowInteractionComponent:shadow:2': policyDescription: 'Allows access to things with shadows' operations: - 'aws.greengrass#ListNamedShadowsForThing' resources: - MyClientDevice*
Example: Allow a single core device to interact with local shadows

The following example authorization policy allows the component com.example.MyShadowInteractionComponent to interact with the classic device shadow and the named shadow myNamedShadow for the device MyThingName. This policy also allows this component to receive messages on local topics for these shadows.

JSON
{ "accessControl": { "aws.greengrass.ShadowManager": { "com.example.MyShadowInteractionComponent:shadow:1": { "policyDescription": "Allows access to shadows", "operations": [ "aws.greengrass#GetThingShadow", "aws.greengrass#UpdateThingShadow", "aws.greengrass#DeleteThingShadow" ], "resources": [ "$aws/things/MyThingName/shadow", "$aws/things/MyThingName/shadow/name/myNamedShadow" ] }, "com.example.MyShadowInteractionComponent:shadow:2": { "policyDescription": "Allows access to things with shadows", "operations": [ "aws.greengrass#ListNamedShadowsForThing" ], "resources": [ "MyThingName" ] } }, "aws.greengrass.ipc.pubsub": { "com.example.MyShadowInteractionComponent:pubsub:1": { "policyDescription": "Allows access to shadow pubsub topics", "operations": [ "aws.greengrass#SubscribeToTopic" ], "resources": [ "$aws/things/MyThingName/shadow/get/accepted", "$aws/things/MyThingName/shadow/name/myNamedShadow/get/accepted" ] } } } }
YAML
accessControl: aws.greengrass.ShadowManager: 'com.example.MyShadowInteractionComponent:shadow:1': policyDescription: 'Allows access to shadows' operations: - 'aws.greengrass#GetThingShadow' - 'aws.greengrass#UpdateThingShadow' - 'aws.greengrass#DeleteThingShadow' resources: - $aws/things/MyThingName/shadow - $aws/things/MyThingName/shadow/name/myNamedShadow 'com.example.MyShadowInteractionComponent:shadow:2': policyDescription: 'Allows access to things with shadows' operations: - 'aws.greengrass#ListNamedShadowsForThing' resources: - MyThingName aws.greengrass.ipc.pubsub: 'com.example.MyShadowInteractionComponent:pubsub:1': policyDescription: 'Allows access to shadow pubsub topics' operations: - 'aws.greengrass#SubscribeToTopic' resources: - $aws/things/MyThingName/shadow/get/accepted - $aws/things/MyThingName/shadow/name/myNamedShadow/get/accepted
Example: Allow a group of core devices to react to local shadow state changes
Important

This example uses a feature that is available for v2.6.0 and later of the Greengrass nucleus component. Greengrass nucleus v2.6.0 adds support for most recipe variables, such as {iot:thingName}, in component configurations. To enable this feature, set the Greengrass nucleus' interpolateComponentConfiguration configuration option to true. For an example that works for all versions of the Greengrass nucleus, see the example authorization policy for a single core device.

The following example access control policy allows the custom com.example.MyShadowReactiveComponent to receive messages on the /update/delta topic for the classic device shadow and the named shadow myNamedShadow on each core device that runs the component.

JSON
{ "accessControl": { "aws.greengrass.ipc.pubsub": { "com.example.MyShadowReactiveComponent:pubsub:1": { "policyDescription": "Allows access to shadow pubsub topics", "operations": [ "aws.greengrass#SubscribeToTopic" ], "resources": [ "$aws/things/{iot:thingName}/shadow/update/delta", "$aws/things/{iot:thingName}/shadow/name/myNamedShadow/update/delta" ] } } } }
YAML
accessControl: aws.greengrass.ipc.pubsub: "com.example.MyShadowReactiveComponent:pubsub:1": policyDescription: Allows access to shadow pubsub topics operations: - 'aws.greengrass#SubscribeToTopic' resources: - $aws/things/{iot:thingName}/shadow/update/delta - $aws/things/{iot:thingName}/shadow/name/myNamedShadow/update/delta
Example: Allow a single core device to react to local shadow state changes

The following example access control policy allows the custom com.example.MyShadowReactiveComponent to receive messages on the /update/delta topic for the classic device shadow and the named shadow myNamedShadow for the device MyThingName.

JSON
{ "accessControl": { "aws.greengrass.ipc.pubsub": { "com.example.MyShadowReactiveComponent:pubsub:1": { "policyDescription": "Allows access to shadow pubsub topics", "operations": [ "aws.greengrass#SubscribeToTopic" ], "resources": [ "$aws/things/MyThingName/shadow/update/delta", "$aws/things/MyThingName/shadow/name/myNamedShadow/update/delta" ] } } } }
YAML
accessControl: aws.greengrass.ipc.pubsub: "com.example.MyShadowReactiveComponent:pubsub:1": policyDescription: Allows access to shadow pubsub topics operations: - 'aws.greengrass#SubscribeToTopic' resources: - $aws/things/MyThingName/shadow/update/delta - $aws/things/MyThingName/shadow/name/myNamedShadow/update/delta

GetThingShadow

Get the shadow for a specified thing.

Request

This operation's request has the following parameters:

thingName (Python: thing_name)

The name of the thing.

Type: string

shadowName (Python: shadow_name)

The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string ("").

Warning

The Amazon IoT Greengrass service uses the AWSManagedGreengrassV2Deployment named shadow to manage deployments that target individual core devices. This named shadow is reserved for use by the Amazon IoT Greengrass service. Do not update or delete this named shadow.

Type: string

Response

This operation's response has the following information:

payload

The response state document as a blob.

Type: object that contains the following information:

state

The state information.

This object contains the following information.

desired

The state properties and values requested to be updated in the device.

Type: map of key-value pairs

reported

The state properties and values reported by the device.

Type: map of key-value pairs

delta

The difference between the desired and reported state properties and values. This property is present only if the desired and reported states are different.

Type: map of key-value pairs

metadata

The timestamps for each attribute in the desired and reported sections so that you can determine when the state was updated.

Type: string

timestamp

The epoch date and time that the response was generated.

Type: integer

clientToken (Python: clientToken)

The token that is used to match the request and corresponding response

Type: string

version

The version of the local shadow document.

Type: integer

Errors

This operation can return the following errors.

InvalidArgumentsError

The local shadow service is unable to validate the request parameters. This can occur if the request contains malformed JSON or unsupported characters.

ResourceNotFoundError

The requested local shadow document can't be found.

ServiceError

An internal service error occurred, or the number of requests to the IPC service exceeded the limits specified in the maxLocalRequestsPerSecondPerThing and maxTotalLocalRequestsRate configuration parameters in the shadow manager component.

UnauthorizedError

The component's authorization policy doesn't include required permissions for this operation.

Examples

The following examples demonstrate how to call this operation in custom component code.

Java (IPC client V1)
Example: Get a thing shadow
Note

This example uses an IPCUtils class to create a connection to the Amazon IoT Greengrass Core IPC service. For more information, see Connect to the Amazon IoT Greengrass Core IPC service.

package com.aws.greengrass.docs.samples.ipc; import com.aws.greengrass.docs.samples.ipc.util.IPCUtils; import software.amazon.awssdk.aws.greengrass.GetThingShadowResponseHandler; import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient; import software.amazon.awssdk.aws.greengrass.model.GetThingShadowRequest; import software.amazon.awssdk.aws.greengrass.model.GetThingShadowResponse; import software.amazon.awssdk.aws.greengrass.model.ResourceNotFoundError; import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError; import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection; import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class GetThingShadow { public static final int TIMEOUT_SECONDS = 10; public static void main(String[] args) { // Use the current core device's name if thing name isn't set. String thingName = args[0].isEmpty() ? System.getenv("AWS_IOT_THING_NAME") : args[0]; String shadowName = args[1]; try (EventStreamRPCConnection eventStreamRPCConnection = IPCUtils.getEventStreamRpcConnection()) { GreengrassCoreIPCClient ipcClient = new GreengrassCoreIPCClient(eventStreamRPCConnection); GetThingShadowResponseHandler responseHandler = GetThingShadow.getThingShadow(ipcClient, thingName, shadowName); CompletableFuture<GetThingShadowResponse> futureResponse = responseHandler.getResponse(); try { GetThingShadowResponse response = futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); String shadowPayload = new String(response.getPayload(), StandardCharsets.UTF_8); System.out.printf("Successfully got shadow %s/%s: %s%n", thingName, shadowName, shadowPayload); } catch (TimeoutException e) { System.err.printf("Timeout occurred while getting shadow: %s/%s%n", thingName, shadowName); } catch (ExecutionException e) { if (e.getCause() instanceof UnauthorizedError) { System.err.printf("Unauthorized error while getting shadow: %s/%s%n", thingName, shadowName); } else if (e.getCause() instanceof ResourceNotFoundError) { System.err.printf("Unable to find shadow to get: %s/%s%n", thingName, shadowName); } else { throw e; } } } catch (InterruptedException e) { System.out.println("IPC interrupted."); } catch (ExecutionException e) { System.err.println("Exception occurred when using IPC."); e.printStackTrace(); System.exit(1); } } public static GetThingShadowResponseHandler getThingShadow(GreengrassCoreIPCClient greengrassCoreIPCClient, String thingName, String shadowName) { GetThingShadowRequest getThingShadowRequest = new GetThingShadowRequest(); getThingShadowRequest.setThingName(thingName); getThingShadowRequest.setShadowName(shadowName); return greengrassCoreIPCClient.getThingShadow(getThingShadowRequest, Optional.empty()); } }
Python (IPC client V1)
Example: Get a thing shadow
import awsiot.greengrasscoreipc import awsiot.greengrasscoreipc.client as client from awsiot.greengrasscoreipc.model import GetThingShadowRequest TIMEOUT = 10 def sample_get_thing_shadow_request(thingName, shadowName): try: # set up IPC client to connect to the IPC server ipc_client = awsiot.greengrasscoreipc.connect() # create the GetThingShadow request get_thing_shadow_request = GetThingShadowRequest() get_thing_shadow_request.thing_name = thingName get_thing_shadow_request.shadow_name = shadowName # retrieve the GetThingShadow response after sending the request to the IPC server op = ipc_client.new_get_thing_shadow() op.activate(get_thing_shadow_request) fut = op.get_response() result = fut.result(TIMEOUT) return result.payload except InvalidArgumentsError as e: # add error handling ... # except ResourceNotFoundError | UnauthorizedError | ServiceError
JavaScript
Example: Get a thing shadow
import { GetThingShadowRequest } from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model'; import * as greengrasscoreipc from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc'; class GetThingShadow { private ipcClient: greengrasscoreipc.Client; private thingName: string; private shadowName: string; constructor() { // Define args parameters here this.thingName = "<define_your_own_thingName>"; this.shadowName = "<define_your_own_shadowName>"; this.bootstrap(); } async bootstrap() { try { this.ipcClient = await getIpcClient(); } catch (err) { // parse the error depending on your use cases throw err } try { await this.handleGetThingShadowOperation(this.thingName, this.shadowName); } catch (err) { // parse the error depending on your use cases throw err } } async handleGetThingShadowOperation( thingName: string, shadowName: string ) { const request: GetThingShadowRequest = { thingName: thingName, shadowName: shadowName }; const response = await this.ipcClient.getThingShadow(request); } } export async function getIpcClient() { try { const ipcClient = greengrasscoreipc.createClient(); await ipcClient.connect() .catch(error => { // parse the error depending on your use cases throw error; }); return ipcClient } catch (err) { // parse the error depending on your use caseså throw err } } const startScript = new GetThingShadow();

UpdateThingShadow

Update the shadow for the specified thing. If a shadow doesn't exist, one is created.

Request

This operation's request has the following parameters:

thingName (Python: thing_name)

The name of the thing.

Type: string

shadowName (Python: shadow_name)

The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string ("").

Warning

The Amazon IoT Greengrass service uses the AWSManagedGreengrassV2Deployment named shadow to manage deployments that target individual core devices. This named shadow is reserved for use by the Amazon IoT Greengrass service. Do not update or delete this named shadow.

Type: string

payload

The request state document as a blob.

Type: object that contains the following information:

state

The state information to update. This IPC operation affects only the specified fields.

This object contains the following information. Typically, you'll use either the desired property or the reported property, but not both in the same request.

desired

The state properties and values requested to be updated in the device.

Type: map of key-value pairs

reported

The state properties and values reported by the device.

Type: map of key-value pairs

clientToken (Python: client_token)

(Optional) The token that is used to match the request and corresponding response by the client token.

Type: string

version

(Optional) The version of the local shadow document to update. The shadow service processes the update only if the specified version matches the latest version that it has.

Type: integer

Response

This operation's response has the following information:

payload

The response state document as a blob.

Type: object that contains the following information:

state

The state information.

This object contains the following information.

desired

The state properties and values requested to be updated in the device.

Type: map of key-value pairs

reported

The state properties and values reported by the device.

Type: map of key-value pairs

delta

The state properties and values reported by the device.

Type: map of key-value pairs

metadata

The timestamps for each attribute in the desired and reported sections so that you can determine when the state was updated.

Type: string

timestamp

The epoch date and time that the response was generated.

Type: integer

clientToken (Python: client_token)

The token that is used to match the request and corresponding response.

Type: string

version

The version of local shadow document after the update is complete.

Type: integer

Errors

This operation can return the following errors.

ConflictError

The local shadow service encountered a version conflict during the update operation. This occurs when the version in the request payload doesn't match the version in the latest available local shadow document.

InvalidArgumentsError

The local shadow service is unable to validate the request parameters. This can occur if the request contains malformed JSON or unsupported characters.

A valid payload has the following properties:

  • The state node exists, and is an object that contains the desired or reported state information.

  • The desired and reported nodes are either objects or null. At least one of these objects must contain valid state information.

  • The depth of the desired and reported objects can't exceed eight nodes.

  • The length of the clientToken value can't exceed 64 characters.

  • The version value must be 1 or higher.

ServiceError

An internal service error occurred, or the number of requests to the IPC service exceeded the limits specified in the maxLocalRequestsPerSecondPerThing and maxTotalLocalRequestsRate configuration parameters in the shadow manager component.

UnauthorizedError

The component's authorization policy doesn't include required permissions for this operation.

Examples

The following examples demonstrate how to call this operation in custom component code.

Java (IPC client V1)
Example: Update a thing shadow
Note

This example uses an IPCUtils class to create a connection to the Amazon IoT Greengrass Core IPC service. For more information, see Connect to the Amazon IoT Greengrass Core IPC service.

package com.aws.greengrass.docs.samples.ipc; import com.aws.greengrass.docs.samples.ipc.util.IPCUtils; import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient; import software.amazon.awssdk.aws.greengrass.UpdateThingShadowResponseHandler; import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError; import software.amazon.awssdk.aws.greengrass.model.UpdateThingShadowRequest; import software.amazon.awssdk.aws.greengrass.model.UpdateThingShadowResponse; import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection; import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class UpdateThingShadow { public static final int TIMEOUT_SECONDS = 10; public static void main(String[] args) { // Use the current core device's name if thing name isn't set. String thingName = args[0].isEmpty() ? System.getenv("AWS_IOT_THING_NAME") : args[0]; String shadowName = args[1]; byte[] shadowPayload = args[2].getBytes(StandardCharsets.UTF_8); try (EventStreamRPCConnection eventStreamRPCConnection = IPCUtils.getEventStreamRpcConnection()) { GreengrassCoreIPCClient ipcClient = new GreengrassCoreIPCClient(eventStreamRPCConnection); UpdateThingShadowResponseHandler responseHandler = UpdateThingShadow.updateThingShadow(ipcClient, thingName, shadowName, shadowPayload); CompletableFuture<UpdateThingShadowResponse> futureResponse = responseHandler.getResponse(); try { futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); System.out.printf("Successfully updated shadow: %s/%s%n", thingName, shadowName); } catch (TimeoutException e) { System.err.printf("Timeout occurred while updating shadow: %s/%s%n", thingName, shadowName); } catch (ExecutionException e) { if (e.getCause() instanceof UnauthorizedError) { System.err.printf("Unauthorized error while updating shadow: %s/%s%n", thingName, shadowName); } else { throw e; } } } catch (InterruptedException e) { System.out.println("IPC interrupted."); } catch (ExecutionException e) { System.err.println("Exception occurred when using IPC."); e.printStackTrace(); System.exit(1); } } public static UpdateThingShadowResponseHandler updateThingShadow(GreengrassCoreIPCClient greengrassCoreIPCClient, String thingName, String shadowName, byte[] shadowPayload) { UpdateThingShadowRequest updateThingShadowRequest = new UpdateThingShadowRequest(); updateThingShadowRequest.setThingName(thingName); updateThingShadowRequest.setShadowName(shadowName); updateThingShadowRequest.setPayload(shadowPayload); return greengrassCoreIPCClient.updateThingShadow(updateThingShadowRequest, Optional.empty()); } }
Python (IPC client V1)
Example: Update a thing shadow
import awsiot.greengrasscoreipc import awsiot.greengrasscoreipc.client as client from awsiot.greengrasscoreipc.model import UpdateThingShadowRequest TIMEOUT = 10 def sample_update_thing_shadow_request(thingName, shadowName, payload): try: # set up IPC client to connect to the IPC server ipc_client = awsiot.greengrasscoreipc.connect() # create the UpdateThingShadow request update_thing_shadow_request = UpdateThingShadowRequest() update_thing_shadow_request.thing_name = thingName update_thing_shadow_request.shadow_name = shadowName update_thing_shadow_request.payload = payload # retrieve the UpdateThingShadow response after sending the request to the IPC server op = ipc_client.new_update_thing_shadow() op.activate(update_thing_shadow_request) fut = op.get_response() result = fut.result(TIMEOUT) return result.payload except InvalidArgumentsError as e: # add error handling ... # except ConflictError | UnauthorizedError | ServiceError
JavaScript
Example: Update a thing shadow
import { UpdateThingShadowRequest } from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model'; import * as greengrasscoreipc from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc'; class UpdateThingShadow { private ipcClient: greengrasscoreipc.Client; private thingName: string; private shadowName: string; private shadowDocumentStr: string; constructor() { // Define args parameters here this.thingName = "<define_your_own_thingName>"; this.shadowName = "<define_your_own_shadowName>"; this.shadowDocumentStr = "<define_your_own_payload>"; this.bootstrap(); } async bootstrap() { try { this.ipcClient = await getIpcClient(); } catch (err) { // parse the error depending on your use cases throw err } try { await this.handleUpdateThingShadowOperation( this.thingName, this.shadowName, this.shadowDocumentStr); } catch (err) { // parse the error depending on your use cases throw err } } async handleUpdateThingShadowOperation( thingName: string, shadowName: string, payloadStr: string ) { const request: UpdateThingShadowRequest = { thingName: thingName, shadowName: shadowName, payload: payloadStr } // make the UpdateThingShadow request const response = await this.ipcClient.updateThingShadow(request); } } export async function getIpcClient() { try { const ipcClient = greengrasscoreipc.createClient(); await ipcClient.connect() .catch(error => { // parse the error depending on your use cases throw error; }); return ipcClient } catch (err) { // parse the error depending on your use cases throw err } } const startScript = new UpdateThingShadow();

DeleteThingShadow

Deletes the shadow for the specified thing.

Beginning in shadow manager v2.0.4, deleting a shadow increments the version number. For example, when you delete the shadow MyThingShadow at version 1, the version of the deleted shadow is 2. If you then recreate a shadow with the name MyThingShadow, the version for that shadow is 3.

Request

This operation's request has the following parameters:

thingName (Python: thing_name)

The name of the thing.

Type: string

shadowName (Python: shadow_name)

The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string ("").

Warning

The Amazon IoT Greengrass service uses the AWSManagedGreengrassV2Deployment named shadow to manage deployments that target individual core devices. This named shadow is reserved for use by the Amazon IoT Greengrass service. Do not update or delete this named shadow.

Type: string

Response

This operation's response has the following information:

payload

An empty response state document.

Errors

This operation can return the following errors.

InvalidArgumentsError

The local shadow service is unable to validate the request parameters. This can occur if the request contains malformed JSON or unsupported characters.

ResourceNotFoundError

The requested local shadow document can't be found.

ServiceError

An internal service error occurred, or the number of requests to the IPC service exceeded the limits specified in the maxLocalRequestsPerSecondPerThing and maxTotalLocalRequestsRate configuration parameters in the shadow manager component.

UnauthorizedError

The component's authorization policy doesn't include required permissions for this operation.

Examples

The following examples demonstrate how to call this operation in custom component code.

Java (IPC client V1)
Example: Delete a thing shadow
Note

This example uses an IPCUtils class to create a connection to the Amazon IoT Greengrass Core IPC service. For more information, see Connect to the Amazon IoT Greengrass Core IPC service.

package com.aws.greengrass.docs.samples.ipc; import com.aws.greengrass.docs.samples.ipc.util.IPCUtils; import software.amazon.awssdk.aws.greengrass.DeleteThingShadowResponseHandler; import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient; import software.amazon.awssdk.aws.greengrass.model.DeleteThingShadowRequest; import software.amazon.awssdk.aws.greengrass.model.DeleteThingShadowResponse; import software.amazon.awssdk.aws.greengrass.model.ResourceNotFoundError; import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError; import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class DeleteThingShadow { public static final int TIMEOUT_SECONDS = 10; public static void main(String[] args) { // Use the current core device's name if thing name isn't set. String thingName = args[0].isEmpty() ? System.getenv("AWS_IOT_THING_NAME") : args[0]; String shadowName = args[1]; try (EventStreamRPCConnection eventStreamRPCConnection = IPCUtils.getEventStreamRpcConnection()) { GreengrassCoreIPCClient ipcClient = new GreengrassCoreIPCClient(eventStreamRPCConnection); DeleteThingShadowResponseHandler responseHandler = DeleteThingShadow.deleteThingShadow(ipcClient, thingName, shadowName); CompletableFuture<DeleteThingShadowResponse> futureResponse = responseHandler.getResponse(); try { futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); System.out.printf("Successfully deleted shadow: %s/%s%n", thingName, shadowName); } catch (TimeoutException e) { System.err.printf("Timeout occurred while deleting shadow: %s/%s%n", thingName, shadowName); } catch (ExecutionException e) { if (e.getCause() instanceof UnauthorizedError) { System.err.printf("Unauthorized error while deleting shadow: %s/%s%n", thingName, shadowName); } else if (e.getCause() instanceof ResourceNotFoundError) { System.err.printf("Unable to find shadow to delete: %s/%s%n", thingName, shadowName); } else { throw e; } } } catch (InterruptedException e) { System.out.println("IPC interrupted."); } catch (ExecutionException e) { System.err.println("Exception occurred when using IPC."); e.printStackTrace(); System.exit(1); } } public static DeleteThingShadowResponseHandler deleteThingShadow(GreengrassCoreIPCClient greengrassCoreIPCClient, String thingName, String shadowName) { DeleteThingShadowRequest deleteThingShadowRequest = new DeleteThingShadowRequest(); deleteThingShadowRequest.setThingName(thingName); deleteThingShadowRequest.setShadowName(shadowName); return greengrassCoreIPCClient.deleteThingShadow(deleteThingShadowRequest, Optional.empty()); } }
Python (IPC client V1)
Example: Delete a thing shadow
import awsiot.greengrasscoreipc import awsiot.greengrasscoreipc.client as client from awsiot.greengrasscoreipc.model import DeleteThingShadowRequest TIMEOUT = 10 def sample_delete_thing_shadow_request(thingName, shadowName): try: # set up IPC client to connect to the IPC server ipc_client = awsiot.greengrasscoreipc.connect() # create the DeleteThingShadow request delete_thing_shadow_request = DeleteThingShadowRequest() delete_thing_shadow_request.thing_name = thingName delete_thing_shadow_request.shadow_name = shadowName # retrieve the DeleteThingShadow response after sending the request to the IPC server op = ipc_client.new_delete_thing_shadow() op.activate(delete_thing_shadow_request) fut = op.get_response() result = fut.result(TIMEOUT) return result.payload except InvalidArgumentsError as e: # add error handling ... # except ResourceNotFoundError | UnauthorizedError | ServiceError
JavaScript
Example: Delete a thing shadow
import { DeleteThingShadowRequest } from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model'; import * as greengrasscoreipc from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc'; class DeleteThingShadow { private ipcClient: greengrasscoreipc.Client; private thingName: string; private shadowName: string; constructor() { // Define args parameters here this.thingName = "<define_your_own_thingName>"; this.shadowName = "<define_your_own_shadowName>"; this.bootstrap(); } async bootstrap() { try { this.ipcClient = await getIpcClient(); } catch (err) { // parse the error depending on your use cases throw err } try { await this.handleDeleteThingShadowOperation(this.thingName, this.shadowName) } catch (err) { // parse the error depending on your use cases throw err } } async handleDeleteThingShadowOperation(thingName: string, shadowName: string) { const request: DeleteThingShadowRequest = { thingName: thingName, shadowName: shadowName } // make the DeleteThingShadow request const response = await this.ipcClient.deleteThingShadow(request); } } export async function getIpcClient() { try { const ipcClient = greengrasscoreipc.createClient(); await ipcClient.connect() .catch(error => { // parse the error depending on your use cases throw error; }); return ipcClient } catch (err) { // parse the error depending on your use cases throw err } } const startScript = new DeleteThingShadow();

ListNamedShadowsForThing

List the named shadows for the specified thing.

Request

This operation's request has the following parameters:

thingName (Python: thing_name)

The name of the thing.

Type: string

pageSize (Python: page_size)

(Optional) The number of shadow names to return in each call.

Type: integer

Default: 25

Maximum: 100

nextToken (Python: next_token)

(Optional) The token to retrieve the next set of results. This value is returned on paged results and is used in the call that returns the next page.

Type: string

Response

This operation's response has the following information:

results

The list of shadow names.

Type: array

timestamp

(Optional) The date and time that the response was generated.

Type: integer

nextToken (Python: next_token)

(Optional) The token value to use in paged requests to retrieve the next page in the sequence. This token isn't present when there are no more shadow names to return.

Type: string

Note

If the requested page size exactly matches the number of shadow names in the response, then this token is present; however, when used, it returns an empty list.

Errors

This operation can return the following errors.

InvalidArgumentsError

The local shadow service is unable to validate the request parameters. This can occur if the request contains malformed JSON or unsupported characters.

ResourceNotFoundError

The requested local shadow document can't be found.

ServiceError

An internal service error occurred, or the number of requests to the IPC service exceeded the limits specified in the maxLocalRequestsPerSecondPerThing and maxTotalLocalRequestsRate configuration parameters in the shadow manager component.

UnauthorizedError

The component's authorization policy doesn't include required permissions for this operation.

Examples

The following examples demonstrate how to call this operation in custom component code.

Java (IPC client V1)
Example: List a thing's named shadows
Note

This example uses an IPCUtils class to create a connection to the Amazon IoT Greengrass Core IPC service. For more information, see Connect to the Amazon IoT Greengrass Core IPC service.

package com.aws.greengrass.docs.samples.ipc; import com.aws.greengrass.docs.samples.ipc.util.IPCUtils; import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient; import software.amazon.awssdk.aws.greengrass.ListNamedShadowsForThingResponseHandler; import software.amazon.awssdk.aws.greengrass.model.ListNamedShadowsForThingRequest; import software.amazon.awssdk.aws.greengrass.model.ListNamedShadowsForThingResponse; import software.amazon.awssdk.aws.greengrass.model.ResourceNotFoundError; import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError; import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class ListNamedShadowsForThing { public static final int TIMEOUT_SECONDS = 10; public static void main(String[] args) { // Use the current core device's name if thing name isn't set. String thingName = args[0].isEmpty() ? System.getenv("AWS_IOT_THING_NAME") : args[0]; try (EventStreamRPCConnection eventStreamRPCConnection = IPCUtils.getEventStreamRpcConnection()) { GreengrassCoreIPCClient ipcClient = new GreengrassCoreIPCClient(eventStreamRPCConnection); List<String> namedShadows = new ArrayList<>(); String nextToken = null; try { // Send additional requests until there's no pagination token in the response. do { ListNamedShadowsForThingResponseHandler responseHandler = ListNamedShadowsForThing.listNamedShadowsForThing(ipcClient, thingName, nextToken, 25); CompletableFuture<ListNamedShadowsForThingResponse> futureResponse = responseHandler.getResponse(); ListNamedShadowsForThingResponse response = futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); List<String> responseNamedShadows = response.getResults(); namedShadows.addAll(responseNamedShadows); nextToken = response.getNextToken(); } while (nextToken != null); System.out.printf("Successfully got named shadows for thing %s: %s%n", thingName, String.join(",", namedShadows)); } catch (TimeoutException e) { System.err.println("Timeout occurred while listing named shadows for thing: " + thingName); } catch (ExecutionException e) { if (e.getCause() instanceof UnauthorizedError) { System.err.println("Unauthorized error while listing named shadows for " + "thing: " + thingName); } else if (e.getCause() instanceof ResourceNotFoundError) { System.err.println("Unable to find thing to list named shadows: " + thingName); } else { throw e; } } } catch (InterruptedException e) { System.out.println("IPC interrupted."); } catch (ExecutionException e) { System.err.println("Exception occurred when using IPC."); e.printStackTrace(); System.exit(1); } } public static ListNamedShadowsForThingResponseHandler listNamedShadowsForThing(GreengrassCoreIPCClient greengrassCoreIPCClient, String thingName, String nextToken, int pageSize) { ListNamedShadowsForThingRequest listNamedShadowsForThingRequest = new ListNamedShadowsForThingRequest(); listNamedShadowsForThingRequest.setThingName(thingName); listNamedShadowsForThingRequest.setNextToken(nextToken); listNamedShadowsForThingRequest.setPageSize(pageSize); return greengrassCoreIPCClient.listNamedShadowsForThing(listNamedShadowsForThingRequest, Optional.empty()); } }
Python (IPC client V1)
Example: List a thing's named shadows
import awsiot.greengrasscoreipc import awsiot.greengrasscoreipc.client as client from awsiot.greengrasscoreipc.model import ListNamedShadowsForThingRequest TIMEOUT = 10 def sample_list_named_shadows_for_thing_request(thingName, nextToken, pageSize): try: # set up IPC client to connect to the IPC server ipc_client = awsiot.greengrasscoreipc.connect() # create the ListNamedShadowsForThingRequest request list_named_shadows_for_thing_request = ListNamedShadowsForThingRequest() list_named_shadows_for_thing_request.thing_name = thingName list_named_shadows_for_thing_request.next_token = nextToken list_named_shadows_for_thing_request.page_size = pageSize # retrieve the ListNamedShadowsForThingRequest response after sending the request to the IPC server op = ipc_client.new_list_named_shadows_for_thing() op.activate(list_named_shadows_for_thing_request) fut = op.get_response() list_result = fut.result(TIMEOUT) # additional returned fields timestamp = list_result.timestamp next_token = result.next_token named_shadow_list = list_result.results return named_shadow_list, next_token, timestamp except InvalidArgumentsError as e: # add error handling ... # except ResourceNotFoundError | UnauthorizedError | ServiceError
JavaScript
Example: List a thing's named shadows
import { ListNamedShadowsForThingRequest } from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model'; import * as greengrasscoreipc from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc'; class listNamedShadowsForThing { private ipcClient: greengrasscoreipc.Client; private thingName: string; private pageSizeStr: string; private nextToken: string; constructor() { // Define args parameters here this.thingName = "<define_your_own_thingName>"; this.pageSizeStr = "<define_your_own_pageSize>"; this.nextToken = "<define_your_own_token>"; this.bootstrap(); } async bootstrap() { try { this.ipcClient = await getIpcClient(); } catch (err) { // parse the error depending on your use cases throw err } try { await this.handleListNamedShadowsForThingOperation(this.thingName, this.nextToken, this.pageSizeStr); } catch (err) { // parse the error depending on your use cases throw err } } async handleListNamedShadowsForThingOperation( thingName: string, nextToken: string, pageSizeStr: string ) { let request: ListNamedShadowsForThingRequest = { thingName: thingName, nextToken: nextToken, }; if (pageSizeStr) { request.pageSize = parseInt(pageSizeStr); } // make the ListNamedShadowsForThing request const response = await this.ipcClient.listNamedShadowsForThing(request); const shadowNames = response.results; } } export async function getIpcClient(){ try { const ipcClient = greengrasscoreipc.createClient(); await ipcClient.connect() .catch(error => { // parse the error depending on your use cases throw error; }); return ipcClient } catch (err) { // parse the error depending on your use cases throw err } } const startScript = new listNamedShadowsForThing();