# Part 4: Adafruit IO (MQTT & Webhooks)
###### tags: `TA Stuff ESP32` `PyCom` `Heltec` `ESP32`
This tutorial covers how to work with Adafruit IO, the IoT platform made by Adafruit. You will learn:
+ How to register and set up a dashboard in Adafruit IO.
+ How to send data over **MQTT** to your dashboard in Adafruit IO and visualize it on a chart.
+ How to control your board LED from your Adafruit IO control panel.
+ How to trigger an event captured by Adafruit and send a **Webhook** message to your Discord server.
This tutorial is based on [Core Electronic basic tutorials](https://core-electronics.com.au/guides/pycom/internet-of-things-with-pycom-and-adafruit-io/) on MQTT message sending over WiFi to the Adafruit IO platform. Before we dive into the how-to-make such a connection we should get familiar with Adafruit **Terms** in the next section.
## Adafruit IO terms
Each IoT cloud platform uses its terminology for different actions and It would be valuable to know them before starting working with them. So before signing up and using Adafruit IO read the following terms, we gathered from Adafruit documentation.
**Feed:** Feeds are the core of the Adafruit IO system. The feed contains the sensor data values that get pushed to Adafruit IO from your device, like temperature value. It also could be the value you need to send from your control panel to the device to control it, like turning on a lamp.
**Blocks:** Blocks are widgets that you can use to visualize feeds. It could be a gauge, a table, or a line chart to visualize data pushed from your device to the feed. Or it could be a toggle switch or a slider to send your commands from the Adafruit control panel to your device.
**Dashboard:** Dashboards allow you to visualize data and control Adafruit IO-connected projects from any modern web browser. Before being able to add any block to visualize your data you need a dashboard, and basically, it is a place to hold several blocks for each project.
**Action:** Actions will initiate a triggered action on a condition. There are two types of actions in Adagruit IO:
* **Reactive Action:** *It will be activated by a condition met from a feed value, like if the temperature reached a certain threshold send an alarm.* **(This is what we learn in this tutorial)**
* **Schedule Action:** *It will periodically trigger a command and work as a scheduler, like sending an open/close valve command to our board.*
Adafruit IO supports the following three trigger reactions:
* **Email me:** *It will email the triggered action to your desired email address.*
* **Send a Webhook message to:** *It can send a webhook message to a platform like sending a message to your Discord.* **(This is what we learn in this tutorial)**
* **Publish a message to:** *It could also change the state of a feed value so your development board can subscribe to the MQTT and read it.*
## Setting Environment in Adafruit IO
In this part we show how to set up **Feeds** and **Blocks** to receive a random value and visualize it on a chart plus define a button to control our onboard LED (On/OFF). follow these steps:
+ **Step 1:** Visit [**this link**](https://accounts.adafruit.com/users/sign_up) to register an account on Adafruit IO. You should provide a **UserName** which is a unique value and need it later to log in and send data to your control panel.
+ **Step 2:** Visit [**this link**](https://io.adafruit.com/) to sign in to your control panel.
+ **Step 3:** Choose **IO** on top of the page and if you can not see any settings press on **Sign in** on the top right corner to see your control panel.
+ **Step 4:** In your control panel navigate to: `Feeds` >> `Feeds | view all` >> `+ New Feed` to create a feed. We basically give a feed a `Name` and `Description` then click on `Create`. **We create two following feeds:**
- `randoms`: A random value generated from the development board (between 0 - 100) and pushed to Adafuit to show it in a line chart. It is a temperature simulation and you can use the same technique to show temperature value.
- `lights`: this feed controls the development board LED and you can turn it on/off from the Adafruit control panel. It is useful when you need to hold something remotely.
Your control panel should look like this after creating feeds:

<br>
+ **Step 5:** In your control panel navigate to: `Dashboards` >> `Dashboards | View all` >> `+ New Dashboard` to create a dashboard. Then click on it and from the right panel like the following screenshot we will add two `Blocks` to our dashboard.

<br>
+ **Step 6:** We create a `Toggle Block` and connect it to `lights Feed` then create a `Line Chart Block` and connect it to `randoms Feed`.
- **Line Chart:** As mentioned above they use a line chart to connect it to the “randoms” feed to show pushed values from your device.
- **Toggle Switch:** This switch is used to send “ON/OFF” commands to the “lights” feed then your development board can subscribe to the feed and based on the state of the “lights” feed turn on/off your board LED.

<br>
+ **Step 7:** After making feeds you can click on the setting `Edit Layout` to make the size of charts and toggle button according to your need. Your dashboard should look like this:

<br>
+ **Step 8:** We are ready now, we need to copy our credentials (**Username and Active Key**) which we can fetch from the `My Key` on the top right in our control panel. We also need the address to our `lights` and `ransoms` Feed which we can get from (`Feeds` >> `Selected Feed` >> `Feed Info` >> `MQTT by key` value. We will paste them into our code to be able to `Publish` and `Subscribe` for the Adafruit **MQTT** server. Screenshots:

<br>

<br>
## Project Code (Publish & Subscribe) To Adafruit MQTT Server
Now we are set to make our project in Atom and run it. (**Note we have used the PyCom device RGB LED in this project you can adjust it for your development board**). Follow these steps:
+ **Step 1:** Create a project in Atom, create a file named `mqtt.py` and copy the content of the file in [**this link**](https://github.com/iot-lnu/applied-iot/blob/master/network-examples/mqtt_ubidots/mqtt.py).
+ **Step 2:** Make `main.py` and copy the following lines in it. You should change some information like your home WiFi credentials and mentioned addresses and keys from Adafruit IO before uploading the project to your development board. Read the code thoroughly it is self-commented:
```python=
from network import WLAN # For operation of WiFi network
import time # Allows use of time.sleep() for delays
import pycom # Base library for Pycom devices
from mqtt import MQTTClient # For use of MQTT protocol to talk to Adafruit IO
import ubinascii # Needed to run any MicroPython code
import machine # Interfaces with hardware components
import micropython # Needed to run any MicroPython code
# BEGIN SETTINGS
# These need to be change to suit your environment
RANDOMS_INTERVAL = 20000 # milliseconds
last_random_sent_ticks = 0 # milliseconds
# Wireless network
WIFI_SSID = "Your_WiFi_Name"
WIFI_PASS = "Your_WiFi_Password" # No this is not our regular password. :)
# Adafruit IO (AIO) configuration
AIO_SERVER = "io.adafruit.com"
AIO_PORT = 1883
AIO_USER = "Your_Adafruit_User_Name"
AIO_KEY = "Your_Adafruit_Application_Key"
AIO_CLIENT_ID = ubinascii.hexlify(machine.unique_id()) # Can be anything
AIO_CONTROL_FEED = "Your_lights_Feed_Address"
AIO_RANDOMS_FEED = "Your_randoms_Feed_Address"
# END SETTINGS
# RGBLED
# Disable the on-board heartbeat (blue flash every 4 seconds)
# We'll use the LED to respond to messages from Adafruit IO
pycom.heartbeat(False)
time.sleep(0.1) # Workaround for a bug.
# Above line is not actioned if another
# process occurs immediately afterwards
pycom.rgbled(0xff0000) # Status red = not working
# WIFI
# We need to have a connection to WiFi for Internet access
wlan = WLAN(mode=WLAN.STA)
wlan.connect(WIFI_SSID, auth=(WLAN.WPA2, WIFI_PASS), timeout=5000)
while not wlan.isconnected(): # Code waits here until WiFi connects
machine.idle()
print("Connected to Wifi")
pycom.rgbled(0xffd7000) # Status orange: partially working
# FUNCTIONS
# Function to respond to messages from Adafruit IO
def sub_cb(topic, msg): # sub_cb means "callback subroutine"
print((topic, msg)) # Outputs the message that was received. Debugging use.
if msg == b"ON": # If message says "ON" ...
pycom.rgbled(0xffffff) # ... then LED on
elif msg == b"OFF": # If message says "OFF" ...
pycom.rgbled(0x000000) # ... then LED off
else: # If any other message is received ...
print("Unknown message") # ... do nothing but output that it happened.
def random_integer(upper_bound):
return machine.rng() % upper_bound
def send_random():
global last_random_sent_ticks
global RANDOMS_INTERVAL
if ((time.ticks_ms() - last_random_sent_ticks) < RANDOMS_INTERVAL):
return; # Too soon since last one sent.
some_number = random_integer(100)
print("Publishing: {0} to {1} ... ".format(some_number, AIO_RANDOMS_FEED), end='')
try:
client.publish(topic=AIO_RANDOMS_FEED, msg=str(some_number))
print("DONE")
except Exception as e:
print("FAILED")
finally:
last_random_sent_ticks = time.ticks_ms()
# Use the MQTT protocol to connect to Adafruit IO
client = MQTTClient(AIO_CLIENT_ID, AIO_SERVER, AIO_PORT, AIO_USER, AIO_KEY)
# Subscribed messages will be delivered to this callback
client.set_callback(sub_cb)
client.connect()
client.subscribe(AIO_CONTROL_FEED)
print("Connected to %s, subscribed to %s topic" % (AIO_SERVER, AIO_CONTROL_FEED))
pycom.rgbled(0x00ff00) # Status green: online to Adafruit IO
try: # Code between try: and finally: may cause an error
# so ensure the client disconnects the server if
# that happens.
while 1: # Repeat this loop forever
client.check_msg()# Action a message if one is received. Non-blocking.
send_random() # Send a random number to Adafruit IO if it's time.
finally: # If an exception is thrown ...
client.disconnect() # ... disconnect the client and clean up.
client = None
wlan.disconnect()
wlan = None
pycom.rgbled(0x000022)# Status blue: stopped
print("Disconnected from Adafruit IO.")
```
:::info
The above code sends a random value (between 0 and100) at random time intervals to your Adafruit control panel by publishing it to their MQTT server. It also subscribes to the same server and while you change the toggle button state (ON/OFF) it turns the RGB LED on your PyCom device accordingly.
:::
<br/><br/>
## Webhooks in Adafruit and sending messages to the Discord server
In this simple tutorial, we will activate the webhook link in our Discord channel, and based on the `randoms` values pushed from the development board if the value is above `80` we forward the value to the Discord. Following we first create a webhook in the Discord and then send the triggered value from Adafruit IO to it.
### Creating a server and activating webhook on a channel in Discord
**Step 1:** Open Discord and from the left pane click on `+` to **Add a Server**.
**Step 2:** From the pop-up window choose **Create My Own**.
**Step 3:** Next window choose **For me and my friends**.
**Step 4:** Give it a name like `LNU Project` and click on **Create**.
**Step 5:** By default you have a `general` channel click on the `gear` sign close to it.

**Step 6:** Click on `Integrations` then on `Create Webhook`.

**Step 7:** Click on `Copy Webhook URL` and save the link somewhere that you need later.

**Step 8:** Finally click on `ESC` in the top right corner to close the window. We are done in Discord.
### Adding a trigger in Adafruit and connect it to your webhook
**Step 1:** Login to your Adafruit IO control panel >> click on `Actions` >> click on `Actions | View all` >> click on `+ New Action`

**Step 2:** Do the following steps:
1. Click on `Reactive Action`
2. Choose `randoms`
3. Choose `greater than`
4. Enter `80`
5. Choose `send a webhook message`
6. Paste the webhook link you got from Discord
7. choose `randoms`
8. choose `Discord Template`
9. click on `Create`

**Step 3:** Everything is set and you can see a new trigger in the trigger’s list.

### Results
Now you can run your code from Core-Electronics and if your board uploaded a value greater than `80` it will forward it to your Discord.

<br/>
:::warning
**⚠️Attention⚠️ Don’t bug Discord by sending too many Webhooks, Adafruit will disable it if recognize too many requests.**
:::
*[MQTT]: Message Queuing Telemetry Transport
<style>
.markdown-body code{
font-size: 1em !important;
}
.markdown-body .a{
font-size: 5em !important;
}
.markdown-body pre {
background-color: #333;
border: 1px solid #333 !important;
color: #dfdfdf;
font-weight: 600;
}
.token.operator, .token.entity,
.token.url, .language-css .token.string,
.style .token.string {
background: #000;
}
.markdown-body table {
display: table;
padding: 1em;
width: 100%;
}
.markdown-body table th,
.markdown-body table td,
.markdown-body table tr {
border: none !important;
}
.markdown-body table tr {
background-color: transparent !important;
border-bottom: 1px solid rgba(0, 0, 0, 0.2) !important;
}
</style>