PySerial
PySerialDocs

Arduino

Connect Python to Arduino with PySerial. Auto-detect ports, send commands, and read sensor data over serial.

PySerial connects Python to Arduino over USB serial for sensor reading, device control, and data collection.

Quick Setup

Upload Arduino Sketch

A minimal sketch that echoes commands and reports sensor data:

void setup() {
    Serial.begin(9600);
    pinMode(13, OUTPUT);
}

void loop() {
    if (Serial.available()) {
        String command = Serial.readString();
        command.trim();

        if (command == "LED_ON") {
            digitalWrite(13, HIGH);
            Serial.println("LED ON");
        } else if (command == "LED_OFF") {
            digitalWrite(13, LOW);
            Serial.println("LED OFF");
        } else if (command == "PING") {
            Serial.println("PONG");
        }
    }
}

Send Commands from Python

import serial
import time

arduino = serial.Serial('/dev/ttyACM0', 9600, timeout=2)
time.sleep(2)  # Wait for Arduino reset

def send_command(cmd):
    arduino.write((cmd + '\n').encode())
    return arduino.readline().decode().strip()

print(send_command("LED_ON"))   # "LED ON"
time.sleep(1)
print(send_command("LED_OFF"))  # "LED OFF"

arduino.close()

Auto-Detect the Arduino Port

import serial.tools.list_ports

def find_arduino():
    for port in serial.tools.list_ports.comports():
        if 'Arduino' in port.description or 'CH340' in port.description:
            return port.device
    return None

port = find_arduino()
if port:
    print(f"Found Arduino on {port}")
else:
    print("Arduino not found")

Log Arduino test data automatically

TofuPilot records test results from your PySerial scripts, tracks pass/fail rates, and generates compliance reports. Free to start.

Temperature Sensor Example

A DHT22 sensor sending JSON over serial, read by a Python script that logs to CSV.

Arduino side:

#include <DHT.h>

#define DHTPIN 2
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

void setup() {
    Serial.begin(9600);
    dht.begin();
}

void loop() {
    float temp = dht.readTemperature();
    float humidity = dht.readHumidity();

    if (!isnan(temp) && !isnan(humidity)) {
        Serial.print("{\"temp\":");
        Serial.print(temp);
        Serial.print(",\"humidity\":");
        Serial.print(humidity);
        Serial.println("}");
    } else {
        Serial.println("ERROR:Sensor read failed");
    }

    delay(2000);
}

Python side:

import serial
import json
import csv
import time
from datetime import datetime

def log_sensor_data(port, csv_path="sensor_data.csv", duration=60):
    ser = serial.Serial(port, 9600, timeout=2)
    time.sleep(2)

    with open(csv_path, "w", newline="") as f:
        writer = csv.writer(f)
        writer.writerow(["timestamp", "temperature", "humidity"])

        start = time.time()
        while time.time() - start < duration:
            line = ser.readline().decode().strip()
            if not line or line.startswith("ERROR"):
                continue

            try:
                data = json.loads(line)
            except json.JSONDecodeError:
                continue

            now = datetime.now().isoformat()
            writer.writerow([now, data["temp"], data["humidity"]])
            print(f"[{now}] {data['temp']:.1f} C, {data['humidity']:.1f}%")

    ser.close()
    print(f"Logged {duration}s of data to {csv_path}")

log_sensor_data("/dev/ttyACM0", duration=120)

Reliable Connection with Retry

Arduino resets when PySerial opens the port. Always wait ~2 seconds before sending commands.

import serial
import time

def connect_arduino(port, baudrate=9600, retries=3):
    for attempt in range(retries):
        try:
            ser = serial.Serial(port, baudrate, timeout=2)
            time.sleep(2)
            ser.reset_input_buffer()

            ser.write(b"PING\n")
            response = ser.readline().decode().strip()
            if response == "PONG":
                print(f"Connected to Arduino on {port}")
                return ser

        except serial.SerialException as e:
            print(f"Attempt {attempt + 1} failed: {e}")
            time.sleep(1)

    raise ConnectionError(f"Could not connect to Arduino on {port}")

arduino = connect_arduino("/dev/ttyACM0")
print(send_command("LED_ON"))
arduino.close()

Arduino Mega and Due use different USB endpoints. Check your board's documentation for the correct port name (/dev/ttyACM0 vs /dev/ttyUSB0 on Linux, COM3 etc. on Windows).

Common Serial Settings

ParameterTypical Arduino ValueNotes
Baud rate9600 or 115200Must match Serial.begin() in the sketch
Data bits8Standard for Arduino
ParityNoneDefault
Stop bits1Default
Timeout1-2sSet in serial.Serial(timeout=...)
Reset delay2stime.sleep(2) after opening port