AWS IoT Shadow - How to handle or reject invalid "desired" states? - amazon-web-services

AWS IoT Shadow has support for dealing with invalid states. From my understanding of the AWS documentation, when a message is published to /update and it is considered invalid (e.g. because it is invalid json), an error message is published to /update/rejected per specification here https://docs.aws.amazon.com/iot/latest/developerguide/device-shadow-error-messages.html
This is clear, but it only concerns generic state update failures.
Question:
What if an AWS IoT shadow state update is valid from the point of view of the AWS IoT Shadow service, but it is not a valid desired state from the point of view of the device?
For example, say a device supports "state": {"desired": {"color": "red"}} and "state": {"desired": {"color": "green"}}.
What is then a good way or best-practice to deal with a request for "state": {"desired": {"color": "black"}} if the device does not support black?
Can this be communicated over any of the default shadow topics?
Note: I found a similar (unanswered) question here: https://forums.aws.amazon.com/thread.jspa?threadID=300362

I recently had a similar problem and found this post on the AWS forum:
https://repost.aws/questions/QUx_YtxvdmTFODhuuNd4D_Yw/how-to-deal-with-shadow-updates-initated-by-device-not-and-server
Basically, the client can clear the "desired" section of the device shadow document to show that it has rejected the changes. This will prevent any more "delta" messages for that particular change. You can clear the device shadow "desired" section by posting a message to /update with null, as follows:
Clear entire desired section:
{
"state" : {
"desired" : null
}
}
Clear an individual field:
{
"state" : {
"desired" : {
"MyField" : null
}
}
}
However, this will not inform the other end (cloud, mobile app, etc) that the "desired" state they requested was invalid.
To do that, you might be able to post your own message to /update/rejected, although I haven't tried this.

Related

Difference between AWS IoT shadow file desired and reported fields

I'm looking at the AWS IoT documentation for shadow states and trying to better understand the use of desired and reported in the shadow file.
The documentation states:
When the shadow's state changes, AWS IoT sends /delta messages to all MQTT subscribers with the difference between the desired and the reported states.
After looking through the rest of the documentation I don't feel like I have a clear grasp of the use case for desired vs reported. Can someone explain the use case? When do we use one vs. the other?
Let's start from the beginning, a device shadow is a persistent virtual shadow of a Thing defined in AWS IoT Registry. Basically, it’s a JSON State Document that is used to store and retrieve current state information for a Thing. You can interact with a Device Shadow using MQTT Topics or REST API calls. The main advantage of Shadows is that you can interact with it, regardless of whether the thing is connected to the Internet or not.
A shadow’s document contains a state property that describes aspects of the device’s state:
{
"state": {
"desired": {
"color": "RED"
},
"reported": {
"color": "GREEN"
},
"delta": {
"color": "RED"
}
}
}
Here's a description of each state:
Apps specify the desired states of device properties by updating the desired object.
Devices report their current state in the reported object.
AWS IoT reports differences between the desired and the reported state in the delta object.
Every shadow has a reserved MQTT Topic and HTTP URL that supports the get, update, and delete actions on the shadow. Let's take a look:
$aws/things/THING_NAME/shadow/update: publish to this Topic to update/create the Thing Shadow;
$aws/things/THING_NAME/shadow/update/accepted: AWS IoT publishes reported or desired portion of the State Document to this Topic, on accepting the update request;
$aws/things/THING_NAME/shadow/update/rejected: AWS IoT publishes an Error Message to this Topic when it rejects update request;
$aws/things/THING_NAME/shadow/update/documents: AWS IoT publishes a State Document with Previous and Current State information to this topic whenever an update to the shadow is successfully performed;
$aws/things/THING_NAME/shadow/update/delta: AWS IoT publishes a response Delta State Document to this topic when it accepts a change for the thing shadow and the request state document contains different values for desired and reported states.
Here's an example. Let's say that we have an air purifier and we want to change the fan speed. The flow will be the following:
User changes the fan speed from the air purifier mobile application
The mobile application publishes the following JSON message to this MQTT topic: $aws/things/THING_NAME/shadow/update to update the device shadow with a new desired state: "fanSpeed": 50. It will look like this:
{
"state": {
"desired": {
"fanSpeed": 50
}
}
}
On successful shadow update, if the previous reported state is different from "fanSpeed": 50, AWS IoT will publish desired state to delta topic $aws/things/THING_NAME/shadow/update/delta.
The shadow state document may look like this:
{
"state": {
"desired": {
"fanSpeed": 50
},
"reported": {
"fanSpeed": 100
},
"delta": {
"fanSpeed": 50
}
}
}
The device (our air purifier) that is subscribed to delta topic will perform the requested operation (set fan speed to 50 in this case), and report back the new state to AWS IoT Device Shadow, using Update Topic $aws/things/THING_NAME/shadow/update with following JSON message:
{
"state": {
"reported": {
"fanSpeed": 50
}
}
}
Now our air purifier has a fan speed of 50... and that's how it works ;)

How can I use TTL to prevent a message backlog when using Firebase Cloud Messaging with Django-Push-Notifications?

I am working with Firebase Cloud Messaging in Django using django-push-notifications to deliver push notifications to our users via desktop notifications.
After a browser is fully closed (such as when the the computer is turned off), our users receive a backlog of all notifications previously sent next time they boot up.
While there are situations where a user would want to receive the entire backlog of messages, this is not one of them.
It seems the answer is to set TTL=0, as per this section of the FCM documentation, but my attempts are not resulting in the desired behavior.
Please help me better understand TTL in this context. If TTL is the right way to go, what is the proper way to format TTL in send_message() using django-push-notifications so that messages will not accumulate if not immediately delivered?
Here is what I have attempted:
devices.send_message(
body,
TTL=0,
time_to_live=0,
link='blah',
extra={'title': 'blah blah', 'icon': '/foo/bar.png'}
)
The format that you send seems different from the one in the documentation you linked. From the documentation:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
},
"apns":{
"headers":{
"apns-expiration":"1604750400"
}
},
"android":{
"ttl":"4500s"
},
"webpush":{
"headers":{
"TTL":"4500"
}
}
}
}
So key here is that the time-to-live for a webpush message is set under webpush/headers/TTL, while you're adding it to the top-level.

AWS SNS: how to send custom data within a push notification

We have a case where we need to send a json object with a push notification. Reading the documentation I found out I can do the following
iOS
{
default: req.body.message,
"APNS": {
"aps": {
"alert": {
"message": req.body.message,
"data": "{JSON Object}"
},
},
}
Android:
{
"GCM": {
"data": {
"messagee": {
"message": req.body.message,
"data": "{JSON Object}"
}
}
}
}
But, I got sceptical if we should use Message Attributes if not then what is the us of the Message Attributes !
Based on your description it seems like you do not need to use message attributes. Quoting the AWS docs:
You can also use message attributes to help structure the push notification message for mobile endpoints. In this scenario the message attributes are only used to help structure the push notification message and are not delivered to the endpoint, as they are when sending messages with message attributes to Amazon SQS endpoints.
There are some use cases for attaching message attributes to push notifications. One such use case is for TTLs on outbound messages. Again quoting the docs:
The TTL message attribute is used to specify expiration metadata about a message. This allows you to specify the amount of time that the push notification service, such as Apple Push Notification Service (APNS) or GCM, has to deliver the message to the endpoint. If for some reason (such as the mobile device has been turned off) the message is not deliverable within the specified TTL, then the message will be dropped and no further attempts to deliver it will be made. To specify TTL within message attributes, you can use the AWS Management Console, AWS software development kits (SDKs), or query API.

AWS IoT to to send once-off real-time command to device

I have a weather station which is publishing to AWS IoT.
It reports it's state as well as measurements of the environment by publishing to shadows service messages of the format:
{
"state": {
"reported": {
"temperature" : 22,
"humidity" : 70,
....
"wind" : 234,
"air" : 345
}
}
The station has some interactive properties like _led1 and _led2 which I can also report and update via Shadows service by setting "desired" state. To do that I can send to a device message like that:
{
"state": {
"desired": {
"_led1" : "on",
"_led2" : "off",
....
"_lock99" : "open"
}
}
Thanks to shadow service Whenever device gets online it will receive synchronized state and will turn the leds and locks into desired position.
However, sometimes I want to operate the device in real-time: when troubleshooting a device - I want to send a real-time command to reboot it - and if device is live and receives the message I want to reboot it. If device was offline, then nothing happens (the reboot command never reaches the device).
So what would be the best way to control device in real-time? Still try to play with the shadows service to achieve that? Or simply create a separate topic eg. my-things/{thing_name}/real-time-commands and force device to subscribe to it?

Yodlee MFA site flow

The yodlee documentation about the MFA flow is a bit blurry/outdated.
I am following this flow chart to refresh a site with MFA: http://developer.yodlee.com/Aggregation_API/Aggregation_Services_Guide/API_Flow/Refresh_Site_Account
On the flow chart, after calling getMFAResponseForSite, we are supposed to check if there is an errorCode field in the response, I don't see such field in the documentation of the getMFAResponseForSite method. Because without this error code field, we cannot go back into the regular flow and wait for the refresh to be completed.
Also what is the difference between retry and isMessageAvailable?
The documentation specify to call stopSiteRefresh method, I don't see it in the flow, it sounds weird for me to call it but the documentation says:
Note that this is one of the APIs that is required to refresh MFA accounts.
Can somebody give me a clear flow when I have to deal with MFA sites? when and how can we go back on the regular process (getSiteRefreshInfo) and wait for the end of the refresh? thanks in advance.
The "errorCode" field only comes when there is no MFA question available and hence you are not seeing it in the sample of the API documentation as the sample contains the response with MFA question.
If you follow the flow closely you can see that you have to call getMFAResponseForSite in a loop and check for errorCode. So please call the API as depicted in the API flow documentation.
Here is a sample with errorCode field present after successfully answering the MFA question.
{
"isMessageAvailable": true,
"fieldInfo": {
"questionAndAnswerValues": [],
"numOfMandatoryQuestions": -1,
"mfaFieldInfoType": "SECURITY_QUESTION"
},
"timeOutTime": 97690,
"itemId": 0,
"errorCode": 0,
"memSiteAccId": xxxxxxxxxx,
"retry": false
}
Please also ignore the stopSiteRefresh API call, we will rectify the API reference documentation, as that API call should not be made in case of getMFAResponseForSite API.