File size: 3,293 Bytes
801f056
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
"""控制面板:主动性调节 + 场景免打扰"""

from enum import Enum
from dataclasses import dataclass, field
from typing import List
import time


class ThermostatMode(Enum):
    """主动性温度计"""
    SILENT = 0      # 完全静默
    MINIMAL = 25    # 仅紧急
    BALANCED = 50   # 伙伴模式
    INSPIRING = 75  # 灵感模式
    FULL = 100      # 全面开放


class SceneMode(Enum):
    """场景模式"""
    NORMAL = "normal"
    WORK = "work"
    MEETING = "meeting"
    SLEEP = "sleep"
    DRIVING = "driving"
    CUSTOM = "custom"


@dataclass
class SceneConfig:
    """场景配置"""
    thermostat: int = 50
    allowed_topics: List[str] = field(default_factory=list)
    blocked_topics: List[str] = field(default_factory=list)
    max_per_hour: int = 3
    quiet_hours_start: int = 23
    quiet_hours_end: int = 7
    geofence: List[str] = field(default_factory=list)  # 地理围栏


SCENE_PRESETS = {
    SceneMode.NORMAL: SceneConfig(thermostat=50, max_per_hour=3),
    SceneMode.WORK: SceneConfig(thermostat=25, max_per_hour=1,
                                 allowed_topics=["work", "reminder"],
                                 blocked_topics=["social", "entertainment"]),
    SceneMode.MEETING: SceneConfig(thermostat=0, max_per_hour=0,
                                    allowed_topics=["emergency"]),
    SceneMode.SLEEP: SceneConfig(thermostat=5, max_per_hour=0,
                                  allowed_topics=["emergency"],
                                  quiet_hours_start=0, quiet_hours_end=24),
    SceneMode.DRIVING: SceneConfig(thermostat=10, max_per_hour=0,
                                    allowed_topics=["urgent_call"]),
}


class ControlPanel:
    """
    用户控制面板
    """

    def __init__(self):
        self._current_mode: SceneMode = SceneMode.NORMAL
        self._custom_config: SceneConfig = SceneConfig()
        self._thermostat: int = 50
        self._manual_overrides: dict = {}     # {"topic": "block"/"allow"}
        self._dnd_schedule: list = []         # [(day_of_week, start_h, end_h)]
        self._device_geofence: str = ""

    @property
    def config(self) -> SceneConfig:
        if self._current_mode == SceneMode.CUSTOM:
            return self._custom_config
        return SCENE_PRESETS.get(self._current_mode, SCENE_PRESETS[SceneMode.NORMAL])

    def set_scene(self, mode: SceneMode):
        self._current_mode = mode
        self._thermostat = self.config.thermostat

    def set_thermostat(self, value: int):
        self._thermostat = max(0, min(100, value))

    def get_decision_threshold(self) -> float:
        """根据温度计值计算决策阈值"""
        # 0°C → 阈值 0.95(极难触发)
        # 50°C → 阈值 0.75
        # 100°C → 阈值 0.5(容易触发)
        return 0.95 - (self._thermostat / 100) * 0.45

    def can_act_on_topic(self, topic: str) -> bool:
        """基于主题和场景判断是否允许"""
        cfg = self.config
        # 黑名单优先
        if topic in self._manual_overrides:
            return self._manual_overrides[topic] == "allow"
        if topic in cfg.blocked_topics:
            return False
        if cfg.allowed_topics and topic not in cfg.allowed_topics:
            return False
        return True