Files

230 lines
10 KiB
Python
Raw Permalink Normal View History

2025-12-15 22:05:56 +08:00
from langchain_core.tools import tool
from miio import DeviceFactory
from miio.miot_device import MiotDevice
import json
from pydantic import BaseModel, Field
import time
import logging
import threading
# 配置日志
logger = logging.getLogger(__name__)
# 设备配置
LAMP_IP = "192.168.110.122"
LAMP_TOKEN = "4a90f98aaa1273ca34685d66d6e13958"
LAMP_MODEL = "yeelink.light.bslamp2"
try:
device = DeviceFactory.create(LAMP_IP, LAMP_TOKEN)
logger.info(f"使用 DeviceFactory 创建设备成功: {LAMP_MODEL}")
except Exception as e:
logger.warning(f"DeviceFactory 创建失败,使用 MiotDevice: {e}")
# 添加线程锁,确保同一时间只有一个操作
device_lock = threading.Lock()
@tool("get_lamp_status", description="获取床头灯当前状态,包括电源、亮度、色温、颜色等信息")
def get_lamp_status():
"""获取床头灯设备状态并以 JSON 格式返回"""
try:
with device_lock: # 使用锁确保串行执行
# 使用 status() 方法获取 DeviceStatus 对象
device_status = device.status()
# 构建状态字典
status = {
"power": device_status.power if hasattr(device_status, 'power') else None,
"is_on": device_status.is_on if hasattr(device_status, 'is_on') else None,
"brightness": device_status.brightness if hasattr(device_status, 'brightness') else None,
"color_temp": device_status.color_temp if hasattr(device_status, 'color_temp') else None,
"color_mode": device_status.color_mode if hasattr(device_status, 'color_mode') else None,
"rgb": device_status.rgb if hasattr(device_status, 'rgb') else None,
"online": True,
"model": LAMP_MODEL
}
return json.dumps(status, indent=2, ensure_ascii=False)
except Exception as e:
logger.error(f"获取床头灯状态失败: {e}")
error_status = {
"error": f"获取设备状态失败: {str(e)}",
"message": "请检查:\n1. 设备是否已开启并连接到网络\n2. 设备IP地址是否配置正确当前配置{ip}\n3. 设备Token是否正确".format(ip=LAMP_IP),
"online": False,
"model": LAMP_MODEL
}
return json.dumps(error_status, indent=2, ensure_ascii=False)
class PowerArgs(BaseModel):
power: bool = Field(..., description="床头灯电源状态true 开启false 关闭")
@tool("set_lamp_power", args_schema=PowerArgs, description="开启或关闭床头灯。power=true 开启power=false 关闭")
def set_lamp_power(power: bool):
"""开启或关闭床头灯"""
try:
with device_lock: # 使用锁确保串行执行
if power:
result = device.on()
else:
result = device.off()
action = "开启" if power else "关闭"
logger.info(f"床头灯已{action}")
return json.dumps({
"message": f"床头灯已{action}",
"power": power,
"result": str(result)
}, indent=2, ensure_ascii=False)
except Exception as e:
logger.error(f"设置床头灯电源失败: {e}")
return json.dumps({
"error": f"设置电源状态失败: {str(e)}",
"message": "请检查:\n1. 设备是否已开启并连接到网络\n2. 设备IP地址是否配置正确当前配置{ip}\n3. 设备Token是否正确".format(ip=LAMP_IP),
"online": False,
"model": LAMP_MODEL
}, indent=2, ensure_ascii=False)
class BrightnessArgs(BaseModel):
brightness: int = Field(..., ge=1, le=100, description="亮度值,范围 1-100")
@tool("set_lamp_brightness", args_schema=BrightnessArgs, description="设置床头灯亮度1-100")
def set_lamp_brightness(brightness: int):
"""设置床头灯亮度"""
try:
with device_lock:
# 参考 Iot.py - 设置亮度 (siid=2, piid=2)
result = device.send("set_bright", [brightness])
logger.info(f"亮度已设置为{brightness}%")
return json.dumps({
"message": f"亮度已设置为{brightness}%",
"brightness": brightness,
"result": str(result)
}, indent=2, ensure_ascii=False)
except Exception as e:
logger.error(f"设置床头灯亮度失败: {e}")
return json.dumps({
"error": f"设置亮度失败: {str(e)}",
"message": "请检查:\n1. 设备是否已开启并连接到网络\n2. 设备IP地址是否配置正确当前配置{ip}\n3. 设备Token是否正确".format(ip=LAMP_IP),
"online": False,
"model": LAMP_MODEL
}, indent=2, ensure_ascii=False)
class ColorTempArgs(BaseModel):
color_temp: int = Field(..., ge=1700, le=6500, description="色温值,范围 1700-6500K")
@tool("set_lamp_color_temp", args_schema=ColorTempArgs, description="设置床头灯色温1700-6500K暖光到冷光")
def set_lamp_color_temp(color_temp: int):
"""设置床头灯色温"""
try:
with device_lock:
result = device.send("set_ct_abx", [color_temp, "smooth", 500])
temp_desc = "暖光" if color_temp < 3000 else "中性光" if color_temp < 5000 else "冷光"
logger.info(f"色温已设置为{color_temp}K ({temp_desc})")
return json.dumps({
"message": f"色温已设置为{color_temp}K ({temp_desc})",
"color_temp": color_temp,
"description": temp_desc,
"result": str(result)
}, indent=2, ensure_ascii=False)
except Exception as e:
logger.error(f"设置床头灯色温失败: {e}")
return json.dumps({
"error": f"设置色温失败: {str(e)}",
"message": "请检查:\n1. 设备是否已开启并连接到网络\n2. 设备IP地址是否配置正确当前配置{ip}\n3. 设备Token是否正确".format(ip=LAMP_IP),
"online": False,
"model": LAMP_MODEL
}, indent=2, ensure_ascii=False)
class ColorArgs(BaseModel):
red: int = Field(..., ge=0, le=255, description="红色值,范围 0-255")
green: int = Field(..., ge=0, le=255, description="绿色值,范围 0-255")
blue: int = Field(..., ge=0, le=255, description="蓝色值,范围 0-255")
@tool("set_lamp_color", args_schema=ColorArgs, description="设置床头灯RGB颜色红、绿、蓝各0-255")
def set_lamp_color(red: int, green: int, blue: int):
"""设置床头灯RGB颜色"""
try:
with device_lock:
color_value = (red << 16) | (green << 8) | blue
result = device.send("set_rgb", [color_value])
logger.info(f"颜色已设置为 RGB({red}, {green}, {blue})")
return json.dumps({
"message": f"颜色已设置为 RGB({red}, {green}, {blue})",
"red": red,
"green": green,
"blue": blue,
"color_hex": f"#{red:02x}{green:02x}{blue:02x}",
"result": str(result)
}, indent=2, ensure_ascii=False)
except Exception as e:
logger.error(f"设置床头灯颜色失败: {e}")
return json.dumps({
"error": f"设置颜色失败: {str(e)}",
"message": "请检查:\n1. 设备是否已开启并连接到网络\n2. 设备IP地址是否配置正确当前配置{ip}\n3. 设备Token是否正确".format(ip=LAMP_IP),
"online": False,
"model": LAMP_MODEL
}, indent=2, ensure_ascii=False)
class SceneArgs(BaseModel):
scene: str = Field(..., description="场景名称: 'reading' (阅读), 'sleep' (睡眠), 'romantic' (浪漫), 'night' (夜灯)")
@tool("set_lamp_scene", args_schema=SceneArgs, description="设置床头灯预设场景(阅读/睡眠/浪漫/夜灯)")
def set_lamp_scene(scene: str):
"""设置床头灯预设场景"""
# 定义预设场景
scenes = {
"reading": {"brightness": 100, "color_temp": 4000, "desc": "阅读模式100%亮度4000K中性光"},
"sleep": {"brightness": 10, "color_temp": 2000, "desc": "睡眠模式10%亮度2000K暖光"},
"romantic": {"brightness": 30, "color": (255, 100, 100), "desc": "浪漫模式30%亮度,粉红色"},
"night": {"brightness": 5, "color_temp": 1700, "desc": "夜灯模式5%亮度1700K极暖光"}
}
if scene not in scenes:
return json.dumps({
"error": f"未知场景: {scene}",
"available_scenes": list(scenes.keys())
}, indent=2, ensure_ascii=False)
try:
with device_lock:
scene_config = scenes[scene]
# 设置亮度
device.set_property_by(2, 2, scene_config["brightness"])
time.sleep(0.3) # 给设备一点响应时间
# 设置色温或颜色
if "color_temp" in scene_config:
device.set_property_by(2, 3, scene_config["color_temp"])
elif "color" in scene_config:
r, g, b = scene_config["color"]
color_value = (r << 16) | (g << 8) | b
device.set_property_by(2, 5, color_value)
logger.info(f"场景已设置为: {scene}")
return json.dumps({
"message": f"场景已设置为: {scene}",
"scene": scene,
"description": scene_config["desc"],
"config": scene_config
}, indent=2, ensure_ascii=False)
except Exception as e:
logger.error(f"设置床头灯场景失败: {e}")
return json.dumps({
"error": f"设置场景失败: {str(e)}",
"message": "请检查:\n1. 设备是否已开启并连接到网络\n2. 设备IP地址是否配置正确当前配置{ip}\n3. 设备Token是否正确".format(ip=LAMP_IP),
"online": False,
"model": LAMP_MODEL
}, indent=2, ensure_ascii=False)