Learning Goals 5 min
Yesterday a single Discord webhook fired one message. Today you wire two destinations — Discord for chat-style logs, IFTTT to bridge into your phone's native notifications, email, Google Sheets and ~700 other services. By the end of this lesson you will:
- POST to a Discord webhook with a rich embed — title, colour, fields — instead of just plain text.
- POST to IFTTT's Maker Webhooks endpoint with three optional string "values" that become variables in IFTTT recipes.
- Use IFTTT to push a phone notification, a Google Sheets row append, and an email — all from one Arduino trigger.
Warm-Up 10 min
Pull up yesterday's doorbell sketch. We'll fork it to send to two destinations instead of one.
Discord vs IFTTT — pick the right one
| Service | Best for | Trade-offs |
|---|---|---|
| Discord webhooks | Chat-style live log; rich embeds (cards with colour, fields); fast (~200 ms) | Requires a Discord channel; one destination |
| IFTTT Webhooks | Bridges to ~700 services: SMS, email, Google Sheets, Spotify, smart bulbs, IoT platforms | Slower (~5–15 s end-to-end); free tier limited to 5 active recipes |
| Direct service APIs (e.g. Telegram bot, Slack, Pushover) | Targeted, polished, no third party | Each service is its own client implementation |
Discord = great for "live debug stream from my devices". IFTTT = great for "trigger an action somewhere in my digital life". Use both.
Set up IFTTT (free)
- Go to
ifttt.com. Make a free account. - My Applets → New → If "Webhooks: Receive a web request" → event name
doorbell. - Then "Notifications: Send a notification from the IFTTT app" → message
Doorbell pressed at {{Value1}}!. - Connect the "Webhooks" service if asked. Find your key under Webhooks → Documentation. URL format:
https://maker.ifttt.com/trigger/doorbell/with/key/YOUR_KEY_HERE
POST to that URL → IFTTT runs your recipe → phone notification. Optionally include up to 3 string values (value1, value2, value3) as JSON body to fill in template slots.
New Concept · Rich Discord embeds + IFTTT values 25 min
Discord embed format
A plain Discord webhook body has just content. An embed adds a structured card:
{
"embeds": [{
"title": "Doorbell pressed",
"description": "Someone is at the door.",
"color": 5814783,
"fields": [
{ "name": "Time", "value": "19:30:01", "inline": true },
{ "name": "Light", "value": "raw 458 (dim)", "inline": true }
]
}]
}
The color field is a decimal integer (RGB packed: 0x58a4ff = 5808895). Discord renders the embed as a coloured-stripe card — much more legible than a plain message wall.
IFTTT JSON body
{
"value1": "19:30:01",
"value2": "458",
"value3": "dim"
}
Up to 3 values. Inside IFTTT's recipe template, refer to them as {{Value1}}, {{Value2}}, {{Value3}}. The recipe can chain them into the notification message, the email body, the Google Sheets cell, etc.
Wrap both in helpers
bool postDiscord(const String& jsonBody) {
SecureClient client;
client.setInsecure();
HTTPClient http;
http.begin(client, DISCORD_URL);
http.addHeader("Content-Type", "application/json");
int status = http.POST(jsonBody);
http.end();
return status >= 200 && status < 300;
}
bool postIFTTT(const String& v1, const String& v2, const String& v3) {
SecureClient client;
client.setInsecure();
HTTPClient http;
http.begin(client, IFTTT_URL);
http.addHeader("Content-Type", "application/json");
String body = "{\"value1\":\"" + v1 +
"\",\"value2\":\"" + v2 +
"\",\"value3\":\"" + v3 + "\"}";
int status = http.POST(body);
http.end();
return status >= 200 && status < 300;
}Building a Discord embed in code
For more complex JSON, use ArduinoJson — it's much cleaner than string concatenation:
#include <ArduinoJson.h>
String buildDiscordEmbed(const char* timeStr, int rawLight) {
StaticJsonDocument<512> doc;
JsonObject embed = doc["embeds"].createNestedObject();
embed["title"] = "Doorbell pressed";
embed["description"] = "Someone is at the door.";
embed["color"] = 0x58A4FF;
JsonArray fields = embed.createNestedArray("fields");
JsonObject f1 = fields.createNestedObject();
f1["name"] = "Time";
f1["value"] = timeStr;
f1["inline"] = true;
JsonObject f2 = fields.createNestedObject();
f2["name"] = "Light";
f2["value"] = String(rawLight) + (rawLight < 300 ? " (dim)" : " (bright)");
f2["inline"] = true;
String out;
serializeJson(doc, out);
return out;
}Worked Example · Doorbell → Discord embed + IFTTT notification 25 min
Step 1 — wire as L03-36 (button on D7)
Step 2 — set up two destinations
Have ready: a Discord webhook URL (from L03-36) and an IFTTT webhook URL with event name doorbell. Both stored as const char* in your sketch (kept private).
Step 3 — the dual-destination sketch
// L03-37 · Dual webhook: Discord embed + IFTTT phone notification
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
using SecureClient = BearSSL::WiFiClientSecure;
#elif defined(ESP32)
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
using SecureClient = WiFiClientSecure;
#endif
#include <ArduinoJson.h>
#include <time.h>
const char* SSID = "YourNetwork";
const char* PASSWORD = "YourPassword";
const char* DISCORD_URL = "https://discord.com/api/webhooks/REPLACE_ME";
const char* IFTTT_URL = "https://maker.ifttt.com/trigger/doorbell/with/key/REPLACE_ME";
const int BTN_PIN = 13;
const int LDR_PIN = A0;
bool lastBtn = HIGH;
unsigned long lastEdge = 0;
unsigned long lastSentAt = 0;
const unsigned long DEBOUNCE_MS = 50;
const unsigned long COOLDOWN_MS = 10000;
bool postJSON(const char* url, const String& body) {
if (WiFi.status() != WL_CONNECTED) return false;
SecureClient client;
client.setInsecure();
HTTPClient http;
http.begin(client, url);
http.addHeader("Content-Type", "application/json");
int status = http.POST(body);
Serial.print("# POST -> ");
Serial.println(status);
http.end();
return status >= 200 && status < 300;
}
void fireDoorbell() {
time_t now = time(nullptr);
struct tm tmNow;
localtime_r(&now, &tmNow);
char timeBuf[20];
strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", &tmNow);
int rawLight = analogRead(LDR_PIN);
const char* lightLabel = rawLight < 300 ? "dim" : "bright";
// 1. Discord — rich embed
{
StaticJsonDocument<512> doc;
JsonObject embed = doc["embeds"].createNestedObject();
embed["title"] = "Doorbell pressed";
embed["description"] = "Someone is at the door.";
embed["color"] = 0x58A4FF;
JsonArray fields = embed.createNestedArray("fields");
JsonObject f1 = fields.createNestedObject();
f1["name"] = "Time";
f1["value"] = timeBuf;
f1["inline"] = true;
JsonObject f2 = fields.createNestedObject();
f2["name"] = "Light";
f2["value"] = String(rawLight) + " (" + lightLabel + ")";
f2["inline"] = true;
String body;
serializeJson(doc, body);
postJSON(DISCORD_URL, body);
}
// 2. IFTTT — phone notification with templated values
{
String body = "{\"value1\":\"";
body += timeBuf;
body += "\",\"value2\":\"";
body += rawLight;
body += "\",\"value3\":\"";
body += lightLabel;
body += "\"}";
postJSON(IFTTT_URL, body);
}
}
void checkButton() {
bool b = digitalRead(BTN_PIN);
if (b == lastBtn) return;
if (millis() - lastEdge < DEBOUNCE_MS) return;
lastEdge = millis();
lastBtn = b;
if (b == LOW && millis() - lastSentAt > COOLDOWN_MS) {
lastSentAt = millis();
fireDoorbell();
}
}
void setup() {
Serial.begin(115200);
pinMode(BTN_PIN, INPUT_PULLUP);
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) { delay(500);
Serial.print(".");
}
Serial.println();
configTime(0, 0, "pool.ntp.org");
setenv("TZ", "UTC0", 1); // your zone (L03-35)
tzset();
while (time(nullptr) < 24 * 3600) delay(200);
Serial.println("# Doorbell armed.");
}
void loop() {
checkButton();
}Step 4 — test
Press the button. Within ~1 s your Discord channel shows a coloured embed card with Time and Light fields. Within ~10 s your phone's IFTTT app pushes a native notification.
Step 5 — add a second IFTTT recipe
In IFTTT, create a second applet listening for the same event doorbell. The action: "Google Sheets: Add row to spreadsheet". Configure to write {{OccurredAt}}, {{Value1}}, {{Value2}}, {{Value3}} as four columns. Now every button press also appends a row to your Google Sheet — a free, persistent doorbell log.
Step 6 — third action: dim the smart lamp at night
Another IFTTT recipe: "If Webhooks doorbell + time is between 21:00 and 06:00" → "Philips Hue: turn on the porch light". (Or any other smart-bulb service IFTTT supports.) Same Arduino trigger, three independent automations.
Basic 5 min
Goal: Change the Discord embed's colour based on time of day — red during the night (22:00–06:00), blue otherwise. Eye-catching for unusual events.
Challenge 1 5 min
Goal: Add a username override on the Discord webhook so messages appear as "Front-Door-Bot" rather than "Webhook".
Challenge 2 5 min
Goal: Two-button device. Button A = "doorbell" (fire normal event). Button B = "suspicious" (fire URGENT event with red embed AND a separate IFTTT recipe that sends an SMS).
Challenge 3 · Fix the bad JSON 10 min
A classmate's doorbell gets 400 Bad Request from Discord, and IFTTT shows empty values. To find out why, they wrote a test sketch. It builds both bodies and prints them, with no WiFi at all.
#include <ArduinoJson.h>
const char* TIME_TEXT = "19:30:01";
const int RAW_LIGHT = 412;
void setup() {
Serial.begin(115200);
String iBody = "{\"value1\":\"";
iBody += TIME_TEXT;
iBody += "\",\"value2\":";
iBody += RAW_LIGHT;
iBody += "\",\"value3\":\"bright\"}";
Serial.println(iBody);
StaticJsonDocument<256> doc;
JsonObject embed = doc.createNestedObject("embeds");
embed["title"] = "Doorbell pressed";
embed["color"] = "0x58A4FF";
String dBody;
serializeJson(doc, dBody);
Serial.println(dBody);
}
void loop() {
}- Upload it and copy the two printed lines.
- Find the one mistake in the IFTTT body and the two in the Discord body. Compare with the Worked Example.
- Fix all three and upload again.
- Work out what number Discord will receive for the colour
0x58A4FF.
It works if the two printed lines match the shapes below exactly.
{"value1":"19:30:01","value2":"412","value3":"bright"}
{"embeds":[{"title":"Doorbell pressed","color":5809407}]}Recap 5 min
Two destinations from one trigger: Discord for live cards (use embeds array with title / colour / fields), IFTTT for bridging into your phone's native notification system, Google Sheets, email, smart bulbs and ~700 other apps. Free tiers are generous enough for school projects. Latency: Discord ~200 ms, IFTTT ~5–15 s. The pattern: POST JSON to URL → service does something. From here you can wire any sensor event to any digital service. Tomorrow we polish into a portable doorbell — Cluster G's capstone.
- IFTTT (If This Then That)
- A free service that bridges triggers from one app to actions in another. Webhooks integration lets your Arduino fire a trigger.
- Maker Webhooks
- IFTTT's built-in webhook receiver. URL format
https://maker.ifttt.com/trigger/EVENT/with/key/KEY. Accepts an optional JSON body withvalue1,value2,value3. - Discord embed
- A coloured-stripe card sent in a Discord message. JSON shape includes title, description, color, fields. Much more legible than plain text for status updates.
- Webhook URL
- The address a service exposes for incoming triggers. Treat as a secret — anyone with the URL can fire your trigger.
- Recipe / applet
- The trigger + action pairing in IFTTT. One recipe per webhook → notification, or webhook → Google Sheet append.
- Template variable
- Placeholders in IFTTT recipe text like
{{Value1}}that get filled in from the webhook payload. - Fire-and-forget
- Sending a request without waiting for the response. Reduces latency in the trigger loop; loses error visibility.
- Username override
- Discord webhook field that lets each message appear as a custom name / avatar, even though it's coming from a generic webhook.
Extra Mission 5 min
Part 1 — Design a home automation
Think of an event at home that is worth a message. Ideas: a plant that has been dry for an hour, a fridge door left open, post arriving in the letterbox. Pick one and design the full automation on paper.
Your design must include:
- The sensor or switch that fires the trigger, and the exact rule (for example "open for more than 60 s").
- The Discord embed: title, colour and at least two fields.
- The IFTTT event name and what
value1,value2andvalue3carry. - What the phone notification says.
- The cooldown, so the event cannot spam you.
Part 2 — Make it
Build your automation on the ESP, starting from the dual-webhook sketch. Use a button or switch to stand in for any sensor you do not have. Print both JSON bodies to the Serial Monitor before you send them, so you can check them.
Bring back next class: your design, your uploaded sketch, and screenshots of the Discord embed and the phone notification.