aboutsummaryrefslogtreecommitdiff
path: root/bridge.go
blob: eda2f25f7fbacd24d6d7ab70ec753d880bd20fe7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package hue

// username: 319b36233bd2328f3e40731b23479207
import (
    "log"
    "os"
    "encoding/xml"
    "encoding/json"
    "net/http"
    "io/ioutil"
    "runtime"
    "fmt"
    "bytes"
)

type Bridge struct {
    IPAddress   string
    Username    string
    Info        BridgeInfo
}

type BridgeInfo struct {
    Info struct {
        Info struct {
            DeviceType          string      `xml:"deviceType"`
            FriendlyName        string      `xml:"friendlyName"`
            Manufacturer        string      `xml:"manufacturer"`
            ManufacturerURL     string      `xml:"manufacturerURL"`
            ModelDescription    string      `xml:"modelDescription"`
            ModelName           string      `xml:"modelName"`
            ModelNumber         string      `xml:"modelNumber"`
            ModelURL            string      `xml:"modelURL"`
            SerialNumber        string      `xml:"serialNumber"`
            UDN                 string      `xml:"UDN"`
        } `xml:"device"`
    } `xml:"root"`
}

// NewBridge defines hardware that is compatible with Hue.
func NewBridge(ip string, username string) *Bridge {
    bridge := Bridge {
        IPAddress: ip,
        Username: username,
    }

    GetBridgeInfo(&bridge)
    return &bridge
}

// GetBridgeInfo retreives the description.xml file from the bridge.
// Go to http://<bridge_ip>/description.xml
func GetBridgeInfo(self *Bridge) {
    response, error := http.Get("http://" + self.IPAddress + "/description.xml")
    if error != nil {
        trace("", error)
    } else if response.StatusCode != 200 {
        trace(fmt.Sprintf("Bridge status error: %d", response.StatusCode), nil)
        os.Exit(1)
    }
    defer response.Body.Close()

    body, error := ioutil.ReadAll(response.Body)
    if error != nil {
        trace("Error parsing bridge description xml.", nil)
        os.Exit(1)
    }

    data := new(BridgeInfo)
    error = xml.Unmarshal(body, &data)
    if error != nil {
        trace("Error using unmarshal to split xml.", nil)
        os.Exit(1)
    }
    self.Info = *data
}

// Error Struct - REST Error Response Format
// http://www.developers.meethue.com/documentation/error-messages
type Error struct {
    response struct {
        Type        string  `xml:"type"`
        Address     string  `xml:"address"`
        Description string  `xml:"description"`
    } `xml:"error"`
}

// CreateUser posts to ./api on the bridge to create a new whitelisted user.
// If the button on the bridge was not pressed then _____todo_____
func CreateUser(bridge *Bridge, deviceType string) (string, error) {
    // Construct the http POST
    params := map[string]string{"devicetype": deviceType}
    request, err := json.Marshal(params)
    if err != nil {
        return "", err
    }

    // Send the request to create the user and read the response
    uri := fmt.Sprintf("http://%s/api", bridge.IPAddress)
    response, err := http.Post(uri, "text/json", bytes.NewReader(request))
    if err != nil {
        return "", err
    }
    defer response.Body.Close()
    body, err := ioutil.ReadAll(response.Body)
    log.Println(string(body))

    data := []Error{}
    err = json.Unmarshal(body, &data)
    if err != nil {
        trace("", err)
        os.Exit(1)
    }
    fmt.Println(data)

    // TODO: decode and return
    // TODO: handle errors. http://www.developers.meethue.com/documentation/error-messages

    return "", err
}

// Log the date, time, file location, line number, and function.
// Message can be "" or Err can be nil (not both)
func trace(message string, err error) {
    pc := make([]uintptr, 10)
    runtime.Callers(2, pc)
    f := runtime.FuncForPC(pc[0])
    file, line := f.FileLine(pc[0])
    if err != nil {
        log.Printf("%s:%d %s: %s\n", file, line, f.Name(), err)
    } else {
        log.Printf("%s:%d %s: %s\n", file, line, f.Name(), message)
    }
}