Most developers automatically reach for C++ and the Arduino IDE when working with the ESP32. But there is another way that makes prototyping incredibly fast, lightweight, and surprisingly fun: Lua. Running the NodeMCU firmware on your ESP32 allows you to write scripts that run instantly on the microchip without waiting minutes for compiler chains to finish. This guide gets you up and running with your very first Lua script on the ESP32 to publish and subscribe to data over MQTT.
Table of Contents
- Flashing NodeMCU Lua onto the ESP32
- The Wi-Fi and MQTT Lua Script
- Uploading, Running, and Monitoring Your Script
- Pro-Tips for Production-Ready Lua IoT Nodes
- Frequently Asked Questions
Flashing NodeMCU Lua onto the ESP32
Before writing a single line of Lua, you need to load the NodeMCU firmware onto your ESP32 chip. NodeMCU is an open-source firmware that embeds a Lua interpreter directly inside the microchip. Because NodeMCU is modular, you only build and flash the features you actually need, saving valuable RAM and system storage.
To get started, you will need to obtain a compiled NodeMCU ESP32 binary. Make sure your build configuration has the wifi, mqtt, net, and gpio modules enabled. Once you have downloaded your firmware binary (usually a .bin file), connect your ESP32 to your computer using a high-quality micro-USB or USB-C cable. You can use the command-line tool esptool.py or a graphical application like NodeMCU PyFlasher to push the firmware onto the board.
If you prefer using the command-line tool, a standard flashing command looks like this:
esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 write_flash -z 0x1000 nodemcu-firmware.bin
Make sure you replace the port with your computer's specific serial port. Once flashed, your ESP32 is ready to run Lua scripts dynamically on boot.

NodeMCU PyFlasher graphical interface showing an ESP32 selected with a custom binary containing WiFi and MQTT modules ready to flash
The Wi-Fi and MQTT Lua Script
One of the best features of using Lua on the ESP32 is how clean the code looks compared to equivalent C++ setups. We do not need to write complex pointer logic or manage messy header files. We simply write an event-driven script that configures our Wi-Fi connection, initializes our MQTT client, connects to a public broker, and handles incoming messages.
Let's write a file called init.lua. This file name is special because NodeMCU automatically runs any file named init.lua as soon as the ESP32 boots up. Here is a robust, clean script to get you connected:
-- Configure WiFi Credentials
local wifi_ssid = "Your_WiFi_SSID"
local wifi_password = "Your_WiFi_Password"
-- MQTT Settings
local mqtt_broker = "broker.hivemq.com"
local mqtt_port = 1883
local client_id = "ESP32_Lua_Demo"
local pub_topic = "esp32/lua/status"
local sub_topic = "esp32/lua/commands"
-- Set WiFi to Station mode and connect
wifi.setmode(wifi.STATION)
wifi.start()
local station_cfg = {}
station_cfg.ssid = wifi_ssid
station_cfg.pwd = wifi_password
wifi.sta.config(station_cfg)
-- Create MQTT Client
local client = mqtt.Client(client_id, 120)
-- Subscribe callback
client:on("message", function(conn, topic, data)
print("Received raw payload on topic: " .. topic)
if data ~= nil then
print("Payload: " .. data)
end
end)
-- Main execution flow
function start_mqtt()
print("Connecting to MQTT Broker...")
client:connect(mqtt_broker, mqtt_port, false, function(conn)
print("Successfully connected to MQTT Broker!")
-- Subscribe to commands topic
client:subscribe(sub_topic, 0, function(conn)
print("Successfully subscribed to " .. sub_topic)
end)
-- Periodically publish status updates every 10 seconds
tmr.create():alarm(10000, tmr.ALARM_AUTO, function()
local heap_size = node.heap()
local payload = '{"status": "online", "free_heap": ' .. heap_size .. '}'
client:publish(pub_topic, payload, 0, 0, function(conn)
print("Sent payload to broker: " .. payload)
end)
end)
end, function(conn, reason)
print("MQTT Connection failed. Reason code: " .. reason)
end)
end
-- Monitor Wi-Fi connection status
wifi.sta.on("got_ip", function(ev, info)
print("WiFi connected! IP address assigned: " .. info.ip)
-- Start MQTT after ensuring we have a stable IP address
start_mqtt()
end)
wifi.sta.on("disconnected", function(ev, info)
print("WiFi connection lost. Reconnecting...")
end)
This script first sets up the hardware Wi-Fi radio. Instead of using a blocking loop that halts execution while waiting for an IP address, NodeMCU uses event listeners. Once the got_ip event fires, the script triggers the start_mqtt() function. From there, we connect to the HiveMQ public broker, subscribe to our input topic, and use a hardware timer to periodically push status telemetry back to the cloud.

Visual flowchart showing the asynchronous event-driven lifecycle of the Lua script from Wi-Fi boot to IP assignment and MQTT connection
Hands-On Experience: Why I Moved to Lua for IoT Prototyping
Honestly, I've tried this myself on several smart home projects where I got incredibly tired of waiting for Arduino's compiler chain to finish. If you have ever spent hours tweaking minor telemetry formatting issues, compiling the entire sketch, uploading it, and discovering a small syntax bug, you know how exhausting that loop can be. When I switched to NodeMCU Lua, that compile-time frustration completely vanished. I could write scripts, upload them in seconds, and execute them on-the-fly. The scripting nature of Lua combined with the fast upload speeds makes debugging feel like you're working with a web browser's console rather than dealing with bare-metal microcontrollers.
Uploading, Running, and Monitoring Your Script
To transfer your init.lua file to the ESP32, you will need a serial uploader utility. While you can use command-line options like nodemcu-tool, a visual tool called ESPlorer is excellent for beginners. It includes a built-in text editor, serial monitor, and quick-action buttons to run and format files on the ESP32 file system.
Open ESPlorer, select your ESP32 serial port, set the baud rate to 115200, and click Open. Once connected, press the reset button on your ESP32 to verify you see the boot messages. Copy the code above into the editor, save it on your computer as init.lua, and then click the Save to ESP button at the bottom of the interface. ESPlorer will upload the script directly into the ESP32 flash memory.
To test that everything works as intended, open an MQTT client on your computer, such as MQTT Explorer. Connect to broker.hivemq.com on port 1883. Subscribe to the topic esp32/lua/status. Within ten seconds, you should see JSON messages appearing in your client showing the free heap memory of your board. To test the opposite direction, publish a test string to esp32/lua/commands and watch the ESPlorer console output print the received payload in real-time.

Screen capture of ESPlorer showing console logs of the connected ESP32 and MQTT Explorer showing incoming JSON state payloads from the device
Pro-Tips for Production-Ready Lua IoT Nodes
While Lua is amazing for quick builds, there are a few practical rules you should follow to ensure your devices remain stable over weeks and months of continuous operation:
Memory Management is Key: Unlike computers, the ESP32 has limited RAM. Always declare your variables locally by using thelocalkeyword. This ensures they go out of scope quickly and can be picked up by Lua's automatic garbage collection engine. You can manually force garbage collection usingcollectgarbage().
Always Handle Reconnection: In any practical deployment, Wi-Fi or MQTT will drop at some point. Ensure your code registers callback handlers for both Wi-Fi drops and MQTT disconnects to automatically attempt re-connection without crashing the system loop.
Frequently Asked Questions
Is Lua on the ESP32 slower than C++?Yes, because Lua is an interpreted language, it runs slower and uses more RAM than optimized C++. However, for standard IoT tasks like reading sensors, managing relays, and sending MQTT telemetry, the performance difference is negligible.
Can I still use standard ESP32 sensors like DHT22 or DS18B20 with Lua?Absolutely. The NodeMCU firmware has pre-built modules for standard sensors, SPI, I2C, and PWM. You just need to compile these modules into your firmware binary when flashing.
What happens if my init.lua has an infinite loop that crashes my ESP32?This is a common issue for beginners. If your script crashes the ESP32 in an infinite loop, you can quickly format the SPIFFS filesystem using esptool.py erase_flash and re-flash the firmware to start fresh.
Need Digital Solutions?
Looking for business automation, a stunning website, or a mobile app? Let's have a chat with our team. We're ready to bring your ideas to life:
- Bots & IoT (Automated systems to streamline your workflow)
- Web Development (Landing pages, Company Profiles, or E-commerce)
- Mobile Apps (User-friendly Android & iOS applications)
Free consultation via WhatsApp: 082272073765
Posting Komentar untuk "Forget C++: How to Build Your First ESP32 MQTT Project Using Lua"