Compare commits
1 Commits
feature/bu
...
feature/do
| Author | SHA1 | Date | |
|---|---|---|---|
| f4f23796d5 |
3
.env.example
Normal file
3
.env.example
Normal file
@@ -0,0 +1,3 @@
|
||||
# Home Assistant Zugriff
|
||||
SILLYHOME_HA_URL=http://localhost:8123
|
||||
SILLYHOME_HA_TOKEN=dein_long_lived_access_token
|
||||
31
README.md
31
README.md
@@ -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
|
||||
```
|
||||
|
||||
@@ -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."
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user