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

3 years ago
  1. package main
  2. import (
  3. "bufio"
  4. "context"
  5. "encoding/json"
  6. "flag"
  7. "fmt"
  8. "git.aiterp.net/lucifer/new-server/app/config"
  9. "git.aiterp.net/lucifer/new-server/models"
  10. "log"
  11. "os"
  12. "sort"
  13. "strconv"
  14. "strings"
  15. "time"
  16. )
  17. var flagDriver = flag.String("driver", string(models.DTNanoLeaf), "The bridge driver to use")
  18. var flagAddress = flag.String("address", "127.0.0.1", "The bridge's address")
  19. var flagToken = flag.String("token", "", "The bridge's access token / api key / login")
  20. var flagPair = flag.Bool("pair", false, "Try to pair with the bridge.")
  21. var flagSearch = flag.Bool("search", false, "Search for devices first.")
  22. var flagSearchTimeout = flag.Duration("search-timeout", time.Second*3, "Timeout for device search.")
  23. func main() {
  24. flag.Parse()
  25. // Find drivers
  26. driver, err := config.DriverProvider().Provide(models.DriverKind(*flagDriver))
  27. if err != nil {
  28. log.Fatalln("Failed to find driver:", err)
  29. }
  30. // Find bridge
  31. bridges, err := driver.SearchBridge(context.Background(), *flagAddress, *flagToken, !*flagPair)
  32. if err != nil {
  33. log.Fatalln("Failed to search bridge:", err)
  34. }
  35. if len(bridges) == 0 {
  36. log.Fatalln("No bridges found")
  37. }
  38. bridge := bridges[0]
  39. if !*flagPair {
  40. bridge.Token = *flagToken
  41. } else {
  42. log.Println("New token:", bridge.Token)
  43. }
  44. ch := config.EventChannel
  45. go func() {
  46. err := driver.Run(context.Background(), bridge, ch)
  47. if err != nil {
  48. log.Fatalln("Run bridge stopped:", err)
  49. }
  50. }()
  51. time.Sleep(time.Second)
  52. // List devices
  53. var devices []models.Device
  54. if *flagSearch {
  55. devices, err = driver.SearchDevices(context.Background(), bridge, *flagSearchTimeout)
  56. if err != nil {
  57. log.Fatalln("Failed to search devices:", err)
  58. }
  59. } else {
  60. devices, err = driver.ListDevices(context.Background(), bridge)
  61. if err != nil {
  62. log.Fatalln("Failed to list devices:", err)
  63. }
  64. }
  65. idMap := make(map[string]int)
  66. nextId := len(devices) + 1
  67. for i := range devices {
  68. devices[i].ID = i + 1
  69. idMap[devices[i].InternalID] = i + 1
  70. }
  71. go func() {
  72. reader := bufio.NewReader(os.Stdin)
  73. _, _ = fmt.Fprintln(os.Stderr, "Format: [id1,id2,...] [on|off] [color] [intensity]")
  74. for _, device := range devices {
  75. _, _ = fmt.Fprintf(os.Stderr, "Device: %d - %s %+v\n", device.ID, device.InternalID, device.Capabilities)
  76. }
  77. _, _ = fmt.Fprintln(os.Stderr, "Format: [id1,id2,...] [on|off] [color]")
  78. for {
  79. text, _ := reader.ReadString('\n')
  80. text = strings.Trim(text, "\t  \r\n")
  81. if text == "search" {
  82. _, _ = driver.SearchDevices(context.Background(), bridge, time.Second)
  83. }
  84. if text == "list" || text == "search" || text == "json" {
  85. devices, err = driver.ListDevices(context.Background(), bridge)
  86. if err != nil {
  87. log.Fatalln("Failed to list devices:", err)
  88. }
  89. for i, device := range devices {
  90. if extId, ok := idMap[device.InternalID]; ok {
  91. devices[i].ID = extId
  92. } else {
  93. idMap[device.InternalID] = nextId
  94. devices[i].ID = nextId
  95. nextId += 1
  96. }
  97. if text != "json" {
  98. _, _ = fmt.Fprintf(os.Stderr, "Device: %d - %s %+v\n", device.ID, device.InternalID, device.Capabilities)
  99. }
  100. }
  101. }
  102. if text == "json" {
  103. j, _ := json.MarshalIndent(devices, "", " ")
  104. fmt.Println(string(j))
  105. }
  106. tokens := strings.Split(text, " ")
  107. if len(tokens) < 4 {
  108. continue
  109. }
  110. color, err := models.ParseColorValue(tokens[2])
  111. if err != nil {
  112. _, _ = fmt.Fprintln(os.Stderr, "Invalid color:", err)
  113. continue
  114. }
  115. intensity, _ := strconv.ParseFloat(tokens[3], 64)
  116. power := strings.ToLower(tokens[1]) == "on"
  117. idsStr := strings.Split(tokens[0], ",")
  118. ids := make([]int, 0, len(idsStr))
  119. for _, idStr := range idsStr {
  120. if idStr == "*" {
  121. ids = append(ids[:0], -1)
  122. break
  123. }
  124. id, err := strconv.Atoi(idStr)
  125. if err != nil {
  126. continue
  127. }
  128. ids = append(ids, id)
  129. }
  130. updatedDevices := devices[:0:0]
  131. for _, device := range devices {
  132. for _, id := range ids {
  133. if id == -1 || id == device.ID {
  134. if (color.IsKelvin() && device.HasCapability(models.DCColorKelvin)) || (color.IsHueSat() && device.HasCapability(models.DCColorHS)) {
  135. device.State.Color = color
  136. }
  137. if device.HasCapability(models.DCPower) {
  138. device.State.Power = power
  139. }
  140. if device.HasCapability(models.DCIntensity) {
  141. device.State.Intensity = intensity
  142. }
  143. updatedDevices = append(updatedDevices, device)
  144. }
  145. }
  146. }
  147. if len(updatedDevices) > 0 {
  148. err := driver.Publish(context.Background(), bridge, updatedDevices)
  149. if err != nil {
  150. log.Fatalln("Publish to bridge failed:", err)
  151. return
  152. }
  153. }
  154. }
  155. }()
  156. for event := range ch {
  157. _, _ = fmt.Fprintf(os.Stderr, "Event %s", event.Name)
  158. keys := make([]string, 0, 8)
  159. for key := range event.Payload {
  160. keys = append(keys, key)
  161. }
  162. sort.Strings(keys)
  163. for _, key := range keys {
  164. _, _ = fmt.Fprintf(os.Stderr, " %s=%#+v", key, event.Payload[key])
  165. }
  166. _, _ = fmt.Fprint(os.Stderr, "\n")
  167. }
  168. }