It is July in Bengaluru. A tomato sapling sits in a pot on a school balcony, and nobody has watered it in four days because the class has been busy with exams. Yet the soil is damp, not cracked. Overnight, a small computer the size of a credit card checked the soil, decided it was dry enough to act on, switched on a water pump for five seconds, and sent a message to a phone: "Watered plant 1 at 6:02 AM, moisture was 34%." No one touched the plant. This is not science fiction — it is a weekend project built around a Raspberry Pi, and by the end of this chapter you will understand exactly how every part of it works, down to the lines of Python that make the decision.
This chapter is about the Internet of Things (IoT) — physical objects that sense the world, make decisions, act on it, and often talk to the internet about it — using the Raspberry Pi as the "brain" that ties sensors and motors together. We will build the idea up piece by piece: first a single output (an LED), then a single input (a button), then a real sensor with a numeric threshold (soil moisture), and finally connect that local decision to the wider internet.
From a Light Switch to a "Smart" Device
Start with something every student already understands: a light switch. You flip it, current flows, the bulb glows. There is a human making the decision ("it's dark, I want light") and a human performing the action (flipping the switch). Nothing about the switch itself is "smart" — it has no idea whether it is dark or bright in the room.
Now imagine replacing the human with three things working together:
- A sensor that measures something about the world — for example, a light-dependent resistor that measures brightness, or a soil probe that measures moisture.
- A small computer that reads the sensor's measurement and applies a rule — "if brightness is below X, turn the light on."
- An actuator — a component that does something physical in response, such as a bulb, a motor, or a water pump.
This loop — sense, decide, act — is the entire idea behind every "smart" device, from a smart streetlight to a smart watering system. The Raspberry Pi's job in this loop is the middle step: reading sensors and deciding what the actuators should do, using a program you write in Python.
Meet the Raspberry Pi
A Raspberry Pi is a fully functional computer built onto a single small circuit board — about the size of a credit card. It has a processor, memory, USB ports, HDMI output, Wi-Fi, and a set of 40 metal pins along one edge called the GPIO header (General Purpose Input/Output). You insert a memory card loaded with a full operating system (Raspberry Pi OS, a version of Linux), plug in a keyboard, mouse, and monitor, and it behaves like an ordinary desktop computer that you can also wire up to sensors and motors.
Common misconception — "Raspberry Pi and Arduino are basically the same thing." They are not, and mixing them up leads to real design mistakes. An Arduino is a microcontroller board: it has no operating system, it runs exactly one program at a time directly on its hardware (this is called running "on bare metal"), it boots that program in a fraction of a second, and it typically cannot run a web browser or manage files the way a computer does. A Raspberry Pi is a microcomputer: it boots a full operating system (which takes tens of seconds), can run many programs at once, has real memory management and a file system, and can just as easily run a Python script that reads a sensor as it can run a web browser. For projects that only flip a switch based on one sensor with no networking, an Arduino is often simpler and cheaper. For projects that need to talk to the internet, store data in files, run a web server, or use a camera, the Raspberry Pi's full operating system makes it the better tool. In this chapter, we use the Raspberry Pi specifically because our project needs to publish data to the internet — something a bare microcontroller cannot do on its own without extra hardware.
Talking to the Physical World: GPIO Pins
The 40 GPIO pins are how the Raspberry Pi's software reaches out and touches physical circuits. Each pin can be configured in software to do one of two things:
- Output mode: the Pi sets the pin's voltage itself — either 3.3 volts (read in code as
HIGHor1) or 0 volts (LOWor0). This is how the Pi controls an LED, a relay, or a motor driver. - Input mode: the Pi measures the voltage some external circuit is putting on the pin, and reports it back to your program as
HIGHorLOW. This is how the Pi reads a button or a digital sensor.
Every GPIO pin only understands two voltage levels — it is fundamentally a digital, on/off signal, not a smooth range of values. Keep that fact in mind; it becomes important later in this chapter when we read a sensor that measures a continuous quantity like "how wet is the soil," not just "is the button pressed or not."
Worked Example 1: Controlling an LED
Let's write the smallest possible IoT-style program: the Pi decides, on its own schedule, to turn a physical LED on and off. We use the RPi.GPIO library, the standard way to control GPIO pins from Python.
import RPi.GPIO as GPIO
import time
LED_PIN = 17 # GPIO17, physical pin 11 on the header
GPIO.setmode(GPIO.BCM) # use Broadcom chip-number naming for pins
GPIO.setup(LED_PIN, GPIO.OUT) # configure pin 17 to send voltage out
for i in range(5):
GPIO.output(LED_PIN, GPIO.HIGH) # set pin to 3.3V -> LED turns ON
time.sleep(1) # wait 1 second
GPIO.output(LED_PIN, GPIO.LOW) # set pin to 0V -> LED turns OFF
time.sleep(1)
GPIO.cleanup() # release the pins back to their default state
Trace through it exactly the way the interpreter does: GPIO.setmode tells Python which numbering scheme to use for the pins (BCM numbers refer to the chip's internal pin names, not their physical position on the header). GPIO.setup configures pin 17 as an output — from this point, the Pi is allowed to push voltage onto that wire. The for loop runs five times; each pass turns the LED on, pauses one second so a human eye can actually see the change, turns it off, and pauses again. After five iterations (10 seconds total), GPIO.cleanup() resets every pin the program touched, which prevents the next program you run from inheriting a pin still stuck in output mode.
Worked Example 2: Reading a Button
Output alone isn't IoT — a device needs to sense something too. A pushbutton is the simplest possible sensor: a mechanical switch that either connects two points in a circuit or doesn't.
import RPi.GPIO as GPIO
import time
BUTTON_PIN = 27 # GPIO27, physical pin 13 on the header
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
print("Press the button (Ctrl+C to stop)...")
try:
while True:
if GPIO.input(BUTTON_PIN) == GPIO.LOW:
print("Button pressed!")
time.sleep(0.3) # debounce delay
except KeyboardInterrupt:
GPIO.cleanup()
The line pull_up_down=GPIO.PUD_UP deserves attention, because it explains a real electrical problem, not just a code detail. If a GPIO pin in input mode is connected to nothing, its voltage is — tiny amounts of electrical noise in the air and the wiring can make it randomly flicker between reading HIGH and LOW, which would make the button appear to "press itself." The Pi has a tiny internal resistor it can switch on to gently pull the pin up to 3.3V (HIGH) whenever nothing else is driving it — that is the "pull-up." The button is then wired so that pressing it connects the pin directly to ground (0V), overpowering the weak pull-up and making the pin read LOW. That is why the check is GPIO.input(BUTTON_PIN) == GPIO.LOW for a "pressed" state, which surprises many beginners who expect "pressed" to mean HIGH. The short time.sleep(0.3) after detecting a press is called debouncing: a mechanical switch's metal contacts physically vibrate for a few milliseconds when pressed, which without this pause could register as five or six presses instead of one.
Sensors That Measure "How Much," Not Just "Yes or No"
A button only ever reports two states. Many real IoT sensors — soil moisture, temperature, light level — measure a continuous quantity. Let's build the running example for the rest of this chapter: a soil moisture sensor that reports a number from 0 (bone dry) to 100 (fully saturated), and a rule that switches on a water pump when that number drops too low.
Suppose our rule is: if moisture reading is below 40, turn the pump on for 5 seconds. Here is a log of hourly readings one morning:
| Time | 9 AM | 10 AM | 11 AM | 12 PM | 1 PM | 2 PM |
|---|---|---|---|---|---|---|
| Moisture % | 46 | 42 | 38 | 55 | 50 | 44 |
Work through it by hand the way the program will: at 9 AM, 46 is not below 40, so no action. At 10 AM, 42 is still not below 40. At 11 AM, the reading is 38, which is below 40 — the rule fires, the pump runs for 5 seconds and wets the soil. By 12 PM the watering has taken effect and the reading has jumped to 55, comfortably above the threshold, so the pump stays off for the rest of the log. This single numeric comparison — "is this measurement below a threshold?" — is the core decision logic behind an enormous number of real IoT systems: a smart thermostat compares a temperature reading to a target, a smart streetlight compares an ambient-light reading to a darkness threshold, a warehouse humidity monitor compares a reading to a safe range.
A Second Misconception: "The Pi Can Just Read an Analog Sensor Like Arduino Does"
Here is a fact that trips up many beginners who have used Arduino before: an Arduino has dedicated analog input pins that can measure a smoothly varying voltage directly and report it as a number. The Raspberry Pi's GPIO pins, as established earlier in this chapter, are digital only — every one of the 40 pins can only distinguish HIGH from LOW, with nothing in between. A moisture sensor's raw output, however, is naturally an analog voltage that varies smoothly with how wet the soil is. Connecting it straight to a Pi GPIO pin would only ever tell you "some voltage above roughly half of 3.3V" or "below it" — not the graded 0–100 percentage our threshold logic needs.
The real-world fix is an ADC (Analog-to-Digital Converter) chip, such as the widely used MCP3008, wired between the sensor and the Pi. The ADC continuously measures the sensor's analog voltage and reports it to the Pi as a digital number the GPIO pins can understand, over a fast digital connection called SPI. The Python library gpiozero includes ready-made support for the MCP3008, which is what makes the next program possible.
Worked Example 3: The Automated Soil-Moisture Watering System
This program combines everything so far: it reads a percentage from the sensor through the ADC, compares it to our threshold of 40, and drives a relay that switches the water pump's separate power circuit on and off.
from gpiozero import MCP3008, OutputDevice
from time import sleep
moisture_sensor = MCP3008(channel=0) # ADC channel 0; .value is 0.0 to 1.0
pump = OutputDevice(4) # GPIO4 drives the pump's relay
THRESHOLD_PERCENT = 40
WATER_SECONDS = 5
while True:
moisture = moisture_sensor.value * 100 # convert 0.0-1.0 to a 0-100 %
print(f"Soil moisture: {moisture:.0f}%")
if moisture < THRESHOLD_PERCENT:
print("Dry -> watering now")
pump.on()
sleep(WATER_SECONDS)
pump.off()
sleep(60) # check again in one minute
Trace it using the 11 AM reading from our table, 38%: moisture_sensor.value returns a fraction like 0.38, multiplying by 100 gives 38.0, and the program prints "Soil moisture: 38%". Since 38 is less than THRESHOLD_PERCENT (40), the if block runs: it prints the warning, calls pump.on() which sets GPIO4 to HIGH and energizes the relay, waits 5 seconds while the pump physically runs, then calls pump.off(). Either way — whether it watered or not — the loop then sleeps for 60 seconds before taking the next reading, which is why our table was recorded once per hour in the worked example rather than once per second: continuously checking a slow-changing quantity like soil moisture wastes power and is unnecessary. Notice this program never stops on its own (while True) — that is intentional for a device meant to run for weeks unattended, unlike Example 1's LED loop, which was written to stop after five blinks so you could watch it run once and be done.
A relay, mentioned in the code comment, deserves a one-line explanation: a water pump typically needs far more current than a Pi's 3.3V GPIO pin can safely supply. A relay is an electrically controlled switch — the Pi's small, safe signal on GPIO4 flips the relay, and the relay's own separate, heavier-duty contacts switch the pump's own power supply. The Pi never touches the pump's higher-current circuit directly; it only ever tells the relay what to do.
From Local Automation to "Internet of Things"
Everything built so far is local automation — the sensing, deciding, and acting all happen on one Pi, with no involvement from any other device. This is already useful, but it isn't yet the "Internet" part of "Internet of Things." The final piece is having the Pi also publish what it observes and does, over Wi-Fi, so that a person — or another program — anywhere in the world can see it and be notified.
A common way to do this is a lightweight messaging system called MQTT (Message Queuing Telemetry Transport). Think of it like a noticeboard in a school corridor: a device that has something to announce (the Pi) pins a note to a labelled section of the board — a "topic," such as farm/plant1/moisture — without needing to know who, if anyone, is reading it. Any other device that has said "I'm interested in notes on farm/plant1/moisture" — a phone app, for instance — is shown the note the moment it's pinned, without the Pi and the phone ever needing to contact each other directly. The noticeboard itself is called a broker, and it typically runs on a server out on the internet, though small setups can also run one on a Raspberry Pi at home. Publishing a value over MQTT, at the level this chapter needs, is conceptually just one extra line in our loop — after computing moisture, the program calls something like client.publish("farm/plant1/moisture", moisture) — the same numeric decision-making from Example 3 now shared with the world rather than kept to itself.
The diagram below shows the complete system: the sensing-deciding-acting loop from Example 3 on the left, and the internet-facing publish-and-notify path on the right.
Read the diagram left to right, then top to bottom: the sensor feeds a percentage to the Pi; the Pi's Python logic compares it to the threshold and, when needed, switches the pump on through GPIO4; the pump wets the soil, which is why the dashed arrow loops back to the sensor — the sensor's own future readings are affected by the actuator's action, which is what makes this a genuine feedback loop rather than a one-way chain. Independently, the Pi also publishes each reading to the MQTT broker, which forwards it to any subscribed phone app. Note that the publish path does not depend on the pump firing — the Pi can report "38%, watering now" or "55%, no action needed" with equal ease, which is exactly what turns a private automation into a connected, remotely observable "thing."
Where This Scales: Beyond One Balcony Plant
The same three-part loop — sense, decide, act, and optionally report over the network — is not limited to one flowerpot. India's Smart Cities Mission, launched by the Government of India in 2015, funds exactly this pattern at city scale: networked sensors on streetlights that dim or brighten based on measured ambient light and reduce electricity use, and sensors in municipal waste bins that report fill-level so collection trucks are routed only where needed, rather than following a fixed schedule. (The 100 cities that eventually joined the mission were not all selected on day one — the selection happened in multiple rounds over the following years.) The hardware in a city-scale deployment is more industrial than a hobby Raspberry Pi, but the underlying decision — "read a sensor, compare it to a threshold, act, and publish the result" — is the same logic you traced by hand in the moisture-percentage table earlier in this chapter.
Test Your Understanding
- A student wires a pushbutton to a Pi GPIO pin using
pull_up_down=GPIO.PUD_UP, but forgets to connect the button's other leg to ground — it is left floating. What willGPIO.input()most likely show when the button is not pressed, and why might it occasionally flicker if the wiring is later touched or moved? - Using the rule "if moisture % is below 40, water for 5 seconds, and assume watering always raises the very next hourly reading back above 40," a sensor logs these hourly readings starting at 9 AM: 46, 42, 38, 55, 50, 44. At which reading(s) does the pump switch on? Explain using the comparison at each hour.
- Explain, in your own words, why a Raspberry Pi needs an external ADC chip like the MCP3008 to read a soil moisture sensor's raw signal, when it does not need one to read a pushbutton.
- A classmate says, "Since both the Raspberry Pi and Arduino have pins you can wire sensors to, they must run code the same way." Name the one difference between them that matters most for a project that needs to publish sensor readings to the internet, and explain why.
- In the automation loop from Worked Example 3, why does the program call
sleep(60)at the end of every iteration regardless of whether the pump fired that round, instead of checking the sensor continuously in a tight loop with no delay?
Summary
An IoT device built around a Raspberry Pi follows one repeating loop: a sensor measures something about the physical world, the Pi's Python program compares that measurement to a rule and decides what to do, and an actuator carries out that decision — often through a relay that isolates the Pi's safe, low-power GPIO signal from a higher-power circuit like a pump or motor. GPIO pins are strictly digital (HIGH or LOW at 3.3V/0V), which is enough for switches and LEDs directly, but reading a smoothly varying analog sensor such as a moisture probe requires an external ADC chip like the MCP3008 to convert that analog voltage into a digital number the Pi can compare against a threshold. A Raspberry Pi differs from an Arduino in a way that matters specifically for this chapter's topic: it is a full microcomputer running a real operating system, capable of networking and publishing data, where an Arduino is a bare microcontroller running one program with no OS. The "Internet" in Internet of Things is the final layer on top of this local loop — a lightweight protocol like MQTT lets the Pi publish each reading and each action to a topic on a broker, so that any subscribed device, anywhere, learns what happened without the two devices ever contacting each other directly. The same pattern, scaled up with sturdier hardware, is what runs sensor-driven streetlights and waste bins under city-wide smart infrastructure programs.
Practice Exercises
Now it is time to practice! Complete these challenges to solidify your understanding:
- Exercise 1: Write a short program that demonstrates the core concept from this chapter. Test it with at least 3 different inputs.
- Exercise 2: Find a real-world example where iot with raspberry pi: connected devices is used in an Indian company (like TCS, Infosys, Flipkart, or ISRO). Write a paragraph explaining the connection.
- Exercise 3: Create a mind-map connecting iot with raspberry pi: connected devices to at least 3 other topics you have studied.