Initial commit: Cyrene Plugins SDK + Plugin Manager
Extracted from Cyrene main repo (backend/pkg/plugins + backend/plugin-manager). Contains SDK interfaces (Plugin/Tool/HostAPI), 13 built-in plugins, ToolRegistry with call log ring buffer, and Plugin Manager REST API service. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
package iotcontrol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene-Plugins/sdk"
|
||||
)
|
||||
|
||||
// IoTController extends IoTClient with control operations.
|
||||
type IoTController interface {
|
||||
GetDevice(ctx context.Context, deviceID string) (*sdk.IoTDeviceState, error)
|
||||
SetDeviceProperty(ctx context.Context, deviceID, property string, value interface{}) error
|
||||
ToggleDevice(ctx context.Context, deviceID string) (*sdk.IoTDeviceState, error)
|
||||
}
|
||||
|
||||
type IoTControlPlugin struct {
|
||||
sdk.BasePlugin
|
||||
iotClient IoTController
|
||||
}
|
||||
|
||||
func NewIoTControlPlugin(client IoTController) *IoTControlPlugin {
|
||||
return &IoTControlPlugin{iotClient: client}
|
||||
}
|
||||
|
||||
func (p *IoTControlPlugin) Metadata() sdk.PluginMetadata {
|
||||
return sdk.PluginMetadata{
|
||||
Name: "iot_control", DisplayName: "IoT Device Control", Version: "1.0.0",
|
||||
Description: "Control smart home devices: toggle, set temperature/brightness/mode/color",
|
||||
Category: "iot", Author: sdk.PluginAuthor{Name: "Cyrene Team"},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *IoTControlPlugin) Tools() []sdk.Tool {
|
||||
return []sdk.Tool{&IoTControlTool{iotClient: p.iotClient}}
|
||||
}
|
||||
|
||||
type IoTControlTool struct {
|
||||
sdk.BaseTool
|
||||
iotClient IoTController
|
||||
}
|
||||
|
||||
func (t *IoTControlTool) Definition() sdk.ToolDefinition {
|
||||
return sdk.ToolDefinition{
|
||||
ID: "iot_control", Name: "iot_control", DisplayName: "IoT Device Control",
|
||||
Description: "Control smart home devices. Supports toggle, turn_on, turn_off, set_temperature, set_brightness, set_position, set_mode, set_color.",
|
||||
Category: "iot", Complexity: sdk.ComplexitySimple,
|
||||
DangerLevel: "medium",
|
||||
Parameters: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"device_id": map[string]interface{}{"type": "string"},
|
||||
"action": map[string]interface{}{"type": "string", "enum": []string{"toggle", "turn_on", "turn_off", "set_temperature", "set_brightness", "set_position", "set_mode", "set_color"}},
|
||||
"value": map[string]interface{}{},
|
||||
},
|
||||
"required": []string{"device_id", "action"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *IoTControlTool) Validate(args map[string]interface{}) error {
|
||||
for _, k := range []string{"device_id", "action"} {
|
||||
if _, ok := args[k]; !ok {
|
||||
return fmt.Errorf("missing required parameter: %s", k)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *IoTControlTool) Execute(ctx context.Context, args map[string]interface{}) (*sdk.ToolResult, error) {
|
||||
if t.iotClient == nil {
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false, Error: "IoT client not configured"}, nil
|
||||
}
|
||||
|
||||
deviceID, _ := args["device_id"].(string)
|
||||
if deviceID == "" {
|
||||
deviceID, _ = args["entity_id"].(string)
|
||||
}
|
||||
action := normalizeAction(args)
|
||||
|
||||
switch action {
|
||||
case "turn_on", "turn_off":
|
||||
status := "on"
|
||||
if action == "turn_off" {
|
||||
status = "off"
|
||||
}
|
||||
if err := t.iotClient.SetDeviceProperty(ctx, deviceID, "status", status); err != nil {
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false, Error: err.Error()}, nil
|
||||
}
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: true,
|
||||
Output: fmt.Sprintf("Device %s turned %s", deviceID, status)}, nil
|
||||
|
||||
case "set_temperature":
|
||||
value := toFloat64(args["value"])
|
||||
old := ""
|
||||
if dev, err := t.iotClient.GetDevice(ctx, deviceID); err == nil {
|
||||
old = fmt.Sprintf(" (was %.1fC)", dev.Temperature)
|
||||
}
|
||||
if err := t.iotClient.SetDeviceProperty(ctx, deviceID, "temperature", value); err != nil {
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false, Error: err.Error()}, nil
|
||||
}
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: true,
|
||||
Output: fmt.Sprintf("Temperature set to %.1fC%s", value, old)}, nil
|
||||
|
||||
case "set_brightness":
|
||||
value := toFloat64(args["value"])
|
||||
if err := t.iotClient.SetDeviceProperty(ctx, deviceID, "brightness", value); err != nil {
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false, Error: err.Error()}, nil
|
||||
}
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: true,
|
||||
Output: fmt.Sprintf("Brightness set to %.0f%%", value)}, nil
|
||||
|
||||
case "set_position":
|
||||
value := toFloat64(args["value"])
|
||||
if err := t.iotClient.SetDeviceProperty(ctx, deviceID, "position", value); err != nil {
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false, Error: err.Error()}, nil
|
||||
}
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: true,
|
||||
Output: fmt.Sprintf("Position set to %.0f%%", value)}, nil
|
||||
|
||||
case "set_mode":
|
||||
value, _ := args["value"].(string)
|
||||
if err := t.iotClient.SetDeviceProperty(ctx, deviceID, "mode", value); err != nil {
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false, Error: err.Error()}, nil
|
||||
}
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: true,
|
||||
Output: fmt.Sprintf("Mode set to %s", value)}, nil
|
||||
|
||||
case "set_color":
|
||||
value, _ := args["value"].(string)
|
||||
if err := t.iotClient.SetDeviceProperty(ctx, deviceID, "color", value); err != nil {
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false, Error: err.Error()}, nil
|
||||
}
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: true,
|
||||
Output: fmt.Sprintf("Color set to %s", value)}, nil
|
||||
|
||||
case "toggle":
|
||||
dev, err := t.iotClient.ToggleDevice(ctx, deviceID)
|
||||
if err != nil {
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false, Error: err.Error()}, nil
|
||||
}
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: true,
|
||||
Output: fmt.Sprintf("Device %s toggled to %s", deviceID, dev.Status)}, nil
|
||||
|
||||
default:
|
||||
return &sdk.ToolResult{ToolName: "iot_control", Success: false,
|
||||
Error: fmt.Sprintf("unknown action: %s", action)}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeAction(args map[string]interface{}) string {
|
||||
action, _ := args["action"].(string)
|
||||
// Chinese aliases
|
||||
switch action {
|
||||
case "打开":
|
||||
return "turn_on"
|
||||
case "关闭", "关掉", "关上":
|
||||
return "turn_off"
|
||||
case "设置温度", "调温度":
|
||||
return "set_temperature"
|
||||
case "设置亮度", "调亮度":
|
||||
return "set_brightness"
|
||||
case "设置位置":
|
||||
return "set_position"
|
||||
case "设置模式":
|
||||
return "set_mode"
|
||||
case "设置颜色":
|
||||
return "set_color"
|
||||
case "开关", "切换":
|
||||
return "toggle"
|
||||
}
|
||||
return action
|
||||
}
|
||||
|
||||
func toFloat64(v interface{}) float64 {
|
||||
switch n := v.(type) {
|
||||
case float64:
|
||||
return n
|
||||
case int:
|
||||
return float64(n)
|
||||
case int64:
|
||||
return float64(n)
|
||||
case string:
|
||||
var f float64
|
||||
fmt.Sscanf(n, "%f", &f)
|
||||
return f
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user