Added timestamp to presence state and use mqtt instead of channel for overall presence
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Dreaded_X 2022-11-18 18:50:36 +01:00
parent 07fa5fc986
commit c49ee841fd
Signed by: Dreaded_X
GPG Key ID: 76BDEC4E165D8AD9
3 changed files with 80 additions and 53 deletions

View File

@ -23,6 +23,7 @@ func Connect(config Config) MQTT {
opts.SetDefaultPublishHandler(defaultHandler) opts.SetDefaultPublishHandler(defaultHandler)
opts.SetUsername(config.Username) opts.SetUsername(config.Username)
opts.SetPassword(config.Password) opts.SetPassword(config.Password)
opts.SetOrderMatters(false)
client := mqtt.NewClient(opts) client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil { if token := client.Connect(); token.Wait() && token.Error() != nil {

46
main.go
View File

@ -7,6 +7,7 @@ import (
"automation/integration/mqtt" "automation/integration/mqtt"
"automation/integration/ntfy" "automation/integration/ntfy"
"automation/presence" "automation/presence"
"encoding/json"
"fmt" "fmt"
"log" "log"
"net/http" "net/http"
@ -16,6 +17,8 @@ import (
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/kelseyhightower/envconfig" "github.com/kelseyhightower/envconfig"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
paho "github.com/eclipse/paho.mqtt.golang"
) )
type config struct { type config struct {
@ -138,11 +141,7 @@ func main() {
} }
// ntfy.sh // ntfy.sh
n := ntfy.Connect(config.NTFY) // n := ntfy.Connect(config.NTFY)
// Presence
p := presence.New()
m.AddHandler("automation/presence/+", p.PresenceHandler)
// Devices that we control and expose to google home // Devices that we control and expose to google home
provider := device.NewProvider(config.Google, &m) provider := device.NewProvider(config.Google, &m)
@ -154,20 +153,30 @@ func main() {
provider.AddDevice(device.NewComputer(info.MACAddress, name, info.Room, info.Url)) provider.AddDevice(device.NewComputer(info.MACAddress, name, info.Room, info.Url))
} }
// Event loop // Presence
go func() { p := presence.New()
fmt.Println("Starting event loop") m.AddHandler("automation/presence/+", p.PresenceHandler)
for {
select { m.AddHandler("automation/presence", func(client paho.Client, msg paho.Message) {
case present := <-p.Presence: if len(msg.Payload()) == 0 {
fmt.Printf("Presence: %t\n", present) // In this case we clear the persistent message
return
}
var message presence.Message
err := json.Unmarshal(msg.Payload(), &message)
if err != nil {
log.Println(err)
return
}
fmt.Printf("Presence: %t\n", message.State)
// Notify users of presence update // Notify users of presence update
n.Presence(present) // n.Presence(present)
// Set presence on the hue bridge // Set presence on the hue bridge
h.SetFlag(41, present) h.SetFlag(41, message.State)
if !present { if !message.State {
// Turn off all the devices that we manage ourselves // Turn off all the devices that we manage ourselves
provider.TurnAllOff() provider.TurnAllOff()
@ -185,12 +194,7 @@ func main() {
} else { } else {
// @TODO Turn on the nest thermostat again // @TODO Turn on the nest thermostat again
} }
})
case <-h.Events:
break
}
}
}()
addr := ":8090" addr := ":8090"
srv := http.Server{ srv := http.Server{

View File

@ -1,40 +1,48 @@
package presence package presence
import ( import (
"fmt" "encoding/json"
"strconv" "log"
"strings" "strings"
"time"
mqtt "github.com/eclipse/paho.mqtt.golang" mqtt "github.com/eclipse/paho.mqtt.golang"
"github.com/kr/pretty"
) )
type Presence struct { type Presence struct {
Presence chan bool
devices map[string]bool devices map[string]bool
current *bool current *bool
} }
type Message struct {
State bool `json:"state"`
Updated int64 `json:"updated"`
}
func New() Presence { func New() Presence {
return Presence{Presence: make(chan bool), devices: make(map[string]bool), current: nil} return Presence{devices: make(map[string]bool), current: nil}
} }
// Handler got automation/presence/+ // Handler got automation/presence/+
func (p *Presence) PresenceHandler(client mqtt.Client, msg mqtt.Message) { func (p *Presence) PresenceHandler(client mqtt.Client, msg mqtt.Message) {
name := strings.Split(msg.Topic(), "/")[2] name := strings.Split(msg.Topic(), "/")[2]
if len(msg.Payload()) == 0 { if len(msg.Payload()) == 0 {
// @TODO What happens if we delete a device that does not exist
delete(p.devices, name) delete(p.devices, name)
} else { } else {
value, err := strconv.Atoi(string(msg.Payload())) var message Message
err := json.Unmarshal(msg.Payload(), &message)
if err != nil { if err != nil {
panic(err) log.Println(err)
return
} }
p.devices[name] = value == 1 p.devices[name] = message.State
} }
present := false present := false
fmt.Println(p.devices) pretty.Println(p.devices)
for _, value := range p.devices { for _, value := range p.devices {
if value { if value {
present = true present = true
@ -42,9 +50,23 @@ func (p *Presence) PresenceHandler(client mqtt.Client, msg mqtt.Message) {
} }
} }
log.Println(present)
if p.current == nil || *p.current != present { if p.current == nil || *p.current != present {
p.current = &present p.current = &present
p.Presence <- present
msg, err := json.Marshal(Message{
State: present,
Updated: time.Now().UnixMilli(),
})
if err != nil {
log.Println(err)
}
token := client.Publish("automation/presence", 1, true, msg)
if token.Wait() && token.Error() != nil {
log.Println(token.Error())
}
} }
} }