diff --git a/cmd/lucy/info.go b/cmd/lucy/info.go new file mode 100644 index 0000000..0c4d5d0 --- /dev/null +++ b/cmd/lucy/info.go @@ -0,0 +1,157 @@ +package main + +import ( + "encoding/json" + "fmt" + "git.aiterp.net/lucifer/new-server/models" + "io" + "sort" + "strings" + "time" +) + +func WriteDeviceInfo(w io.Writer, devices []models.Device, fields []string) { + if len(fields) == 1 && fields[0] == "all" { + fields = allFields + } else { + fields = append(fields[:0:0], fields...) + for i, field := range fields { + if aliased, ok := fieldAliases[field]; ok { + fields[i] = aliased + } + } + } + + length := 0 + for _, field := range fields { + if mlFields[field] { + continue + } + + if len(field) > length { + length = len(field) + } + } + + for i, device := range devices { + if i > 0 { + fmt.Println() + } + + for _, field := range fields { + if formatter, ok := fieldFormatters[field]; ok { + _, _ = fmt.Fprintf(w, "%-*s %s\n", length+1, field+":", formatter(&device)) + } else { + _, _ = fmt.Fprintf(w, "%-*s (unknown field)\n", length+1, field+":") + } + } + } +} + +var allFields = []string{ + "id", "name", "icon", "bridgeId", "tags", "buttonNames", + "power", "color", "intensity", "temperature", + "internalId", "sceneAssignment", "userProperties", "driverProperties", +} + +var mlFields = map[string]bool{ + "sceneAssignment": true, + "userProperties": true, + "driverProperties": true, +} + +var fieldFormatters = map[string]func(d *models.Device) string{ + "id": func(d *models.Device) string { return fmt.Sprint(d.ID) }, + "internalId": func(d *models.Device) string { return d.InternalID }, + "name": func(d *models.Device) string { return d.Name }, + "icon": func(d *models.Device) string { return d.Icon }, + "bridgeId": func(d *models.Device) string { return fmt.Sprint(d.BridgeID) }, + "tags": func(d *models.Device) string { return strings.Join(d.Tags, ", ") }, + "buttonNames": func(d *models.Device) string { return strings.Join(d.ButtonNames, ", ") }, + "power": func(d *models.Device) string { return fmt.Sprint(d.State.Power) }, + "color": func(d *models.Device) string { return d.State.Color.String() }, + "intensity": func(d *models.Device) string { return fmt.Sprint(d.State.Intensity) }, + "temperature": func(d *models.Device) string { return fmt.Sprint(d.State.Temperature) }, + + "sceneAssignment": func(d *models.Device) string { + str := &strings.Builder{} + str.Grow(64) + for _, scene := range d.SceneAssignments { + _, _ = fmt.Fprintf(str, "\n - id: %d\n", scene.SceneID) + _, _ = fmt.Fprintf(str, " duration: %d\n", scene.DurationMS) + _, _ = fmt.Fprintf(str, " group: %s\n", scene.Group) + _, _ = fmt.Fprintf(str, " startTime: %s", scene.StartTime.Format(time.RFC3339)) + } + if len(d.SceneAssignments) == 0 { + str.Reset() + str.WriteString("(none)") + } + + return str.String() + }, + + "userProperties": func(d *models.Device) string { + str := &strings.Builder{} + str.Grow(64) + str.WriteString("\n") + keys := make([]string, 0, len(d.UserProperties)) + for key := range d.UserProperties { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + _, _ = fmt.Fprintf(str, " %s: %s\n", key, d.UserProperties[key]) + } + if len(d.UserProperties) == 0 { + str.Reset() + str.WriteString("(none)") + } + + return str.String() + }, + + "driverProperties": func(d *models.Device) string { + str := &strings.Builder{} + str.Grow(256) + str.WriteString("\n") + keys := make([]string, 0, len(d.DriverProperties)) + for key := range d.DriverProperties { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + j, _ := json.Marshal(d.DriverProperties[key]) + _, _ = fmt.Fprintf(str, " %s: %s\n", key, string(j)) + } + if len(d.DriverProperties) == 0 { + str.Reset() + str.WriteString("(none)") + } + + return str.String() + }, + + "capabilities": func(d *models.Device) string { + capStr := make([]string, len(d.Capabilities)) + for i := range d.Capabilities { + capStr[i] = string(d.Capabilities[i]) + } + return strings.Join(capStr, ", ") + }, +} + +var fieldAliases = map[string]string{ + "bridge": "bridgeId", + "buttons": "buttonNames", + "internal": "internalId", + "caps": "capabilities", + "cap": "capabilities", + "userprops": "userProperties", + "uprops": "userProperties", + "driverprops": "driverProperties", + "dprops": "driverProperties", + "internalid": "internalId", + "bridgeid": "bridgeId", + "buttonnames": "buttonNames", + "scene": "sceneAssignment", +} diff --git a/cmd/lucy/main.go b/cmd/lucy/main.go index f9223b3..995a1b8 100644 --- a/cmd/lucy/main.go +++ b/cmd/lucy/main.go @@ -37,8 +37,8 @@ func main() { log.Fatalln(err) } - if cmd.Params.Get("info").StringOr("false") == "true" { - WriteDeviceInfoTable(os.Stdout, devices) + if info := cmd.Params.Get("info").String(); info != nil { + WriteDeviceInfo(os.Stdout, devices, strings.Split(*info, ",")) } else { WriteDeviceStateTable(os.Stdout, devices) }