In this article, I'll show you how to connect your ESP8266 or ESP32 microcontroller to a Node.js application using HiveMQ's public MQTT broker. HiveMQ offers a reliable cloud-based MQTT broker that's perfect for IoT projects, providing better reliability than public test brokers for your applications.
HiveMQ provides:
A free public broker for testing
High reliability and uptime
WebSocket support for browser-based clients
Scalability for when your project grows
ESP8266 or ESP32 development board
Arduino IDE (for programming the ESP)
Node.js installed on your computer
Basic knowledge of JavaScript and Arduino programming
For the HiveMQ public broker, use these connection details:
Broker URL: broker.hivemq.com
Port: 1883 (MQTT) or 8883 (MQTT over TLS)
WebSocket: 8000 (ws) or 8884 (wss)
No authentication is required for the public broker, but consider this for production:
const client = mqtt.connect('mqtt://broker.hivemq.com:1883', {
clientId: 'your-unique-client-id',
// username: 'your-username', // For authenticated brokers
// password: 'your-password' // For authenticated brokers
});
Install the PubSubClient library in your Arduino IDE if you haven't already.
Here's the updated ESP code for HiveMQ:
#include <ESP8266WiFi.h> // Use #include <WiFi.h> for ESP32
#include <PubSubClient.h>
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
const char* mqtt_server = "broker.hivemq.com";
WiFiClient espClient;
PubSubClient client(espClient);
// Generate a unique client ID
String clientId = "ESP8266Client-";
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// Handle different commands
if (message == "LED_ON") {
digitalWrite(LED_BUILTIN, LOW);
client.publish("esp8266/status", "LED is ON");
} else if (message == "LED_OFF") {
digitalWrite(LED_BUILTIN, HIGH);
client.publish("esp8266/status", "LED is OFF");
}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str())) {
Serial.println("connected");
client.subscribe("esp8266/commands"); // Subscribe to commands topic
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Publish a heartbeat message every 10 seconds
unsigned long now = millis();
if (now - lastMsg > 10000) {
lastMsg = now;
snprintf(msg, MSG_BUFFER_SIZE, "heartbeat #%ld", lastMsg);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("esp8266/heartbeat", msg);
}
}
Create a new Node.js project:
npm init -y
npm install mqtt express
Here's an enhanced Node.js server that connects to HiveMQ:
const mqtt = require('mqtt');
const express = require('express');
const app = express();
const path = require('path');
// Connect to HiveMQ broker
const client = mqtt.connect('mqtt://broker.hivemq.com:1883', {
clientId: 'nodejs-client-' + Math.random().toString(16).substr(2, 8),
clean: true,
reconnectPeriod: 1000
});
// Middleware
app.use(express.json());
app.use(express.static(path.join(__dirname, 'public')));
// MQTT Connection handlers
client.on('connect', () => {
console.log('Connected to HiveMQ broker');
// Subscribe to ESP topics
client.subscribe('esp8266/status', (err) => {
if (!err) console.log('Subscribed to esp8266/status');
});
client.subscribe('esp8266/heartbeat', (err) => {
if (!err) console.log('Subscribed to esp8266/heartbeat');
});
});
// Handle incoming messages
client.on('message', (topic, message) => {
console.log(`Received message on ${topic}: ${message.toString()}`);
// You could store this in a database or process it further
});
// API endpoint to send commands
app.post('/api/command', (req, res) => {
const { command } = req.body;
if (!command) {
return res.status(400).json({ error: 'Command is required' });
}
client.publish('esp8266/commands', command, { qos: 1 }, (err) => {
if (err) {
return res.status(500).json({ error: 'Failed to send command' });
}
res.json({ status: 'Command sent', command });
});
});
// Web interface
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
// Error handling
client.on('error', (err) => {
console.error('MQTT error:', err);
});
process.on('SIGINT', () => {
client.end();
process.exit();
});
Create a public/index.html
file with a more interactive UI:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP Control via HiveMQ</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.control-panel {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
button {
padding: 12px 24px;
font-size: 16px;
cursor: pointer;
border: none;
border-radius: 4px;
}
#led-on {
background-color: #4CAF50;
color: white;
}
#led-off {
background-color: #f44336;
color: white;
}
#toggle-led {
background-color: #2196F3;
color: white;
}
#status {
padding: 15px;
background-color: #f8f8f8;
border-radius: 4px;
margin-top: 20px;
}
.logs {
margin-top: 30px;
border: 1px solid #ddd;
padding: 10px;
height: 200px;
overflow-y: auto;
background-color: #f9f9f9;
}
</style>
</head>
<body>
<h1>ESP8266/ESP32 Control Panel</h1>
<p>Connected via HiveMQ MQTT Broker</p>
<div class="control-panel">
<button id="led-on">Turn LED ON</button>
<button id="led-off">Turn LED OFF</button>
<button id="toggle-led">Toggle LED</button>
</div>
<div id="status">Status: Waiting for updates...</div>
<h2>Event Log</h2>
<div class="logs" id="event-log"></div>
<script>
// DOM elements
const ledOnBtn = document.getElementById('led-on');
const ledOffBtn = document.getElementById('led-off');
const toggleBtn = document.getElementById('toggle-led');
const statusDiv = document.getElementById('status');
const eventLog = document.getElementById('event-log');
// Add timestamp to logs
function getTimestamp() {
return new Date().toLocaleTimeString();
}
// Add message to event log
function addLog(message) {
const logEntry = document.createElement('div');
logEntry.textContent = `[${getTimestamp()}] ${message}`;
eventLog.appendChild(logEntry);
eventLog.scrollTop = eventLog.scrollHeight;
}
// Send command to ESP
async function sendCommand(command) {
try {
const response = await fetch('/api/command', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ command })
});
const data = await response.json();
addLog(`Command sent: ${data.command}`);
} catch (err) {
addLog(`Error: ${err.message}`);
console.error('Error:', err);
}
}
// Button event listeners
ledOnBtn.addEventListener('click', () => sendCommand('LED_ON'));
ledOffBtn.addEventListener('click', () => sendCommand('LED_OFF'));
toggleBtn.addEventListener('click', () => sendCommand('TOGGLE_LED'));
// Connect to MQTT via WebSocket for real-time updates
// Note: This requires the server to support WebSocket proxying or CORS
// Alternatively, you could use Server-Sent Events or polling
const eventSource = new EventSource('/api/events');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.topic === 'esp8266/status') {
statusDiv.textContent = `Status: ${data.message}`;
addLog(`Status update: ${data.message}`);
} else if (data.topic === 'esp8266/heartbeat') {
addLog(`Heartbeat: ${data.message}`);
}
};
eventSource.onerror = (err) => {
addLog('EventSource error:', err);
};
</script>
</body>
</html>
To make the web interface truly real-time without polling, add SSE support to your Node.js server:
// Add this near the top with other requires
const { EventEmitter } = require('events');
const mqttEvents = new EventEmitter();
// Modify the message handler to emit events
client.on('message', (topic, message) => {
console.log(`Received message on ${topic}: ${message.toString()}`);
mqttEvents.emit('mqtt_message', { topic, message: message.toString() });
});
// Add SSE endpoint
app.get('/api/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const sendEvent = (data) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
mqttEvents.on('mqtt_message', sendEvent);
req.on('close', () => {
mqttEvents.off('mqtt_message', sendEvent);
});
});
While the public HiveMQ broker is great for testing, remember:
No authentication: Anyone can subscribe to your topics
No encryption: Data is sent in clear text (use port 8883 for TLS)
Unique topics: Use unique, complex topic names to avoid collisions
Client IDs: Ensure your client IDs are unique
For production, consider:
Using HiveMQ Cloud with authentication
Implementing your own MQTT broker with proper security
Adding TLS encryption
Implementing application-level security
This implementation gives you a solid foundation. You could extend it by:
Adding sensor data collection from the ESP
Implementing a database to store historical data
Creating user authentication for the web interface
Building a mobile app that connects to the same MQTT topics
Adding OTA (Over-The-Air) updates for your ESP
You've now created a complete system where:
Your ESP device connects to HiveMQ's public broker
A Node.js server also connects to the same broker
You have a web interface to control the ESP
Status updates are shown in real-time
This architecture is scalable and can be the foundation for more complex IoT applications. The use of HiveMQ ensures reliable message delivery, and the separation of components makes your system more maintainable
Join parminder on Peerlist!
Join amazing folks like parminder and thousands of other people in tech.
Create ProfileJoin with parminder’s personal invite link.
1
12
0