Skip to content

week9. Input Devices ​

Assignment ​

Group assignment ​

  • probe an input device's analog levels and digital signals

Individual assignment ​

  • measure something: add a sensor to a microcontroller board that you have designed and read it

Group assignment ​

For more information about group projects, please see the group project page on the FabLab Kannai website. Group assignment page is here

Microcontroller motion sensing and browser display using Node.js ​

This application demonstrates how to use the XIAO ESP32-C3 as a wireless sensor node that detects motion using the RCWL-0516 microwave radar sensor. When motion is detected, the ESP32-C3 sends a message via the serial port to a Node.js server, which then displays the detection event in real-time in a web browser.

This system builds on the work from the week4 assignment page, and the ESP32-C3 is mounted on the custom development board created in week8.

1. Node and Sensor Integration ​

  • The RCWL-0516 sensor is connected to a digital input pin (e.g. GPI10) on the ESP32-C3.
  • When motion is detected, the sensor's OUT pin goes HIGH.
  • The ESP32-C3 reads this signal and sends "Motion detected!" via the serial port.

2. Network Communication ​

  • A Node.js server running on a connected computer reads the serial data from the ESP32-C3.
  • The server uses Socket.IO to emit the motion detection message to the browser in real-time.
  • The browser dynamically updates the screen with each detection event.

motion-output1.jpg

JavaScript ​

JavaScript is used on the client side to listen for motion events and update the DOM accordingly.

https://developer.mozilla.org/en-US/docs/Web/JavaScript

Node.js ​

Node.js acts as a server-side middleware, bridging the serial port input from the ESP32-C3 to a web client using Socket.IO.

https://nodejs.org/en/

Installing Node.js ​

For macOS:

brew install node
npm install

Start the server:

node index.js

Node.js Application Code Structure ​

realtime-motion-display/
├── node_modules/
├── public/
│   └── index.html
├── index.js
├── package.json
├── package-lock.json

index.js (Node.js Server) ​

js
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const { SerialPort } = require("serialport");
const { ReadlineParser } = require("@serialport/parser-readline");

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

app.use(express.static("public"));

async function findAndConnectSerialPort() {
 try {
  const ports = await SerialPort.list();

  const targetPort = ports.find((port) => {
   return (
           port.path.includes("usbmodem") || // macOS
           port.path.includes("usbserial")   // Windows/Linux fallback
   );
  });

  if (!targetPort) {
   console.error("No compatible serial port found.");
   return;
  }

  console.log(`✅ Found serial port: ${targetPort.path}`);

  const port = new SerialPort({ path: targetPort.path, baudRate: 9600 });
  const parser = port.pipe(new ReadlineParser({ delimiter: "\n" }));

  parser.on("data", (data) => {
   const trimmed = data.trim();
   console.log("Received:", trimmed);
   io.emit("sensorData", trimmed);
  });

  port.on("error", (err) => {
   console.error("SerialPort Error:", err.message);
  });
 } catch (err) {
  console.error("Failed to list serial ports:", err);
 }
}

server.listen(3000, () => {
 console.log("Server running at http://localhost:3000");
 findAndConnectSerialPort();
});

public/index.html ​

html
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Joke Viewer</title>
 <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
 <style>
  body {
   font-family: sans-serif;
   background-color: #f4a09c;
   text-align: center;
   padding: 50px;
  }

  h1 {
   font-size: 2rem;
  }

  #sensorData {
   font-size: 1.5rem;
   margin-top: 30px;
   color: #333;
   padding: 20px;
   border: 2px solid #eee;
   background: #fff;
   display: inline-block;
   max-width: 600px;
   white-space: pre-wrap;
   word-wrap: break-word;
   text-align: left;
  }
 </style>
</head>
<body>
<h1>🤣 Live RCWL-0516 Display</h1>
<div id="sensorData">Waiting for sensorData...</div>

<script>
 const socket = io();

 socket.on("sensorData", (data) => {
  document.getElementById("sensorData").textContent = data;
 });
</script>
</body>
</html>

ESP32-C3 Code (XIAO) ​

cpp
// Connect the output pin of RCWL-0516 to GPIO3 (D10)
#define MOTION_PIN 10

void setup() {
  Serial.begin(115200);

  pinMode(MOTION_PIN, INPUT);  // RCWL-0516 output pin
  delay(1000);
  Serial.println("Serial initialized");
}

void loop() {
  int val = digitalRead(MOTION_PIN);
  if (val == 1) {  // 1 is being detected!
    Serial.println("detected!");
  } else {
    Serial.println("not detected!");
  }
  delay(500);
}

Motion Detection Video ​

When the RCWL-0516 detects motion, the OUT pin immediately goes HIGH and remains HIGH for about 2 seconds, even if the motion stops. If the motion continues, the HIGH state is extended accordingly, and it only returns to LOW about 2 seconds after all motion has ceased. Therefore, the sensor continues to indicate detection for 2 seconds even after a person has left.

While this sensor is very convenient for use as a general motion detector, I found that it is not suitable for my final project, the "Golgo 13 Machine." This is because it continues to signal detection for 2 seconds after a person leaves, and it reacts to all kinds of movement, not just people. As a result, I realized that I will need to look for a different sensor specifically for my final project.

Afterthoughts ​

  • This assignment was a good opportunity to explore the integration of physical sensors, microcontroller GPIO, serial communication, and real-time browser output.

  • I was able to clearly visualize motion detection events through a custom networked pipeline using the ESP32-C3 and Node.js.

  • I found that the RCWL-0516 is a very convenient sensor to use as a motion detector for sensing human presence.