feat: Round 5 - Memory Service, Tool Engine, Call Records, Thinking Logs
- Fix: Session history flash (race condition + WS guard) - Fix: Chat background overlay + sidebar transparency - Fix: IoT device control (Chinese action names, status field) - Feat: Independent memory-service (port 8091, 13 endpoints) - Feat: Independent tool-engine service (port 8092, 13 tools) - Feat: Tool call logs with paginated DevTools panel - Feat: Thinking log records with DevTools panel - Feat: Future development roadmap document - Chore: Updated .gitignore, go.work, DevTools config - Chore: 5-service health check, project review docs
This commit is contained in:
@@ -227,7 +227,7 @@ func (ds *DeviceStore) Toggle(id string) (*Device, error) {
|
||||
return &cp, nil
|
||||
}
|
||||
|
||||
// SetProperty 设置设备属性(温度、亮度、位置、模式、颜色等)
|
||||
// SetProperty 设置设备属性(状态、温度、亮度、位置、模式、颜色等)
|
||||
func (ds *DeviceStore) SetProperty(id, field string, value interface{}) (*Device, error) {
|
||||
ds.mu.Lock()
|
||||
defer ds.mu.Unlock()
|
||||
@@ -240,6 +240,73 @@ func (ds *DeviceStore) SetProperty(id, field string, value interface{}) (*Device
|
||||
now := time.Now().UTC().Format(time.RFC3339)
|
||||
|
||||
switch field {
|
||||
case "status", "power":
|
||||
// 声明式电源控制:支持 "on"/"off"/"open"/"closed"/"locked"/"unlocked"
|
||||
// 同时支持中文值: "开"/"关"/"打开"/"关闭"
|
||||
// 支持布尔值: true/false → on/off
|
||||
var newStatus string
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
newStatus = normalizeStatus(v, d.Type)
|
||||
if newStatus == "" {
|
||||
return nil, fmt.Errorf("无效的状态值: %s (设备类型 %s 不支持此状态)", v, d.Type)
|
||||
}
|
||||
case bool:
|
||||
if v {
|
||||
newStatus = "on"
|
||||
} else {
|
||||
newStatus = "off"
|
||||
}
|
||||
case float64:
|
||||
if v == 0 {
|
||||
newStatus = "off"
|
||||
} else {
|
||||
newStatus = "on"
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("status 需要字符串、布尔值或数字")
|
||||
}
|
||||
// 对于非 on/off 设备类型(curtain/lock),转换为对应状态
|
||||
switch d.Type {
|
||||
case TypeCurtain:
|
||||
if newStatus == "on" {
|
||||
newStatus = "open"
|
||||
} else if newStatus == "off" {
|
||||
newStatus = "closed"
|
||||
}
|
||||
case TypeLock:
|
||||
if newStatus == "on" {
|
||||
newStatus = "unlocked"
|
||||
} else if newStatus == "off" {
|
||||
newStatus = "locked"
|
||||
}
|
||||
}
|
||||
|
||||
if d.Status == newStatus {
|
||||
// 状态未变化,直接返回
|
||||
cp := *d
|
||||
return &cp, nil
|
||||
}
|
||||
oldStatus := d.Status
|
||||
d.Status = newStatus
|
||||
// 根据设备类型设置关联属性
|
||||
switch d.Type {
|
||||
case TypeLight:
|
||||
if newStatus == "off" {
|
||||
d.Brightness = 0
|
||||
} else if d.Brightness == 0 {
|
||||
d.Brightness = 80
|
||||
}
|
||||
case TypeCurtain:
|
||||
if newStatus == "closed" {
|
||||
d.Position = 0
|
||||
} else {
|
||||
d.Position = 100
|
||||
}
|
||||
}
|
||||
d.LastUpdated = now
|
||||
ds.addHistory(id, "status", oldStatus, newStatus)
|
||||
|
||||
case "temperature":
|
||||
v, ok := toFloat64(value)
|
||||
if !ok {
|
||||
@@ -323,6 +390,36 @@ func (ds *DeviceStore) SetProperty(id, field string, value interface{}) (*Device
|
||||
return &cp, nil
|
||||
}
|
||||
|
||||
// normalizeStatus 标准化电源状态值
|
||||
// 支持英文: "on"/"off"/"open"/"closed"/"locked"/"unlocked"
|
||||
// 支持中文: "开"/"关"/"打开"/"关闭"/"开启"/"解锁"/"锁定"/"上锁"
|
||||
// 支持布尔兼容: "true"/"false"
|
||||
// 返回空字符串表示无效值
|
||||
func normalizeStatus(v string, dType DeviceType) string {
|
||||
switch strings.ToLower(strings.TrimSpace(v)) {
|
||||
case "on", "true", "开", "打开", "开启":
|
||||
return "on"
|
||||
case "off", "false", "关", "关闭":
|
||||
return "off"
|
||||
case "open":
|
||||
if dType == TypeCurtain {
|
||||
return "open"
|
||||
}
|
||||
return "on"
|
||||
case "closed":
|
||||
if dType == TypeCurtain {
|
||||
return "closed"
|
||||
}
|
||||
return "off"
|
||||
case "locked", "锁定", "上锁":
|
||||
return "locked"
|
||||
case "unlocked", "解锁":
|
||||
return "unlocked"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// toFloat64 将 interface{} 转换为 float64
|
||||
func toFloat64(v interface{}) (float64, bool) {
|
||||
switch val := v.(type) {
|
||||
|
||||
Reference in New Issue
Block a user