Python & GPIO: code meets circuit
420-302-VA · WEEK 4 · FALL 2026

Stage 2 of 6 · Theory, hands on the REPL · about 30 minutes

Python from zero

Every program you will write this semester, up to the term project's control logic, is built from four moves: store values, decide, repeat, and name recipes. This page introduces all four, small enough to try each one as you read.

What a program is

A program is a text file of instructions that a machine performs exactly and in order. The machine here is the interpreter, a program named python3 that reads your file top to bottom and does what each line says: compute a value, print text, wait, or, from the First light page on, pull a GPIO pin high.

Your .py text file goes into the python3 interpreter, which executes it line by line, producing effects: computed values, printed text, waits, and changed GPIO pins blink.py your instructions, plain text, top to bottom python3 the interpreter: reads a line, performs it, next Effects values computed · text printed time waited · pins driven no compiling step, no build button: save the text, run the text
Interpreted, not compiled. Languages like C are translated to machine code once, then run. Python is performed directly from the text, which makes the edit-run loop instant, a fair trade of some speed for a lot of learning comfort.

Coming from ladder logic, one difference deserves naming: a PLC scan loops over all rungs continuously by itself. A Python script runs once, top to bottom, then exits, unless you write the loop yourself. The "scan cycle" of your IoT programs will be a while loop you can see and control, which is why loops get their own section below.

Two ways to run Python

The REPL · for trying things

Type python3 alone and you get the >>> prompt: Read, Evaluate, Print, Loop. Each line runs immediately and shows its result. It is a calculator, an experiment bench, and the fastest way to answer "what does this do?". Quit with exit() or Ctrl+D.

Scripts · for keeping work

Write the same lines into a file with nano hello.py, run it with python3 hello.py. Scripts are repeatable, committable and gradeable; every hand-in from now on is a script in your repository. Rule of thumb: explore in the REPL, keep in a script.

$ python3
Python 3.11.2 (main, ...) on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 3.3 - 2.0
1.2999999999999998
>>> (3.3 - 2.0) / 330        # the LED current calculation from the GPIO page, in amps
0.00393939393939394
>>> exit()

About that 1.2999999999999998

Computers store decimals in binary, and most decimal fractions have no exact binary form, so tiny rounding appears. It is universal to floating-point arithmetic, not a Python bug, and it is why measurement code compares with tolerances ("within 0.01") rather than exact equality. File the fact away; it returns with sensor readings.

Variables and types

A variable is a name attached to a value. Naming values is how programs stay readable and changeable: alter delay once and every use follows.

>>> delay = 0.5              # a float (decimal number)
>>> blinks = 10              # an int (whole number)
>>> name = "lastname-pi"     # a str (text, in quotes)
>>> running = True           # a bool: True or False, capitalized
>>> blinks * delay
5.0
>>> print(f"{name} will blink {blinks} times")
lastname-pi will blink 10 times
  • = means assign, "attach this name to this value", not mathematical equality. (Equality testing is ==, next section.)
  • The main types this course uses: int, float, str, bool. type(delay) tells you what you have.
  • print() writes to the terminal; an f"..." string with {name} inside splices values into text. You will format every sensor reading this way.
  • Names: lowercase with underscores (press_count), chosen to make the code read like the Week 5 pseudocode it came from.

Decisions: if and else

temperature = 31.5

if temperature > 30:
    print("Too hot, fan on")
elif temperature < 18:
    print("Too cold, heater on")
else:
    print("In range")

Three things to absorb, because every control program is made of them:

  • The condition (temperature > 30) is an expression that evaluates to True or False. Comparisons: > < >= <= == (equals) != (not equals); combine with and, or, not.
  • The colon and the indent define the block: everything indented under the if belongs to it. This is the thermostat logic of Assignment 2 in miniature.
  • elif chains further tests; else catches everything remaining. At most one branch runs.

Indentation is grammar, not decoration

In Python the indent is the block structure: four spaces per level, consistently. Mixing widths, or mixing tabs and spaces, produces IndentationError or, worse, code that runs but does the wrong thing because a line sits outside the block you meant. nano on the Pi and every serious editor insert spaces for you; when a block ends, unindent back to the previous level. If a program misbehaves, checking the indentation is step one.

Repetition: while and for

while · repeat as long as

from time import sleep

count = 0
while count < 5:
    print(f"blink {count}")
    sleep(0.5)
    count = count + 1

Runs while the condition stays true. while True: runs forever, and that is not a mistake: it is the scan cycle of every monitoring program you will write. Stop a running script with Ctrl+C.

for · repeat for each

for count in range(5):
    print(f"blink {count}")

for colour in ["red", "green", "blue"]:
    print(colour)

Walks through a sequence: range(5) yields 0,1,2,3,4; a list in square brackets yields its items. Use for when the collection or count is known, while when a condition decides.

The sleep() call comes from the time module via an import: from time import sleep at the top of the file makes the function available. Imports are how all borrowed code arrives, including gpiozero two pages from now; the Environments page explains where imported code actually lives.

Functions: naming a recipe

from time import sleep

def blink_message(times, delay):
    """Print a blink message 'times' times, 'delay' seconds apart."""
    for n in range(times):
        print(f"blink {n}")
        sleep(delay)

blink_message(3, 0.5)     # fast
blink_message(2, 1.0)     # slow

A function wraps a block under a name, with parameters for the parts that vary. Defining it does nothing; calling it runs it. Functions are how programs stop being one long scroll: the same recipe, reused with different values, testable on its own. A function can also return a value to its caller (def celsius(raw): return raw * 0.1), which is how sensor-reading code will hand you numbers. Week 6 builds classes out of exactly this idea.

Tracebacks: errors that explain themselves

You will cause errors today, on purpose and otherwise. Python reports them with a traceback, and like Git's messages in Week 1, it is written to be read:

$ python3 blink.py
Traceback (most recent call last):
  File "/home/username/iot/week4/blink.py", line 4, in <module>
    print(f"blink {countt}")
                   ^^^^^^
NameError: name 'countt' is not defined. Did you mean: 'count'?
  • Read from the bottom. The last line is the diagnosis: the error type (NameError) and the explanation, here with the fix suggested.
  • The lines above give the address: file and line number. Open the file at that line; the answer is almost always there or one line earlier.
  • The frequent ones this week: SyntaxError (typo in the grammar, often a missing colon or quote), IndentationError (see the stop box above), NameError (misspelled name, or used before assignment), ModuleNotFoundError (import failed, an environment question, not a code one).

Read more, practise more

The official Python tutorial covers this page's material in chapters 1 to 4, in the language's own words. For a gentler second telling with projects, the free book Automate the Boring Stuff with Python is the classic; its first chapters map onto today exactly. Both are linked with the other references on the Resources page.

Checklist for this stage

Check yourself

What does the interpreter do with a script, and how is that different from a PLC scan?
It performs the file's lines once, top to bottom, then exits. A PLC rescans its logic continuously by itself; in Python, continuous behaviour is a while loop you write explicitly.
When do you reach for the REPL, and when for a script?
REPL for exploring: one-line experiments with instant answers, discarded on exit. Scripts for keeping: repeatable, committable work. Typical flow: figure it out in the REPL, then write it down in the script.
What is the difference between = and ==?
= assigns: attach a name to a value. == compares: evaluate to True or False. Writing if x = 5: is a SyntaxError precisely to catch this mix-up.
Why is while True: legitimate in this course's programs?
Monitoring and control programs must run until stopped: read sensors, decide, act, repeat. The infinite loop is that scan cycle made explicit, with Ctrl+C (and later, cleaner shutdowns) as the exit.
A traceback fills the screen. Which line do you read first, and what do the others give you?
The last line first: it names the error type and usually the cause. The lines above are the address, file and line number, telling you where to look.
Defining a function ran no code. Why not, and what does?
def only records the recipe under a name. Calling it, blink_message(3, 0.5), runs it, with the arguments filling the parameters. One definition, many calls, is the whole point.