You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

194 lines
4.9 KiB

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, *flagToken, !*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)
}
ch := config.EventChannel
go func() {
err := driver.Run(context.Background(), bridge, ch)
if err != nil {
log.Fatalln("Run bridge stopped:", err)
}
}()
time.Sleep(time.Second)
// 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)
}
}
idMap := make(map[string]int)
nextId := len(devices) + 1
for i := range devices {
devices[i].ID = i + 1
idMap[devices[i].InternalID] = i + 1
}
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 == "search" {
_, _ = driver.SearchDevices(context.Background(), bridge, time.Second)
}
if text == "list" || text == "search" || text == "json" {
devices, err = driver.ListDevices(context.Background(), bridge)
if err != nil {
log.Fatalln("Failed to list devices:", err)
}
for i, device := range devices {
if extId, ok := idMap[device.InternalID]; ok {
devices[i].ID = extId
} else {
idMap[device.InternalID] = nextId
devices[i].ID = nextId
nextId += 1
}
if text != "json" {
_, _ = fmt.Fprintf(os.Stderr, "Device: %d - %s %+v\n", device.ID, device.InternalID, device.Capabilities)
}
}
}
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")
}
}