141 lines
2.8 KiB
Go
141 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"automation/device"
|
|
"automation/integration/hue"
|
|
"automation/integration/kasa"
|
|
"automation/integration/mqtt"
|
|
"automation/integration/ntfy"
|
|
"automation/presence"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/joho/godotenv"
|
|
"github.com/kelseyhightower/envconfig"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type config struct {
|
|
Hue hue.Config `yaml:"hue"`
|
|
NTFY ntfy.Config `yaml:"ntfy"`
|
|
MQTT mqtt.Config `yaml:"mqtt"`
|
|
|
|
Kasa struct {
|
|
Outlets map[string]string `yaml:"outlets"`
|
|
} `yaml:"kasa"`
|
|
|
|
Computer map[string]struct {
|
|
MACAddress string `yaml:"mac"`
|
|
Room string `yaml:"room"`
|
|
Url string `yaml:"url"`
|
|
} `yaml:"computers"`
|
|
|
|
Google device.Config `yaml:"google"`
|
|
}
|
|
|
|
func GetConfig() config {
|
|
// First load the config from the yaml file
|
|
f, err := os.Open("config.yml")
|
|
if err != nil {
|
|
log.Fatalln("Failed to open config file", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
var cfg config
|
|
decoder := yaml.NewDecoder(f)
|
|
err = decoder.Decode(&cfg)
|
|
if err != nil {
|
|
log.Fatalln("Failed to parse config file", err)
|
|
}
|
|
|
|
// Then load values from environment
|
|
// This can be used to either override the config or pass in secrets
|
|
err = envconfig.Process("", &cfg)
|
|
if err != nil {
|
|
log.Fatalln("Failed to parse environmet config", err)
|
|
}
|
|
|
|
return cfg
|
|
}
|
|
|
|
func main() {
|
|
_ = godotenv.Load()
|
|
|
|
config := GetConfig()
|
|
|
|
// MQTT
|
|
m := mqtt.Connect(config.MQTT)
|
|
defer m.Disconnect()
|
|
|
|
// Hue
|
|
h := hue.Connect(config.Hue)
|
|
|
|
// Kasa
|
|
kasaDevices := make(map[string]kasa.Kasa)
|
|
for name, ip := range config.Kasa.Outlets {
|
|
kasaDevices[name] = kasa.New(ip)
|
|
}
|
|
|
|
// ntfy.sh
|
|
n := ntfy.Connect(config.NTFY)
|
|
|
|
// Presence
|
|
p := presence.New()
|
|
m.AddHandler("automation/presence/+", p.PresenceHandler)
|
|
|
|
// Devices that we control and expose to google home
|
|
provider := device.NewProvider(config.Google, &m)
|
|
|
|
r := mux.NewRouter()
|
|
r.HandleFunc("/assistant", provider.Service.FullfillmentHandler)
|
|
|
|
for name, info := range config.Computer {
|
|
provider.AddDevice(device.NewComputer(info.MACAddress, name, info.Room, info.Url))
|
|
}
|
|
|
|
// Event loop
|
|
go func() {
|
|
fmt.Println("Starting event loop")
|
|
for {
|
|
select {
|
|
case present := <-p.Presence:
|
|
fmt.Printf("Presence: %t\n", present)
|
|
// Notify users of presence update
|
|
n.Presence(present)
|
|
|
|
// Set presence on the hue bridge
|
|
h.SetFlag(41, present)
|
|
|
|
if !present {
|
|
// Turn off all the devices that we manage ourselves
|
|
provider.TurnAllOff()
|
|
|
|
// Turn off kasa devices
|
|
for _, device := range kasaDevices {
|
|
device.SetState(false)
|
|
}
|
|
|
|
// @TODO Turn off nest thermostat
|
|
} else {
|
|
// @TODO Turn on the nest thermostat again
|
|
}
|
|
|
|
case <-h.Events:
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
|
|
addr := ":8090"
|
|
srv := http.Server{
|
|
Addr: addr,
|
|
Handler: r,
|
|
}
|
|
|
|
log.Printf("Starting server on %s (PID: %d)\n", addr, os.Getpid())
|
|
srv.ListenAndServe()
|
|
}
|