Design for Named Shadow support in Shadow Library
Introduction
The AWS Shadow service supports multiple Shadow documents for an IoT Thing using a feature called Named Shadows. More
details about this addition can be found in the
AWS release announcement and in the
AWS Shadow Service documentation. Support for Named Shadows is not present
in the Device Shadow library up to the
v1.0.2 release. This document describes the design of the Named Shadow support in the
Device Shadow library.
Design
The design for the Named Shadow is an extension of the design for the Classic Shadow for an IoT Thing. The
existing version of the Device Shadow library, helps in building and matching the Classic
Shadow MQTT topics used for interacting with the AWS Shadow service. Refer to the
design and design diagram of the Shadow library in AWS docs. The design
for Named Shadows is an extension of the same design. The topics used by Classic Shadows and Named Shadows differ only in
the topic prefix. This table shows the topic prefix used by each shadow type.
|
ShadowTopicPrefix |
Shadow type |
1 |
$aws/things/thingName/shadow |
Unnamed (classic) shadow |
2 |
$aws/things/thingName/shadow/name/shadowName |
Named shadow |
To provide support for Named Shadow MQTT topics, additional APIs and helper MACROs are introduced. Compared to the
already existing APIs, these APIs and MACROs take additional parameters for the shadow name and length. The new APIs and
MACROs are discussed in the sections below.
APIs
Two new APIs are added for providing the support for Named Shadows.
-
An API to assemble MQTT topic strings for a Shadow - Shadow_AssembleTopicString(). This API will
work for both Classic Shadow and Named Shadow. Apps that do not know the Thing Name and Shadow names at compile
time can use this function to assemble the topic string at run time.
ShadowStatus_t Shadow_AssembleTopicString( ShadowTopicStringType_t topicType,
const char * pThingName,
uint8_t thingNameLength,
const char * pShadowName,
uint8_t shadowNameLength,
char * pTopicBuffer,
uint16_t bufferSize,
uint16_t * pOutLength );
-
An API to check if an MQTT topic is a Shadow topic- Shadow_MatchTopicString(). This API will
work for both Classic Shadow and Named Shadow.
ShadowStatus_t Shadow_MatchTopicString( const char * pTopic,
uint16_t topicLength,
ShadowMessageType_t * pMessageType,
const char ** pThingName,
uint8_t * pThingNameLength,
const char ** pShadowName,
uint8_t * pShadowNameLength );
Backward compatibility
Backward compatibility will be provided to the already existing Device Shadow APIs, which will only support Classic
Shadow.
#define Shadow_GetTopicString( topicType, pThingName, thingNameLength, pTopicBuffer, bufferSize, pOutLength ) \
Shadow_AssembleTopicString( topicType, pThingName, thingNameLength, SHADOW_NAME_CLASSIC, 0, \
pTopicBuffer, bufferSize, pOutLength )
ShadowStatus_t Shadow_MatchTopic( const char * pTopic,
uint16_t topicLength,
ShadowMessageType_t * pMessageType,
const char ** pThingName,
uint16_t * pThingNameLength )
{
uint8_t thingNameLength = 0U;
ShadowStatus_t shadowStatus = Shadow_MatchTopicString( pTopic,
topicLength,
pMessageType,
pThingName,
&thingNameLength,
NULL,
NULL );
if( pThingNameLength != NULL )
{
*pThingNameLength = thingNameLength;
}
return shadowStatus;
}
MACROs
A new set of function-like MACROS provide the support for Named Shadows. There is a matching new function-like
macro for each old function-like macro:
Old |
New |
SHADOW_TOPIC_STRING |
SHADOW_TOPIC_STR |
SHADOW_TOPIC_LENGTH |
SHADOW_TOPIC_LEN |
SHADOW_TOPIC_LENGTH_MAX |
SHADOW_TOPIC_LEN_MAX |
SHADOW_TOPIC_STRING_UPDATE |
SHADOW_TOPIC_STR_UPDATE |
SHADOW_TOPIC_LENGTH_UPDATE |
SHADOW_TOPIC_LEN_UPDATE |
SHADOW_TOPIC_STRING_UPDATE_ACCEPTED |
SHADOW_TOPIC_STR_UPDATE_ACC |
SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED |
SHADOW_TOPIC_LEN_UPDATE_ACC |
SHADOW_TOPIC_STRING_UPDATE_REJECTED |
SHADOW_TOPIC_STR_UPDATE_REJ |
SHADOW_TOPIC_LENGTH_UPDATE_REJECTED |
SHADOW_TOPIC_LEN_UPDATE_REJ |
SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS |
SHADOW_TOPIC_STR_UPDATE_DOCS |
SHADOW_TOPIC_LENGTH_UPDATE_DOCUMENTS |
SHADOW_TOPIC_LEN_UPDATE_DOCS |
SHADOW_TOPIC_STRING_UPDATE_DELTA |
SHADOW_TOPIC_STR_UPDATE_DELTA |
SHADOW_TOPIC_LENGTH_UPDATE_DELTA |
SHADOW_TOPIC_LEN_UPDATE_DELTA |
SHADOW_TOPIC_STRING_GET |
SHADOW_TOPIC_STR_GET |
SHADOW_TOPIC_LENGTH_GET |
SHADOW_TOPIC_LEN_GET |
SHADOW_TOPIC_STRING_GET_ACCEPTED |
SHADOW_TOPIC_STR_GET_ACC |
SHADOW_TOPIC_LENGTH_GET_ACCEPTED |
SHADOW_TOPIC_LEN_GET_ACC |
SHADOW_TOPIC_STRING_GET_REJECTED |
SHADOW_TOPIC_STR_GET_REJ |
SHADOW_TOPIC_LENGTH_GET_REJECTED |
SHADOW_TOPIC_LEN_GET_REJ |
SHADOW_TOPIC_STRING_DELETE |
SHADOW_TOPIC_STR_DELETE |
SHADOW_TOPIC_LENGTH_DELETE |
SHADOW_TOPIC_LEN_DELETE |
SHADOW_TOPIC_STRING_DELETE_ACCEPTED |
SHADOW_TOPIC_STR_DELETE_ACC |
SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED |
SHADOW_TOPIC_LEN_DELETE_ACC |
SHADOW_TOPIC_STRING_DELETE_REJECTED |
SHADOW_TOPIC_STR_DELETE_REJ |
SHADOW_TOPIC_LENGTH_DELETE_REJECTED |
SHADOW_TOPIC_LEN_DELETE_REJ |
The new macro names respect MISRA 5.1. We ensure that every macro is, conservatively, 31 characters or fewer.
The new macros accept a shadowName or shadowNameLength parameter. They can be used for both Named and Classic shadows.
Here is an example using a new macro:
#define SHADOW_TOPIC_STR_UPDATE_ACC( thingName, shadowName ) \
SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_ACCEPTED )
All old macros are retained for backwards compatibility. Here is an example:
#define SHADOW_ASSEMBLE_TOPIC_STRING ( operation, thingName, shadowName ) \
( ( sizeof( shadowName ) > 1 ) ? \
( SHADOW_PREFIX thingName SHADOW_NAMED_ROOT shadowName operation ) : \
( SHADOW_PREFIX thingName SHADOW_CLASSIC_ROOT operation ) )
#define SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( thingName ) \
SHADOW_TOPIC_STR_UPDATE_ACC( thingName, SHADOW_NAME_CLASSIC )
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.