GPIO and reTerminal

GPIO Overview

  • 40 GPIO pins on Raspberry Pi / reTerminal
  • Logic level: 3.3V (outputs HIGH = 3.3V, inputs accept up to 3.3V)
  • Max per-pin current: 16mA
  • No native ADC — use Grove Base Hat for analog sensors

Check pinout: pinout (provided by GPIO Zero package)

GPIO Zero — Python Library

Uses BCM (Broadcom) pin numbering by default — LED(17) means BCM17, not physical pin 17.

from gpiozero import LED, Button, PWMLED, Servo
from time import sleep
from signal import pause

LED (GPIO 17)

led = LED(17)
led.on()
led.off()
led.toggle()
led.blink()       # blinks indefinitely in background

PWMLED (variable brightness)

led = PWMLED(17)
led.value = 0      # off
led.value = 0.5    # half brightness
led.value = 1      # full brightness
led.pulse()        # continuously fade in/out

Button (GPIO 2)

button = Button(2)
 
# Poll state
if button.is_pressed:
    print("Pressed")
 
# Blocking waits
button.wait_for_press()
button.wait_for_release()
 
# Callbacks (non-blocking — MUST call pause() to keep script alive)
button.when_pressed = led.on
button.when_released = led.off
 
# Hold detection
btn = Button(17, hold_time=2)
btn.when_held = shutdown_function    # fires after held 2 seconds
 
pause()  # REQUIRED: keeps script alive so callbacks can fire

signal.pause() — if you set callbacks and let the script end, GPIOs reset and callbacks never fire. Always call pause() after setting callbacks.

Button + LED shorthand

led.source = button   # LED mirrors button state directly (no loop needed)
pause()

Button + LED explicit loop

from gpiozero import LED, Button
led = LED(17)
button = Button(2)
while True:
    if button.is_pressed:
        led.on()
    else:
        led.off()

Enabling I2C (required for Grove Hat ADC)

I2C is disabled by default. Enable before using Grove Base Hat or AHT20.

sudo raspi-config   # Interface Options → I2C → Yes → reboot
sudo apt-get install -y python3-smbus i2c-tools
i2cdetect -y 1      # verify devices detected (UU = in use by kernel driver)

Grove Base Hat (ADC)

Adds 12-bit ADC to Pi (which has NO native ADC):

  • 8 analog channels (A0–A7, 0–4095 values, 0–3.3V)
  • Communicates to Pi over I2C (not SPI)
  • Also: 6 digital, 3 I2C, 1 PWM, 1 UART connectors

grove.adc API

from grove.adc import ADC
import time
 
adc = ADC()                        # I2C address 0x04 by default
 
adc.read_voltage(0)                # channel A0 → voltage in mV
adc.read_raw(0)                    # channel A0 → raw 12-bit int (0–4095)
adc.read(0)                        # channel A0 → ratio vs supply (0.1% units)
 
# Example: read joystick X/Y axes
x_mv = adc.read_voltage(0)        # VRx → analog port A0
y_mv = adc.read_voltage(1)        # VRy → analog port A1

reTerminal Built-In Devices

LEDs and Buzzer via /sys/

DevicePath
LED 0/sys/class/leds/usr_led0/brightness
LED 1/sys/class/leds/usr_led1/brightness
LED 2/sys/class/leds/usr_led2/brightness
Buzzer/sys/class/leds/usr_buzzer/brightness

Values: 0 = off, 255 = on (max brightness)

Problem: these files are root-owned — echo > file fails even with sudo.

Solution: sudo + tee

echo 255 | sudo tee /sys/class/leds/usr_led0/brightness    # LED on
echo 0   | sudo tee /sys/class/leds/usr_led0/brightness    # LED off
echo 1   | sudo tee /sys/class/leds/usr_buzzer/brightness  # Buzzer on

Why tee works: sudo applies to tee, which writes to the file with root permission.

Luminosity Sensor

cat /sys/bus/iio/devices/iio:device0/in_illuminance_input
# Output: 2719 (Lux) — readable without sudo

seeed-python-rpi Library

pip install git+https://github.com/Seeed-Studio/Seeed_Python_RPi/
pip install RPi-GPIO
import seeed_python_rpi.core as rt
import time
 
rt.buzzer = True       # buzzer on
time.sleep(1)
rt.buzzer = False      # buzzer off
# Also: rt.led0, rt.led1, rt.led2 etc.

Run with root (required for hardware access)

sudo $(which python) script.py      # recommended: use venv python with sudo
sudo ./.venv/bin/python script.py   # alternative: direct path

AHT20 Sensor (I2C, via Grove Hat)

Temperature: -40°C to 85°C | Humidity: 0–100% RH

Preferred method: smbus2 direct (grove.py is broken as of A1).
Critical: reTerminal uses I2C bus 4, not bus 1.

from smbus2 import SMBus
from time import sleep
 
class AHT20:
    def __init__(self, address=0x38, bus=4):   # bus=4 on reTerminal!
        self.address = address
        self.bus = SMBus(bus)
        self.bus.write_i2c_block_data(self.address, 0xBE, [0x08, 0x00])
        sleep(0.02)
 
    def read(self):
        self.bus.write_i2c_block_data(self.address, 0xAC, [0x33, 0x00])
        sleep(0.08)
        data = self.bus.read_i2c_block_data(self.address, 0x00, 7)
        humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4
        humidity = humidity * 100 / 1048576.0
        temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]
        temperature = temperature * 200 / 1048576.0 - 50
        return temperature, humidity

Install: pip install smbus2 or uv add smbus2

Alternative (adafruit, still works):

pip install adafruit-circuitpython-ahtx0 adafruit-extended-bus

ydotool (Mouse/Keyboard Automation)

Used to control the reTerminal mouse programmatically (e.g. from joystick input).

# Start daemon first (required!)
sudo ydotoold & disown
 
# Add to ~/.bashrc
export YDOTOOL_SOCKET=/tmp/.ydotool_socket
 
# Optionally allow without sudo
sudo chmod 777 /tmp/.ydotool_socket
ydotool mousemove -x -100 -y 100            # relative move
ydotool mousemove --absolute -x 100 -y 100  # absolute move
ydotool click 0xC0                          # left click
ydotool click 0xC1                          # right click
ydotool type 'hello'

From Python:

import subprocess
subprocess.run(['ydotool', 'mousemove', '-x', str(dx), '-y', str(dy)])
subprocess.run(['ydotool', 'click', '0xC0'])

Permissions

User must be in gpio group (default user already is):

sudo usermod -a -G gpio <username>

See Also