diff --git a/awsiot/iotshadow.py b/awsiot/iotshadow.py index eddc8bd0..f3366c6f 100644 --- a/awsiot/iotshadow.py +++ b/awsiot/iotshadow.py @@ -1277,9 +1277,11 @@ def from_payload(cls, payload): val = payload.get('desired') if val is not None: new.desired = val + val = payload.get('reported') if val is not None: new.reported = val + return new class ShadowState(awsiot.ModeledClass): @@ -1329,6 +1331,47 @@ def to_payload(self): payload['reported'] = self.reported return payload +class ShadowClearState(awsiot.ModeledClass): + """ + + (Potentially partial) clear state of an AWS IoT thing's shadow. + + Used to clear all of the desired and/or reported state properties of an AWS IoT thing's shadow. + All attributes are None by default and may be set by keyword in the constructor. + + Keyword Args: + clear_desired (bool): Whether to clear the desired shadow state (defaults to false) + clear_reported (bool): Whether to clear the reported shadow state (defaults to false) + + Attributes: + clear_desired (bool): Whether to clear the desired shadow state (defaults to false) + clear_reported (bool): Whether to clear the reported shadow state (defaults to false) + """ + + __slots__ = ['clear_desired', 'clear_reported'] + + def __init__(self, *args, **kwargs): + self.clear_desired = kwargs.get('clear_desired') + self.clear_reported = kwargs.get('clear_reported') + + @classmethod + def from_payload(cls, payload): + # type: (typing.Dict[str, typing.Any]) -> ShadowState + new = cls() + # nothing to do here - shouldn't occur + return new + + def to_payload(self): + # type: () -> typing.Dict[str, typing.Any] + payload = {} # type: typing.Dict[str, typing.Any] + if self.clear_desired is not None: + if self.clear_desired == True: + payload['desired'] = None + if self.clear_reported is not None: + if self.clear_reported == True: + payload['reported'] = None + return payload + class ShadowStateWithDelta(awsiot.ModeledClass): """ diff --git a/samples/shadow.py b/samples/shadow.py index 61d06825..dd16da07 100644 --- a/samples/shadow.py +++ b/samples/shadow.py @@ -192,7 +192,10 @@ def on_update_shadow_accepted(response): return try: - print("Finished updating reported shadow value to '{}'.".format(response.state.reported[shadow_property])) # type: ignore + if (response.state.reported != None): + print("Finished updating reported shadow value to '{}'.".format(response.state.reported[shadow_property])) # type: ignore + else: + print ("Shadow states cleared.") print("Enter desired value: ") # remind user they can input new values except: exit("Updated shadow is missing the target property.") @@ -238,14 +241,31 @@ def change_shadow_value(value): # any "response" messages received on the /accepted and /rejected topics token = str(uuid4()) - request = iotshadow.UpdateShadowRequest( - thing_name=thing_name, - state=iotshadow.ShadowState( - reported={ shadow_property: value }, - desired={ shadow_property: value }, - ), - client_token=token, - ) + # if the value is "clear_shadow" then send a ShadowClearState to clear the shadow state document + if (value == "clear_shadow"): + request = iotshadow.UpdateShadowRequest( + thing_name=thing_name, + state=iotshadow.ShadowClearState( + clear_reported=True, + clear_desired=True + ), + client_token=token, + ) + # otherwise, send a ShadowState to update the shadow state document + else: + # if the user types none, then clear the property by setting the value to a None type + if (value == "none"): + value = None + + request = iotshadow.UpdateShadowRequest( + thing_name=thing_name, + state=iotshadow.ShadowState( + reported={ shadow_property: value}, + desired={ shadow_property: value}, + ), + client_token=token, + ) + future = shadow_client.publish_update_shadow(request, mqtt.QoS.AT_LEAST_ONCE) locked_data.request_tokens.add(token)