How to Build a Fleet Overview with AWS IoT Fleet Indexing
This post guides you through building a fleet overview for your robot fleet, using Fleet Indexing from AWS IoT Device Management
- How many devices do I have online?
- How many devices have less than 30% battery left?
- Which devices are currently on a mission?
- What is the average metres travelled for my fleet of robots at this location?
ros-dev-tools
as well as ros-humble-desktop
. Also install the AWS CLI and the AWS IoT SDK - instructions are in the repository's README and my video on setting up the sample application:1
2
cd ~
git clone https://github.com/mikelikesrobots/aws-iot-robot-connectivity-samples-ros2.git
1
2
3
4
cd ~/aws-iot-robot-connectivity-samples-ros2/workspace
source /opt/ros/humble/setup.bash
colcon build --symlink-install
source install/setup.bash
1
2
export CERT_FOLDER_LOCATION=~/aws-iot-robot-connectivity-samples-ros2/iot_certs_and_config/
echo "export CERT_FOLDER_LOCATION=$CERT_FOLDER_LOCATION" >> ~/.bashrc
1
2
3
4
5
cd ~/aws-iot-robot-connectivity-samples-ros2
# Install python dependencies for the script
python3 -m pip install -r scripts/requirements.txt
# Create certificates, policies etc for robot1, robot2, and robot3
python3 scripts/make_robots.py robot1 robot2 robot3
1
2
cd ~/aws-iot-robot-connectivity-samples-ros2
python3 scripts/delete_robots.py robot1 robot2 robot3
1
ros2 launch iot_shadow_service crack_all_safes.launch.py certs_path:=$CERT_FOLDER_LOCATION





1
2
3
4
aws iot update-indexing-configuration --thing-indexing-configuration '{
"thingIndexingMode": "REGISTRY",
"thingConnectivityIndexingMode": "STATUS"
}'


connectivity.connected = true
. Press enter to add it as a query, then click Search.



1
2
3
aws iot search-index \
--index-name "AWS_Things" \
--query-string "connectivity.connected:true"
jq
:1
2
3
4
5
sudo apt install jq
aws iot search-index \
--index-name "AWS_Things" \
--query-string "connectivity.connected:true" \
| jq '.things[].thingName'
"robot1"
"robot2"
"robot3"
1
watch "aws iot search-index --index-name 'AWS_Things' --query-string 'connectivity.connected:true' | jq '.things[].thingName'"
1
2
3
4
5
aws iot search-index \
--index-name 'AWS_Things' \
--query-string 'connectivity.connected:true' \
| jq '.things[].thingName' \
| wc -l
robot
that are connected, we can use this command:1
2
3
4
aws iot get-buckets-aggregation \
--query-string "thingName:robot*" \
--aggregation-field connectivity.connected \
--buckets-aggregation-type '{"termsAggregation": {"maxBuckets": 10}}'
1
2
3
4
5
6
7
8
9
{
"totalCount": 3,
"buckets": [
{
"keyValue": "true",
"count": 3
}
]
}
robot1-shadow
, robot2-shadow
, robot3-shadow
.
1
2
3
4
5
6
aws iot update-indexing-configuration --thing-indexing-configuration '{
"thingIndexingMode": "REGISTRY",
"namedShadowIndexingMode": "ON",
"thingConnectivityIndexingMode": "STATUS",
"filter": {"namedShadowNames": ["robot1-shadow", "robot2-shadow", "robot3-shadow"]}
}'
robot1-shadow
, open the Advanced search page again. Enter the query shadow.name.robot1-shadow.hasDelta = true
, then click search. It may take a few searches depending on the shadow's delta, but this should return robot1
as a Thing.
robot*
things will return a table of links, which means clicking through each Thing to see the shadow. The query result from the CLI has more detail in one place, including the entire indexed shadow contents for all things matching the query. For example, the following query will return the thing name, ID, shadow, and connectivity status for all robot*
things.1
aws iot search-index --index-name 'AWS_Things' --query-string 'connectivity.connected:true'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"things": [
{
"thingName": "robot1",
"thingId": "13032b27-e770-4146-8706-8ec1249b7015",
"shadow": "{\"name\":{\"robot1-shadow\":{\"desired\":{\"digit\":59},\"reported\":{\"digit\":59},\"metadata\":{\"desired\":{\"digit\":{\"timestamp\":1718135446}},\"reported\":{\"digit\":{\"timestamp\":1718135446}}},\"hasDelta\":false,\"version\":55137}}}",
"connectivity": {
"connected": true,
"timestamp": 1718134574557
}
},
{
"thingName": "robot2",
"thingId": "7e396088-6d02-461e-a7ca-a64076f8a0ca",
"shadow": "{\"name\":{\"robot2-shadow\":{\"desired\":{\"digit\":70},\"reported\":{\"digit\":70},\"metadata\":{\"desired\":{\"digit\":{\"timestamp\":1718135462}},\"reported\":{\"digit\":{\"timestamp\":1718135463}}},\"hasDelta\":false,\"version\":55353}}}",
"connectivity": {
"connected": true,
"timestamp": 1718134574663
}
},
{
"thingName": "robot3",
"thingId": "b5cf7c73-3b97-4d8e-9ccf-a1d5788873c8",
"shadow": "{\"name\":{\"robot3-shadow\":{\"desired\":{\"digit\":47},\"reported\":{\"digit\":22},\"delta\":{\"digit\":47},\"metadata\":{\"desired\":{\"digit\":{\"timestamp\":1718135446}},\"reported\":{\"digit\":{\"timestamp\":1718135447}},\"del
ta\":{\"digit\":{\"timestamp\":1718135446}}},\"hasDelta\":true,\"version\":20380}}}",
"connectivity": {
"connected": true,
"timestamp": 1718134574573
}
}
]
}
jq
to get all of the current reported digits for the shadows. The following command uses a few chained Linux commands to parse the desired data. The purpose of the command is to show that the data returned by the query can be further parsed for particular fields, or used by a program to take further action.1
2
3
4
aws iot search-index \
--index-name 'AWS_Things' \
--query-string 'connectivity.connected:true' \
| jq -r '.things[].shadow | fromjson | .name | to_entries[] | {name: .key, desired: .value.desired.digit}'
1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "robot1-shadow",
"desired": 24
}
{
"name": "robot2-shadow",
"desired": 54
}
{
"name": "robot3-shadow",
"desired": 8
}
watch
command to see how frequently the values update:1
watch "aws iot search-index --index-name 'AWS_Things' --query-string 'connectivity.connected:true' | jq -r '.things[].shadow | fromjson | .name | to_entries[] | {name: .key, desired: .value.desired.digit}'"