AWS IoT Button Automation Revisited

With the AWS IoT button going away, is it still possible to build simple automations with IoT buttons and connect them to AWS IoT Core?

Five years ago, I originally wrote an article after sleepless nights being up late with my young son. To this day, that small project of building an AWS IoT button is one of my favorite small projects. The project revolved around solving a very real need of needing to track diapers.

But! Amazon has announced that they are moving away from AWS IoT 1-Click services and more importantly, their beloved AWS IoT button. They aren’t allowing new customers to onboard buttons so the old hardware is now just dust in the wind. So it begs the question, can you still build simple IoT automations and connect them to AWS?

Yes, you absolutely can! In this article, I'll show how you can connect an IoT button to a Raspberry Pi over Zigbee, and then bridge MQTT messages from the Raspberry Pi to AWS IoT Core.

Zigbee automation diagram

Tutorial

Step 1 - Set up your Raspberry Pi

To start, this project needs a few pieces of hardware. Here is my shopping list for anyone who wants to get going with this tutorial. But many of these things could easily be swapped out for similar devices as well.

Parts

  • Zigbee Button - I like this button mostly because of the colors 😂 but it has different click types which I like. It also just takes AAA batteries, which makes it easy for maintenance.

  • Raspberry Pi - I actually already had a Raspberry Pi 3 laying around, so I used that, but any of the newer ones will work. And if you are looking for a reason to buy one, then let this be it! They are a great way to scratch the itch in playing around with new technologies.

    • Note: When you buy a Pi, it usually only includes the device. So you will also need the power cord and micro SD card as well to get off the ground.
  • Zigbee Adapter - I bought this one because it had decent reviews and has been working fine. Zigbee is a different protocol than Wifi, so you will need a specific USB device to retrieve the button clicks from the button. I haven’t had any problems with this one. Cool thing about buying this as well is that now you have a Zigbee Adapter and can do more home automation with Zigbee!

Zigbee is a wireless protocol specifically designed to provide low cost and lower power communication between IoT devices or home automation systems.

Once you receive everything in the mail, let's do some setup!

Image your Raspberry Pi

This step is fairly simple using the Raspberry Pi Imager. Follow the steps to get going with the instructions from their website: Raspberry Pi Imager.

Make sure you edit your settings before completing the process to connect to your wifi, set up the hostname (using the default raspberrypi.local is great), set up a username and password, and enable remote connectivity via SSH.

The instructions here will also show you how to do everything and provide a good overview: Install Raspberry Pi OS, Set Up Wi-Fi, Enable and Connect with SSH.

Install an MQTT Broker

We first need to set up our MQTT Broker. This is the software that will handle our MQTT messages from our button and ultimately send them to AWS. We will be using Mosquitto for this.

MQTT is a messaging protocol that is designed for IoT. MQTT is similar to HTTP, but allows bidirectional communication.

I’m not really going to go in depth on the installation process though. There is a fantastic tutorial here: Install Mosquitto MQTT Broker on Raspberry Pi. Make note of where you install Mosquitto though, because we will need to add a configuration file to create our bridge from the Raspberry Pi to AWS later on.

Install Zigbee2MQTT

Zigbee2MQTT is a great and widely used framework for translating Zigbee devices communication to MQTT. Under the hood, you can use any MQTT broker, but Mosquitto works well and is easy to get started with.

The Zigbee2MQTT docs are pretty good so go ahead and follow the example to get going with setting it up on Linux: Linux Installation for Zigbee2MQTT.

We are going to be creating the bridge on Mosquitto and not on Zigbee2MQTT, so you should be able to only do the defaults on your installation. There are ways to set up Zigbee2MQTT to directly create the bridge to AWS, but I have spent too many hours trying to figure it out, so this tutorial will not include it 😀, but if you know how, please update the docs for us all!

Test your Zigbee Button

With everything installed, you should be able to test your button locally. The easiest way to connect to a device with Zigbee2MQTT is to navigate to the UI. I set up my Raspberry Pi with the hostname RaspberryPi.local. So if you go to your hostname on port 8080, you should be able to see the UI running. Mine is running at this URL on my network: http://raspberrypi.local:8080/.

Put your button in pairing mode, and you should be able to connect to your button! Then you will see your button on the UI and you are golden!

Zigbee Button UI

Step 2 - Create a thing in AWS IoT Core

I’ve seen a lot of examples online that recommend you use the AWS CLI. I think that is a great way to generate the necessary files, but I think an easier way is to use the online walkthrough that is in IoT Core.

AWS IoT Connect one device

The first step will ensure you have connectivity to IoT Core by sending a ping request from your device. The second step will have you create a thing name. I named mine ‘ZigbeeButton’ but feel free to name it whatever you want.

Step three you choose the platform you are running it from. I put mine as Linux / macOS because it's going to run from a Raspberry Pi. I also chose Python for the Device SDK, although this doesn’t matter too much because we are going to set up the bridge with Mosquitto.

Step four is important because it is what is going to generate the appropriate certificates. You will need these to actually connect to IoT Core. Download the connection kit, and then get it over to your Raspberry Pi either with scp or using an FTP client.

Finally, on step 5, go ahead and run the start script from your device. If this works, then you know your connection is good! We will be modifying the Policy in the next step, but the default policy will work when using the start script from the connection kit.

Step 3 - Modify Policy for Mosquitto Bridge

The default policy that was created was specifically for an sdk and is pretty restrictive as we are hacking away.

From the AWS IoT Core page with your thing created, navigate to your newly created policy. To do this, first navigate to Security -> Policies. You should see your policy here. Mine is named ZigbeeButton-Policy.

Edit the active version and add a wildcard to open up connections with this policy.

AWS IAM Policy

You can also just modify the json as well. An example can be found below:

{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": "iot:*","Resource": "*"}]}

Make sure that you also select the checkbox to make this the new active policy.

Nice! Now we have our certificate files, the policy is opened up for connections from our Raspberry Pi, and we are fully prepared to move our attention back to the Raspberry Pi to create the bridge between AWS and the Pi.

Step 4 - Create the bridge between AWS and our MQTT broker, Mosquitto

The great thing with creating the bridge is that it will automatically forward selected MQTT topics to AWS.

To start, we will need to create a bridge configuration file. I have Mosquitto installed at /etc/mosquitto so I will create my conf file at the following path: /etc/mosquitto/conf.d/bridge.conf. Use the following values for your bridge.conf.


# ============================================================
# Bridge to AWS IOT
# ============================================================
connection awsiot

#<Paste your AWS IoT Core ATS endpoint retrieved from the AWS CLI in the form of xxxxxxxxxxxxxxx-ats.iot.<region>.amazonaws.com:8883

address xxxxxxxxxxxxxxx-ats.iot.<region>.amazonaws.com:8883
# Specifying which topics are bridged and in what fashion
topic zigbee2mqtt/+ out 1

# Setting protocol version explicitly
bridge_protocol_version mqttv311
bridge_insecure false

# Bridge connection name and MQTT client Id, enabling the connection automatically when the broker starts.
cleansession true
clientid bridgeawsiot
start_type automatic
notifications false
log_type all
tls_version tlsv1.3
# ============================================================
# Certificate based SSL/TLS support
# ============================================================
#Path to the rootCA
bridge_cafile /opt/zigbee2mqtt/root-CA.crt

# Path to the PEM encoded client certificate
bridge_certfile /opt/zigbee2mqtt/ZigbeeButton.cert.pem

# Path to the PEM encoded client private key
bridge_keyfile /opt/zigbee2mqtt/ZigbeeButton.private.key

#END of bridge.conf

A few notes of the conf file above. You can get your endpoint from the AWS IoT Core console. Your topics are what topics you want sent to AWS. My base topic for Zigbee2MQTT is zigbee2mqtt, so I set a wildcard + to send all messages from Zigbee2MQTT, but you can also specify specific topics if you don’t want all messages.

Lastly, the three certificates are from when you created your thing on the AWS console. Modify the paths to correctly navigate to your own certificate files that you generated earlier.

Last, you need to restart Mosquitto!

Running sudo systemctl restart mosquitto should do the trick!

Step 5 - Test your Zigbee Button’s connect with AWS

Now that you have everything configured, let's ensure that we can see our IoT button’s messages in AWS.

In AWS IoT Core, navigate to the MQTT test client. From here, I find it easiest to just subscribe to a wildcard for all messages, but feel free to navigate specifically to your topic if you have other active topics.

After subscribing, press the button on your IOT button…

And voila! You should see your message from your button in the console!

Subscription of raw mqtt topic message

Step 6 - Route Messages to DynamoDB

Now that we have our button successfully sending messages to AWS, let's do something with that data!

Let’s start with the database. I like DynamoDB for these cases because of its flexibility. You can quickly create a table by going to the DynamoDB console and creating a table with the following settings. I named mine ZigbeeEventsTable.

We can keep the default settings for everything else.

Next, let's work on moving those events to our newly created table.

We can use AWS IoT Core for this as well. Lets first create a rule that will send our event data to a database.

Navigate to Message Routing -> Rules. Rules are a way for us to use a SQL statement to query our incoming events and do something with them.

First create a rule. I named mine ZigbeeButtonRule. Next, we will configure a SQL statement. You can use the statement below:

SELECT * FROM 'zigbee2mqtt/Button'

Make sure you change the FROM to whatever topic you are sending topics from. I configured my button to send on my zigbee2mqtt/Button topic.

The next step is the actual rule action which will handle the movement of the event data.

There are some DynamoDB specific syntax fields but I’ve included a screenshot of all of the data.

DynamoDB Rule Action on AWS IoT Core

The two things to note are that we are first going to use the ieeeAddr as the id. This will work, especially if you decide to add other events to this table down the road. The second thing is for the sort key, we are using the timestamp() function, which will simply give us a timestamp at the time of insert.

Last, I used the Create Role to create the IAM role. I named my new role ZigbeeIoTRole.

We have the table set up! We have the rule which will forward our messages! Let’s check to see if our table is being populated!

DynamoDB Table Scan

Success!

Step 7 - Query your table with Lambda

Head over to the Lambda console, and create a new function. I’m going to name mine ZigbeeQueryLambda and I'll be using Python for the runtime. Everything else will be the defaults.

Lambda Creation Screen

After creation, I went to my policy that was created, and I added one additional permission policy. We will need to give access to our DynamoDB table, so I selected read only access and attached it to my policy.

Lambda Permission Policy on IAM

Next, let's paste in some code to do a quick query of the data!

import json
import boto3

dynamo_db = boto3.resource('dynamodb')
table_name = 'ZigbeeEventsTable'  # Replace with your actual table name
table = dynamo_db.Table(table_name)

def lambda_handler(event, context):
    try:
        response = table.scan()
        items = response['Items']
        filtered_items = []

        for item in items:
            filtered_item = {
                'action': item['payload']['action'],
                'battery': item['payload']['action']
            }
            filtered_items.append(filtered_item)

        return {
            'statusCode': 200,
            'body': json.dumps(filtered_items)
        }
    except Exception as e:
        return {
            'statusCode': 400,
            'error': f"Error: {str(e)}"
        }

Now if we run a Test, we should see our response…

Lambda Response

Perfect! And with that, we have the Lambda querying our database correctly!

From here, you can do anything you want with the data. You can query APIs, use it to populate a UI (like I did in this article here: AWS IoT Automation with React), or really any other endless possibility!

Wrap Up

There have been a lot of moving parts, so make sure you go back through and clean up everything if this was just for experimentation. Here is a quick list of things to clean up to help save any additional costs:

  • DynamoDB Table
  • IoT Thing
  • IoT Thing Rule
  • IAM Policies you generated along the way

Putting it all together

In this tutorial, we went from a simple button, sent that click event to a Zigbee adapter, linked that adapter with Zigbee2MQTT, bridged the MQTT messages with Mosquitto to AWS, sent the events to AWS IoT Core, created a SQL rule to move those events from the topic to a database, then finally queried that data with a Python Lambda. Wow!

That is seriously no joke.

So to answer the initial question, is it still possible to build simple automations with IoT buttons and connect them to AWS IoT Core?

Yes and No 😆

Is it possible? Absolutely! Is it still simple? Well it definitely has become more complex. But by introducing Zigbee and the RaspberryPi, the automation possibilities are now limitless!

And finally, even if something is difficult or complex, try it anyway. Feed that inner curiosity!


Want to be notified about new posts?

Then sign up to get posts directly to your email. You can opt-out at any time.

Drake Loud - © 2024