mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-22 21:44:18 +02:00
improvements
This commit is contained in:
parent
adb18f2e8e
commit
35ca7c65d3
1 changed files with 109 additions and 12 deletions
|
|
@ -101,36 +101,95 @@ def list_groups() -> list[str]:
|
|||
|
||||
|
||||
@lights_mcp.tool()
|
||||
def list_scenes() -> list[str]:
|
||||
"""Lists the names of all available Hue scenes."""
|
||||
def list_scenes() -> dict[str, list[str]] | list[str]:
|
||||
"""Lists Hue scenes, grouped by the light group they belong to.
|
||||
|
||||
Returns:
|
||||
dict[str, list[str]]: A dictionary mapping group names to a list of scene names within that group.
|
||||
list[str]: An error message list if the bridge connection fails or an error occurs.
|
||||
"""
|
||||
if not (bridge := _get_bridge()):
|
||||
return ["Error: Bridge not connected"]
|
||||
try:
|
||||
# phue2 get_scene() returns a dict {id: {details}} including name
|
||||
scenes = bridge.get_scene()
|
||||
return [scene_details["name"] for scene_details in scenes.values()]
|
||||
scenes_data = bridge.get_scene() # Returns dict {scene_id: {details...}}
|
||||
groups_data = bridge.get_group() # Returns dict {group_id: {details...}}
|
||||
|
||||
# Create a lookup for group name by group ID
|
||||
group_id_to_name = {gid: ginfo["name"] for gid, ginfo in groups_data.items()}
|
||||
|
||||
scenes_by_group: dict[str, list[str]] = {}
|
||||
for scene_id, scene_details in scenes_data.items():
|
||||
scene_name = scene_details.get("name")
|
||||
# Scenes might be associated with a group via 'group' key or lights
|
||||
# Using 'group' key if available is more direct for group scenes
|
||||
group_id = scene_details.get("group")
|
||||
if scene_name and group_id and group_id in group_id_to_name:
|
||||
group_name = group_id_to_name[group_id]
|
||||
if group_name not in scenes_by_group:
|
||||
scenes_by_group[group_name] = []
|
||||
# Avoid duplicate scene names within a group listing (though unlikely)
|
||||
if scene_name not in scenes_by_group[group_name]:
|
||||
scenes_by_group[group_name].append(scene_name)
|
||||
|
||||
# Sort scenes within each group for consistent output
|
||||
for group_name in scenes_by_group:
|
||||
scenes_by_group[group_name].sort()
|
||||
|
||||
return scenes_by_group
|
||||
except (PhueException, Exception) as e:
|
||||
return [f"Error listing scenes: {e}"]
|
||||
# Return error as list to match other list-returning tools on error
|
||||
return [f"Error listing scenes by group: {e}"]
|
||||
|
||||
|
||||
@lights_mcp.tool()
|
||||
def activate_scene(group_name: str, scene_name: str) -> dict[str, Any]:
|
||||
"""Activates a specific scene within a specified light group."""
|
||||
"""Activates a specific scene within a specified light group, verifying the scene belongs to the group."""
|
||||
if not (bridge := _get_bridge()):
|
||||
return {"error": "Bridge not connected", "success": False}
|
||||
try:
|
||||
# Note: phue2 run_scene uses group_name and scene_name directly
|
||||
# 1. Find the target group ID
|
||||
groups_data = bridge.get_group()
|
||||
target_group_id = None
|
||||
for gid, ginfo in groups_data.items():
|
||||
if ginfo.get("name") == group_name:
|
||||
target_group_id = gid
|
||||
break
|
||||
if not target_group_id:
|
||||
return {"error": f"Group '{group_name}' not found", "success": False}
|
||||
|
||||
# 2. Find the target scene and check its group association
|
||||
scenes_data = bridge.get_scene()
|
||||
scene_found = False
|
||||
scene_in_correct_group = False
|
||||
for sid, sinfo in scenes_data.items():
|
||||
if sinfo.get("name") == scene_name:
|
||||
scene_found = True
|
||||
# Check if this scene is associated with the target group ID
|
||||
if sinfo.get("group") == target_group_id:
|
||||
scene_in_correct_group = True
|
||||
break # Found the scene in the correct group
|
||||
|
||||
if not scene_found:
|
||||
return {"error": f"Scene '{scene_name}' not found", "success": False}
|
||||
|
||||
if not scene_in_correct_group:
|
||||
return {
|
||||
"error": f"Scene '{scene_name}' does not belong to group '{group_name}'",
|
||||
"success": False,
|
||||
}
|
||||
|
||||
# 3. Activate the scene (now that we've verified it)
|
||||
result = bridge.run_scene(group_name=group_name, scene_name=scene_name)
|
||||
# run_scene returns True on success, we'll make the response richer
|
||||
|
||||
if result:
|
||||
return {
|
||||
"group": group_name,
|
||||
"activated_scene": scene_name,
|
||||
"success": True,
|
||||
"phue2_result": result, # Include the raw True/False
|
||||
"phue2_result": result,
|
||||
}
|
||||
else:
|
||||
# This case might indicate the scene/group exists but activation failed
|
||||
# This case might indicate the scene/group exists but activation failed internally
|
||||
return {
|
||||
"group": group_name,
|
||||
"scene": scene_name,
|
||||
|
|
@ -139,7 +198,7 @@ def activate_scene(group_name: str, scene_name: str) -> dict[str, Any]:
|
|||
}
|
||||
|
||||
except (KeyError, PhueException, Exception) as e:
|
||||
# KeyError likely means group or scene name is wrong
|
||||
# Handle potential errors during bridge communication or data parsing
|
||||
return handle_phue_error(f"{group_name}/{scene_name}", "activate_scene", e)
|
||||
|
||||
|
||||
|
|
@ -193,3 +252,41 @@ def set_group_attributes(group_name: str, attributes: HueAttributes) -> dict[str
|
|||
}
|
||||
except (KeyError, PhueException, ValueError, Exception) as e:
|
||||
return handle_phue_error(group_name, "set_group_attributes", e)
|
||||
|
||||
|
||||
@lights_mcp.tool()
|
||||
def list_lights_by_group() -> dict[str, list[str]] | list[str]:
|
||||
"""Lists Hue lights, grouped by the room/group they belong to.
|
||||
|
||||
Returns:
|
||||
dict[str, list[str]]: A dictionary mapping group names to a list of light names within that group.
|
||||
list[str]: An error message list if the bridge connection fails or an error occurs.
|
||||
"""
|
||||
if not (bridge := _get_bridge()):
|
||||
return ["Error: Bridge not connected"]
|
||||
try:
|
||||
groups_data = bridge.get_group() # dict {group_id: {details}}
|
||||
lights_data = bridge.get_light_objects("id") # dict {light_id: {details}}
|
||||
|
||||
lights_by_group: dict[str, list[str]] = {}
|
||||
for group_id, group_details in groups_data.items():
|
||||
group_name = group_details.get("name")
|
||||
light_ids = group_details.get("lights", [])
|
||||
if group_name and light_ids:
|
||||
light_names = []
|
||||
for light_id in light_ids:
|
||||
# phue uses string IDs for lights in group, but int IDs in get_light_objects
|
||||
light_id_int = int(light_id)
|
||||
if light_id_int in lights_data:
|
||||
light_name = lights_data[light_id_int].name
|
||||
if light_name:
|
||||
light_names.append(light_name)
|
||||
if light_names:
|
||||
light_names.sort() # Keep light list sorted
|
||||
lights_by_group[group_name] = light_names
|
||||
|
||||
return lights_by_group
|
||||
|
||||
except (PhueException, Exception) as e:
|
||||
# Return error as list
|
||||
return [f"Error listing lights by group: {e}"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue