Bootstrap SillyHome Future v2 core
This commit is contained in:
130
app/core/models.py
Normal file
130
app/core/models.py
Normal file
@@ -0,0 +1,130 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from enum import StrEnum
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class HandoffMode(StrEnum):
|
||||
SHADOW = "shadow"
|
||||
CANDIDATE = "candidate"
|
||||
CONTROLLED = "controlled"
|
||||
CONFLICT = "conflict"
|
||||
ROLLBACK = "rollback"
|
||||
|
||||
|
||||
class SafetyStage(StrEnum):
|
||||
OBSERVE = "observe"
|
||||
DRY_RUN = "dry_run"
|
||||
ACTIVE = "active"
|
||||
BLOCKED = "blocked"
|
||||
|
||||
|
||||
class EntityState(BaseModel):
|
||||
entity_id: str = Field(pattern=r"^[a-z0-9_]+\.[a-z0-9_]+$")
|
||||
domain: str
|
||||
state: str | None = None
|
||||
changed_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
area_name: str | None = None
|
||||
device_id: str | None = None
|
||||
friendly_name: str | None = None
|
||||
|
||||
|
||||
class StateEvent(BaseModel):
|
||||
entity_id: str = Field(pattern=r"^[a-z0-9_]+\.[a-z0-9_]+$")
|
||||
new_state: str | None = None
|
||||
changed_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
attributes: dict[str, str] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class BehaviorPatternV2(BaseModel):
|
||||
actuator_entity_id: str
|
||||
target_state: str
|
||||
trigger_entity_id: str | None = None
|
||||
trigger_state: str | None = None
|
||||
context: dict[str, str] = Field(default_factory=dict)
|
||||
support: int = Field(default=1, ge=1)
|
||||
confidence: float = Field(default=0.0, ge=0.0, le=1.0)
|
||||
source: str = Field(default="observed", max_length=40)
|
||||
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
|
||||
|
||||
class LearningProfile(BaseModel):
|
||||
actuator_entity_id: str
|
||||
patterns: list[BehaviorPatternV2] = Field(default_factory=list)
|
||||
feedback_positive: int = Field(default=0, ge=0)
|
||||
feedback_negative: int = Field(default=0, ge=0)
|
||||
model_version: str = "empty"
|
||||
|
||||
|
||||
class ControlProfile(BaseModel):
|
||||
actuator_entity_id: str
|
||||
stage: SafetyStage = SafetyStage.OBSERVE
|
||||
min_confidence: float = Field(default=0.82, ge=0.0, le=1.0)
|
||||
manual_block: bool = False
|
||||
cooldown_seconds: int = Field(default=900, ge=0)
|
||||
handoff_mode: HandoffMode = HandoffMode.SHADOW
|
||||
related_automation_ids: list[str] = Field(default_factory=list)
|
||||
paused_automation_ids: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class RoomProfile(BaseModel):
|
||||
room_id: str = Field(pattern=r"^[a-z0-9_-]{1,64}$")
|
||||
name: str
|
||||
actuator_entity_ids: list[str] = Field(default_factory=list)
|
||||
context_entity_ids: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class SceneProfile(BaseModel):
|
||||
scene_id: str = Field(pattern=r"^[a-z0-9_-]{1,64}$")
|
||||
name: str
|
||||
actuator_entity_ids: list[str] = Field(default_factory=list)
|
||||
trigger_entity_id: str | None = None
|
||||
confidence: float = Field(default=0.0, ge=0.0, le=1.0)
|
||||
|
||||
|
||||
class Decision(BaseModel):
|
||||
actuator_entity_id: str
|
||||
target_state: str | None = None
|
||||
confidence: float = Field(default=0.0, ge=0.0, le=1.0)
|
||||
allowed: bool = False
|
||||
executed: bool = False
|
||||
dry_run: bool = False
|
||||
reason: str
|
||||
blockers: list[str] = Field(default_factory=list)
|
||||
trigger_entity_id: str | None = None
|
||||
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
|
||||
|
||||
class AuditEvent(BaseModel):
|
||||
event_id: str
|
||||
kind: str = Field(max_length=40)
|
||||
entity_id: str | None = None
|
||||
message: str = Field(max_length=700)
|
||||
decision: Decision | None = None
|
||||
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
|
||||
|
||||
class RuntimeState(BaseModel):
|
||||
entities: dict[str, EntityState] = Field(default_factory=dict)
|
||||
audit: list[AuditEvent] = Field(default_factory=list)
|
||||
websocket_status: str = "unavailable"
|
||||
|
||||
|
||||
class LearningState(BaseModel):
|
||||
profiles: dict[str, LearningProfile] = Field(default_factory=dict)
|
||||
rooms: dict[str, RoomProfile] = Field(default_factory=dict)
|
||||
scenes: dict[str, SceneProfile] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class ControlState(BaseModel):
|
||||
profiles: dict[str, ControlProfile] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class BackupBundle(BaseModel):
|
||||
exported_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
runtime: RuntimeState
|
||||
learning: LearningState
|
||||
control: ControlState
|
||||
|
||||
Reference in New Issue
Block a user