71f0a1abdb
- 所有Go模块路径从 github.com/yourname/cyrene-ai 迁移到 git.yeij.top/AskaEth/Cyrene - 5个Go Dockerfile添加 GOPROXY=https://goproxy.cn,direct 解决国内构建问题 - ai-core go.mod 添加 pkg/plugins replace 指令 - Caddyfile 简化为 http:// 通配 + handle 保留 /api 前缀 - ethend Dockerfile 适配 (npm install + 仅 COPY package.json) - ethend 新增 RUNNING_IN_DOCKER 环境变量,健康检查改用Docker服务名 - ethend 数据库状态检查支持Docker hostname (postgres/redis/qdrant/minio) - process-manager 新增 CONTAINER_SVC_MAP + Docker模式自动检测 - 统一 docker-compose.dev.db.yml 卷名 (pg_data/redis_data/qdrant_data/minio_data) - docker-compose.yml ethend服务挂载docker.sock + 端口变量化 - 清理 .env 统一后的残留文件与提示信息 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
121 lines
3.6 KiB
Go
121 lines
3.6 KiB
Go
package iotquery
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene/pkg/plugins/sdk"
|
|
)
|
|
|
|
// IoTClient is the interface for IoT device access.
|
|
type IoTClient interface {
|
|
GetAllDevices(ctx context.Context) ([]sdk.IoTDeviceState, error)
|
|
GetDevice(ctx context.Context, deviceID string) (*sdk.IoTDeviceState, error)
|
|
}
|
|
|
|
type IoTQueryPlugin struct {
|
|
sdk.BasePlugin
|
|
iotClient IoTClient
|
|
}
|
|
|
|
func NewIoTQueryPlugin(client IoTClient) *IoTQueryPlugin {
|
|
return &IoTQueryPlugin{iotClient: client}
|
|
}
|
|
|
|
func (p *IoTQueryPlugin) Metadata() sdk.PluginMetadata {
|
|
return sdk.PluginMetadata{
|
|
Name: "iot_query", DisplayName: "IoT Device Query", Version: "1.0.0",
|
|
Description: "Query smart home device status (single device or all devices)",
|
|
Category: "iot", Author: sdk.PluginAuthor{Name: "Cyrene Team"},
|
|
}
|
|
}
|
|
|
|
func (p *IoTQueryPlugin) Tools() []sdk.Tool { return []sdk.Tool{&IoTQueryTool{iotClient: p.iotClient}} }
|
|
|
|
type IoTQueryTool struct {
|
|
sdk.BaseTool
|
|
iotClient IoTClient
|
|
}
|
|
|
|
func (t *IoTQueryTool) Definition() sdk.ToolDefinition {
|
|
return sdk.ToolDefinition{
|
|
ID: "iot_query", Name: "iot_query", DisplayName: "IoT Device Query",
|
|
Description: "Query smart home device status. Device status is typically auto-injected; use this only when status is stale.",
|
|
Category: "iot", Complexity: sdk.ComplexitySimple,
|
|
Parameters: map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{"device_id": map[string]interface{}{"type": "string"}},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (t *IoTQueryTool) Validate(args map[string]interface{}) error { return nil }
|
|
|
|
func (t *IoTQueryTool) Execute(ctx context.Context, args map[string]interface{}) (*sdk.ToolResult, error) {
|
|
if t.iotClient == nil {
|
|
return &sdk.ToolResult{ToolName: "iot_query", Success: false, Error: "IoT client not configured"}, nil
|
|
}
|
|
|
|
deviceID, _ := args["device_id"].(string)
|
|
if deviceID != "" {
|
|
dev, err := t.iotClient.GetDevice(ctx, deviceID)
|
|
if err != nil {
|
|
return &sdk.ToolResult{ToolName: "iot_query", Success: false, Error: err.Error()}, nil
|
|
}
|
|
return &sdk.ToolResult{ToolName: "iot_query", Success: true, Output: formatDevice(dev)}, nil
|
|
}
|
|
|
|
devices, err := t.iotClient.GetAllDevices(ctx)
|
|
if err != nil {
|
|
return &sdk.ToolResult{ToolName: "iot_query", Success: false, Error: err.Error()}, nil
|
|
}
|
|
if len(devices) == 0 {
|
|
return &sdk.ToolResult{ToolName: "iot_query", Success: true, Output: "No devices found"}, nil
|
|
}
|
|
var out string
|
|
for _, d := range devices {
|
|
out += formatDeviceLine(&d) + "\n"
|
|
}
|
|
return &sdk.ToolResult{ToolName: "iot_query", Success: true, Output: out}, nil
|
|
}
|
|
|
|
func formatDevice(d *sdk.IoTDeviceState) string {
|
|
emoji := deviceEmoji(d.Type)
|
|
return fmt.Sprintf("%s %s (%s)\n Status: %s\n ID: %s", emoji, d.Name, d.Type, d.Status, d.ID)
|
|
}
|
|
|
|
func formatDeviceLine(d *sdk.IoTDeviceState) string {
|
|
emoji := deviceEmoji(d.Type)
|
|
switch d.Type {
|
|
case "light":
|
|
return fmt.Sprintf("%s %s: %s (brightness: %d, color: %s)", emoji, d.Name, d.Status, d.Brightness, d.Color)
|
|
case "ac":
|
|
return fmt.Sprintf("%s %s: %s (mode: %s, temp: %.1fC)", emoji, d.Name, d.Status, d.Mode, d.Temperature)
|
|
case "curtain":
|
|
return fmt.Sprintf("%s %s: %s (position: %d%%)", emoji, d.Name, d.Status, d.Position)
|
|
case "sensor":
|
|
return fmt.Sprintf("%s %s: %.1f%s", emoji, d.Name, d.Value, d.Unit)
|
|
case "lock":
|
|
return fmt.Sprintf("%s %s: %s (battery: %d%%)", emoji, d.Name, d.Status, d.Battery)
|
|
default:
|
|
return fmt.Sprintf("%s %s: %s", emoji, d.Name, d.Status)
|
|
}
|
|
}
|
|
|
|
func deviceEmoji(t string) string {
|
|
switch t {
|
|
case "light":
|
|
return "\U0001F4A1"
|
|
case "ac":
|
|
return "❄️"
|
|
case "curtain":
|
|
return "\U0001F3E0"
|
|
case "sensor":
|
|
return "\U0001F4CA"
|
|
case "lock":
|
|
return "\U0001F512"
|
|
default:
|
|
return "\U0001F4E6"
|
|
}
|
|
}
|