huego/huego.go

150 lines
3.4 KiB
Go
Raw Normal View History

2024-07-17 04:10:05 +00:00
package main
import (
"bufio"
"bytes"
"encoding/json"
2024-07-17 04:10:05 +00:00
"fmt"
"io"
2024-07-17 04:10:05 +00:00
"log"
2024-07-17 05:37:56 +00:00
"net"
"net/http"
"os"
"strings"
2024-07-17 04:10:05 +00:00
"time"
"github.com/grandcat/zeroconf"
"golang.org/x/net/context"
)
type Bridge struct {
2024-07-17 05:37:56 +00:00
IP net.IP
Name string
}
2024-07-17 04:10:05 +00:00
type RegisteredApplication struct {
bridge Bridge
applicationName string
deviceName string
token string
}
func discoverHueBridge() ([]Bridge, error) {
2024-07-17 04:10:05 +00:00
// Create a new resolver
resolver, err := zeroconf.NewResolver(nil)
if err != nil {
log.Fatalf("Failed to initialize resolver: %v", err)
}
// Instantiate a new bridges slice
bridges := make([]Bridge, 0)
2024-07-17 05:37:56 +00:00
2024-07-17 04:10:05 +00:00
// Set up a context with a timeout
2024-07-17 05:37:56 +00:00
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
2024-07-17 04:10:05 +00:00
defer cancel()
// Channel to recive the results
entries := make(chan *zeroconf.ServiceEntry)
// Start the lookup for the Hue Bridge
go func() {
err = resolver.Browse(ctx, "_hue._tcp", "local.", entries)
if err != nil {
log.Fatalf("Failed to browse for Hue Bridge: %v", err)
}
}()
// Process the results
go func() {
for entry := range entries {
bridges = append(bridges, Bridge{IP: entry.AddrIPv4[0], Name: entry.HostName})
2024-07-17 04:10:05 +00:00
}
}()
// Wait for the context to expire
<-ctx.Done()
fmt.Println("mDNS query finished")
fmt.Printf("Number of devices found: %d\n", len(bridges))
for _, device := range bridges {
2024-07-17 05:37:56 +00:00
fmt.Printf("Device: %s\n", device.Name)
fmt.Printf("IP Address: %s\n", device.IP)
}
return bridges, nil
}
func registerApplication(bridge Bridge) RegisteredApplication {
var applicationName string
var deviceName string
var token string
fmt.Printf("Enter name of your application: ")
fmt.Scan(&applicationName)
fmt.Printf("Enter name of your device: ")
fmt.Scan(&deviceName)
for {
resp, err := http.Post(
"http://"+bridge.IP.String()+"/api",
"application/json",
bytes.NewBuffer([]byte(`{"devicetype":"`+applicationName+`#`+deviceName+`"}`)))
if err != nil {
log.Fatal(err)
}
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Fatal(err)
}
type Success struct {
Username string `json:"username"`
}
if !strings.Contains(string(body), "link button not pressed") {
// Define a struct matching the expected JSON response structure
type SuccessResponse struct {
Success struct {
Username string `json:"username"`
} `json:"success"`
}
// Unmarshal the response body into the struct
var successResponse []SuccessResponse
if err := json.Unmarshal(body, &successResponse); err != nil {
log.Fatalf("Error parsing response: %v", err)
}
// Assign the username to the token
if len(successResponse) > 0 {
token = successResponse[0].Success.Username
}
break
}
fmt.Println("Link button not pressed. Press link button on bridge and press Enter to continue.")
bufio.NewReader(os.Stdin).ReadBytes('\n')
}
registeredApplication := RegisteredApplication{
bridge: bridge,
applicationName: applicationName,
deviceName: deviceName,
token: token,
}
return registeredApplication
2024-07-17 05:37:56 +00:00
}
func main() {
bridges, err := discoverHueBridge()
if err != nil {
log.Fatal(err)
}
registeredApplications := make([]RegisteredApplication, 0)
for _, bridge := range bridges {
newApplication := registerApplication(bridge)
registeredApplications = append(registeredApplications, newApplication)
}
fmt.Println(registeredApplications)
2024-07-17 04:10:05 +00:00
}