- UnifiClient service (art-of-wifi/unifi-api-client) talks to the local UDM with a read-only account (self-signed cert, verify_ssl off). Verified live: logged in and read 32 active clients. - presence:poll command (scheduled every minute, withoutOverlapping): "home" immediately on association, "away" only after an 8-min debounce so iPhone WLAN sleep can't cause false-aways. Broadcasts PresenceChanged on the presence channel. - Persons page: "Person hinzufügen" modal picks the representing device straight from the live UniFi client list (falls back to manual MAC entry if UniFi is down); the sweep then tracks that person's presence. mac + last_seen_home_at on persons. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| app | ||
| bootstrap | ||
| config | ||
| database | ||
| docker | ||
| lang | ||
| public | ||
| resources | ||
| routes | ||
| sidecar | ||
| storage | ||
| tests | ||
| .editorconfig | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| .npmrc | ||
| CLAUDE.md | ||
| README.md | ||
| artisan | ||
| composer.json | ||
| composer.lock | ||
| design-mockup.html | ||
| docker-compose.yml | ||
| handoff.md | ||
| package-lock.json | ||
| package.json | ||
| phpunit.xml | ||
| rules.md | ||
| vite.config.js | ||
README.md
HomeOS
Self-built smart-home control plane — single household, self-hosted, LAN-first. Laravel 13 · Livewire v3 · Tailwind v4 · PostgreSQL 17 + TimescaleDB · Redis/Horizon · Reverb.
Everything runs in Docker; the host needs only Docker (no PHP/Composer/Node).
Authoritative spec: handoff.md · conventions: rules.md · guide: CLAUDE.md.
First-run setup
cp .env.example .env # dev defaults work as-is
docker compose build # build the app image
docker compose run --rm app bash docker/app/bootstrap.sh # deps + key + assets + migrate/seed
bash docker/mosquitto/gen-passwd.sh # broker credentials (fills empty MQTT_*_PASSWORD)
docker compose up -d # start the full stack
docker compose upalone is not the first command —vendor/,node_modules,public/buildand the Mosquitto passwd file are not committed, so the steps above must run first.
Then open http://localhost and sign in with the seeded dev admin:
- admin@homeos.local / homeos-dev ← change this for anything but local dev.
Production
.env.example ships development defaults. For a real deployment you must:
- set
APP_ENV=productionandAPP_DEBUG=false(otherwise exceptions are exposed and the demo household is seeded into your real database); - set strong values for
DB_PASSWORD, theREVERB_APP_*keys andHOMEOS_ADMIN_PASSWORD(seeding aborts if the admin password is unset outside local/testing), and runphp artisan key:generate.
The demo seeder (DemoHomeSeeder) only runs in local/testing.
Everyday commands (in-container, R8)
docker compose exec app php artisan … # artisan
docker compose exec app composer … # composer
docker compose exec app npm run build # rebuild assets (or `npm run dev` for HMR)
docker compose exec app php artisan test # test suite
docker compose logs -f app # logs
Services & ports
| Service | Role | Host port |
|---|---|---|
app |
php-fpm + nginx + supervisor | ${APP_PORT:-80} |
reverb |
websockets (proxied same-origin via nginx /app) |
${REVERB_HOST_PORT:-6001} |
horizon · scheduler |
queue workers · cron | — |
db |
PostgreSQL 17 + TimescaleDB | 127.0.0.1:${DB_HOST_PORT:-5432} |
redis |
cache / queue | — |
All ports and HOST_UID/HOST_GID are env-driven in .env.