diff --git a/main/xiaozhi-server/plugins_func/functions/hass_get_state.py b/main/xiaozhi-server/plugins_func/functions/hass_get_state.py index 5ce511eb..e8167db4 100644 --- a/main/xiaozhi-server/plugins_func/functions/hass_get_state.py +++ b/main/xiaozhi-server/plugins_func/functions/hass_get_state.py @@ -17,57 +17,78 @@ hass_get_state_function_desc = { "properties": { "entity_id": { "type": "string", - "description": "需要操作的设备id,homeassistant里的entity_id" + "description": "需要操作的设备id,homeassistant里的entity_id", } }, - "required": ["entity_id"] - } - } + "required": ["entity_id"], + }, + }, } @register_function("hass_get_state", hass_get_state_function_desc, ToolType.SYSTEM_CTL) -def hass_get_state(conn, entity_id=''): +def hass_get_state(conn, entity_id=""): try: future = asyncio.run_coroutine_threadsafe( - handle_hass_get_state(conn, entity_id), - conn.loop + handle_hass_get_state(conn, entity_id), conn.loop ) ha_response = future.result() - return ActionResponse( Action.REQLLM, ha_response , None ) + return ActionResponse(Action.REQLLM, ha_response, None) except Exception as e: logger.bind(tag=TAG).error(f"处理设置属性意图错误: {e}") async def handle_hass_get_state(conn, entity_id): - HASS_CACHE = initialize_hass_handler(conn) - api_key = HASS_CACHE['api_key'] - base_url = HASS_CACHE['base_url'] + ha_config = initialize_hass_handler(conn) + api_key = ha_config.get("api_key") + base_url = ha_config.get("base_url") url = f"{base_url}/api/states/{entity_id}" - headers = { - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json" - } + headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} response = requests.get(url, headers=headers) if response.status_code == 200: - responsetext = '设备状态:' + response.json()['state'] + ' ' + responsetext = "设备状态:" + response.json()["state"] + " " logger.bind(tag=TAG).info(f"api返回内容: {response.json()}") - if 'media_title' in response.json()['attributes']: - responsetext = responsetext+ '正在播放的是:'+str(response.json()['attributes']['media_title'])+' ' - if 'volume_level' in response.json()['attributes']: - responsetext = responsetext+ '音量是:'+str(response.json()['attributes']['volume_level'])+' ' - if 'color_temp_kelvin' in response.json()['attributes']: - responsetext = responsetext+ '色温是:'+str(response.json()['attributes']['color_temp_kelvin'])+' ' - if 'rgb_color' in response.json()['attributes']: - responsetext = responsetext+ 'rgb颜色是:'+str(response.json()['attributes']['rgb_color'])+' ' - if 'brightness' in response.json()['attributes']: - responsetext = responsetext+ '亮度是:'+str(response.json()['attributes']['brightness'])+' ' + if "media_title" in response.json()["attributes"]: + responsetext = ( + responsetext + + "正在播放的是:" + + str(response.json()["attributes"]["media_title"]) + + " " + ) + if "volume_level" in response.json()["attributes"]: + responsetext = ( + responsetext + + "音量是:" + + str(response.json()["attributes"]["volume_level"]) + + " " + ) + if "color_temp_kelvin" in response.json()["attributes"]: + responsetext = ( + responsetext + + "色温是:" + + str(response.json()["attributes"]["color_temp_kelvin"]) + + " " + ) + if "rgb_color" in response.json()["attributes"]: + responsetext = ( + responsetext + + "rgb颜色是:" + + str(response.json()["attributes"]["rgb_color"]) + + " " + ) + if "brightness" in response.json()["attributes"]: + responsetext = ( + responsetext + + "亮度是:" + + str(response.json()["attributes"]["brightness"]) + + " " + ) logger.bind(tag=TAG).info(f"查询返回内容: {responsetext}") return responsetext - #return response.json()['attributes'] - #response.attributes + # return response.json()['attributes'] + # response.attributes else: return f"切换失败,错误码: {response.status_code}" diff --git a/main/xiaozhi-server/plugins_func/functions/hass_init.py b/main/xiaozhi-server/plugins_func/functions/hass_init.py index 3a5458d3..8a28eef9 100644 --- a/main/xiaozhi-server/plugins_func/functions/hass_init.py +++ b/main/xiaozhi-server/plugins_func/functions/hass_init.py @@ -4,8 +4,6 @@ from core.utils.util import check_model_key TAG = __name__ logger = setup_logging() -HASS_CACHE = {} - def append_devices_to_prompt(conn): if conn.intent_type == "function_call": @@ -25,19 +23,22 @@ def append_devices_to_prompt(conn): def initialize_hass_handler(conn): - global HASS_CACHE - if HASS_CACHE == {}: - if conn.load_function_plugin: - funcs = conn.config["Intent"][conn.config["selected_module"]["Intent"]].get( - "functions", [] + ha_config = {} + if conn.load_function_plugin: + if conn.config["plugins"].get("home_assistant"): + ha_config["base_url"] = conn.config["plugins"]["home_assistant"].get( + "base_url" ) - if "hass_get_state" in funcs or "hass_set_state" in funcs: - HASS_CACHE["base_url"] = conn.config["plugins"]["home_assistant"].get( - "base_url" - ) - HASS_CACHE["api_key"] = conn.config["plugins"]["home_assistant"].get( - "api_key" - ) - - check_model_key("home_assistant", HASS_CACHE["api_key"]) - return HASS_CACHE + ha_config["api_key"] = conn.config["plugins"]["home_assistant"].get( + "api_key" + ) + check_model_key("home_assistant", ha_config.get("api_key")) + elif conn.config["plugins"].get("hass_get_state"): + ha_config["base_url"] = conn.config["plugins"]["hass_get_state"].get( + "base_url" + ) + ha_config["api_key"] = conn.config["plugins"]["hass_get_state"].get( + "api_key" + ) + check_model_key("home_assistant", ha_config.get("api_key")) + return ha_config diff --git a/main/xiaozhi-server/plugins_func/functions/hass_play_music.py b/main/xiaozhi-server/plugins_func/functions/hass_play_music.py index 502f784e..fa6527b6 100644 --- a/main/xiaozhi-server/plugins_func/functions/hass_play_music.py +++ b/main/xiaozhi-server/plugins_func/functions/hass_play_music.py @@ -17,46 +17,43 @@ hass_play_music_function_desc = { "properties": { "media_content_id": { "type": "string", - "description": "可以是音乐或有声书的专辑名称、歌曲名、演唱者,如果未指定就填random" + "description": "可以是音乐或有声书的专辑名称、歌曲名、演唱者,如果未指定就填random", }, "entity_id": { "type": "string", - "description": "需要操作的音箱的设备id,homeassistant里的entity_id,media_player开头" - } + "description": "需要操作的音箱的设备id,homeassistant里的entity_id,media_player开头", + }, }, - "required": ["media_content_id", "entity_id"] - } - } + "required": ["media_content_id", "entity_id"], + }, + }, } -@register_function('hass_play_music', hass_play_music_function_desc, ToolType.SYSTEM_CTL) -def hass_play_music(conn, entity_id='', media_content_id='random'): +@register_function( + "hass_play_music", hass_play_music_function_desc, ToolType.SYSTEM_CTL +) +def hass_play_music(conn, entity_id="", media_content_id="random"): try: # 执行音乐播放命令 future = asyncio.run_coroutine_threadsafe( - handle_hass_play_music(conn, entity_id, media_content_id), - conn.loop + handle_hass_play_music(conn, entity_id, media_content_id), conn.loop ) ha_response = future.result() - return ActionResponse(action=Action.RESPONSE, result="退出意图已处理", response=ha_response) + return ActionResponse( + action=Action.RESPONSE, result="退出意图已处理", response=ha_response + ) except Exception as e: logger.bind(tag=TAG).error(f"处理音乐意图错误: {e}") async def handle_hass_play_music(conn, entity_id, media_content_id): - HASS_CACHE = initialize_hass_handler(conn) - api_key = HASS_CACHE['api_key'] - base_url = HASS_CACHE['base_url'] + ha_config = initialize_hass_handler(conn) + api_key = ha_config.get("api_key") + base_url = ha_config.get("base_url") url = f"{base_url}/api/services/music_assistant/play_media" - headers = { - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json" - } - data = { - "entity_id": entity_id, - "media_id": media_content_id - } + headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} + data = {"entity_id": entity_id, "media_id": media_content_id} response = requests.post(url, headers=headers, json=data) if response.status_code == 200: return f"正在播放{media_content_id}的音乐" diff --git a/main/xiaozhi-server/plugins_func/functions/hass_set_state.py b/main/xiaozhi-server/plugins_func/functions/hass_set_state.py index b9de146b..30b2ac45 100644 --- a/main/xiaozhi-server/plugins_func/functions/hass_set_state.py +++ b/main/xiaozhi-server/plugins_func/functions/hass_set_state.py @@ -20,40 +20,39 @@ hass_set_state_function_desc = { "properties": { "type": { "type": "string", - "description": "需要操作的动作,打开设备:turn_on,关闭设备:turn_off,增加亮度:brightness_up,降低亮度:brightness_down,设置亮度:brightness_value,增加音量:volume_up,降低音量:volume_down,设置音量:volume_set,设置色温:set_kelvin,设置颜色:set_color,设备暂停:pause,设备继续:continue,静音/取消静音:volume_mute" + "description": "需要操作的动作,打开设备:turn_on,关闭设备:turn_off,增加亮度:brightness_up,降低亮度:brightness_down,设置亮度:brightness_value,增加音量:volume_up,降低音量:volume_down,设置音量:volume_set,设置色温:set_kelvin,设置颜色:set_color,设备暂停:pause,设备继续:continue,静音/取消静音:volume_mute", }, "input": { "type": "integer", - "description": "只有在设置音量,设置亮度时候才需要,有效值为1-100,对应音量和亮度的1%-100%" + "description": "只有在设置音量,设置亮度时候才需要,有效值为1-100,对应音量和亮度的1%-100%", }, "is_muted": { "type": "string", - "description": "只有在设置静音操作时才需要,设置静音的时候该值为true,取消静音时该值为false" + "description": "只有在设置静音操作时才需要,设置静音的时候该值为true,取消静音时该值为false", + }, + "rgb_color": { + "type": "list", + "description": "只有在设置颜色时需要,这里填目标颜色的rgb值", }, - "rgb_color":{ - "type":"list", - "description": "只有在设置颜色时需要,这里填目标颜色的rgb值" - } }, - "required": ["type"] + "required": ["type"], }, "entity_id": { "type": "string", - "description": "需要操作的设备id,homeassistant里的entity_id" - } + "description": "需要操作的设备id,homeassistant里的entity_id", + }, }, - "required": ["state", "entity_id"] - } - } + "required": ["state", "entity_id"], + }, + }, } -@register_function('hass_set_state', hass_set_state_function_desc, ToolType.SYSTEM_CTL) -def hass_set_state(conn, entity_id='', state={}): +@register_function("hass_set_state", hass_set_state_function_desc, ToolType.SYSTEM_CTL) +def hass_set_state(conn, entity_id="", state={}): try: future = asyncio.run_coroutine_threadsafe( - handle_hass_set_state(conn, entity_id, state), - conn.loop + handle_hass_set_state(conn, entity_id, state), conn.loop ) ha_response = future.result() return ActionResponse(Action.REQLLM, ha_response, None) @@ -62,21 +61,21 @@ def hass_set_state(conn, entity_id='', state={}): async def handle_hass_set_state(conn, entity_id, state): - HASS_CACHE = initialize_hass_handler(conn) - api_key = HASS_CACHE['api_key'] - base_url = HASS_CACHE['base_url'] - ''' + ha_config = initialize_hass_handler(conn) + api_key = ha_config.get("api_key") + base_url = ha_config.get("base_url") + """ state = { "type":"brightness_up","input":"80","is_muted":"true"} - ''' + """ domains = entity_id.split(".") if len(domains) > 1: domain = domains[0] else: return "执行失败,错误的设备id" - action = '' - arg = '' - value = '' - if state['type'] == 'turn_on': + action = "" + arg = "" + value = "" + if state["type"] == "turn_on": description = "设备已打开" if domain == "cover": action = "open_cover" @@ -84,91 +83,87 @@ async def handle_hass_set_state(conn, entity_id, state): action = "start" else: action = "turn_on" - elif state['type'] == 'turn_off': + elif state["type"] == "turn_off": description = "设备已关闭" - if domain == 'cover': + if domain == "cover": action = "close_cover" - elif domain == 'vacuum': + elif domain == "vacuum": action = "stop" else: action = "turn_off" - elif state['type'] == 'brightness_up': + elif state["type"] == "brightness_up": description = "灯光已调亮" - action = 'turn_on' - arg = 'brightness_step_pct' + action = "turn_on" + arg = "brightness_step_pct" value = 10 - elif state['type'] == 'brightness_down': + elif state["type"] == "brightness_down": description = "灯光已调暗" - action = 'turn_on' - arg = 'brightness_step_pct' + action = "turn_on" + arg = "brightness_step_pct" value = -10 - elif state['type'] == 'brightness_value': + elif state["type"] == "brightness_value": description = f"亮度已调整到{state['input']}" - action = 'turn_on' - arg = 'brightness_pct' - value = state['input'] - elif state['type'] == 'set_color': + action = "turn_on" + arg = "brightness_pct" + value = state["input"] + elif state["type"] == "set_color": description = f"颜色已调整到{state['rgb_color']}" - action = 'turn_on' - arg = 'rgb_color' - value = state['rgb_color'] - elif state['type'] == 'set_kelvin': + action = "turn_on" + arg = "rgb_color" + value = state["rgb_color"] + elif state["type"] == "set_kelvin": description = f"色温已调整到{state['input']}K" - action = 'turn_on' - arg = 'kelvin' - value = state['input'] - elif state['type'] == 'volume_up': + action = "turn_on" + arg = "kelvin" + value = state["input"] + elif state["type"] == "volume_up": description = "音量已调大" - action = state['type'] - elif state['type'] == 'volume_down': + action = state["type"] + elif state["type"] == "volume_down": description = "音量已调小" - action = state['type'] - elif state['type'] == 'volume_set': + action = state["type"] + elif state["type"] == "volume_set": description = f"音量已调整到{state['input']}" - action = state['type'] - arg = 'volume_level' - value = state['input'] - if state['input'] >= 1: - value = state['input']/100 - elif state['type'] == 'volume_mute': + action = state["type"] + arg = "volume_level" + value = state["input"] + if state["input"] >= 1: + value = state["input"] / 100 + elif state["type"] == "volume_mute": description = f"设备已静音" - action = state['type'] - arg = 'is_volume_muted' - value = state['is_muted'] - elif state['type'] == 'pause': + action = state["type"] + arg = "is_volume_muted" + value = state["is_muted"] + elif state["type"] == "pause": description = f"设备已暂停" - action = state['type'] - if domain == 'media_player': - action = 'media_pause' - if domain == 'cover': - action = 'stop_cover' - if domain == 'vacuum': - action = 'pause' - elif state['type'] == 'continue': + action = state["type"] + if domain == "media_player": + action = "media_pause" + if domain == "cover": + action = "stop_cover" + if domain == "vacuum": + action = "pause" + elif state["type"] == "continue": description = f"设备已继续" - if domain == 'media_player': - action = 'media_play' - if domain == 'vacuum': - action = 'start' + if domain == "media_player": + action = "media_play" + if domain == "vacuum": + action = "start" else: return f"{domain} {state.type}功能尚未支持" - if arg == '': + if arg == "": data = { "entity_id": entity_id, } else: - data = { - "entity_id": entity_id, - arg: value - } + data = {"entity_id": entity_id, arg: value} url = f"{base_url}/api/services/{domain}/{action}" - headers = { - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json" - } + headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} response = requests.post(url, headers=headers, json=data) - logger.bind(tag=TAG).info(f"设置状态:{description},url:{url},return_code:{response.status_code}") + logger.bind(tag=TAG).info( + f"设置状态:{description},url:{url},return_code:{response.status_code}" + ) if response.status_code == 200: return description else: