wangrong
2026-08-24 beef6536e7c8dd3f5cbe8f73585611479910bea7
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
import logging
import time
from typing import Any
 
from app.config import settings
from app.mqtt.init_dispatcher import InitTaskDispatcher
from app.mqtt.client import MqttService
from app.services.init_registry import InitRegistry
 
logger = logging.getLogger(__name__)
 
 
class AutoInitService:
    def __init__(
        self,
        registry: InitRegistry,
        dispatcher: InitTaskDispatcher,
        mqtt: MqttService,
    ) -> None:
        self.registry = registry
        self.dispatcher = dispatcher
        self.mqtt = mqtt
 
    def _run_full_init(self, device_id: str) -> list[dict[str, Any]]:
        commands = self.dispatcher.dispatch_device_init(device_id)
        logger.info("Device init dispatched for %s (%d commands)", device_id, len(commands))
 
        course_commands = self.dispatcher.dispatch_base_courses_sync(device_id)
        commands.extend(course_commands)
        logger.info(
            "Base courses sync dispatched for %s (%d courseTask messages)",
            device_id,
            len(course_commands),
        )
 
        self.registry.update_record(
            device_id,
            courses_synced=True,
            courses_sync_at=int(time.time()),
            courses_sync_count=len(course_commands),
        )
        return commands
 
    def on_device_state(self, device_id: str, payload: dict[str, Any], timestamp: int) -> list[dict[str, Any]] | None:
        if not settings.auto_init_enabled:
            return None
 
        if self.registry.is_initialized(device_id):
            return None
 
        if not self.mqtt.connected:
            logger.warning("Skip auto-init for %s: MQTT not connected", device_id)
            return None
 
        mode = payload.get("mode")
        if not self.registry.try_claim(device_id, source="auto", mode=mode, timestamp=timestamp):
            return None
 
        try:
            commands = self._run_full_init(device_id)
            logger.info("Auto-init completed for device %s (total %d commands)", device_id, len(commands))
            return commands
        except Exception:
            self.registry.remove(device_id)
            logger.exception("Auto-init failed for device %s, registry entry rolled back", device_id)
            raise
 
    def dispatch_manual_init(self, device_id: str, force: bool = False) -> tuple[list[dict[str, Any]], str]:
        if self.registry.is_initialized(device_id) and not force:
            return [], "already_initialized"
 
        if force:
            self.registry.remove(device_id)
 
        if not self.registry.try_claim(device_id, source="manual"):
            return [], "already_initialized"
 
        try:
            commands = self._run_full_init(device_id)
            return commands, "dispatched"
        except Exception:
            self.registry.remove(device_id)
            raise