Logging Pi temperatures to SQLite
The server lives in a cupboard with the router and a Raspberry Pi. In July the cupboard felt warm to the touch, and I wanted numbers instead of a feeling.
- Project
- pitemp
- Stack
- Python, SQLite, a 1-wire sensor
- Time spent
- About 6 evenings
- Status
- alerts pending
didWhat I did
Two readings, once a minute. The Pi's own CPU temperature comes from a file the kernel exposes. Air temperature comes from a cheap 1-wire sensor on a short cable, which also shows up as a file once the overlay is enabled in the boot config.
CPU_PATH = Path("/sys/class/thermal/thermal_zone0/temp")
SENSOR_GLOB = "/sys/bus/w1/devices/28-*/w1_slave"
def read_cpu() -> float:
return int(CPU_PATH.read_text()) / 1000
A Python script reads both and stores them in SQLite with a timestamp. A second script renders a small SVG chart of the last seven days into a static page, served next to the status page.
The first month of data was the interesting part. The cupboard peaked at 38 °C on a Sunday evening, exactly when the weekly backup prune was running, with the Pi's CPU at 61 °C. Leaving the cupboard door open by two centimetres brought the peak down to 33 °C.
brokeWhat broke
85 degrees out of nowhere. Every few days a single reading of exactly 85.0 °C appeared. That is the sensor's power-on reset value: it means a conversion didn't finish, not that anything is hot. The sensor file also has a CRC line that ends in YES or NO, which I had been ignoring.
POWER_ON_VALUE = 85_000
def read_air(path: Path) -> float | None:
crc_line, data_line = path.read_text().splitlines()[:2]
if not crc_line.endswith("YES"):
return None
raw = int(data_line.rsplit("t=", 1)[1])
return None if raw == POWER_ON_VALUE else raw / 1000
Missing readings. When I moved the sensor to a longer cable, about one reading in ten went missing. The pull-up resistor I had used was too weak for the length. A 4.7 kΩ one fixed it, which is what the datasheet said in the first place.
SD card wear. One write per minute is small, but each one is a separate transaction on an SD card. I switched SQLite to WAL mode and now keep readings in memory, writing them in one batch every ten minutes. Losing up to ten minutes on a power cut is fine for this.
nextWhat's next
- A threshold check type for the status page: amber above 35 °C in the cupboard, red above 40 °C.
- A second sensor outside the cupboard, so I can tell a hot room from a hot cupboard.
- Move the weekly prune to the early morning, when the flat is coolest, and see if the peak moves with it.