feat!: complete rearrangement for multi-module platform-specific modules
31
.scripts/Install.ps1
Normal file
@@ -0,0 +1,31 @@
|
||||
# A build & install script for the project's Windows version.
|
||||
$ErrorActionPreference = "Stop"
|
||||
$executableName = "door_tray"
|
||||
|
||||
if (-Not (Test-Path -Path "./go.mod")) {
|
||||
Write-Error "Please run this script from the project's root directory (go.mod not found)."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build
|
||||
go build -o "bin/$executableName-temp.exe" -ldflags "-s -w" "./cmd/windows/"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Build failed with exit code $LASTEXITCODE."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Compress
|
||||
upx "bin/$executableName-temp.exe" -o "bin/$executableName.exe" -5 -f
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Compression failed with exit code $LASTEXITCODE."
|
||||
exit 1
|
||||
}
|
||||
Remove-Item "bin/$executableName-temp.exe"
|
||||
|
||||
# Setup service
|
||||
$serviceName = "DoorTray"
|
||||
|
||||
# TODO: Stop old service
|
||||
# TODO: Install new binary
|
||||
# TODO: Start & verify service
|
||||
# TODO: Cleanup, print latest logs
|
||||
@@ -1,7 +1,9 @@
|
||||
# hass-tray
|
||||
# door-tray
|
||||
|
||||
A simple Go application to display basic state details (via a tray icon) from a Home Assistant instance.
|
||||
|
||||
- Easy install with a single binary
|
||||
- Windows (Service), Linux (Systemd)
|
||||
- Ultra simple configuration
|
||||
- YAML configuration file
|
||||
- Environment variables
|
||||
|
||||
77
cmd/windows/main.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"internal"
|
||||
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/debug"
|
||||
)
|
||||
|
||||
type WrapperService struct {
|
||||
service internal.Service
|
||||
}
|
||||
|
||||
func (wrapper *WrapperService) Execute(args []string, requestChannel <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {
|
||||
const acceptedCommands = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
|
||||
tick := time.Tick(5 * time.Second)
|
||||
|
||||
status <- svc.Status{State: svc.StartPending}
|
||||
status <- svc.Status{State: svc.Running, Accepts: acceptedCommands}
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-tick:
|
||||
slog.Debug("Tick Handled...!")
|
||||
case changeRequest := <-requestChannel:
|
||||
switch changeRequest.Cmd {
|
||||
case svc.Interrogate:
|
||||
slog.Debug("Interrogate Requested", "changeRequest", changeRequest)
|
||||
status <- changeRequest.CurrentStatus
|
||||
case svc.Stop, svc.Shutdown:
|
||||
slog.Warn("Shutdown Requested", "changeRequest", changeRequest)
|
||||
break loop
|
||||
case svc.Pause:
|
||||
wrapper.service.Pause()
|
||||
slog.Warn("Pause Requested", "changeRequest", changeRequest)
|
||||
status <- svc.Status{State: svc.Paused, Accepts: acceptedCommands}
|
||||
case svc.Continue:
|
||||
slog.Info("Continue Requested", "changeRequest", changeRequest)
|
||||
status <- svc.Status{State: svc.Running, Accepts: acceptedCommands}
|
||||
default:
|
||||
slog.Warn("Unexpected Change Request", "changeRequest", changeRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Service Stopping")
|
||||
status <- svc.Status{State: svc.StopPending}
|
||||
return false, 1
|
||||
}
|
||||
|
||||
func runService(name string, isDebug bool) {
|
||||
service := WrapperService{
|
||||
service: internal.NewApp(),
|
||||
}
|
||||
|
||||
if isDebug {
|
||||
err := debug.Run(name, &service)
|
||||
if err != nil {
|
||||
log.Fatalln("Error running service in debug mode.")
|
||||
}
|
||||
} else {
|
||||
err := svc.Run(name, &service)
|
||||
if err != nil {
|
||||
log.Fatalln("Error running service in Service Control mode.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
runService("DoorTray", true)
|
||||
}
|
||||
27
configs/hass_tray.service
Normal file
@@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=A description
|
||||
ConditionPathExists=/home/ubuntu/work/src/door_tray/door_tray
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=door_tray
|
||||
Group=door_tray
|
||||
LimitNOFILE=1024
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
startLimitIntervalSec=60
|
||||
|
||||
WorkingDirectory=/home/ubuntu/work/src/door_tray
|
||||
ExecStart=/home/ubuntu/work/src/door_tray/door_tray --name=foo
|
||||
|
||||
# make sure log directory exists and owned by syslog
|
||||
PermissionsStartOnly=true
|
||||
ExecStartPre=/bin/mkdir -p /var/log/door_tray
|
||||
ExecStartPre=/bin/chown syslog:adm /var/log/door_tray
|
||||
ExecStartPre=/bin/chmod 755 /var/log/door_tray
|
||||
SyslogIdentifier=door_tray
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
20
go.mod
@@ -1,7 +1,21 @@
|
||||
module xevion.dev/hass-tray
|
||||
module xevion.dev/door-tray
|
||||
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
golang.org/x/sys v0.1.0
|
||||
internal v1.0.0
|
||||
)
|
||||
|
||||
replace internal => ./internal/
|
||||
|
||||
require (
|
||||
github.com/getlantern/systray v1.2.2 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
saml.dev/gome-assistant v0.2.3 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect
|
||||
@@ -9,17 +23,13 @@ require (
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect
|
||||
github.com/getlantern/systray v1.2.2 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/gobuffalo/envy v1.10.2 // indirect
|
||||
github.com/gobuffalo/packd v1.0.2 // indirect
|
||||
github.com/gobuffalo/packr v1.30.1 // indirect
|
||||
github.com/golang-module/carbon v1.7.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/nathan-osman/go-sunrise v1.1.0 // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
saml.dev/gome-assistant v0.2.3 // indirect
|
||||
)
|
||||
|
||||
8
go.sum
@@ -5,6 +5,7 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
|
||||
@@ -40,7 +41,6 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
@@ -61,6 +61,7 @@ github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgF
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
@@ -83,6 +84,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -100,6 +103,8 @@ golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -107,6 +112,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
saml.dev/gome-assistant v0.2.3 h1:WuT0yMuUjyM78eHYjry/mbhMypSZ7GKmc4vr+Y4YOQ4=
|
||||
saml.dev/gome-assistant v0.2.3/go.mod h1:NAj56yKBq4PXmHIdrn9oeTmM5SHaNYoLfSWpzTpKjXY=
|
||||
|
||||
5
go.work.sum
Normal file
@@ -0,0 +1,5 @@
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
190
internal/app.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/getlantern/systray"
|
||||
dotenv "github.com/joho/godotenv"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
ga "saml.dev/gome-assistant"
|
||||
)
|
||||
|
||||
var ()
|
||||
|
||||
type TrayApp struct {
|
||||
doorIdentifier string
|
||||
log *slog.Logger
|
||||
stateChannel chan string
|
||||
app *ga.App
|
||||
service *ga.Service
|
||||
}
|
||||
|
||||
// Status will return the operational status of the service
|
||||
func (ta *TrayApp) Status() Status {
|
||||
return StatusUnknown
|
||||
}
|
||||
|
||||
func (ta *TrayApp) State() string {
|
||||
// TODO: Implement this method
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ta *TrayApp) Connected() bool {
|
||||
// TODO: Implement this method
|
||||
return false
|
||||
}
|
||||
|
||||
func (ta *TrayApp) Reload() error {
|
||||
// TODO: Implement this method
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ta *TrayApp) Pause() error {
|
||||
// TODO: Implement this method
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ta *TrayApp) Resume() error {
|
||||
// TODO: Implement this method
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewApp() *TrayApp {
|
||||
// Connect to Home Assistant
|
||||
app, err := ga.NewApp(ga.NewAppRequest{
|
||||
IpAddress: "home.imfucked.lol", // Replace with your Home Assistant IP Address
|
||||
HAAuthToken: os.Getenv("HA_AUTH_TOKEN"),
|
||||
HomeZoneEntityId: "zone.home",
|
||||
Port: "443",
|
||||
Secure: true,
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("Error connecting to Home Assistant", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
service := app.GetService()
|
||||
|
||||
return &TrayApp{
|
||||
app: app,
|
||||
service: service,
|
||||
stateChannel: make(chan string),
|
||||
doorIdentifier: "binary_sensor.bedroom_door_opening",
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed "resources/*.ico"
|
||||
icons embed.FS
|
||||
)
|
||||
|
||||
func (ta *TrayApp) HandleState(newState string) {
|
||||
switch newState {
|
||||
case "on":
|
||||
ta.stateChannel <- "open"
|
||||
case "off":
|
||||
ta.stateChannel <- "closed"
|
||||
default:
|
||||
slog.Error("unknown state encountered", "newState", newState)
|
||||
ta.stateChannel <- "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func (ta *TrayApp) setupHomeAssistant() {
|
||||
var err error
|
||||
|
||||
// Get the initial state
|
||||
state, err := ta.app.GetState().Get(ta.doorIdentifier)
|
||||
if err != nil {
|
||||
slog.Error("Unable to get initial state", "error", err)
|
||||
} else {
|
||||
slog.Debug("Initial State Received")
|
||||
ta.HandleState(state.State)
|
||||
}
|
||||
|
||||
ta.app.RegisterEntityListeners(ga.
|
||||
NewEntityListener().
|
||||
EntityIds(ta.doorIdentifier).
|
||||
Call(func(service *ga.Service, state ga.State, sensor ga.EntityData) {
|
||||
slog.Debug("Event Received", "identifier", ta.doorIdentifier, "sensor", sensor)
|
||||
ta.HandleState(sensor.ToState)
|
||||
}).
|
||||
Build())
|
||||
|
||||
ta.app.Start()
|
||||
|
||||
slog.Warn("Home Assistant thread died")
|
||||
ta.stateChannel <- "unknown"
|
||||
}
|
||||
|
||||
func (ta *TrayApp) Start() {
|
||||
dotenv.Load()
|
||||
|
||||
slog.SetDefault(slog.New(slog.NewJSONHandler(
|
||||
os.Stdout,
|
||||
&slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
},
|
||||
)))
|
||||
// binfo, err := buildinfo.
|
||||
slog.Info("Startup", "runtime", runtime.Version(), "os", runtime.GOOS, "arch", runtime.GOARCH, "pid", os.Getpid())
|
||||
|
||||
go ta.setupHomeAssistant()
|
||||
systray.Run(ta.onReady, func() {})
|
||||
}
|
||||
|
||||
func (ta *TrayApp) onReady() {
|
||||
systray.SetTitle("door-tray")
|
||||
systray.SetTooltip("Setting up...")
|
||||
menuQuit := systray.AddMenuItem("Quit", "Stops the application")
|
||||
menuOpenLogs := systray.AddMenuItem("Open Logs", "Opens the logs in the default editor")
|
||||
menuOpenLogs.Disable()
|
||||
|
||||
// Load icons
|
||||
systray.SetIcon(getIcon("unknown"))
|
||||
|
||||
// Handle Ctrl+C interrupt
|
||||
interruptChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(interruptChannel, os.Interrupt)
|
||||
signal.Notify(interruptChannel, os.Kill)
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case signal := <-interruptChannel:
|
||||
slog.Info("Received interrupt signal, quitting", "signal", signal)
|
||||
break loop
|
||||
case <-menuQuit.ClickedCh:
|
||||
slog.Info("Quit clicked")
|
||||
break loop
|
||||
case <-menuOpenLogs.ClickedCh:
|
||||
slog.Info("Open Logs clicked")
|
||||
case newState := <-ta.stateChannel:
|
||||
timeString := time.Now().Format("3:04 PM")
|
||||
if newState != "unknown" {
|
||||
systray.SetTooltip(fmt.Sprintf("%s as of %s", cases.Title(language.AmericanEnglish, cases.NoLower).String(newState), timeString))
|
||||
switch newState {
|
||||
case "open":
|
||||
systray.SetIcon(getIcon("open_fault"))
|
||||
case "closed":
|
||||
systray.SetIcon(getIcon("closed"))
|
||||
}
|
||||
} else {
|
||||
slog.Warn("Unknown state", "state", newState)
|
||||
systray.SetTooltip(fmt.Sprintf("Unknown as of %s", timeString))
|
||||
systray.SetIcon(getIcon("unknown"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Cleaning up")
|
||||
systray.Quit()
|
||||
ta.app.Cleanup()
|
||||
}
|
||||
16
internal/config.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
)
|
||||
|
||||
func getIcon(icon string) []byte {
|
||||
iconBytes, err := icons.ReadFile(fmt.Sprintf("resources/%s.ico", icon))
|
||||
if err != nil {
|
||||
slog.Error("Unable to load icon", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return iconBytes
|
||||
}
|
||||
26
internal/go.mod
Normal file
@@ -0,0 +1,26 @@
|
||||
module internal
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect
|
||||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect
|
||||
github.com/getlantern/systray v1.2.2 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/gobuffalo/envy v1.10.2 // indirect
|
||||
github.com/gobuffalo/packd v1.0.2 // indirect
|
||||
github.com/gobuffalo/packr v1.30.1 // indirect
|
||||
github.com/golang-module/carbon v1.7.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/nathan-osman/go-sunrise v1.1.0 // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
saml.dev/gome-assistant v0.2.3 // indirect
|
||||
)
|
||||
113
internal/go.sum
Normal file
@@ -0,0 +1,113 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
|
||||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So=
|
||||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
|
||||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk=
|
||||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
|
||||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
|
||||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
|
||||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||
github.com/getlantern/systray v1.2.2 h1:dCEHtfmvkJG7HZ8lS/sLklTH4RKUcIsKrAD9sThoEBE=
|
||||
github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgNMY5HvhHhcE=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4=
|
||||
github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8=
|
||||
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
|
||||
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
|
||||
github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw=
|
||||
github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8=
|
||||
github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
|
||||
github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
|
||||
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
|
||||
github.com/golang-module/carbon v1.7.1 h1:EDPV0YjxeS2kE2cRedfGgDikU6l5D79HB/teHuZDLu8=
|
||||
github.com/golang-module/carbon v1.7.1/go.mod h1:M/TDTYPp3qWtW68u49dLDJOyGmls6L6BXdo/pyvkMaU=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/nathan-osman/go-sunrise v1.1.0 h1:ZqZmtmtzs8Os/DGQYi0YMHpuUqR/iRoJK+wDO0wTCw8=
|
||||
github.com/nathan-osman/go-sunrise v1.1.0/go.mod h1:RcWqhT+5ShCZDev79GuWLayetpJp78RSjSWxiDowmlM=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
saml.dev/gome-assistant v0.2.3 h1:WuT0yMuUjyM78eHYjry/mbhMypSZ7GKmc4vr+Y4YOQ4=
|
||||
saml.dev/gome-assistant v0.2.3/go.mod h1:NAj56yKBq4PXmHIdrn9oeTmM5SHaNYoLfSWpzTpKjXY=
|
||||
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
BIN
internal/resources/error.ico
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
BIN
internal/resources/open_fault.ico
Normal file
|
After Width: | Height: | Size: 340 B |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
19
internal/types.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package internal
|
||||
|
||||
type Status int
|
||||
|
||||
const (
|
||||
StatusUnknown Status = iota
|
||||
StatusRunning
|
||||
StatusStopped
|
||||
StatusError
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
Status() Status
|
||||
State() string
|
||||
Connected() bool
|
||||
Reload() error
|
||||
Pause() error
|
||||
Resume() error
|
||||
}
|
||||
14
internal/utility.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package internal
|
||||
|
||||
import "runtime/debug"
|
||||
|
||||
var Commit = func() string {
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
for _, setting := range info.Settings {
|
||||
if setting.Key == "vcs.revision" {
|
||||
return setting.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}()
|
||||
150
main.go
@@ -1,150 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/getlantern/systray"
|
||||
dotenv "github.com/joho/godotenv"
|
||||
ga "saml.dev/gome-assistant"
|
||||
)
|
||||
|
||||
var (
|
||||
doorIdentifier = "binary_sensor.bedroom_door_opening"
|
||||
service *ga.Service
|
||||
log *slog.Logger
|
||||
stateChannel chan string
|
||||
app *ga.App
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed "resources/*.ico"
|
||||
icons embed.FS
|
||||
)
|
||||
|
||||
func HandleState(newState string) {
|
||||
switch newState {
|
||||
case "on":
|
||||
stateChannel <- "open"
|
||||
case "off":
|
||||
stateChannel <- "closed"
|
||||
default:
|
||||
slog.Error("unknown state encountered", "newState", newState)
|
||||
stateChannel <- "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func setupHomeAssistant() {
|
||||
var err error
|
||||
|
||||
// Connect to Home Assistant
|
||||
app, err = ga.NewApp(ga.NewAppRequest{
|
||||
IpAddress: "home.imfucked.lol", // Replace with your Home Assistant IP Address
|
||||
HAAuthToken: os.Getenv("HA_AUTH_TOKEN"),
|
||||
HomeZoneEntityId: "zone.home",
|
||||
Port: "443",
|
||||
Secure: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("Error connecting to Home Assistant", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
service = app.GetService()
|
||||
|
||||
// Get the initial state
|
||||
state, err := app.GetState().Get(doorIdentifier)
|
||||
if err != nil {
|
||||
slog.Error("Unable to get initial state", "error", err)
|
||||
} else {
|
||||
slog.Debug("Initial State Received")
|
||||
HandleState(state.State)
|
||||
}
|
||||
|
||||
app.RegisterEntityListeners(ga.
|
||||
NewEntityListener().
|
||||
EntityIds(doorIdentifier).
|
||||
Call(func(service *ga.Service, state ga.State, sensor ga.EntityData) {
|
||||
slog.Debug("Event Received", "identifier", doorIdentifier, "sensor", sensor)
|
||||
HandleState(sensor.ToState)
|
||||
}).
|
||||
Build())
|
||||
|
||||
app.Start()
|
||||
}
|
||||
|
||||
func main() {
|
||||
dotenv.Load()
|
||||
stateChannel = make(chan string)
|
||||
|
||||
slog.SetDefault(slog.New(slog.NewJSONHandler(
|
||||
os.Stdout,
|
||||
&slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
},
|
||||
)))
|
||||
slog.Info("Starting hass-tray")
|
||||
|
||||
go setupHomeAssistant()
|
||||
systray.Run(onReady, func() {})
|
||||
}
|
||||
|
||||
func onReady() {
|
||||
systray.SetTitle("hass-tray")
|
||||
systray.SetTooltip("Refreshed")
|
||||
menuQuit := systray.AddMenuItem("Quit", "Stops the application")
|
||||
menuOpenLogs := systray.AddMenuItem("Open Logs", "Opens the logs in the default editor")
|
||||
menuOpenLogs.Disable()
|
||||
|
||||
// Load icons
|
||||
openIcon, err := icons.ReadFile("resources/open.ico")
|
||||
if err != nil {
|
||||
slog.Error("Unable to load icon", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
closedIcon, err := icons.ReadFile("resources/closed.ico")
|
||||
if err != nil {
|
||||
slog.Error("Unable to load icon", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
unknownIcon, err := icons.ReadFile("resources/unknown.ico")
|
||||
if err != nil {
|
||||
slog.Error("Unable to load icon", "error", err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
slog.Debug("Icons loaded")
|
||||
}
|
||||
systray.SetIcon(unknownIcon)
|
||||
|
||||
// Handle Ctrl+C interrupt
|
||||
interruptChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(interruptChannel, os.Interrupt)
|
||||
signal.Notify(interruptChannel, os.Kill)
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case signal := <-interruptChannel:
|
||||
slog.Info("Received interrupt signal, quitting", "signal", signal)
|
||||
break loop
|
||||
case <-menuQuit.ClickedCh:
|
||||
slog.Info("Quit clicked")
|
||||
break loop
|
||||
case newState := <-stateChannel:
|
||||
if newState == "open" {
|
||||
systray.SetIcon(openIcon)
|
||||
} else if newState == "closed" {
|
||||
systray.SetIcon(closedIcon)
|
||||
} else {
|
||||
slog.Warn("Unknown state", "state", newState)
|
||||
systray.SetIcon(unknownIcon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Cleaning up")
|
||||
systray.Quit()
|
||||
app.Cleanup()
|
||||
}
|
||||
|
Before Width: | Height: | Size: 15 KiB |