feat: expose action input specifications
This commit is contained in:
@@ -50,10 +50,11 @@ type ValueListItem struct {
|
||||
}
|
||||
|
||||
type ActionSpec struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
SIID int `json:"siid"`
|
||||
AIID int `json:"aiid"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
SIID int `json:"siid"`
|
||||
AIID int `json:"aiid"`
|
||||
Inputs []PropertySpec `json:"inputs,omitempty"`
|
||||
}
|
||||
|
||||
type DeviceSelector struct {
|
||||
@@ -230,6 +231,7 @@ func parseDeviceInfoHTML(body []byte) (DeviceInfo, error) {
|
||||
IID int `json:"iid"`
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description"`
|
||||
Inputs []int `json:"in"`
|
||||
} `json:"actions"`
|
||||
} `json:"services"`
|
||||
} `json:"tree"`
|
||||
@@ -245,6 +247,7 @@ func parseDeviceInfoHTML(body []byte) (DeviceInfo, error) {
|
||||
propertyNames := make(map[string]struct{})
|
||||
actionNames := make(map[string]struct{})
|
||||
for _, service := range page.Props.Tree.Services {
|
||||
serviceProperties := make(map[int]PropertySpec, len(service.Properties))
|
||||
for _, property := range service.Properties {
|
||||
propertyType := property.Format
|
||||
if strings.HasPrefix(propertyType, "int") {
|
||||
@@ -265,7 +268,9 @@ func parseDeviceInfoHTML(body []byte) (DeviceInfo, error) {
|
||||
for index, item := range property.ValueList {
|
||||
valueList[index] = ValueListItem{Value: item.Value, Description: item.Description, DescZhCN: page.Props.I18n.ZhCN[item.I18nKey]}
|
||||
}
|
||||
info.Properties = append(info.Properties, PropertySpec{Name: name, Description: description, Type: propertyType, RW: accessString(property.Access), Range: property.ValueRange, ValueList: valueList, SIID: service.IID, PIID: property.IID})
|
||||
propertySpec := PropertySpec{Name: name, Description: description, Type: propertyType, RW: accessString(property.Access), Range: property.ValueRange, ValueList: valueList, SIID: service.IID, PIID: property.IID}
|
||||
serviceProperties[property.IID] = propertySpec
|
||||
info.Properties = append(info.Properties, propertySpec)
|
||||
}
|
||||
for _, action := range service.Actions {
|
||||
name := action.Type
|
||||
@@ -274,7 +279,15 @@ func parseDeviceInfoHTML(body []byte) (DeviceInfo, error) {
|
||||
}
|
||||
actionNames[name] = struct{}{}
|
||||
description := localizedDescription(action.Description, page.Props.I18n.ZhCN[fmt.Sprintf("service:%03d:action:%03d", service.IID, action.IID)])
|
||||
info.Actions = append(info.Actions, ActionSpec{Name: name, Description: description, SIID: service.IID, AIID: action.IID})
|
||||
inputs := make([]PropertySpec, len(action.Inputs))
|
||||
for index, propertyIID := range action.Inputs {
|
||||
propertySpec, ok := serviceProperties[propertyIID]
|
||||
if !ok {
|
||||
return DeviceInfo{}, fmt.Errorf("action %q references unknown property IID %d", name, propertyIID)
|
||||
}
|
||||
inputs[index] = clonePropertySpec(propertySpec)
|
||||
}
|
||||
info.Actions = append(info.Actions, ActionSpec{Name: name, Description: description, SIID: service.IID, AIID: action.IID, Inputs: inputs})
|
||||
}
|
||||
}
|
||||
return info, nil
|
||||
@@ -553,6 +566,11 @@ func validateDeviceInfo(info DeviceInfo, model string) error {
|
||||
if strings.TrimSpace(action.Name) == "" || action.SIID <= 0 || action.AIID <= 0 {
|
||||
return fmt.Errorf("action %d is invalid", index)
|
||||
}
|
||||
for inputIndex, input := range action.Inputs {
|
||||
if !validPropertyType(input.Type) || input.SIID <= 0 || input.PIID <= 0 || input.SIID != action.SIID {
|
||||
return fmt.Errorf("action %d input %d is invalid", index, inputIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -620,9 +638,7 @@ func NewDevice(ctx context.Context, client *Client, selector DeviceSelector, opt
|
||||
func (device *Device) Properties() map[string]PropertySpec {
|
||||
properties := make(map[string]PropertySpec, len(device.properties))
|
||||
for name, property := range device.properties {
|
||||
property.Range = append([]json.Number(nil), property.Range...)
|
||||
property.ValueList = append([]ValueListItem(nil), property.ValueList...)
|
||||
properties[name] = property
|
||||
properties[name] = clonePropertySpec(property)
|
||||
}
|
||||
return properties
|
||||
}
|
||||
@@ -630,11 +646,22 @@ func (device *Device) Properties() map[string]PropertySpec {
|
||||
func (device *Device) Actions() map[string]ActionSpec {
|
||||
actions := make(map[string]ActionSpec, len(device.actions))
|
||||
for name, action := range device.actions {
|
||||
inputs := make([]PropertySpec, len(action.Inputs))
|
||||
for index, input := range action.Inputs {
|
||||
inputs[index] = clonePropertySpec(input)
|
||||
}
|
||||
action.Inputs = inputs
|
||||
actions[name] = action
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
func clonePropertySpec(property PropertySpec) PropertySpec {
|
||||
property.Range = append([]json.Number(nil), property.Range...)
|
||||
property.ValueList = append([]ValueListItem(nil), property.ValueList...)
|
||||
return property
|
||||
}
|
||||
|
||||
func (device *Device) Get(ctx context.Context, name string) (any, error) {
|
||||
property, ok := device.properties[name]
|
||||
if !ok {
|
||||
|
||||
Reference in New Issue
Block a user