Motion sensors are key components for security systems and are very useful when paired with IoT. In this tutorial, we’ll use one along with an ESP32 which will send an MQTT message based on the sensor’s state. Another ESP32 with a connected LED will receive a message and glow LED if motion is detected. We’ll use the Toit platform to program both devices to benefit from its seamless device connectivity. This way, you can have your sensor placed anywhere and have the IoT motion alert system right on your desk, without any physical connection between the two systems.
Getting the components
- 2x ESP32 WROOM development boards
- PIR motion sensor
- LED
- 2x Micro-USB cables
- Breadboard and connecting wires
Wiring up the circuit
The wiring is extremely simple for both devices. PIR (Passive Infrared Receiver) is a passive sensor that absorbs infrared signals and gives a high output if it crosses a threshold. The sensor has three terminals: VCC, GND and digital output. We connect GPIO-32 to the output of the sensor. On the other device, a single LED is connected between a 330 ohms current limiting resistor attached to GPIO-19 and the GND terminal. Note that there is no physical connection between the two devices.
Setting up Toit
If you’re new to the Toit platform, sign up here to get your account with up to 10 devices free forever. Next, head over to its Quick Start Guide and follow the few simple steps given there. Once it’s done, your device should appear in the Devices tab with the status as Healthy.
Next up, we need to install the MQTT package from Toit’s package registry. Run the following command in the Toit CLI inside your working directory:
$ toit pkg install github.com/toitware/mqtt
The packages (or libraries) are now installed locally in the working directory. All other packages come bundled with the firmware. Finally, create two .toit files in the project folder. I’ve named them pir-sensor.toit and led-alarm.toit.
Programming the PIR sensor side (MQTT transmitter)
The program starts with importing the necessary libraries and declaring a few global variables. For this tutorial, we’re using the public MQTT broker from EMQ X IoT cloud. However, it is better to create your own MQTT broker if you’re planning to deploy it as a long-lived application. The MQTT topic is named as toit/sensor/pir.
import net
import mqtt
import encoding.json
import device
import gpio
// GPIO pin the PIR sensor is connected to.
PIR_SENSOR::= 32
// Unique MQTT client ID to identify each client that connects to the MQTT broker.
CLIENT_ID ::= “$device.hardware_id“
// The publicly available EMQ X MQTT server/broker
HOST ::= “broker.emqx.io”
// MQTT port 1883 is for unencrypted communication.
PORT ::= 1883
// MQTT topic name
TOPIC ::= “toit/sensor/pir”
Next, we jump into the main function where we define the sensor pin as input and the object for MQTT client.
main:
pir ::= gpio.Pin PIR_SENSOR –input
socket := net.open.tcp_connect HOST PORT
// Connect the Toit MQTT client to the broker
client := mqtt.Client
CLIENT_ID
mqtt.TcpTransport socket
// The client is now connected.
print “Connected to MQTT Broker @ $HOST:$PORT“
As this device will only publish on the MQTT topic, we create a function for it that sends the message in JSON format.
publish client/mqtt.Client payload/bool:
// Publish message to topic
client.publish
TOPIC
json.encode {
“value”: payload
}
–retain=true
// print “Published message `$payload` on ‘$TOPIC'”
Now, at the end of the main function, we create an infinite loop. It waits for the PIR sensor pin to go HIGH and publish true if motion is detected. After that, we wait for the pin to go LOW and publish false, which indicates no more motion is detected. This keeps on repeating.
while true:
// Wait till movement is detected (high sensor output)
pir.wait_for 1
print “Motion detected! Time: $(Time.now) UTC”
publish client true
// Wait till no more movement is detected (low sensor output)
pir.wait_for 0
publish client false
With this, the transmitter side is completed
Programming the LED alarm side (MQTT receiver)
The same libraries are used for the receiver as well, along with the same MQTT global variables. Here, we define the GPIO-19 as output for our LED.
// GPIO pin the LED is connected to.
LED ::= 19
main:
led := gpio.Pin LED –output
Contrary to the other device, this device just needs to listen for incoming MQTT messages and change the LED state according to what’s received. So, we subscribe to the MQTT topic and start listening to it.
// Start subscribing to the topic.
client.subscribe TOPIC –qos=1
print “Subscribed to topic ‘$TOPIC‘”
// Process subscribed messages.
client.handle: | topic/string payload/ByteArray |
decoded := json.decode payload
// print “Received message ‘$(decoded[“value”])’ on ‘$topic'”
if decoded[“value”]:
led.set 1
print “LED turned ON! Time: $(Time.now) UTC”
else:
led.set 0
print “LED turned OFF! Time: $(Time.now) UTC”
With this, the whole programming for the IoT motion alert system is done.
Run the IoT motion alert setup
For running and deploying the apps, you have two options: Toit CLI and Toit’s VS Code extension. If you’re fond of doing everything using the command line, run the following two commands in separate terminals inside the working directory:
$ toit run -d LED-ESP32 led-alarm.toit
$ toit run -d PIR-ESP32 pir-sensor.toit
The -d parameter defines the device name, so replace LED-ESP32 and PIR-ESP32 by your device’s name. The output should be the following if motion is detected.
On the other hand, you can also run programs with just a click of a button using Toit’s VS code extension.
The output will be like the following
With everything working well, we can now deploy the apps as long-lived applications. In the same folder, create two.yaml files with the content given below:
name: PIR sensor MQTT
entrypoint: pir-sensor.toit
name: LED alarm for PIR sensor
entrypoint: led-alarm.toit
Now, click on the Deploy button in VS code and the app should now be visible under the Apps section in the Toit console. You can view the device’s logs to check the time at which the motion was detected.
All the programs used for this IoT motion alert tutorial can be found in this Github repository.

Harsh Chaudhary is an engineering student currently pursuing Electrical Engineering. He’s a robotics and tech enthusiast and likes to write about stuff related to IoT and embedded systems. His vision is to use Robotics to make the life of humans easier.