A platform-agnostic home topology kernel for modeling spaces and attaching behavior modules
Project description
home-topology
A platform-agnostic home topology kernel for modeling spaces (Locations), attaching behavior (Modules), and wiring everything together with a location-aware Event Bus.
home-topology is the structural backbone for smart homes:
- It models where things are (rooms, floors, zones, virtual spaces).
- It lets you attach modules like Occupancy, Actions, Comfort, Energy.
- It routes events through this topology so modules can react cleanly.
- It stays independent of Home Assistant or any specific platform.
Think of it as a tiny "operating system" for your home's spatial model.
Occupancy, automations, energy logic, etc. are apps running on top.
Why Home Topology?
If every room had a perfect presence sensor, occupancy detection would be trivial. But reality is different:
- Sensors are expensive – $30-50 per room adds up fast for a whole house
- Batteries die – Motion sensors need constant maintenance
- Devices go offline – More devices = more failure points
- Coverage gaps – Even good sensors miss corners and edges
Home Topology lets you use what you already have:
| Device | Occupancy Signal |
|---|---|
| 💡 Light switch turned on | Someone's in the room |
| 🚪 Door opened | Someone entered |
| 📺 TV playing | Living room is occupied |
| 🌡️ Thermostat adjusted | Someone's home |
| 🔊 Speaker volume changed | Activity detected |
Combine signals from motion sensors, switches, doors, media players, and more into reliable occupancy detection – without buying more hardware.
Your storage room doesn't need a motion sensor. Turn on the light → room is occupied → lights turn off after timeout. Simple.
Features
-
🧱 Location graph (topology)
Structured model of your home: house → floors → rooms → zones, with optional links to Home Assistant Areas. -
🧠 Modules as plug-ins
Occupancy, Actions, Comfort, Energy, etc. are independent modules that attach to Locations and react to events. -
🔁 Location-aware Event Bus
Simple, synchronous event pipeline with filters for type / location / ancestors / descendants. Location mutations can publish core events (location.created,location.renamed,location.parent_changed,location.deleted,location.reordered) whenLocationManageris attached to an event bus. -
🧩 Schema-driven configuration
Each module exposes a config schema; UIs can render dynamic forms per location without custom frontend code. -
🧪 Platform agnostic
Core library has no dependency on Home Assistant. HA support is a thin adapter layer. -
💾 Config & state evolution
Modules can version and migrate their configs, and optionally dump/restore runtime state via the host platform.
Installation
pip install home-topology
(Placeholder – adjust once published.)
Core Concepts
Location
A Location is a logical space: a room, floor, area, or virtual zone.
from dataclasses import dataclass
from typing import Optional, Dict, List
@dataclass
class Location:
id: str
name: str
parent_id: Optional[str]
ha_area_id: Optional[str] # optional link to a HA Area
entity_ids: List[str] # platform entity IDs mapped here
modules: Dict[str, Dict] # per-module config blobs
Locations form a hierarchy (e.g. house → main_floor → kitchen → kitchen_table_zone).
LocationManager
LocationManager owns the topology and config, not the behavior.
Responsibilities:
-
Store the location tree.
-
Provide graph queries:
parent_of,children_of,ancestors_of,descendants_of. -
Maintain canonical sibling ordering (
Location.order) and indexed reorder operations. -
Maintain entity → location mappings.
-
Store per-location module config:
location.modules["occupancy"] # config for the Occupancy module on this location
It does not implement occupancy, energy, or actions logic.
Event Bus
The Event Bus is a simple, synchronous dispatcher for domain events:
from dataclasses import dataclass
from datetime import datetime
from typing import Optional, Dict, Any
@dataclass
class Event:
type: str # "sensor.state_changed", "occupancy.changed", ...
source: str # "ha", "occupancy", "actions", ...
location_id: Optional[str]
entity_id: Optional[str]
payload: Dict[str, Any]
timestamp: datetime
publish(event)synchronously delivers events to subscribers.- Handlers are wrapped in
try/exceptso one bad module cannot crash the kernel. - Modules treat handlers as fast and CPU-bound.
- For I/O-heavy work, the host integration should offload asynchronously.
Modules
Modules are plug-ins that add behavior to the topology:
- OccupancyModule – computes
occupied/confidenceper Location. - ActionsModule – runs automations in response to semantic events.
- ComfortModule (future) – room comfort metrics.
- EnergyModule (future) – room-level energy and power.
A module:
- Receives events from the Event Bus.
- Uses the
LocationManagerto understand hierarchy. - Maintains its own runtime state.
- Emits semantic events that other modules can consume.
Example interface (simplified):
class LocationModule:
id: str
CURRENT_CONFIG_VERSION: int
def attach(self, bus, loc_manager) -> None:
"""Register event subscriptions and capture references."""
def default_config(self) -> dict:
"""Default per-location config."""
def location_config_schema(self) -> dict:
"""JSON-schema-like definition for UI configuration."""
def migrate_config(self, config: dict) -> dict:
"""Upgrade older config versions to CURRENT_CONFIG_VERSION."""
def on_location_config_changed(self, location_id: str, config: dict) -> None:
"""React to config updates for a given location."""
def dump_state(self) -> dict:
"""Optional: serialize runtime state (host is responsible for storage)."""
def restore_state(self, state: dict) -> None:
"""Optional: restore runtime state from serialized form."""
Quick Example
Note: This is illustrative, not a final API.
from home_topology.core.manager import LocationManager
from home_topology.core.bus import EventBus, Event
from home_topology.modules.occupancy.module import OccupancyModule
# 1. Kernel components
loc_mgr = LocationManager()
bus = EventBus()
# 2. Create a simple topology
kitchen = loc_mgr.create_location(
id="kitchen",
name="Kitchen",
parent_id="main_floor",
ha_area_id="area.kitchen",
)
# Map a motion sensor entity to the kitchen
loc_mgr.add_entity_to_location("binary_sensor.kitchen_motion", "kitchen")
# 3. Attach the Occupancy module
occupancy = OccupancyModule()
occupancy.attach(bus, loc_mgr)
# Optionally override per-location config
loc_mgr.set_module_config(
location_id="kitchen",
module_id="occupancy",
config={
"version": occupancy.CURRENT_CONFIG_VERSION,
"motion_sensors": ["binary_sensor.kitchen_motion"],
"timeout_seconds": 300,
},
)
# 4. Feed a normalized occupancy signal into the kernel
bus.publish(
Event(
type="occupancy.signal",
source="ha_adapter",
location_id="kitchen",
entity_id="binary_sensor.kitchen_motion",
payload={
"event_type": "trigger",
"source_id": "binary_sensor.kitchen_motion",
"timeout": 300,
},
timestamp=datetime.utcnow(),
)
)
# 5. Query occupancy state (implementation-dependent)
state = occupancy.get_location_state("kitchen")
print(state.occupied, state.confidence)
In a Home Assistant integration, you'd:
- Translate HA state changes →
Events. - Expose module state back as HA entities.
- Optionally provide a UI to configure modules per location.
See the Integration Guide for a complete, production-ready Home Assistant integration example.
Relationship to Home Assistant
home-topology is not a Home Assistant custom component.
It's a pure Python library that can back a HA integration (and other platforms).
A typical HA setup would add:
-
custom_components/home_topology/-
Uses this library to:
- Build a location graph from HA Areas / devices / entities.
- Feed HA events into the Event Bus.
- Expose module state (e.g., occupancy sensors) back to HA.
- Provide a UI for Locations and their modules (with an "Unassigned/Inbox" view for entities).
-
Building an integration? See the complete Integration Guide for step-by-step instructions, patterns, and a full Home Assistant example.
Project Status
This is a work-in-progress architecture focused on:
- Clean separation between topology, events, and behavior.
- Extensibility via modules.
- Strong testability in pure Python (without spinning up HA).
Expect breaking changes while the core stabilizes.
Development
Quick Start
# Clone and setup
git clone https://github.com/mjcumming/home-topology.git
cd home-topology
python3 -m venv .venv
source .venv/bin/activate
# Install in development mode
make dev-install
# Run tests
make test
# Run example
make example
# Run all checks
make check
Documentation
📖 Start Here:
- README.md - This file (project overview)
- docs/project-status.md ⭐ - Current sprint status, task dashboard
🔌 Integration:
- docs/integration/integration-guide.md ⭐ - Complete guide for platform integrators
📊 Project:
- docs/decisions-pending.md - Decisions log (decided and deferred)
- SECURITY.md - Security policy and vulnerability reporting
🏗️ Architecture:
- docs/architecture.md ⭐ - Complete kernel architecture specification
- docs/adr-log.md - Architecture decision records with rationale
- docs/coding-standards.md - Code style and patterns
- CONTRIBUTING.md - How to contribute
📦 Modules:
- docs/modules/occupancy-integration.md ⭐ - Occupancy integration contract and mappings
- docs/modules/occupancy-presence-interaction.md - Occupancy and presence interaction model
- docs/modules/automation-architecture.md - Automation module architecture
- docs/modules/ambient-module-design.md - Ambient module design
🧪 Testing:
- docs/testing/guide.md - Full testing documentation
- docs/testing/commands.md - Quick test reference card
📚 Reference:
- docs/project-overview.md - Detailed project guide
- docs/ai-development-guide.md - AI-assisted development guide
- CHANGELOG.md - Version history
Development Commands
make help # Show all available commands
make test-cov # Run tests with coverage
make format # Format code with black
make lint # Run ruff linter
make typecheck # Run mypy type checker
make check # Run all quality checks
Contributing
Contributions are welcome! Please read CONTRIBUTING.md before submitting PRs.
Key guidelines:
- Follow docs/coding-standards.md
- Add tests for new functionality
- Update documentation
- Run
make checkbefore committing
License
MIT License - see LICENSE for details.
Links
- Documentation: docs/
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file home_topology-0.2.0a0.tar.gz.
File metadata
- Download URL: home_topology-0.2.0a0.tar.gz
- Upload date:
- Size: 227.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
453ef48f4f1ce7984e2e85beecdf5e7c17c7c66a9ad1ce2259dea7250a8d6d06
|
|
| MD5 |
58680a8f97e841455046a0b284ffc16c
|
|
| BLAKE2b-256 |
7845f23406b3f7a7c9e6e3ff18e950c3cf43759af9138af5e43a366e650405de
|
Provenance
The following attestation bundles were made for home_topology-0.2.0a0.tar.gz:
Publisher:
release.yml on mjcumming/home-topology
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
home_topology-0.2.0a0.tar.gz -
Subject digest:
453ef48f4f1ce7984e2e85beecdf5e7c17c7c66a9ad1ce2259dea7250a8d6d06 - Sigstore transparency entry: 997257229
- Sigstore integration time:
-
Permalink:
mjcumming/home-topology@35a985499703ebdd4ba66fe7f106d6015aee4d63 -
Branch / Tag:
refs/tags/v0.2.0a0 - Owner: https://github.com/mjcumming
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35a985499703ebdd4ba66fe7f106d6015aee4d63 -
Trigger Event:
push
-
Statement type:
File details
Details for the file home_topology-0.2.0a0-py3-none-any.whl.
File metadata
- Download URL: home_topology-0.2.0a0-py3-none-any.whl
- Upload date:
- Size: 63.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd5c6b85a231b646c510a201622f8719ef8f9cb89820f981373bbeab9dbaf501
|
|
| MD5 |
e4f6bc014d1274488b31c69efd1dcb98
|
|
| BLAKE2b-256 |
1169c88e2c83df3704d26457bffbbbf954eada631f02dc0122f7a1d3831f809a
|
Provenance
The following attestation bundles were made for home_topology-0.2.0a0-py3-none-any.whl:
Publisher:
release.yml on mjcumming/home-topology
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
home_topology-0.2.0a0-py3-none-any.whl -
Subject digest:
cd5c6b85a231b646c510a201622f8719ef8f9cb89820f981373bbeab9dbaf501 - Sigstore transparency entry: 997257230
- Sigstore integration time:
-
Permalink:
mjcumming/home-topology@35a985499703ebdd4ba66fe7f106d6015aee4d63 -
Branch / Tag:
refs/tags/v0.2.0a0 - Owner: https://github.com/mjcumming
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35a985499703ebdd4ba66fe7f106d6015aee4d63 -
Trigger Event:
push
-
Statement type: