Compare commits

..

1 Commits

Author SHA1 Message Date
f4f23796d5 DOC-005: Quickstart ENV-Doku hinzufügen
- .env.example mit SILLYHOME_HA_URL und SILLYHOME_HA_TOKEN
- README: Quickstart-Sektion mit Installation, Start, ENV, Prüfung, Tests
- Hinweis zu Secrets und .gitignore
2026-06-11 03:48:33 +02:00
4 changed files with 38 additions and 33 deletions

3
.env.example Normal file
View File

@@ -0,0 +1,3 @@
# Home Assistant Zugriff
SILLYHOME_HA_URL=http://localhost:8123
SILLYHOME_HA_TOKEN=dein_long_lived_access_token

View File

@@ -12,3 +12,34 @@ TheSillyHome zeigte die Idee: statt statischer Regeln das Zuhause aus Verhaltens
- Automationen vorschlagen und direkt generieren
- Lokal-first ohne Cloudpflicht
- Erweiterbar, testbar, dokumentiert
## Quickstart (lokaler Betrieb)
1. **Voraussetzungen**
- Python 3.11+
- Home Assistant mit REST-API erreichbar
- `pip install -e .[dev]`
2. **Umgebungsvariablen** (`.env` im Projektroot)
```
SILLYHOME_HA_URL=http://localhost:8123
SILLYHOME_HA_TOKEN=dein_long_lived_access_token
```
Tipp: `.env.example` kopieren und anpassen. Tokens niemals committen!
3. **Server starten**
```
uvicorn app.main:app --reload
```
4. **Prüfen**
- OpenAPI-Docs: http://localhost:8000/docs
- Health: http://localhost:8000/health
- Entities: http://localhost:8000/v1/entities (benötigt gültige HA-Konfiguration)
5. **Tests**
```
pytest -q
ruff check .
mypy app tests
```

View File

@@ -9,21 +9,7 @@ from app.rules.recommender import Rule
class HeatingRule(Rule):
def matches(self, entities: Sequence[HaEntitySummary]) -> bool:
domains = {item.domain for item in entities}
if "climate" in domains:
return True
if "sensor" in domains:
# Nur Sensoren mit Heizungs-/Klimarelevanz
relevant_device_classes = {
"temperature",
"humidity",
"occupancy",
"presence",
"heating",
}
for entity in entities:
if entity.domain == "sensor" and entity.device_class in relevant_device_classes:
return True
return False
return "climate" in domains or "sensor" in domains
def recommendation(self, entities: Sequence[HaEntitySummary]) -> str:
return "Prüfe Heizungsregelung: Aktiviere energiesparenden Modus bei Abwesenheit."

View File

@@ -5,8 +5,8 @@ from app.rules.heating import HeatingRule
from app.rules.recommender import Recommender
def _sensor(entity_id: str, device_class: str | None = None) -> HaEntitySummary:
return HaEntitySummary(entity_id=entity_id, domain="sensor", device_class=device_class)
def _sensor(entity_id: str) -> HaEntitySummary:
return HaEntitySummary(entity_id=entity_id, domain="sensor")
def _climate(entity_id: str) -> HaEntitySummary:
@@ -16,22 +16,7 @@ def _climate(entity_id: str) -> HaEntitySummary:
def test_heating_rule_triggers() -> None:
rule = HeatingRule()
assert rule.matches([_climate("climate.living_room")])
# Relevante Sensoren
assert rule.matches([_sensor("sensor.temperature_living", device_class="temperature")])
assert rule.matches([_sensor("sensor.humidity_bath", device_class="humidity")])
assert rule.matches([_sensor("sensor.occupancy_living", device_class="occupancy")])
assert rule.matches([_sensor("sensor.presence_entry", device_class="presence")])
assert rule.matches([_sensor("sensor.heating_status", device_class="heating")])
def test_heating_rule_ignores_non_relevant_sensors() -> None:
rule = HeatingRule()
# Nicht-relevante Sensoren
assert not rule.matches([_sensor("sensor.power", device_class="power")])
assert not rule.matches([_sensor("sensor.voltage", device_class="voltage")])
assert not rule.matches([_sensor("sensor.door", device_class="door")])
assert not rule.matches([_sensor("sensor.window", device_class="window")])
assert not rule.matches([_sensor("sensor.light", device_class="illuminance")])
assert rule.matches([_sensor("sensor.temperature_living")])
def test_recommender_uses_rule() -> None: