Sitemap
Janaarthan Manohar

Janaarthan Manohar

Software Engineer having 9+ years of IT experience

Controlling an LED Using AWS IoT Core and ESP-12E NodeMCU

10 min readSep 17, 2026

--

From Cloud Command to Physical LED Control Using AWS IoT Core

Press enter or click to view image in full size

The Internet of Things (IoT) becomes particularly interesting when a command generated in the cloud can produce a physical action in the real world.

As my first milestone in exploring AWS IoT and embedded systems, I built a simple IoT-controlled LED system using an ESP-12E NodeMCU, AWS IoT Core, an MQTT connection, and a 5 V relay module.

The objective was straightforward:

Send a command from AWS IoT Core → ESP-12E receives the MQTT message → relay changes state → LED turns ON or OFF.

This experiment establishes the foundation for a more practical home-automation setup. The current prototype controls a low-power LED, and the next enhancement will be to extend the setup to control a 9 W household LED bulb using the relay.

1. What I Built

The prototype consists of the following components:

  • ESP-12E NodeMCU
  • Wi-Fi network
  • AWS IoT Core
  • MQTT
  • 5 V relay module
  • Red LED
  • 3.75 V Li-ion battery/power source for the LED
  • 5 V power supply for the NodeMCU
  • Breadboard
  • Jumper wires

The ESP-12E acts as the IoT device. It connects to the local Wi-Fi network and establishes a secure MQTT connection with AWS IoT Core.

Press enter or click to view image in full size

Once connected, the ESP subscribes to an MQTT topic:

led/controller/command

Commands published to this topic are received by the ESP-12E and translated into physical actions.

For example:

LED_ON

causes the relay to switch ON, while:

LED_OFF

causes the relay to switch OFF.

2. High-Level Architecture

The complete flow can be represented as:

AWS Cloud
┌─────────────────┐
│ AWS IoT Core │
│ │
│ MQTT Topic │
│ led/controller/ │
│ command │
└────────┬────────┘
│
│ Secure MQTT
│ TLS / Port 8883
▼
┌─────────────────────┐
│ ESP-12E NodeMCU │
│ │
│ Wi-Fi + MQTT Client │
└──────────┬──────────┘
│
│ GPIO
▼
┌─────────────┐
│ 5 V Relay │
└──────┬──────┘
│
│ Switching
▼
┌─────────┐
│ Red LED │
└─────────┘

The important aspect of this architecture is that the ESP-12E does not need to expose an HTTP endpoint to the internet.

Instead, it maintains an outbound secure MQTT connection to AWS IoT Core and receives commands through an MQTT subscription.

3. Why AWS IoT Core and MQTT?

MQTT is widely used in IoT applications because it follows a lightweight publish/subscribe communication model.

Rather than having the ESP constantly poll a server for commands, it subscribes to a topic and waits for messages.

In this experiment:

Publisher
|
| LED_ON
▼
AWS IoT Core
|
| MQTT
▼
ESP-12E
|
▼
Relay
|
▼
LED

This model can later be extended to multiple devices and multiple topics without fundamentally changing the architecture.

For example:

home/livingroom/light
home/bedroom/light
home/kitchen/light
home/garage/light

Each device can subscribe to the topic relevant to it.

4. AWS IoT Core Setup

The first step was to create an IoT Thing in AWS IoT Core.

The Thing used for this experiment is:

led_controller_01

The AWS IoT endpoint is specific to the AWS account and region.

The ESP-12E connects to this endpoint using MQTT over TLS on port:

8883

The connection uses certificate-based authentication.

The ESP therefore needs:

  1. AWS IoT Root CA certificate
  2. Device certificate
  3. Device private key

These credentials allow AWS IoT Core to authenticate the device.

Security note: Never publish the actual device certificate/private key in a public GitHub repository or blog post. The certificate and private key shown in the source code for this article should always be replaced with placeholders.

5. MQTT Topic

The MQTT topic used in this experiment is:

led/controller/command

The ESP-12E subscribes to this topic after establishing the AWS IoT connection.

The device can then receive commands such as:

LED_ON
LED_OFF

Additional commands have also been included in the program to prepare the application for future expansion:

RED_ON
RED_OFF

GREEN_ON
GREEN_OFF

BLUE_ON
BLUE_OFF

ALL_ON
ALL_OFF

The current hardware implementation only physically controls the relay/LED for the commands that are implemented.

The additional commands provide a foundation for expanding the project to multiple LEDs or RGB lighting.

6. ESP-12E Wi-Fi Connection

The ESP-12E first connects to the configured Wi-Fi network.

The relevant logic is:

void connectWiFi() {
Serial.println();
Serial.print("Connecting to Wi-Fi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("Wi-Fi connected!");
Serial.print("ESP IP Address: ");
Serial.println(WiFi.localIP());
}

Once the connection is established, the ESP prints its IP address to the Serial Monitor.

For example:

Wi-Fi connected!
ESP IP Address: 192.168.x.x

The ESP is now ready to communicate with AWS IoT Core.

7. Why Time Synchronization Is Required

One of the interesting aspects of establishing a TLS connection from an embedded device is that the device needs an accurate system clock.

The ESP synchronizes its time using NTP:

configTime(
0,
0,
"pool.ntp.org",
"time.nist.gov"
);

The program waits until a valid time is obtained:

time_t now = time(nullptr);
while (now < 100000) {
delay(500);
Serial.print(".");
now = time(nullptr);
}

This is important because TLS certificate validation depends on certificate validity periods.

The simplified startup sequence therefore becomes:

ESP Startup
|
▼
Connect to Wi-Fi
|
▼
Synchronize NTP time
|
▼
Configure TLS certificates
|
▼
Connect to AWS IoT Core

8. Secure MQTT Connection

The ESP8266 provides the WiFiClientSecure class for secure network communication.

The application creates:

WiFiClientSecure net;
PubSubClient client(net);

The AWS certificates are loaded using BearSSL:

BearSSL::X509List* ca =
new BearSSL::X509List(AWS_CERT_CA);
BearSSL::X509List* cert =
new BearSSL::X509List(AWS_CERT_CRT);
BearSSL::PrivateKey* privateKey =
new BearSSL::PrivateKey(AWS_CERT_PRIVATE);

The certificates are then configured:

net.setTrustAnchors(ca);
net.setClientRSACert(
cert,
privateKey
);

Finally, the MQTT server is configured:

client.setServer(
AWS_IOT_ENDPOINT,
8883
);

The result is an MQTT connection protected by TLS.

9. Connecting the ESP-12E to AWS IoT Core

The device uses the Thing name as its MQTT client identifier:

client.connect(THING_NAME)

The Thing name in this project is:

led_controller_01

After successfully connecting, the ESP subscribes to:

led/controller/command

The program prints messages similar to:

Connecting to AWS IoT Core...
Thing Name: led_controller_01
Endpoint: <endpoint>.amazonaws.com
AWS IoT Core connected!
Subscribed to: led/controller/command

At this point, the complete cloud-to-device communication path is operational.

10. Receiving MQTT Commands

The PubSubClient library invokes the callback function whenever an MQTT message arrives.

The callback is:

void messageReceived(
char* topic,
byte* payload,
unsigned int length)

The received payload is converted into a String:

String message;
for (unsigned int i = 0; i < length; i++) {
message += (char) payload[i];
}

The command is then evaluated.

Get Janaarthan Manohar’s stories in your inbox

Join Medium for free to get updates from this writer.

For example:

if (message == "LED_ON") {
relayOn();
}
else if (message == "LED_OFF") {
relayOff();
}

This provides a very simple command protocol between AWS IoT Core and the embedded device.

11. Controlling the Relay

The relay is connected to the ESP-12E using:

#define RELAY_PIN D1

The prototype uses an active-low relay configuration:

#define RELAY_ON  LOW
#define RELAY_OFF HIGH

The relay ON operation is:

void relayOn() {
digitalWrite(RELAY_PIN, RELAY_ON);
Serial.println("Relay ON - LED Bulb ON");
}

The OFF operation is:

void relayOff() {
digitalWrite(RELAY_PIN, RELAY_OFF);
Serial.println("Relay OFF - LED Bulb OFF");
}

The program also explicitly turns the relay OFF during startup:

pinMode(RELAY_PIN, OUTPUT);
digitalWrite(
RELAY_PIN,
RELAY_OFF
);

This is a useful safety measure because it prevents the connected load from unintentionally being switched ON during boot.

12. End-to-End Test

Once the ESP-12E is connected to AWS IoT Core, a message can be published to:

led/controller/command

with the payload:

LED_ON

The message travels through the following path:

AWS IoT Core
|
| LED_ON
▼
MQTT Subscription
|
▼
ESP-12E
|
▼
messageReceived()
|
▼
relayOn()
|
▼
GPIO D1 = LOW
|
▼
Relay Activated
|
▼
LED ON

The reverse operation works in exactly the same way:

LED_OFF

causes the relay to deactivate and the LED to turn OFF.

13. Serial Monitor Output

During operation, the Serial Monitor provides useful information for troubleshooting.

A successful startup looks approximately like:

Connecting to Wi-Fi: <wifi_name>
......
Wi-Fi connected!
ESP IP Address: 192.168.x.x

Synchronizing time...
.....
Time synchronized
Configuring AWS IoT TLS...
AWS IoT TLS configured
Connecting to AWS IoT Core...
Thing Name: led_controller_01
Endpoint: <endpoint>.amazonaws.com
AWS IoT Core connected!
Subscribed to: led/controller/command

When a command is received:

================================
MQTT Topic: led/controller/command
Message: LED_ON
================================
Relay ON - LED Bulb ON

And when the OFF command is received:

================================
MQTT Topic: led/controller/command
Message: LED_OFF
================================
Relay OFF - LED Bulb OFF

This makes the Serial Monitor useful for validating each stage of the system.

14. Hardware Power Arrangement

The prototype uses separate power arrangements for the controller and the LED circuit.

ESP-12E NodeMCU

The NodeMCU is powered using a:

5 V power supply

through its appropriate power input.

LED

The prototype LED is powered from a:

3.75 V Li-ion battery source

The relay acts as the switching element between the control system and the LED circuit.

Conceptually:

ESP-12E
|
| GPIO D1
▼
┌───────────┐
│ 5 V Relay│
└─────┬─────┘
|
| Switch
|
┌────────┴────────┐
│ │
Battery Red LED
~3.75 V

The exact relay-module wiring should follow the specifications of the particular relay board being used.

15. Why Use a Relay?

The ESP-12E GPIO is designed for low-voltage control signals. It should not be used to directly switch a household AC appliance.

A relay provides electrical switching between the low-voltage control side and the load side.

This becomes particularly important when moving from the prototype LED to the next stage of the project.

The intended next step is:

Control a 9 W household LED bulb through AWS IoT Core.

The architecture will remain conceptually similar:

AWS IoT Core
|
| MQTT
▼
ESP-12E
|
| GPIO
▼
Relay
|
| Switching
▼
9 W Household LED Bulb

However, household AC voltage introduces significant electrical safety considerations. The AC side must be properly isolated, enclosed, insulated, fused/protected as appropriate, and wired using components rated for the mains voltage and load. It should not be assembled on the same exposed breadboard used for the low-voltage prototype.

16. Current Prototype vs. Next Milestone

The project is intentionally being developed incrementally.

Current milestone

AWS IoT Core
↓
Secure MQTT
↓
ESP-12E
↓
5 V Relay
↓
Red LED

This milestone validates the complete cloud-to-device control path.

Next milestone

AWS IoT Core
↓
Secure MQTT
↓
ESP-12E
↓
Relay
↓
9 W Household LED Bulb

The next version will transform the prototype from an LED demonstration into a small practical home-automation experiment.

17. Possible Future Enhancements

There are several directions in which this project can evolve.

1. Multiple lights

The command structure can be expanded to control multiple independent outputs:

LIVING_ROOM_ON
LIVING_ROOM_OFF

BEDROOM_ON
BEDROOM_OFF

KITCHEN_ON
KITCHEN_OFF

2. RGB LED control

The existing command structure already contains:

RED_ON
GREEN_ON
BLUE_ON

This can eventually be connected to an RGB LED or RGB lighting controller.

3. Automatic OFF timer

A command such as:

LED_ON

could turn the light ON and automatically switch it OFF after a configurable period.

For example:

LED_ON
↓
Wait 10 seconds
↓
LED_OFF

4. Device status reporting

The ESP could publish its current status back to AWS IoT Core.

For example:

{
"device": "led_controller_01",
"status": "ON",
"timestamp": "..."
}

This would create two-way communication:

AWS IoT Core
/ \
/ \
COMMAND STATUS
↓ ↑
ESP-12E ────────────┘
|
↓
Relay

5. Mobile or Web Application

A web or mobile application could eventually provide buttons such as:

┌─────────────────────────────┐
│ Home Lighting │
│ │
│ Living Room [ ON ] │
│ Bedroom [ OFF ] │
│ Kitchen [ ON ] │
│ │
└─────────────────────────────┘

The application could publish commands to AWS IoT Core instead of manually publishing MQTT messages.

18. Lessons Learned

This first experiment brought together several important IoT concepts in a single system:

  • ESP8266/ESP-12E programming
  • Wi-Fi connectivity
  • MQTT
  • AWS IoT Core
  • X.509 certificate authentication
  • TLS
  • NTP time synchronization
  • MQTT publish/subscribe architecture
  • GPIO control
  • Relay-based switching
  • Cloud-to-device communication
  • Embedded hardware power management

What makes the experiment particularly useful is that the individual components are simple, but together they form the basic architecture of a real IoT system.

The same pattern can eventually be used for much more than controlling an LED.

19. Final Architecture

The completed prototype can be summarized as:

                  ┌─────────────────────┐
│ AWS Cloud │
│ │
│ AWS IoT Core │
└──────────┬──────────┘
│
MQTT over TLS
Port 8883
│
▼
┌─────────────────────┐
│ ESP-12E │
│ NodeMCU │
│ │
│ Wi-Fi + MQTT Client │
└──────────┬──────────┘
│
GPIO D1
│
▼
┌───────────┐
│ 5 V Relay │
└─────┬─────┘
│
▼
┌───────┐
│ LED │
└───────┘

The most important achievement of this experiment is not simply turning an LED ON and OFF.

It is establishing a complete communication chain:

Cloud → Secure MQTT → Embedded Device → GPIO → Physical Hardware

That is the foundation on which more sophisticated IoT applications can be built.

Conclusion

This experiment marks my first milestone in controlling physical hardware through AWS IoT Core.

Using an ESP-12E NodeMCU, Wi-Fi, MQTT, TLS certificates, AWS IoT Core, and a relay module, I successfully established a secure cloud-to-device communication path and used it to control an LED.

The current setup is deliberately simple, but it provides a strong foundation for the next stage.

The upcoming enhancement will be to replace the prototype LED setup with a properly isolated and safely enclosed relay arrangement capable of controlling a 9 W household LED bulb. From there, the project can evolve toward device status reporting, timers, multiple lights, web/mobile control, and a broader home-automation architecture.

This small experiment demonstrates an important IoT principle:

A cloud message can become a physical action.

And this is only the beginning.

Technologies Used

  • AWS IoT Core
  • MQTT
  • TLS / X.509 Certificates
  • ESP-12E NodeMCU
  • ESP8266
  • Arduino IDE
  • Wi-Fi
  • 5 V Relay Module
  • LED
  • NTP
#AWSIoT #AWSIoTCore #InternetOfThings #IoT #ESP8266 #ESP12E #NodeMCU #Arduino #MQTT #MQTTProtocol #EmbeddedSystems #IoTProjects #AWS #CloudIoT #SmartHome #HomeAutomation #IoTDevelopment #ElectronicsProjects #EmbeddedProgramming #CloudComputing #IoTAutomation #ESP8266Projects #AWSProjects #DIYIoT #SmartHomeAutomation

--

--

Janaarthan Manohar
Janaarthan Manohar

Software Engineer having 9+ years of IT experience