package core import ( "time" "github.com/BurntSushi/xgb/screensaver" "github.com/BurntSushi/xgb/xproto" "github.com/brutella/hc/accessory" "github.com/brutella/hc/log" "github.com/brutella/hc/service" "github.com/bwdezend/occupancyd/internal/telemetry" "github.com/BurntSushi/xgb" "github.com/BurntSushi/xgb/dpms" ) //CheckOccupied checks for x11 idle time func CheckOccupied(X *xgb.Conn, idleTimerDuration uint32, enableMetrics bool) bool { screensaver.Init(X) root := xproto.Setup(X).DefaultScreen(X).Root info, err := screensaver.QueryInfo(X, xproto.Drawable(root)).Reply() if err != nil { log.Info.Println(err) panic(err) } //log.Info.Println(info.MsSinceUserInput) if enableMetrics == true { telemetry.IdleTime.Set(float64(info.MsSinceUserInput / 1000)) } if info.MsSinceUserInput < (idleTimerDuration * 1000) { return true } return false } //UpdateOccupiedStatus sets occupied status func UpdateOccupiedStatus(sensor service.OccupancySensor, idleTimerDuration uint32, sleepInterval int, enableMetrics bool) { X, err := xgb.NewConn() if err != nil { log.Info.Println(err) panic(err) } occupancyState := CheckOccupied(X, idleTimerDuration, enableMetrics) if occupancyState == true { sensor.OccupancyDetected.Int.SetValue(1) } else { sensor.OccupancyDetected.Int.SetValue(0) } for { occupied := CheckOccupied(X, idleTimerDuration, enableMetrics) if occupied != occupancyState { telemetry.OccupancyActivations.Inc() log.Info.Println("Setting occupancy to", occupied) occupancyState = occupied } if occupied == true { sensor.OccupancyDetected.Int.SetValue(1) } else { sensor.OccupancyDetected.Int.SetValue(0) } time.Sleep(time.Second * time.Duration(sleepInterval)) } } //UpdateScreenStatus updates HomeKit Lightbulb screen status func UpdateScreenStatus(screen accessory.Lightbulb, sleepInterval int) error { X, err := xgb.NewConn() if err != nil { return err } screenState := CheckScreen(X) log.Info.Println("UpdateScreenStatus setting screen.Lightbulb.On.SetValue to", screenState) if screenState == true { screen.Lightbulb.On.SetValue(true) } else { screen.Lightbulb.On.SetValue(false) } for { powered := CheckScreen(X) if powered != screenState { log.Info.Println("Setting screen to", powered) screenState = powered if powered == true { screen.Lightbulb.On.SetValue(true) } else { screen.Lightbulb.On.SetValue(false) } } time.Sleep(time.Second * time.Duration(sleepInterval)) } } //CheckScreen looks up the current state of DPMS func CheckScreen(X *xgb.Conn) bool { dpms.Init(X) info, err := dpms.Info(X).Reply() if err != nil { log.Info.Println("ERROR:", err) } return info.State } //SetScreenPower toggles dpms states func SetScreenPower(powerState bool) bool { telemetry.LightbulbActivations.Inc() X, err := xgb.NewConn() if err != nil { log.Info.Println(err) } dpms.Init(X) var state uint16 state = 0 if powerState == false { state = 3 } dpms.ForceLevel(X, state) return true }