aboutsummaryrefslogtreecommitdiff
path: root/example_hk.go
blob: ee89281cb60c99e2399fa8b877e43abcd7b1eb69 (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
package main

import (
	"encoding/json"
	"fmt"
	"github.com/brutella/hc"
	"github.com/brutella/hc/accessory"
	"github.com/mcrute/go-inform/inform"
	"io/ioutil"
	"log"
	"os"
)

// Load devices into state
// Gather current initial state from devices
// Track state transitions
// Inputs:
// - Homekit
// - Devices

type Port struct {
	Label string `json:"label"`
	Port  int    `json:"port"`
}

type Device struct {
	Key    string  `json:"key"`
	Name   string  `json:"name"`
	Model  string  `json:"model"`
	Serial string  `json:"serial"`
	Ports  []*Port `json:"ports"`
}

type DeviceMap map[string]*Device

func LoadKeys(file string) (DeviceMap, error) {
	var keys DeviceMap

	kp, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer kp.Close()

	kd, err := ioutil.ReadAll(kp)
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(kd, &keys)
	if err != nil {
		return nil, err
	}

	return keys, nil
}

func main() {
	devs, err := LoadKeys("data/device_keys.json")
	if err != nil {
		log.Println("Error loading key file")
		log.Println(err.Error())
		return
	}

	keys := make(map[string]string, len(devs))
	for i, d := range devs {
		keys[i] = d.Key
	}

	h := inform.NewInformHandler(&inform.Codec{keys})
	s, _ := inform.NewServer(h)
	as := make([]*accessory.Accessory, 0, len(devs)*3)

	for i, d := range devs {
		for _, p := range d.Ports {
			a := accessory.NewSwitch(accessory.Info{
				Name:         p.Label,
				SerialNumber: fmt.Sprintf("%s-%d", d.Serial, p.Port),
				Manufacturer: "Ubiquiti",
				Model:        d.Model,
			})

			// Capture these for the closure, otherwise they're bound to the
			// single loop variable and will only see the final value of that
			// variable
			dev, port := i, p.Port

			a.Switch.On.OnValueRemoteUpdate(func(on bool) {
				h.SetState(dev, port, on)
			})

			h.AddPort(dev, port)
			as = append(as, a.Accessory)
		}
	}

	// The root accessory is what gets used to name the bridge so let's make it
	// an actual bridge
	br := accessory.New(accessory.Info{
		Name:         "UnifiBridge",
		Manufacturer: "Mike Crute",
		Model:        "0.1",
	}, accessory.TypeBridge)

	config := hc.Config{
		Pin:         "12344321",
		Port:        "12345",
		StoragePath: "./db",
	}

	t, err := hc.NewIPTransport(config, br, as...)
	if err != nil {
		log.Fatal(err)
		return
	}

	hc.OnTermination(func() {
		t.Stop()
		os.Exit(0) // Otherwise homekit doesn't actually stop
	})

	go t.Start()
	s.ListenAndServe()
}