Using N8n WhatsApp Controlled Home Automation Using ESP32
by SRK597 in Circuits > Microcontrollers
238 Views, 1 Favorites, 0 Comments
Using N8n WhatsApp Controlled Home Automation Using ESP32
Controlling electronic devices remotely has always been a fascinating project for makers and IoT enthusiasts. In this guide, we'll walk through how we built a system to control an ESP32 relay using WhatsApp messages via Twilio, n8n, Adafruit IO, and ngrok.
Supplies
Before diving into the implementation, let's review the essential components and tools required for this project:
● ESP32 development board - The main microcontroller that will control the relay
● Relay module - Connected to ESP32 for switching electrical devices
● n8n workflow automation tool - Acts as the middleware to process messages
● Twilio WhatsApp Sandbox - Enables WhatsApp integration for messaging
● Adafruit IO (MQTT) - Cloud service for IoT data communication
● ngrok - Creates secure tunnels to localhost for webhook testing
● PowerShell / Terminal - For testing HTTP requests locally
● Your PC with internet connection - Development environment
The beauty of this project lies in how these different services work together seamlessly. Each component plays a specific role: ESP32 handles the hardware control, Adafruit IO manages the data flow, n8n processes the logic, and Twilio bridges WhatsApp communication.
⚙️Step 1: Setting Up ESP32 with Relay
We programmed the ESP32 in Arduino IDE with C++ code to subscribe to Adafruit IO MQTT feed. The logic is straightforward: when it receives ON → Relay turns ON, OFF → Relay turns OFF.
The ESP32 continuously monitors the MQTT feed for incoming messages and responds accordingly. This approach ensures real-time responsiveness while maintaining a stable connection.
ESP32 Arduino Code (C++)
#include <WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#define WLAN_SSID "your_wifi_name"
#define WLAN_PASS "your_wifi_password"
#define AIO_SERVER "io.adafruit.com"
#define AIO_SERVERPORT 1883
#define AIO_USERNAME "SRK05"
#define AIO_KEY "your_adafruit_io_key"
WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
Adafruit_MQTT_Subscribe relay = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/light");
#define RELAY_PIN 2
void setup() {
pinMode(RELAY_PIN, OUTPUT);
Serial.begin(115200);
WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected!");
mqtt.subscribe(&relay);
}
void loop() {
MQTT_connect();
Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(1000))) {
if (subscription == &relay) {
String command = (char *)relay.lastread;
Serial.print("Received: ");
Serial.println(command);
if (command == "ON") {
digitalWrite(RELAY_PIN, HIGH);
Serial.println("Relay turned ON");
}
else if (command == "OFF") {
digitalWrite(RELAY_PIN, LOW);
Serial.println("Relay turned OFF");
}
}
}
}
void MQTT_connect() {
int8_t ret;
if (mqtt.connected()) {
return;
}
Serial.print("Connecting to MQTT... ");
uint8_t retries = 3;
while ((ret = mqtt.connect()) != 0) {
Serial.println(mqtt.connectErrorString(ret));
Serial.println("Retrying MQTT connection in 5 seconds...");
mqtt.disconnect();
delay(5000);
retries--;
if (retries == 0) {
while (1);
}
}
Serial.println("MQTT Connected!");
}
Important: Make sure to replace the WiFi credentials and Adafruit IO key with your actual values. The relay pin is set to GPIO 2, but you can modify this based on your hardware setup.
⚙️Step 2: Create Adafruit IO Feed
Setting up Adafruit IO is straightforward, but getting the configuration right is crucial for the entire system to work:
1. Navigate to Adafruit IO and create a free account
2. Click on "Feeds" in the left sidebar
3. Create a new feed called light
4. Go to "My Key" section and copy your AIO Key and username (in our case SRK05)
5. Note down the full topic path: username/feeds/feedname
The feed acts as a communication channel between your n8n workflow and the ESP32. Think of it as a mailbox where messages are delivered and picked up by different services.
Pro Tip: Keep your AIO key secure and never commit it to public repositories. Consider using environment variables for production deployments.
⚙️Step 3: Set Up n8n Workflow
The n8n workflow is the brain of our system. It orchestrates the entire process by receiving WhatsApp messages, processing them, and triggering appropriate responses.
We created an n8n workflow to:
1. Receive WhatsApp message via Twilio Webhook
2. Parse and validate the message content (ON or OFF)
3. Publish the command to Adafruit IO via MQTT
4. Send a confirmation response back to WhatsApp
Workflow Overview
The workflow consists of several interconnected nodes that handle different aspects of the message processing pipeline. Each node has a specific responsibility, making the system modular and easy to troubleshoot.
Key Nodes:
1. Webhook Trigger
The webhook trigger is the entry point for all incoming WhatsApp messages from Twilio:
● HTTP Method: POST
● Path: /webhook/twilio-wa
● Authentication: None (handled by Twilio's security)
Configure the webhook to automatically respond to incoming requests. This ensures Twilio receives acknowledgment within the required timeframe.
2. Set Pin Node
This node extracts and processes the message body from the incoming webhook data. We use n8n's expression editor to parse the WhatsApp message content:
{{$json.body && $json.body.Body ? $json.body.Body.toUpperCase().trim() : ""}}
The expression handles potential null values and normalizes the input by converting to uppercase and removing whitespace. This makes the system more robust against user input variations.
3. IF Node (ON/OFF Validation)
The IF node validates whether the received message contains a valid command. This prevents invalid commands from being sent to the ESP32:
● Condition Type: Expression
● Expression: {{$json["pin"]}} matches regex ^(ON|OFF)$
Valid commands proceed to the MQTT publishing step, while invalid commands trigger an error response.
4. MQTT Publish to Adafruit IO
This node publishes the validated command to the Adafruit IO MQTT broker:
● Protocol: MQTT
● Host: io.adafruit.com
● Port: 1883
● Username: Your Adafruit IO username
● Password: Your AIO key
● Topic: SRK05/feeds/light
● Message: {{$json["pin"]}}
The MQTT protocol ensures reliable message delivery even if there are temporary network issues.
5. Respond to Webhook (Reply to WhatsApp)
The final node sends a confirmation message back to WhatsApp using Twilio's response format:
{{$json["pin"]
? `<Response><Message>✅ Light ${$json["pin"]}</Message></Response>`
: `<Response><Message>❌ Please send ON or OFF</Message></Response>`}}
● Response Headers: Content-Type: text/xml
● Status Code: 200
The XML format follows Twilio's TwiML specification for WhatsApp messaging.
⚙️Step 4: ngrok Tunnel Setup
Since n8n runs locally during development, we need ngrok to create a secure tunnel that allows Twilio to reach our webhook endpoint. This is essential for testing before deploying to production.
First, install ngrok and authenticate with your account:
# Download ngrok from https://ngrok.com/download
# Install and authenticate
ngrok config add-authtoken YOUR_REAL_TOKEN
# Start tunnel for n8n (default port 5678)
ngrok http 5678
Once started, ngrok provides a public URL that forwards to your local n8n instance. The URL looks something like: https://abc123.ngrok-free.app
Security Note: The free ngrok plan provides public URLs that anyone can access. For production use, consider ngrok's paid plans or deploy n8n to a cloud server.
⚙️Step 5: Configure Twilio WhatsApp Sandbox
Twilio's WhatsApp Sandbox allows you to test WhatsApp functionality without going through the full WhatsApp Business API approval process.
Follow these steps to configure the sandbox:
1. Go to Twilio Console
2. Navigate to "Messaging" > "Try it out" > "Send a WhatsApp message"
3. In the "Sandbox settings" section, configure the webhook URL:
○ When a message comes in: https://your-ngrok-url.ngrok-free.app/webhook/twilio-wa
○ HTTP Method: POST
4. Save the configuration
5. Join the sandbox by sending the provided join code to +14155238886
The join process typically involves sending a message like "join [code]" to Twilio's WhatsApp
⚙️Step 6: Testing with PowerShell
Before testing with actual WhatsApp messages, it's good practice to test the webhook locally using PowerShell or curl. This helps isolate issues and verify the workflow logic.
# Test ON command
Invoke-WebRequest `
-Uri "http://localhost:5678/webhook/twilio-wa" `
-Method POST `
-Headers @{ "Content-Type" = "application/x-www-form-urlencoded" } `
-Body "Body=ON&From=whatsapp:+919445540390"
# Expected Response:
# <Response><Message>✅ Light ON</Message></Response>
# Test OFF command
Invoke-WebRequest `
-Uri "http://localhost:5678/webhook/twilio-wa" `
-Method POST `
-Headers @{ "Content-Type" = "application/x-www-form-urlencoded" } `
-Body "Body=OFF&From=whatsapp:+919445540390"
# Test invalid command
Invoke-WebRequest `
-Uri "http://localhost:5678/webhook/twilio-wa" `
-Method POST `
-Headers @{ "Content-Type" = "application/x-www-form-urlencoded" } `
-Body "Body=INVALID&From=whatsapp:+919445540390"
Monitor the n8n execution log and ESP32 serial monitor to verify that commands are processed correctly end-to-end
⚙️Step 7: Final Testing with WhatsApp
Now comes the exciting part - testing the complete system with actual WhatsApp messages:
1. Open WhatsApp and find your conversation with the Twilio sandbox number
2. Send ON - You should see the relay activate and receive "✅ Light ON" response
3. Send OFF - The relay should deactivate and you'll receive "✅ Light OFF" response
4. Try sending invalid commands to test error handling
The entire process typically takes 1-3 seconds from sending the WhatsApp message to seeing the relay respond. The response time depends on network conditions and server load.
During my testing, I found that the system works reliably even with poor network conditions, thanks to MQTT's built-in retry mechanisms and Twilio's robust messaging infrastructure
🚨 Troubleshooting
Based on common issues encountered during development and testing, here are solutions to frequent problems:
Error: Webhook not found (404)
● Cause: n8n workflow is not active or webhook path is incorrect
● Solution:
○ Ensure workflow is Active in n8n (toggle switch should be blue)
○ Verify webhook path matches exactly: /webhook/twilio-wa
○ Check ngrok tunnel is still running and URL hasn't changed
"items not defined" error in Code node
● Cause: Using outdated n8n syntax
● Solution: Replace old code nodes with Set nodes and use expressions like {{$json.fieldname}}
Authtoken error in ngrok
● Cause: Invalid or missing authentication token
● Solution:
○ Get your real token from ngrok dashboard (not the example token)
○ Run: ngrok config add-authtoken YOUR_ACTUAL_TOKEN
No data appearing in Adafruit IO
● Cause: MQTT topic mismatch or authentication issues
● Solution:
○ Verify topic format exactly: username/feeds/feedname
○ Check AIO key is correct and has not expired
○ Monitor n8n execution logs for MQTT connection errors
ESP32 not responding to commands
● Cause: WiFi connectivity or MQTT subscription issues
● Solution:
○ Check serial monitor for connection status
○ Verify WiFi credentials are correct
○ Ensure ESP32 and Adafruit IO are using the same feed name
WhatsApp messages not triggering workflow
● Cause: Twilio webhook configuration or ngrok tunnel issues
● Solution:
○ Verify ngrok URL is still active (they expire after 8 hours on free plan)
○ Check Twilio webhook URL matches current ngrok URL
○ Test webhook directly with PowerShell first
📌 Recommendations
To enhance this project further and make it production-ready, consider these improvements:
Add Status Command
Implement a STATUS command that returns the current relay state. This requires storing the state in a database or querying the ESP32 directly.
Deploy n8n on Cloud
For 24/7 reliability, deploy n8n on a VPS or cloud platform like:
● DigitalOcean Droplet
● AWS EC2
● Google Cloud Platform
● Railway or Render for easier deployment
Security Enhancements
● Restrict allowed WhatsApp numbers by checking the From field
● Implement rate limiting to prevent spam
● Use API keys for additional authentication layers
● Consider using Twilio's signature verification for webhook security
Advanced Features
● Add scheduling capabilities ("Turn ON at 6 PM")
● Implement multiple device control
● Create a web dashboard for monitoring
● Add logging and analytics
● Support for voice messages using speech-to-text
Error Handling
● Add retry logic for failed MQTT publishes
● Implement dead letter queues for failed messages
Conclusion
We successfully built a project where sending ON/OFF messages in WhatsApp controls an ESP32 relay in real-time, with confirmations sent back to WhatsApp. This integrates Twilio, n8n, Adafruit IO, and ngrok into one smooth IoT pipeline.