summaryrefslogtreecommitdiff
path: root/mqtt-controller/unified_switch.go
blob: fb62c7aa9d12cfe1ef78c939d8cdba334cba3f5f (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
package main

import (
	"hash/crc64"
	"log"
	"sync"

	"github.com/brutella/hc/accessory"
)

type UnifiedSwitch struct {
	HomeKitSwitch *accessory.Switch
	MqttDevice    Device
	Commands      <-chan Command
	metrics       chan Metric
	events        chan Event
	infos         chan interface{}
}

func NewUnifiedSwitch(b *MQTTBroker, d Device) (*UnifiedSwitch, error) {
	us := &UnifiedSwitch{
		MqttDevice: d,
		metrics:    make(chan Metric, 100),
		events:     make(chan Event, 100),
		infos:      make(chan interface{}, 100),
	}

	cmd, err := d.Connect(b, us.events, us.metrics, us.infos)
	if err != nil {
		log.Printf("Error connecting device: %e", err)
		return nil, err
	}

	us.Commands = cmd
	us.makeHomekitSwitch()

	return us, nil
}

func (s *UnifiedSwitch) MessageLoop(done <-chan interface{}, wg *sync.WaitGroup) {
	wg.Add(1)
	defer wg.Done()

	log.Printf("Starting switch %s", s.MqttDevice.Identity())

C:
	for {
		select {
		case e := <-s.events:
			direction := "output"
			if e.Direction == DirectionInput {
				direction = "input"
			}

			s.HomeKitSwitch.Switch.On.SetValue(e.Active)

			log.Printf("New event for '%s'.%d %s: %t", e.Device.Identity(), e.Index, direction, e.Active)
		case m := <-s.metrics:
			/*
				switch t := m.Value.(type) {
				case float64:
					log.Printf("New metric '%s' for '%s': %#v", m.Name, m.Device.Identity(), t)
				case int64:
					log.Printf("New metric '%s' for '%s': %#v", m.Name, m.Device.Identity(), t)
				case bool:
					log.Printf("New metric '%s' for '%s': %#v", m.Name, m.Device.Identity(), t)
				default:
					log.Printf("Unknown metric: %#v", m.Value)
				}
			*/
			_ = m
		case i := <-s.infos:
			switch it := i.(type) {
			case ShellyStatus:
				// TODO: Handle multiple relays
				log.Printf("Info relays: %#v", it.Relays)
				s.HomeKitSwitch.Switch.On.SetValue(it.Relays[0].IsOn)
			default:
				// Just discard them for now
			}
		case <-done:
			log.Printf("Shutting down switch %s", s.MqttDevice.Identity())
			break C
		}
	}

	log.Printf("Switch %s shut down", s.MqttDevice.Identity())
}

func (s *UnifiedSwitch) HomeKitID() uint64 {
	h64 := crc64.New(crc64.MakeTable(crc64.ISO))
	h64.Write([]byte(s.MqttDevice.Identity()))
	return h64.Sum64()
}

func (s *UnifiedSwitch) makeHomekitSwitch() {
	// TODO: Get name from local DB?
	switch dt := s.MqttDevice.(type) {
	case *ShellyDevice:
		s.HomeKitSwitch = accessory.NewSwitch(accessory.Info{
			ID:               s.HomeKitID(),
			Name:             s.MqttDevice.Identity(),
			Manufacturer:     dt.Manufacturer,
			Model:            dt.Model,
			FirmwareRevision: dt.FirmwareVersion,
		})
	default:
		s.HomeKitSwitch = accessory.NewSwitch(accessory.Info{
			ID:   s.HomeKitID(),
			Name: s.MqttDevice.Identity(),
		})
	}
	s.HomeKitSwitch.Switch.On.SetValue(false)
	s.HomeKitSwitch.Switch.On.OnValueRemoteUpdate(s.HomeKitSetValue)
}

func (s *UnifiedSwitch) HomeKitSetValue(state bool) {
	log.Printf("Client updated state: %t", state)
	if state {
		s.MqttDevice.OutputOn(0)
	} else {
		s.MqttDevice.OutputOff(0)
	}
}