What the House Heard:以 TabPFN 和 Gemma 離線把智能家居感測器記錄寫成鬼故事
What the House Heard: a ghost story told by your smart home's sensor logs, offline with TabPFN and Gemma
What the House Heard 以 TabPFN 分析智能家居感測器記錄,逐分鐘判斷各房間是否有人,再由本地運行的 Gemma 4 撰寫經事實核查的鬼故事。示範使用四房單位的合成數據,包括七個普通夜晚和一個萬聖節夜晚;TabPFN 標記出三宗預設的異常事件,沒有誤標看似奇怪但有合理解釋的情況。
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
What I Built
A house with sensors keeps a diary every night. CO₂ climbs when someone breathes in a closed room, the hallway motion sensor fires when someone walks past, a contact sensor knows when the front door opens. What the House Heard reads one night of that diary on your own computer and asks: who was in which room, minute by minute, and did anything turn up in a room that nobody walked to?
TabPFN, Prior Labs' tabular foundation model, estimates for every room and every minute how likely it is that a person was there. Anything that looks like a person in a room nobody reached through the hallway, while the bedroom is still occupied, gets flagged. Gemma 4, running locally through llama.cpp, then tells the night back as a short ghost story, and a fact check makes sure the story quotes only times and readings that are really in the logs.
That is how I read the theme: the ghost story is already in the machine, and the job is to let it out without the diary leaving the house.
The data in the demo is synthetic. A simulator writes seven ordinary nights for a four-room flat and one Halloween night with three events nobody can explain, plus decoys that look strange but are not: a cat that sets off motion sensors, a lamp left on after bedtime, a fridge compressor that hums every 45 minutes, and a resident who cannot sleep and sits in the dark living room.
Demo
Live report: https://hyunsikparker.github.io/what-the-house-heard/sample/report.html
TabPFN flagged exactly the three injected events and none of the decoys:
| Time | Room | Why it is strange |
|---|---|---|
| 02:47–02:55 | living room | nobody crossed the hallway, the bedroom still looked occupied; CO₂ up 45.6 ppm in the dark (1.4 lux at most), sound up to 53.5 dBA, 7 motion triggers |
| 03:12–03:19 | kitchen | same pattern with the light on (82.3 lux) and CO₂ up 99.3 ppm |
| 03:33 | hallway | the front door contact opened and the hallway motion sensor saw nothing |
The resident who sat in the dark living room at 00:51 and the walk to the kitchen at 01:58 came through the hallway, so they count as explained. The cat's walk at 04:18 was not flagged; in the simulation a cat trips motion sensors but adds no CO₂.
Here is part of what Gemma wrote from that evidence:
You lie in the dark, listening to the rhythmic breathing of your partner beside you. The house is silent until the sensors begin to betray your sanctuary. At 02:47, something moves in the living room despite no one leaving the bedroom. You hear a disturbance, a sound reaching 53.5 dBA, while the humidity climbs to 46.7%.
The boring explanation: A faulty sensor or a small pest is moving through the walls and vents, while a neighbor may have briefly propped the door open.
The report ends with: Fact check passed: 3 clock times and 6 readings in the story all appear in the evidence (attempt 1).
Code
HyunsikParker
/
what-the-house-heard
Offline ghost stories from smart-home sensor logs: TabPFN finds who was where, Gemma tells the night, a fact check keeps it honest. Synthetic data.
What the House Heard
A smart home records a lot at night: CO₂, light, sound, motion, the front door. What the House Heard reads one night of those logs on your own computer and asks a plain question: who was in which room, minute by minute? Anything that looks like a person in a room nobody walked to gets flagged. A local Gemma model then tells the night back as a short ghost story, and a fact check makes sure every time and reading in the story comes from the logs.
Built with PriorLabs-TabPFN. Made for the DEV Hacktoberfest Open-Source AI Challenge, Week 4: Ghost in the Machine
All data in this repository is synthetic (see simulate.py).
How it works
-
simulate.pywrites seven ordinary nights for a four-room flat (labelled: which rooms had a person in them) and one unlabelled Halloween night. The ordinary nights include the things that…
How I Built It
Occupancy with TabPFN. Each room-minute becomes one row with twelve features: CO₂ and its five-minute rise, how far CO₂ sits above the room's recent floor, light, sound above the room's median, motion over three minutes, temperature and humidity changes, the door contact, the time of night and the room. TabPFN gets a 3,000-row sample of the labelled nights as its context. There is no training loop: fit() stores the context and predict_proba() scores all 2,160 room-minutes of the new night. As a check, I gave it six labelled nights and asked about the seventh: it labelled every room-minute correctly. Simulated sensors are much cleaner than real ones, so I read that as "the pipeline works", not as a claim about a real home. Two fits (the check and the real night) take about a minute on the CPU of an M4 Mac mini.
From probabilities to ghosts. A room counts as occupied when TabPFN puts it above 0.5 for at least two minutes. The event is unexplained when nobody crossed the hallway in the three minutes before and the bedroom still looks occupied. "Crossed the hallway" means TabPFN's hallway probability or the raw hallway motion count, because during development the motion sensor alone missed a quick walk and turned a trip to the kitchen into a ghost.
The story with Gemma. Gemma 4 12B (QAT, Q4_0) runs in llama.cpp's server with thinking turned off. The prompt contains only the evidence: two residents in bed, the explained walks, and the flagged events with their readings. The rules ask for a second-person story of 150 to 220 words that quotes at least three readings exactly and invents nothing the sensors could not record. One story takes 25 to 45 seconds.
The fact check. Gemma is a good storyteller and a careless clerk. An early draft gave the kitchen "a sound up to 45.3 lux": the right number with the wrong unit, which my first, number-only check let through. The check now pairs every number with its unit (ppm, lux, dBA, %) and every clock time with an event window. When a story fails, the narrator asks again with the next seed, up to four times. Gemma also kept telling the reader they were alone in the house although the logs show two people in the bedroom; telling it that the reader lies awake next to the other resident fixed that. The check does not catch every flourish: the door still "clicks open" in the story, although a contact sensor records no sound.
Why Does Open Innovation Matter?
Sensor logs are a record of when you sleep, when you get up and when your home is empty. Here that record never leaves the computer: TabPFN runs on the CPU, Gemma runs in llama.cpp, nothing calls a hosted API, and the whole thing works with the Wi-Fi off.
Local weights also made the fact check cheap. Retrying a story with a new seed costs half a minute on my own machine rather than another metered request, so the pipeline can afford to reject a story over one wrong unit.
TabPFN's in-context learning suits homes, because every flat is laid out differently and nobody wants to train a model per household. In the simulation, six or seven labelled nights as context were enough.
A note on versions: Prior Labs recommends TabPFN-3.5, which needs a licence acceptance on their platform. I used TabPFN v2 because its weights run offline without an account; 3.5 uses the same scikit-learn interface.
Prize Categories
- Best Use of TabPFN
- Best Use of Gemma
Built with PriorLabs-TabPFN. All sensor data in the demo is synthetic. The code and this post were produced with Claude, Anthropic's AI agent.
來源:DEV Community · dev.to

