ACT-001: actuator-first sensor lifecycle
This commit is contained in:
102
app/actuators/models.py
Normal file
102
app/actuators/models.py
Normal file
@@ -0,0 +1,102 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from enum import StrEnum
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.ha.discovery import EntityRole
|
||||
|
||||
|
||||
class AssignmentSource(StrEnum):
|
||||
NONE = "none"
|
||||
AUTOMATIC = "automatic"
|
||||
MANUAL = "manual"
|
||||
|
||||
|
||||
class LifecycleStatus(StrEnum):
|
||||
PENDING_ASSIGNMENT = "pending_assignment"
|
||||
REVIEW_REQUIRED = "review_required"
|
||||
PENDING_HISTORY = "pending_history"
|
||||
TRAINED = "trained"
|
||||
STALE = "stale"
|
||||
INVALID = "invalid"
|
||||
ORPHANED = "orphaned"
|
||||
ARCHIVED = "archived"
|
||||
|
||||
|
||||
class AssignmentCandidate(BaseModel):
|
||||
entity_id: str
|
||||
domain: str
|
||||
role: EntityRole
|
||||
device_class: str | None = None
|
||||
state_class: str | None = None
|
||||
unit_of_measurement: str | None = None
|
||||
friendly_name: str | None = None
|
||||
area_name: str | None = None
|
||||
device_name: str | None = None
|
||||
score: float = Field(ge=0.0)
|
||||
confidence: float = Field(ge=0.0, le=1.0)
|
||||
auto_accepted: bool = False
|
||||
evidence: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class AssignmentSelection(BaseModel):
|
||||
selected_numeric_entity_id: str | None = None
|
||||
selected_context_entity_ids: list[str] = Field(default_factory=list)
|
||||
source: AssignmentSource = AssignmentSource.NONE
|
||||
confidence: float = Field(default=0.0, ge=0.0, le=1.0)
|
||||
review_required: bool = True
|
||||
reason: str = "Noch keine Zuordnung vorhanden."
|
||||
|
||||
|
||||
class ManualOverride(BaseModel):
|
||||
numeric_entity_id: str | None = None
|
||||
context_entity_ids: list[str] = Field(default_factory=list)
|
||||
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
note: str | None = None
|
||||
|
||||
|
||||
class LifecycleAuditEntry(BaseModel):
|
||||
at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
action: str = Field(min_length=1, max_length=120)
|
||||
reason: str = Field(min_length=1, max_length=500)
|
||||
|
||||
|
||||
class ModelLifecycleState(BaseModel):
|
||||
model_id: str
|
||||
status: LifecycleStatus = LifecycleStatus.PENDING_ASSIGNMENT
|
||||
last_reconciled_at: datetime | None = None
|
||||
last_trained_at: datetime | None = None
|
||||
last_history_signature: str | None = None
|
||||
last_history_point_count: int = Field(default=0, ge=0)
|
||||
reason: str = "Noch keine Trainingsdaten ausgewertet."
|
||||
next_action: str = "Aktuator auswählen und Zuordnung prüfen."
|
||||
audit: list[LifecycleAuditEntry] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ActuatorRecord(BaseModel):
|
||||
actuator_entity_id: str = Field(pattern=r"^[a-z0-9_]+\.[a-z0-9_]+$")
|
||||
enabled: bool = True
|
||||
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
assignment: AssignmentSelection = Field(default_factory=AssignmentSelection)
|
||||
manual_override: ManualOverride | None = None
|
||||
numeric_candidates: list[AssignmentCandidate] = Field(default_factory=list)
|
||||
context_candidates: list[AssignmentCandidate] = Field(default_factory=list)
|
||||
lifecycle: ModelLifecycleState
|
||||
|
||||
|
||||
class ReconciliationState(BaseModel):
|
||||
last_started_at: datetime | None = None
|
||||
last_completed_at: datetime | None = None
|
||||
last_trigger: str | None = None
|
||||
running: bool = False
|
||||
configured_actuators: int = Field(default=0, ge=0)
|
||||
review_required: int = Field(default=0, ge=0)
|
||||
trained_models: int = Field(default=0, ge=0)
|
||||
last_summary: str = "Noch keine Reconciliation ausgeführt."
|
||||
|
||||
|
||||
def model_id_for_actuator(actuator_entity_id: str) -> str:
|
||||
return f"actuator.{actuator_entity_id}"
|
||||
Reference in New Issue
Block a user