forked from raumzeitlabor/pinpad-controller
-
Notifications
You must be signed in to change notification settings - Fork 0
/
controller.go
145 lines (124 loc) · 3.51 KB
/
controller.go
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
134
135
136
137
138
139
140
141
142
143
144
145
// vim:ts=4:sw=4:noexpandtab
package main
import (
"fmt"
"log"
"flag"
"time"
"pinpad-controller/frontend"
"pinpad-controller/pinpad"
"pinpad-controller/pinstore"
"pinpad-controller/hometec"
"pinpad-controller/ctrlsocket"
"pinpad-controller/tuerstatus"
mqtt "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
)
var pin_url *string = flag.String(
"pin_url",
"https://blackbox.raumzeitlabor.de/BenutzerDB/pins/getraenkelager",
"URL to load the PINs from")
var pin_path *string = flag.String(
"pin_path",
"/perm/pins.json",
"Path to store the PINs permanently")
var broker = flag.String(
"broker",
"tcp://infra.rzl:1883",
"The mqtt server to connect to")
var topic = flag.String(
"topic",
"/service/status",
"The topic to which the door state will be published")
var lastPublishedStatus tuerstatus.Tuerstatus
var newStatus tuerstatus.Tuerstatus
// Wir haben folgende Bestandteile:
// 1) Das Frontend
// 2) Die Pin-Synchronisierung
// Ein http-req auf die BenutzerDB.
// 3) Die Hausbus-API für SSH-öffnen
// Separates Programm, welches dann via Hausbus den /open_door anspricht
// 4) Sensoren lesen (türstatus)
// Hier müssen wir nur auf das RZL-Jail POSTen (vorerst).
// Wo läuft die rrdtool-db? am besten auf dem jail zukünftig
// Am besten stellt man den Türstatus via Hausbus-API bereit und kann das
// dann verbasteln.
// Kann man inotify auf /sys machen mit den GPIOs?
func updatePins(pins *pinstore.Pinstore, fe *frontend.Frontend) {
for {
time.Sleep(1 * time.Minute)
pins.Update(*pin_url, fe)
}
}
func publishMqtt() {
opts := mqtt.NewClientOptions()
opts.SetBroker(*broker)
opts.SetClientId("pinpad-main")
opts.SetCleanSession(true)
opts.SetTraceLevel(mqtt.Off)
opts.SetOnConnectionLost(func(client *mqtt.MqttClient, err error) {
fmt.Printf("lost mqtt connection, trying to reconnect: %s\n", err)
client.Start()
})
client := mqtt.NewClient(opts)
_, err := client.Start()
if err != nil {
fmt.Printf("could not connect to mqtt broker: %s\n", err)
return
}
var msg string
if (newStatus.Open) {
msg = "\"open\""
} else {
msg = "\"closed\""
}
mqttMsg := mqtt.NewMessage([]byte(msg))
mqttMsg.SetQoS(mqtt.QOS_ONE)
mqttMsg.SetRetainedFlag(true)
r := client.PublishMessage(*topic, mqttMsg)
<-r
lastPublishedStatus = newStatus
client.ForceDisconnect()
}
func main() {
flag.Parse()
fe, _ := frontend.OpenFrontend("/dev/ttyAMA0")
if e := fe.Beep(frontend.BEEP_SHORT); e != nil {
fmt.Println("cannot beep")
}
hometec, _ := hometec.OpenHometec()
tuerstatusChannel := make(chan tuerstatus.Tuerstatus)
go tuerstatus.TuerstatusPoll(tuerstatusChannel, 250 * time.Millisecond)
go func() {
for {
newStatus = <-tuerstatusChannel
if newStatus.Open {
fe.LcdSet(" \nOpen")
} else {
fe.LcdSet(" \nClosed")
}
}
}()
// Ensure last door state is published. For example, if door state was
// changed during netsplit, we need to ensure that the newest state
// will be published as soon as network is up again.
go func() {
for {
if (newStatus.Open && ! lastPublishedStatus.Open) {
publishMqtt()
} else if (! newStatus.Open && lastPublishedStatus.Open) {
publishMqtt()
}
time.Sleep(250 * time.Millisecond)
}
}()
pins, err := pinstore.Load(*pin_path)
if err != nil {
log.Fatalf("Could not load pins: %v", err)
}
if err := pins.Update(*pin_url, fe); err != nil {
fmt.Printf("Cannot update pins: %v\n", err)
}
go updatePins(pins, fe)
ctrlsocket.Listen(fe, hometec.Control)
pinpad.ValidatePin(pins, fe, hometec.Control)
}