FastAPI and HTTP Backend
uv Package Manager
uv is a modern Python package manager that replaces venv + pip.
uv init myproject # create project with pyproject.toml
uv add fastapi['standard'] # add dependency
uv add smbus2
uv remove <package> # remove dependency| uv | pip + venv | |
|---|---|---|
| Project init | uv init | python -m venv .venv |
| Install | uv add <pkg> | pip install <pkg> |
| Lock file | pyproject.toml | requirements.txt |
| Modern? | Yes (2024+) | Standard but older |
FastAPI Setup
uv add fastapi['standard']# app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"status": "ok"}Run:
fastapi run # production mode (accessible on network via Tailscale IP)
fastapi dev # development with auto-reloadAuto-generated API docs available at /docs endpoint.
Sensor / Actuator Pattern (model.py)
from typing import Any
class Sensor():
device: Any
UNIT: str = ""
def __init__(self, device: Any):
self.device = device
def read_sensor(self) -> str:
"""Returns current reading as string."""
pass
class Actuator():
device: Any
state: str = ""
def __init__(self, device: Any):
self.device = device
def control_actuator(self, state: str) -> str:
"""Changes state, returns new state as string."""
passREST Endpoints
@app.get("/read/{sensor_id}")
def read_sensor(sensor_id: str):
return {"value": sensors[sensor_id].read_sensor()}
@app.put("/control/{actuator_id}")
def control_actuator(actuator_id: str, state: str):
return {"state": actuators[actuator_id].control_actuator(state)}Sensor IDs: "temperature", "humidity"
Actuator IDs: "led", "fan"
AHT20 via smbus2
CRITICAL: reTerminal uses I2C bus 4, not bus 1. The
Seeed-grove.pylibrary is broken — use this directly.
from smbus2 import SMBus
from time import sleep
class AHT20:
def __init__(self, address=0x38, bus=4):
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
# One instance shared by both TemperatureSensor and HumiditySensor
aht20 = AHT20(bus=4)reTerminal Display
# Rotate screen to landscape (270°)
wlr-randr --output <display-name> --transform 270
# Fix "cannot open display" when running GUI over SSH
export DISPLAY=:0See Also
- a1-reterminal-control-center source (full assignment details)
- IoT System Architecture topic
- MQTT and IoT Protocols topic (HTTP vs MQTT)
- Python Essentials topic (uv, venv)
- using-devices source (AHT20 installation options)