Raspberry Pi Zero W Multi-Sensor Logger: Flame, Rain, and PIR Motion

 

Build a Multi-Sensor Environment Monitor Using a Raspberry Pi Zero W

01 Overview

This project builds a headless Multi-Sensor Environment Monitor using a Raspberry Pi Zero W and a 16-in-1 sensor kit. The system continuously reads three sensors - a PIR motion sensor, a flame sensor, and a rain sensor - and logs every reading to a CSV file with a timestamp. When any of the three sensors is triggered, the Pi automatically switches a relay module on, which powers an LED and buzzer alarm as a real-world safety response, and records the event to a separate event log. The entire monitor runs as a background service that starts automatically on boot, with no monitor, keyboard, or mouse attached. A live feed of events can be viewed remotely over SSH on the local network, or over the internet through Raspberry Pi Connect, making the system fully operable from a separate device.

Project Use Case

This monitor is useful for low-cost environmental and safety monitoring in spaces where a full computer would be impractical. Because it runs headless and logs to files, it can be left running unattended in a room, storeroom, greenhouse, or workshop, with the relay providing an automated response to a fire hazard. Potential applications include early fire detection with automatic actuation, intrusion or presence detection through the motion sensor, and rain or moisture detection for protecting equipment. The project also serves as a practical introduction to GPIO programming, headless Linux administration, systemd services, and remote access on the Raspberry Pi.

02 Hardware and Software Components

Gather everything below before you start. This is your checklist - names, models, and versions only.

Hardware Components

Component Description
Raspberry Pi Zero W Single-board computer that reads the sensors, controls the relay, and runs the logging software headlessly over Wi-Fi.
PIR Motion Sensor Detects movement within range by sensing changes in infrared radiation. Outputs a digital HIGH signal when motion is detected.
Flame Sensor Module Detects the presence of flame or a strong infrared light source. One of the three sensors that trigger the relay alarm.
Rain Sensor Module Detects water or moisture on its sensing board and outputs a digital signal when rain is present.
Relay Module An electrically operated switch that the Pi activates when any sensor is triggered. Its output contacts power the LED and buzzer alarm.
microSD Card (8GB or larger) Stores the Raspberry Pi OS and the project files.
5V / 2.5A Power Supply (micro-USB) Supplies stable power to the Pi. Higher current rating prevents undervoltage when the relay switches.
Jumper Wires (female-to-female) Connect the sensor and relay modules to the Pi's GPIO header.
LED Visual alarm indicator. Powered through the relay.
Active Buzzer Audible alarm indicator. Powered through the relay.

Software Tools

Software Version / Details
Raspberry Pi OS Lite Latest version (headless, no desktop)
Raspberry Pi Imager Latest version
Python 3 Pre-installed with Raspberry Pi OS
gpiozero library Pre-installed with Raspberry Pi OS
SSH client (PowerShell / Terminal) Built into Windows, macOS, and Linux
Note: The Raspberry Pi Zero W uses an ARMv6 processor, which is not supported by the current VS Code Remote-SSH server. Code on this board is edited directly over SSH using the nano terminal editor or written with a heredoc.

03 Application Discussion

Digital Sensors and the GPIO Header

The Raspberry Pi Zero W communicates with the outside world through its General Purpose Input/Output (GPIO) header. Each sensor in this project reports its state as a simple digital signal - either HIGH (3.3V) or LOW (0V) - which the Pi reads on a GPIO pin configured as an input. This is different from an analog reading; the Pi Zero W has no built-in analog-to-digital converter, so all three sensors are wired through their digital output (DO) pins rather than their analog (AO) pins.

The flame and rain modules each include a small potentiometer that sets the threshold at which the digital output flips state. Turning the potentiometer adjusts the sensitivity, allowing the trigger point to be calibrated for the environment. The PIR motion sensor similarly outputs a clean digital HIGH when motion crosses its field of view.

The flame and rain modules used here are active-low: their digital output goes LOW when something is detected. The PIR is active-high: its output goes HIGH on motion. The software reads each sensor with this polarity in mind so that a detection is registered correctly regardless of whether the line goes high or low.

The Relay as an Automated Actuator

A relay is an electrically controlled switch. A small signal from a GPIO pin energizes the relay's coil, which mechanically closes (or opens) a separate, isolated circuit capable of switching much larger loads. In this project the relay is the "real action" - when any of the three sensors becomes active, the Pi drives the relay so that the connected alarm devices, an LED and a buzzer, are activated automatically without human intervention.

Relay modules can be either active-low (the relay switches ON when the GPIO pin is driven LOW) or active-high (ON when the pin is driven HIGH). The relay module used in this project is wired active-high, so the code is configured to match. The relay rests in the OFF state and only energizes when at least one sensor is triggered.

Headless Operation and Remote Access

A headless system runs without a display, keyboard, or mouse. The Raspberry Pi boots, connects to Wi-Fi, and starts the monitoring program automatically through a systemd service. The operator interacts with the device entirely over the network using SSH. This makes the monitor compact and self-contained, and allows the live event feed to be streamed to a remote terminal in real time using a single command.

This project uses two complementary remote-access methods. SSH provides a direct connection when the Pi and the controlling device share the same local network. Raspberry Pi Connect provides a cloud-based alternative that works even when the two devices are on different networks, by routing a remote shell through a secure relay. Connect serves as a fallback for situations where local SSH is unavailable, such as on networks that block device-to-device connections.

04 Hardware Setup

Wire each sensor and the relay module to the Raspberry Pi's GPIO header using the connection tables below. All GPIO numbers refer to the BCM numbering scheme. Power off the Pi before wiring.

GPIO Pin Assignments

Component Pi GPIO (BCM) Physical Pin
Relay Module (IN) GPIO 18 Pin 12
Rain Sensor (DO) GPIO 17 Pin 11
Flame Sensor (DO) GPIO 27 Pin 13
PIR Motion Sensor (OUT) GPIO 22 Pin 15

Power and Ground Connections

Module VCC connects to GND connects to
Relay Module 5V (Pin 2) GND (Pin 6)
Rain Sensor 3.3V (Pin 1) GND (Pin 9)
Flame Sensor 3.3V (Pin 17) GND (Pin 14)
PIR Motion Sensor 5V (Pin 4) GND (Pin 20)

Assembly Instructions

  1. Ensure the Raspberry Pi is powered off and disconnected from the power supply.
  2. Connect each sensor's VCC and GND pins to the Pi's power and ground pins as listed in the table above.
  3. Connect the relay module's IN pin to GPIO 18 (physical pin 12).
  4. Connect the rain sensor's DO (digital output) pin to GPIO 17 (physical pin 11). Do not use the AO pin.
  5. Connect the flame sensor's DO pin to GPIO 27 (physical pin 13).
  6. Connect the PIR sensor's OUT pin to GPIO 22 (physical pin 15).
  7. Double-check every connection before reconnecting power.
Note: Always use the digital output (DO) pin on the flame and rain sensors. The Raspberry Pi Zero W cannot read analog signals, so the AO pins will not work.

Alarm Output (LED and Buzzer)

The LED and active buzzer are not connected to the GPIO header. Instead, they are wired to the output (load) side of the relay module, in series with a power source. When the Pi triggers the relay on a sensor detection, the relay contacts close and complete the alarm circuit, switching the LED and buzzer on. This keeps the alarm electrically isolated from the Pi and means no additional GPIO pins or code are needed to drive them - the existing relay logic controls them automatically.

Note: Because the LED and buzzer are powered by the relay output rather than the Pi, the relay clicking on is what energizes the alarm. They will activate together whenever the relay is triggered.

05 Software Setup

Follow these steps in order. The goal is a headless Raspberry Pi that boots, joins Wi-Fi, and is reachable over SSH so the monitoring program can be written and run remotely.

Step 1: Flash Raspberry Pi OS Lite

  1. Download and install Raspberry Pi Imager from raspberrypi.com on your computer.
  2. Insert the microSD card into your computer using a card reader.
  3. Open Imager, choose Raspberry Pi OS Lite as the operating system, and select your microSD card as the storage.
  4. Open the customization settings (the gear icon) before writing.
Important: Always triple-check that the selected storage device is the microSD card and not an internal drive. Selecting the wrong drive will erase it.

Step 2: Configure the Customization Settings

In the OS customization menu, set the following so the Pi can be reached headlessly on first boot.

Setting Value
Hostname raspberrypi (or a custom name)
Enable SSH On - use password authentication
Username & Password Set and record both
Configure Wireless LAN Enter SSID and password exactly
Wireless LAN Country PH

Save the settings, write the card, and allow the write and verification to finish completely before removing the card.

Step 3: Boot and Connect via SSH

  1. Insert the flashed card into the Pi and connect the power supply to the PWR micro-USB port (the one on the edge of the board).
  2. Wait two to three minutes for the first boot to complete.
  3. On your laptop, open a terminal and connect using the IP address of the Pi:
bash
ssh username@<pi-ip-address>

Replace username with the one set in Imager and <pi-ip-address> with the Pi's address (for example, 172.20.10.12 on an iPhone hotspot). To find the address, run hostname -I on the Pi. If hostname resolution works on your network, ssh username@raspberrypi.local may also work, though this is unreliable on Windows. Accept the host key when prompted and enter your password.

Step 4: Prepare the Project Folder and Libraries

Once connected over SSH, create the project folder and confirm the required software is present.

bash
mkdir -p ~/monitor
cd ~/monitor
python3 --version
python3 -c "import gpiozero; print('gpiozero ok')"

If gpiozero reports an error, install it with:

bash
sudo apt update
sudo apt install python3-gpiozero -y
Note: If running the script later produces a "pin factory" or "lgpio" error, install the backend with sudo apt install python3-lgpio -y. Only run this if that specific error appears.

Step 5: Enable Raspberry Pi Connect (Remote Access)

Raspberry Pi Connect provides a second way to reach the Pi remotely. Unlike SSH, which requires the Pi and the controlling device to be on the same local network, Connect routes through a secure cloud relay, so the Pi can be accessed from a browser on a different network entirely. This is useful when local SSH is blocked or when the Pi and the controlling device are not on the same Wi-Fi.

On a headless Raspberry Pi OS Lite setup, install the lightweight version of Connect, which provides remote shell access:

bash
sudo apt update
sudo apt install rpi-connect-lite -y

Turn Connect on and sign in. These commands are run without sudo, because Connect runs as a user service:

bash
rpi-connect on
rpi-connect signin

If the account was already linked during the Raspberry Pi Imager setup, the signin command reports that the device is already signed in and no further action is needed. Otherwise, it prints a URL with a verification code. Open that URL in a browser, sign in with the Raspberry Pi account, and approve the device.

To keep Connect running even when no SSH session is active, enable user lingering, then confirm the status:

bash
loginctl enable-linger $USER
rpi-connect status

To access the Pi, open connect.raspberrypi.com in a browser on any device, sign in with the same Raspberry Pi account, and select the device from the list. Choose Remote shell to open a terminal to the Pi directly in the browser.

Note: Screen sharing is not available on the Raspberry Pi Zero W running Raspberry Pi OS Lite, because there is no graphical desktop. Remote shell provides full command-line access, which is all that is required for this project.

06 Code

Create the monitoring script inside the project folder. On the Pi Zero W, the most reliable way to write a multi-line file over SSH is a heredoc, which writes the file exactly as given and avoids the indentation problems that can occur when pasting Python into nano. Paste the entire block below, from cat through the final EOF, then press Enter.

Monitoring Script - monitor.py

bash
cat > ~/monitor/monitor.py << 'EOF'
#!/usr/bin/env python3
"""
RPi Zero W environmental monitor
Relay-driven LED + rain, flame, and PIR motion sensors.

Pin map (BCM numbering):
  Relay IN  -> GPIO18  (Pin 12)
  Rain  DO  -> GPIO17  (Pin 11)   active-LOW
  Flame DO  -> GPIO27  (Pin 13)   active-LOW
  PIR   OUT -> GPIO22  (Pin 15)   active-HIGH

Run:  python3 monitor.py
Stop: Ctrl+C
"""

from gpiozero import OutputDevice, Button, MotionSensor
from datetime import datetime
import csv
import os
import time

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CSV_FILE = os.path.join(BASE_DIR, "readings.csv")
LOG_FILE = os.path.join(BASE_DIR, "events.log")

# Relay: this module is active-high. Set False for an active-low board.
RELAY_ACTIVE_HIGH = True
relay = OutputDevice(18, active_high=RELAY_ACTIVE_HIGH, initial_value=False)

# Sensors: Button(pull_up=True) reads is_pressed == True when the DO line
# goes LOW, which is "detected" for these active-low boards.
rain  = Button(17, pull_up=True)
flame = Button(27, pull_up=True)
pir   = MotionSensor(22)


def log_event(message):
    line = f"{datetime.now():%Y-%m-%d %H:%M:%S}  {message}"
    with open(LOG_FILE, "a") as f:
        f.write(line + "\n")
    print(line)


def status():
    return (
        f"rain={'YES' if rain.is_pressed else 'no '}   "
        f"flame={'YES' if flame.is_pressed else 'no '}   "
        f"motion={'YES' if pir.motion_detected else 'no '}"
    )


print("Warming up PIR (~30-60 s). Ignore motion readings until it settles.\n")

new_file = not os.path.exists(CSV_FILE)
csvf = open(CSV_FILE, "a", newline="")
writer = csv.writer(csvf)
if new_file:
    writer.writerow(["timestamp", "rain", "flame", "motion", "relay"])

log_event("Monitor started")

prev_rain = False
prev_flame = False
prev_motion = False

try:
    while True:
        is_rain   = rain.is_pressed
        is_flame  = flame.is_pressed
        is_motion = pir.motion_detected

        # Any active sensor triggers the relay alarm
        alarm = is_flame or is_rain or is_motion
        if alarm:
            relay.on()
        else:
            relay.off()

        # Event logging on state changes
        if is_flame and not prev_flame:
            log_event("FLAME DETECTED")
        if is_rain and not prev_rain:
            log_event("Rain detected")
        if is_motion and not prev_motion:
            log_event("Motion detected")

        prev_rain = is_rain
        prev_flame = is_flame
        prev_motion = is_motion

        # Log every reading to CSV
        writer.writerow([
            datetime.now().isoformat(timespec="seconds"),
            int(is_rain), int(is_flame), int(is_motion), int(relay.value)
        ])
        csvf.flush()

        print(status(), "| LED", "ON " if relay.value else "OFF")
        time.sleep(0.5)

except KeyboardInterrupt:
    relay.off()
    log_event("Monitor stopped")
    csvf.close()
    print("\nStopped. Relay off.")
EOF

Confirm the file was written and is valid Python:

bash
ls -la ~/monitor
cd ~/monitor
python3 -m py_compile monitor.py && echo "Code is valid"

systemd Service File - monitor.service

To make the monitor run headlessly on boot and restart automatically if it crashes, create a systemd service. The same heredoc method is used here. Confirm your username first with whoami, and replace raspberrypi below if yours differs.

bash
sudo tee /etc/systemd/system/monitor.service > /dev/null << 'EOF'
[Unit]
Description=Multi-Sensor Environment Monitor
After=network.target

[Service]
User=raspberrypi
WorkingDirectory=/home/raspberrypi/monitor
ExecStart=/usr/bin/python3 /home/raspberrypi/monitor/monitor.py
Restart=always

[Install]
WantedBy=multi-user.target
EOF

Reload systemd, enable the service so it starts on boot, start it now, and check its status:

bash
sudo systemctl daemon-reload
sudo systemctl enable monitor.service
sudo systemctl start monitor.service
sudo systemctl status monitor.service

The status should show active (running). Press q to exit the status view.

Note: Once the service is running, it is already using the sensors. Do not also run python3 monitor.py by hand at the same time, since both would try to write the same files. To run the script manually for a demo, stop the service first with sudo systemctl stop monitor.service.

07 Code Breakdown

Imports and Device Setup

The script uses the gpiozero library to interact with the GPIO pins. MotionSensor handles the PIR. The flame and rain sensors are read with Button(pin, pull_up=True): because these modules are active-low, their is_pressed property reads True when the line goes LOW, which corresponds to a detection. OutputDevice controls the relay.

Relay Configuration

The relay is created with active_high=True (set by the RELAY_ACTIVE_HIGH flag) and initial_value=False, which matches the active-high relay module used here and ensures it starts in the OFF state. If a different relay board behaves in reverse, changing the single flag to False adapts the code without further edits.

The log_event Function

This helper writes a timestamped, human-readable line to events.log and also prints it. The event log is separate from the CSV so that meaningful events - such as a flame being detected - can be read at a glance or streamed live over SSH.

The status Function and Live Display

The status() function returns a single readable line showing the current state of each sensor, for example rain=no flame=no motion=YES. This line is printed every cycle alongside the LED state, giving a continuous live readout when the script is run by hand.

The Main Loop

Twice per second the loop reads all three sensors. The three readings are combined into a single alarm condition that is true when any of rain, flame, or motion is active; the relay is switched on while the alarm is true and off when all sensors are clear. Each sensor's event is logged only when its state changes, to avoid flooding the log. Every cycle, a full row is written to readings.csv capturing the timestamp and the state of all three sensors plus the relay. The csvf.flush() call forces each row to disk immediately so no data is lost if power is removed.

Graceful Shutdown

The try/except KeyboardInterrupt block ensures that if the script is stopped manually with Ctrl+C, the relay is switched off, the CSV file is closed, and a final "Monitor stopped" event is recorded, leaving the hardware in a safe state.

08 Testing and Calibration

Initial Test Run

Before relying on the service, run the script manually to confirm the sensors respond correctly. If the service is already running, stop it first so the two do not conflict.

bash
sudo systemctl stop monitor.service
cd ~/monitor
python3 monitor.py

Wave a hand in front of the PIR to confirm a "Motion detected" line appears and the relay alarm activates. Briefly present a flame source (such as a lighter, used safely) to the flame sensor to confirm "FLAME DETECTED" is logged and the relay clicks on. Apply a few drops of water across the rain sensor board to confirm rain detection. Each of the three sensors should trigger the relay, and the alarm should switch off once all sensors are clear. Press Ctrl+C to stop, then restart the service with sudo systemctl start monitor.service.

Calibrating the Sensors

If a sensor triggers constantly or not at all, adjust the potentiometer on the module. Turn it slowly until the onboard indicator LED switches right at the threshold you want. The flame and rain sensors are the most sensitive to this adjustment.

Note: If the flame column reads 1 even with no flame present, the flame sensor is too sensitive. With no flame nearby, turn its potentiometer until the module's onboard indicator LED just switches off, so it only trips on an actual flame.

Viewing the Live Event Feed over SSH

With the service running, the live event log can be streamed to any SSH session in real time. This is the project's headless live feed.

bash
tail -f ~/monitor/events.log

New events appear instantly as they are detected. Press Ctrl+C to stop watching without affecting the running service.

Note: The same tail -f command works in a Raspberry Pi Connect remote shell, allowing the live feed to be viewed from a browser on any network.

Viewing the Full Live Status

When the script runs as a service, its status() printout is captured by the system journal instead of the terminal. To watch the full readable readout (rain, flame, motion, and LED state) live, use journalctl:

bash
journalctl -u monitor.service -f

Press Ctrl+C to stop watching. For a perfectly smooth, every-half-second display, stop the service and run the script by hand instead, as described in the Initial Test Run.

Checking the CSV Log

To confirm readings are being recorded, view the most recent rows of the CSV file, or count how many readings have been logged.

bash
tail ~/monitor/readings.csv
cat ~/monitor/events.log
wc -l ~/monitor/readings.csv

Each CSV row records the timestamp followed by the rain, flame, motion, and relay states as 0 or 1, for example 2026-06-22T10:02:53,0,0,1,1.

Service Management Commands

The following commands manage the background service during testing and operation.

Command Purpose
sudo systemctl status monitor.service Check whether the service is running.
sudo systemctl start monitor.service Start the monitor.
sudo systemctl stop monitor.service Stop the monitor (do this before running by hand).
sudo systemctl restart monitor.service Restart after editing the code so changes take effect.

09 System Demonstration

Video Demonstration

The video below demonstrates the working monitor, showing the live event feed responding to motion, flame, and rain, with the relay alarm activating on each detection.

10 Conclusion

This project successfully demonstrated a headless Multi-Sensor Environment Monitor built on a Raspberry Pi Zero W. Three digital sensors - rain, flame, and motion - were read continuously and logged to a timestamped CSV file, satisfying the data-logging requirement. The relay automation provided a real, automated action by switching on whenever any of the three sensors was triggered, powering an LED and buzzer alarm and recording the event to a separate human-readable log. By running the program as a systemd service and streaming the event log over SSH with tail -f, the system delivered a fully headless live sensor feed that required no monitor or keyboard. Raspberry Pi Connect added a cloud-based remote shell as a fallback for accessing the device from outside the local network. Together these elements form a compact, self-contained environmental monitor that is reliable, remotely accessible, and easily extendable.

Possible Improvements and Future Enhancements

  • Add the remaining sensors from the kit, such as temperature, humidity, or light, for a richer environmental picture.
  • Push readings to a cloud dashboard or database for remote monitoring and historical analysis.
  • Send an alert by email, SMS, or push notification when a sensor is triggered.
  • Separate the alarm so different sensors drive different responses instead of a single shared relay.

11 References

  • Raspberry Pi Documentation - Getting Started and Configuration
  • Raspberry Pi Documentation - Remote Access (SSH and Raspberry Pi Connect)
  • gpiozero Library Documentation
  • Python 3 Standard Library - csv and datetime modules
  • systemd Service Unit Documentation
  • 16-in-1 Sensor Kit for Raspberry Pi - Component Reference

12 Project Authors

  • Keen Montilla
  • Ben Sumauang
Multi-Sensor Environment Monitor Using a Raspberry Pi Zero W - CreateLabz

 

Flame detectionHeadlessHome automationIotMotion sensorPythonRain sensorRaspberry connectRaspberry pi zero wSsh

Leave a comment

All comments are moderated before being published