package main import ( "bufio" "context" "encoding/json" "flag" "fmt" "git.aiterp.net/lucifer/new-server/app/config" "git.aiterp.net/lucifer/new-server/models" "log" "os" "sort" "strconv" "strings" "time" ) var flagDriver = flag.String("driver", string(models.DTNanoLeaf), "The bridge driver to use") var flagAddress = flag.String("address", "127.0.0.1", "The bridge's address") var flagToken = flag.String("token", "", "The bridge's access token / api key / login") var flagPair = flag.Bool("pair", false, "Try to pair with the bridge.") var flagSearch = flag.Bool("search", false, "Search for devices first.") var flagSearchTimeout = flag.Duration("search-timeout", time.Second*3, "Timeout for device search.") func main() { flag.Parse() // Find drivers driver, err := config.DriverProvider().Provide(models.DriverKind(*flagDriver)) if err != nil { log.Fatalln("Failed to find driver:", err) } // Find bridge bridges, err := driver.SearchBridge(context.Background(), *flagAddress, !*flagPair) if err != nil { log.Fatalln("Failed to search bridge:", err) } if len(bridges) == 0 { log.Fatalln("No bridges found") } bridge := bridges[0] if !*flagPair { bridge.Token = *flagToken } else { log.Println("New token:", bridge.Token) } // List devices var devices []models.Device if *flagSearch { devices, err = driver.SearchDevices(context.Background(), bridge, *flagSearchTimeout) if err != nil { log.Fatalln("Failed to search devices:", err) } } else { devices, err = driver.ListDevices(context.Background(), bridge) if err != nil { log.Fatalln("Failed to list devices:", err) } } for i := range devices { devices[i].ID = i + 1 } ch := config.EventChannel go func() { err := driver.Run(context.Background(), bridge, ch) if err != nil { log.Fatalln("Run bridge stopped:", err) } }() go func() { reader := bufio.NewReader(os.Stdin) _, _ = fmt.Fprintln(os.Stderr, "Format: [id1,id2,...] [on|off] [color] [intensity]") for _, device := range devices { _, _ = fmt.Fprintf(os.Stderr, "Device: %d - %s %+v\n", device.ID, device.InternalID, device.Capabilities) } _, _ = fmt.Fprintln(os.Stderr, "Format: [id1,id2,...] [on|off] [color]") for { text, _ := reader.ReadString('\n') text = strings.Trim(text, "\t  \r\n") if text == "json" { j, _ := json.MarshalIndent(devices, "", " ") fmt.Println(string(j)) } tokens := strings.Split(text, " ") if len(tokens) < 4 { continue } color, err := models.ParseColorValue(tokens[2]) if err != nil { _, _ = fmt.Fprintln(os.Stderr, "Invalid color:", err) continue } intensity, _ := strconv.ParseFloat(tokens[3], 64) power := strings.ToLower(tokens[1]) == "on" idsStr := strings.Split(tokens[0], ",") ids := make([]int, 0, len(idsStr)) for _, idStr := range idsStr { if idStr == "*" { ids = append(ids[:0], -1) break } id, err := strconv.Atoi(idStr) if err != nil { continue } ids = append(ids, id) } updatedDevices := devices[:0:0] for _, device := range devices { for _, id := range ids { if id == -1 || id == device.ID { if (color.IsKelvin() && device.HasCapability(models.DCColorKelvin)) || (color.IsHueSat() && device.HasCapability(models.DCColorHS)) { device.State.Color = color } if device.HasCapability(models.DCPower) { device.State.Power = power } if device.HasCapability(models.DCIntensity) { device.State.Intensity = intensity } updatedDevices = append(updatedDevices, device) } } } if len(updatedDevices) > 0 { err := driver.Publish(context.Background(), bridge, updatedDevices) if err != nil { log.Fatalln("Publish to bridge failed:", err) return } } } }() for event := range ch { _, _ = fmt.Fprintf(os.Stderr, "Event %s", event.Name) keys := make([]string, 0, 8) for key := range event.Payload { keys = append(keys, key) } sort.Strings(keys) for _, key := range keys { _, _ = fmt.Fprintf(os.Stderr, " %s=%#+v", key, event.Payload[key]) } _, _ = fmt.Fprint(os.Stderr, "\n") } }