HouseFly runs a rate model of 4,724 identified Drosophila neurons, wired together by 126,108 measured synapses, inside Home Assistant. Your sensors go to the neurons that carry that kind of information in the animal. It walks across your dashboard. It learns which rooms it likes.
HouseFly v1 described itself as a โleaky reservoir inspired by fruit-fly motifsโ. That framing was
doing a lot of work. The brain was a 256-unit reservoir whose recurrent weights, input projections
and readouts were all drawn from rng.gauss โ and none of which ever changed.
So every motor channel was a fixed random projection of a random projection of your sensors:
statistically, a smoothed Gaussian hovering near 0.5. Nothing the fly did depended on anything.
Every behaviour you could actually observe โ the mode classifier, hunger, phototaxis โ was a
hand-written if sitting beside the reservoir rather than emerging from it. You could
have deleted the reservoir without changing what the integration appeared to do.
It also named the connectome in its docstring and then explicitly declined to use it. And it
fired a service call at every configured output every ten seconds with a value that was noise โ
cover was a supported output domain, so the documented configuration surface included your
garage door.
The question was never how to improve the reservoir. It was why there is one.
The replacement is not a bigger network. It is a set of circuits that have a known function, each receiving the kind of signal it receives in the animal.
| Circuit | What it does in the fly | What it gets from your house |
|---|---|---|
| EPG / PEN / PEG / ฮ7 | Ring attractor holding heading | Integrates the fly's own turns into a compass |
| ER ring neurons | Visual bearing into the ellipsoid body | Bearing to every card on your dashboard |
| PFL3 | Compares heading to goal, commands a turn | Steering (see the caveat below) |
| KC โ MBON | Associative memory, real plasticity | Learns which parts of the house are good |
| PAM / PPL1 | Reward and punishment teaching signals | Feeding it, and swatting at it |
| LPLC2 โ DNp09/10 | Looming detection โ escape | Motion sensors firing; your cursor |
| Projection neurons | Odour identity | The state of your house, as a smell |
| s-LNv / LNd / DN1 | Circadian morning + evening oscillators | Real local time |
There is no rule anywhere that says be active at dawn. The morning cells are driven by morning, the evening cells by evening, and arousal is read off their firing rate. The fly is crepuscular because the circuit is.
This is the part worth showing people. Nobody wrote a ring attractor. The connectome contains one.
Take the effective EPG โ ฮ7 โ EPG coupling โ using only measured synapse counts and the protocerebral bridge glomerulus labels โ and bin it by heading offset:
python3 tools/build_connectome.py and it prints this from the raw data.The first version of this gave both halves of the protocerebral bridge the same angular order. That produced a much weaker 2.7:1 profile, and a compass that held a heading perfectly well but would only ever turn one way.
The real bridge is a mirror-symmetric double map. Correcting it sharpened the signature from 2.7:1 to 23:1. The connectome said the anatomy was wrong before a single neuron was simulated.
You do not have to assume. It is readable straight out of the synapse counts:
EPG โ LEFT PEN1 โ EPG loop shift: +12.5ยฐ
EPG โ RIGHT PEN1 โ EPG loop shift: โ11.5ยฐ
EPG โ LEFT PEG โ EPG loop shift: โ5.6ยฐ
EPG โ RIGHT PEG โ EPG loop shift: +0.9ยฐ
PEN loops shift the bump in opposite directions per hemisphere. PEG loops do not shift it at all. That is the textbook split between the loop that moves the bump and the loop that holds it โ and it fell out of the data.
Learning in Drosophila happens at Kenyon cell โ MBON synapses. A Kenyon cell active at the same moment as a dopaminergic neuron in that MBON's compartment gets depressed. That is the whole rule. It is anti-Hebbian, and it is why a fly stops approaching things that turned out to be bad.
HouseFly implements exactly that, on 20,391 real KCโMBON connections. Each MBON's compartment valence is derived from which dopaminergic class dominates its input, rather than hard-coded. Those gains are what persists across restarts โ the fly does not forget your house when Home Assistant updates.
Two things were expected to fall out of the wiring and did not. Both are worth stating plainly, because โwe tried to derive it and could notโ is a result.
The plan was to read the landmark-bearing โ heading mapping off the ER โ EPG connectivity. It isn't there: that projection is near-uniform, about 7% modulation depth, with no consistent phase.
This is not a gap in the data. In the real animal that map is learned, in plastic ERโEPG synapses (Fisher et al. 2019; Kim et al. 2019). A naive fly does not have one. So HouseFly doesn't fake it โ the compass integrates the fly's own turns, exactly as a real one does in the dark, and it drifts when it cannot see.
In the animal, PFL3's left-right imbalance is the turn command, because each cell's fan-shaped-body arbor sits about a quarter turn from its bridge arbor, in opposite directions per hemisphere.
We tried it both ways โ feeding the goal into the fan-shaped body and letting the connectome do the rest, and imposing the quarter-turn offset explicitly. Neither gave reliable goal-following: the correlation between turn command and the sine of the heading error ranged from +0.03 to โ0.54 depending on the trajectory, and the closed loop never converged. That offset is where the arbors physically sit, and synapse counts between cell types do not carry it.
So the goal-seeking controller lives in coordinator.py โ four lines of proportional
control, labelled as a controller. The fly holds a heading using a connectome-derived ring
attractor, which is real, and chooses which heading to hold using arithmetic, which is not.
Keeping those visibly separate matters more than having one more thing to claim.
The fake ten-room testbed was generated, tidy and metric. Pointed at a live installation instead โ Swedish, 30 lights, Bluetooth room-presence sensors, a power meter and an electricity price โ the sensory front end turned out to be destroying most of its input before a single neuron saw it.
Any state that wasn't numeric returned a constant 0.35. So
Allrum, Loft and Kitchen all arrived as
the same smell, and the mushroom body could not learn that one room differed
from another. The information was gone before it reached a neuron.
Words now pick a glomerulus rather than a magnitude โ which is how odour identity actually works: it is carried by which neurons respond, not how hard one does. With 131 glomeruli some states inevitably collide, as they do in a real fly with about 50 for an unbounded number of odours. That is resolved where the animal resolves it: two colliding inputs still produce clearly different Kenyon cell codes โ 67 and 39 cells active with 12% overlap โ because the projection-neuron-to-Kenyon-cell divergence in the connectome pulls them apart.
tanh(value / 60) put seven temperatures spanning 11โ25 ยฐC into a
0.2-wide band, pinned a 2,840 W power sensor flat at 1.0, and turned an
electricity price of 0.43 into 0.007. Two of those channels were constants and
the third had no resolution left.
Each channel now learns its own range and reports where the current value sits inside it โ receptor neurons adapt their gain to the stimulus range they actually receive, which is why you can see indoors and outdoors. It costs two floats per entity and they persist across restarts.
abs(value) meant โ15 ยฐC and +15 ยฐC were identical readings.
On a Swedish install, that sign is the signal.sun.sun reports above_horizon, which didn't parse
as a number โ so the sun was a constant.unknown and nothing said so. A sensor stuck
on unknown is not a smell of nothing; it is no smell at all.LPLC2 โ the population that drives escape โ fires at an object expanding in the visual field. For a target of size L at range r closing at speed v, the angular size is ฮธ โ L/r, so the expansion rate is ฮธฬ = Lยทv/rยฒ. That rยฒ is the whole character of the response: the same footsteps count for far more at one metre than at five, which is why a real fly leaves it so late and then goes all at once.
A ranging sensor โ mmWave radar, ultrasonic, BLE distance โ gives r directly and v by differencing, so it delivers exactly the quantity the circuit is built for, by radar instead of by photons. Someone walking up to the door produces a genuine looming response:
Optic flow needs frames close enough together to correspond. The first house this ran on had
exactly one camera โ a motorway traffic camera whose own photo_time showed it updating
every five minutes. At that spacing there is no correspondence between frames at
all: flow would be noise, and a looming detector fed from it would fire constantly and mean
nothing. The radar in the hallway was the better eye.
This is a real model of real circuits, and it is still a model.
It is not conscious, it is not an agent, it does not understand your house, and it is not a scientific instrument. It is a small animal's wiring diagram with your sensors plugged into it.
python3 tools/validate.py runs the shipped brain and checks all
twenty-nine claims, printing the numbers โ including the marginal ones. CI runs
it on every push, alongside HACS's own validation action and Home Assistant's
hassfest.
a bump forms peak 0.223, trough 0.000 PASS
it holds still with no self-motion 0 deg of drift PASS
turning rotates the bump, right direction correlation +0.99 PASS
punishment depresses KCโMBON synapses 20,391 plastic synapses PASS
looming raises descending drive 0.0000 โ 0.2452 PASS
...and the escape is transient fell back to 0.0000 PASS
PFL3 cells are not all at the same rate spread 0.0038 PASS
arousal 03:00 0.17 06:00 1.00 12:00 0.08 18:45 1.00 23:00 0.10 PASS
HouseFly is a HACS custom repository. In Home Assistant:
https://github.com/Vortitron/HouseFly, type IntegrationBoth Lovelace cards register themselves โ no resource setup needed:
# Lets the fly out onto this dashboard. Draws nothing itself: it reports
# where your cards are and paints the fly over the top of them.
- type: custom:housefly-overlay
show_debug: true
# The connectome, with live activity in it.
- type: custom:housefly-brain-card
The repository ships a testbed/ โ a throwaway Home Assistant with a fake ten-room house:
24 lights, 23 switches, 30 drifting sensors, 15 motion detectors, all template helpers with nothing
behind them, plus six entities that exist purely so you can watch the safety layer refuse them.
git clone https://github.com/Vortitron/HouseFly
cd HouseFly/testbed && ./up.sh # http://localhost:8124
Or skip the setup entirely: Vome hosts Home Assistant instances you can create in a few seconds, which is where the live demo of this runs.
A fly with write access to your house is a bad idea unless the boundaries are real ones.
lock, alarm_control_panel,
cover, climate, water_heater, humidifier, valve,
vacuum, lawn_mower, script, automation, scene.boiler,
freezer, pump, oven, server, alarm,
garage, charger, and about twenty more.Start it on a spare lamp.
Both datasets are CC-BY 4.0, and both are fetched at build time rather than vendored.
The flies did the hard part.