first
This commit is contained in:
0
backend/app/services/__init__.py
Normal file
0
backend/app/services/__init__.py
Normal file
134
backend/app/services/entity_actions.py
Normal file
134
backend/app/services/entity_actions.py
Normal file
@@ -0,0 +1,134 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from sqlmodel import Session
|
||||
|
||||
from app.database import get_engine
|
||||
from app.ha_client import ha_client
|
||||
from app.models import EntityCache, EntityFlag, AuditLog
|
||||
|
||||
|
||||
def _get_current_state(session: Session, entity_id: str) -> str | None:
|
||||
"""Récupère l'état actuel d'une entité depuis le cache."""
|
||||
entity = session.get(EntityCache, entity_id)
|
||||
return entity.state if entity else None
|
||||
|
||||
|
||||
def _save_original_state(session: Session, entity_id: str):
|
||||
"""Sauvegarde l'état original avant désactivation."""
|
||||
flag = session.get(EntityFlag, entity_id)
|
||||
if not flag:
|
||||
flag = EntityFlag(entity_id=entity_id)
|
||||
# Ne sauvegarder que si pas déjà désactivé (garder le vrai état original)
|
||||
if not flag.original_state:
|
||||
flag.original_state = _get_current_state(session, entity_id)
|
||||
flag.disabled_at = datetime.utcnow()
|
||||
session.add(flag)
|
||||
return flag
|
||||
|
||||
|
||||
def _clear_original_state(session: Session, entity_id: str):
|
||||
"""Efface l'état original lors de la réactivation."""
|
||||
flag = session.get(EntityFlag, entity_id)
|
||||
if flag:
|
||||
flag.original_state = None
|
||||
flag.disabled_at = None
|
||||
session.add(flag)
|
||||
|
||||
|
||||
async def disable_entity(entity_id: str) -> dict:
|
||||
mode = "local_flag"
|
||||
error = ""
|
||||
|
||||
# Sauvegarder l'état original
|
||||
with Session(get_engine()) as session:
|
||||
_save_original_state(session, entity_id)
|
||||
session.commit()
|
||||
|
||||
# Tenter désactivation via HA registry
|
||||
try:
|
||||
await ha_client.update_entity_registry(entity_id, disabled_by="user")
|
||||
mode = "ha_registry"
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
# Fallback : flag local
|
||||
with Session(get_engine()) as session:
|
||||
flag = session.get(EntityFlag, entity_id)
|
||||
if not flag:
|
||||
flag = EntityFlag(entity_id=entity_id)
|
||||
flag.ignored_local = True
|
||||
session.add(flag)
|
||||
session.commit()
|
||||
|
||||
_log_action("disable", [entity_id], mode, error)
|
||||
return {"entity_id": entity_id, "mode": mode, "error": error}
|
||||
|
||||
|
||||
async def enable_entity(entity_id: str) -> dict:
|
||||
mode = "local_flag"
|
||||
error = ""
|
||||
|
||||
try:
|
||||
await ha_client.update_entity_registry(entity_id, disabled_by=None)
|
||||
mode = "ha_registry"
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
with Session(get_engine()) as session:
|
||||
flag = session.get(EntityFlag, entity_id)
|
||||
if flag:
|
||||
flag.ignored_local = False
|
||||
session.add(flag)
|
||||
session.commit()
|
||||
|
||||
# Effacer l'état original
|
||||
with Session(get_engine()) as session:
|
||||
_clear_original_state(session, entity_id)
|
||||
session.commit()
|
||||
|
||||
_log_action("enable", [entity_id], mode, error)
|
||||
return {"entity_id": entity_id, "mode": mode, "error": error}
|
||||
|
||||
|
||||
def set_flag(entity_ids: list[str], action: str) -> list[dict]:
|
||||
results = []
|
||||
with Session(get_engine()) as session:
|
||||
for eid in entity_ids:
|
||||
flag = session.get(EntityFlag, eid)
|
||||
if not flag:
|
||||
flag = EntityFlag(entity_id=eid)
|
||||
|
||||
if action == "favorite":
|
||||
flag.favorite = True
|
||||
elif action == "unfavorite":
|
||||
flag.favorite = False
|
||||
elif action == "ignore":
|
||||
# Sauvegarder l'état original avant ignore
|
||||
if not flag.original_state:
|
||||
flag.original_state = _get_current_state(session, eid)
|
||||
flag.disabled_at = datetime.utcnow()
|
||||
flag.ignored_local = True
|
||||
elif action == "unignore":
|
||||
flag.ignored_local = False
|
||||
flag.original_state = None
|
||||
flag.disabled_at = None
|
||||
|
||||
session.add(flag)
|
||||
results.append({"entity_id": eid, "action": action, "ok": True})
|
||||
|
||||
session.commit()
|
||||
|
||||
_log_action(action, entity_ids, "ok", "")
|
||||
return results
|
||||
|
||||
|
||||
def _log_action(action: str, entity_ids: list[str], result: str, error: str):
|
||||
with Session(get_engine()) as session:
|
||||
log = AuditLog(
|
||||
ts=datetime.utcnow(),
|
||||
action=action,
|
||||
entity_ids_json=json.dumps(entity_ids),
|
||||
result=result,
|
||||
error=error,
|
||||
)
|
||||
session.add(log)
|
||||
session.commit()
|
||||
53
backend/app/services/scanner.py
Normal file
53
backend/app/services/scanner.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.database import get_engine
|
||||
from app.ha_client import ha_client, normalize_entity
|
||||
from app.models import EntityCache
|
||||
from app.scan_state import scan_state
|
||||
|
||||
|
||||
async def run_scan():
|
||||
scan_state.start()
|
||||
try:
|
||||
states = await ha_client.fetch_all_states()
|
||||
scan_state.total = len(states)
|
||||
|
||||
# Tenter de récupérer le registry (peut échouer si WS non dispo)
|
||||
registry_map: dict[str, dict] = {}
|
||||
try:
|
||||
registry = await ha_client.fetch_entity_registry()
|
||||
registry_map = {e["entity_id"]: e for e in registry}
|
||||
except Exception:
|
||||
pass # On continue sans registry
|
||||
|
||||
with Session(get_engine()) as session:
|
||||
for i, state in enumerate(states):
|
||||
entity_id = state.get("entity_id", "")
|
||||
reg_entry = registry_map.get(entity_id)
|
||||
normalized = normalize_entity(state, reg_entry)
|
||||
|
||||
existing = session.get(EntityCache, entity_id)
|
||||
if existing:
|
||||
for key, value in normalized.items():
|
||||
if key != "entity_id":
|
||||
setattr(existing, key, value)
|
||||
existing.fetched_at = datetime.utcnow()
|
||||
else:
|
||||
entity = EntityCache(
|
||||
**normalized,
|
||||
fetched_at=datetime.utcnow(),
|
||||
)
|
||||
session.add(entity)
|
||||
|
||||
scan_state.progress = i + 1
|
||||
|
||||
session.commit()
|
||||
|
||||
scan_state.finish(len(states))
|
||||
|
||||
except Exception as e:
|
||||
scan_state.fail(str(e))
|
||||
raise
|
||||
Reference in New Issue
Block a user