177 lines
5.7 KiB
Python
177 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
NFC管理模块
|
||
实现NFC读取和角色切换功能
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import re
|
||
import subprocess
|
||
import threading
|
||
import time
|
||
from pathlib import Path
|
||
from typing import Callable, Dict, Optional
|
||
|
||
|
||
class NFCManager:
|
||
"""NFC管理器,负责NFC读取和角色切换"""
|
||
|
||
def __init__(self, characters_dir: str = "characters"):
|
||
self.characters_dir = Path(characters_dir)
|
||
self.uid_to_character = {}
|
||
self.running = False
|
||
self.read_thread = None
|
||
self.current_uid = None
|
||
self.character_switch_callback: Optional[Callable] = None
|
||
|
||
# 加载角色NFC映射
|
||
self._load_character_mappings()
|
||
|
||
def _load_character_mappings(self):
|
||
"""加载角色NFC映射"""
|
||
self.uid_to_character = {}
|
||
|
||
if not self.characters_dir.exists():
|
||
print(f"⚠️ 角色目录不存在: {self.characters_dir}")
|
||
return
|
||
|
||
for config_file in self.characters_dir.glob("*.json"):
|
||
try:
|
||
with open(config_file, 'r', encoding='utf-8') as f:
|
||
config = json.load(f)
|
||
|
||
if 'nfc_uid' in config:
|
||
uid = config['nfc_uid'].upper().strip()
|
||
character_name = config_file.stem
|
||
self.uid_to_character[uid] = character_name
|
||
print(f"✅ 加载角色映射: {character_name} -> {uid}")
|
||
|
||
except Exception as e:
|
||
print(f"❌ 加载角色配置失败 {config_file}: {e}")
|
||
|
||
if not self.uid_to_character:
|
||
print("⚠️ 未找到任何带NFC UID的角色配置")
|
||
|
||
def _read_uid(self) -> Optional[str]:
|
||
"""读取NFC UID"""
|
||
os.environ['LIBNFC_DRIVER'] = 'pn532_i2c'
|
||
os.environ['LIBNFC_DEVICE'] = 'pn532_i2c:/dev/i2c-1'
|
||
|
||
try:
|
||
result = subprocess.run(['nfc-list'], capture_output=True, text=True, timeout=10)
|
||
if result.returncode == 0:
|
||
match = re.search(r'UID\s*\(NFCID1\):\s*([0-9A-Fa-f\s]+)', result.stdout)
|
||
if match:
|
||
return match.group(1).strip().replace(' ', '').upper()
|
||
except subprocess.TimeoutExpired:
|
||
print("⚠️ NFC读取超时")
|
||
except Exception as e:
|
||
print(f"❌ NFC读取失败: {e}")
|
||
|
||
return None
|
||
|
||
def _read_loop(self):
|
||
"""NFC读取循环"""
|
||
print("🔄 启动NFC读取循环...")
|
||
|
||
while self.running:
|
||
try:
|
||
uid = self._read_uid()
|
||
|
||
if uid and uid != self.current_uid:
|
||
print(f"🎯 检测到NFC卡片: {uid}")
|
||
|
||
if uid in self.uid_to_character:
|
||
character_name = self.uid_to_character[uid]
|
||
print(f"🎭 切换角色: {character_name}")
|
||
|
||
# 更新当前UID
|
||
self.current_uid = uid
|
||
|
||
# 调用角色切换回调
|
||
if self.character_switch_callback:
|
||
self.character_switch_callback(character_name)
|
||
else:
|
||
print(f"⚠️ 未找到UID对应角色: {uid}")
|
||
|
||
|
||
except Exception as e:
|
||
print(f"❌ NFC读取循环出错: {e}")
|
||
|
||
# 等待5秒
|
||
time.sleep(1)
|
||
|
||
def set_character_switch_callback(self, callback: Callable):
|
||
"""设置角色切换回调函数"""
|
||
self.character_switch_callback = callback
|
||
|
||
def start(self):
|
||
"""启动NFC管理器"""
|
||
if self.running:
|
||
print("⚠️ NFC管理器已在运行")
|
||
return
|
||
|
||
self.running = True
|
||
self.read_thread = threading.Thread(target=self._read_loop, daemon=True)
|
||
self.read_thread.start()
|
||
print("✅ NFC管理器已启动")
|
||
|
||
def stop(self):
|
||
"""停止NFC管理器"""
|
||
if not self.running:
|
||
return
|
||
|
||
self.running = False
|
||
if self.read_thread:
|
||
self.read_thread.join(timeout=5)
|
||
|
||
print("🛑 NFC管理器已停止")
|
||
|
||
def get_current_character(self) -> Optional[str]:
|
||
"""获取当前角色"""
|
||
if self.current_uid and self.current_uid in self.uid_to_character:
|
||
return self.uid_to_character[self.current_uid]
|
||
return None
|
||
|
||
def reload_mappings(self):
|
||
"""重新加载角色映射"""
|
||
print("🔄 重新加载角色NFC映射...")
|
||
self._load_character_mappings()
|
||
|
||
def __del__(self):
|
||
"""析构函数"""
|
||
self.stop()
|
||
|
||
# 单例模式
|
||
_nfc_manager_instance = None
|
||
|
||
def get_nfc_manager(characters_dir: str = "characters") -> NFCManager:
|
||
"""获取NFC管理器单例"""
|
||
global _nfc_manager_instance
|
||
if _nfc_manager_instance is None:
|
||
_nfc_manager_instance = NFCManager(characters_dir)
|
||
return _nfc_manager_instance
|
||
|
||
if __name__ == "__main__":
|
||
# 测试NFC管理器
|
||
def on_character_switch(character_name):
|
||
print(f"🎭 角色切换回调: {character_name}")
|
||
|
||
nfc_manager = get_nfc_manager()
|
||
nfc_manager.set_character_switch_callback(on_character_switch)
|
||
|
||
try:
|
||
nfc_manager.start()
|
||
print("🔄 NFC管理器运行中,按Ctrl+C退出...")
|
||
|
||
while True:
|
||
time.sleep(1)
|
||
|
||
except KeyboardInterrupt:
|
||
print("\n👋 用户中断")
|
||
finally:
|
||
nfc_manager.stop()
|