initial work for handling battery power detection + pausing

This commit is contained in:
cryptonote-social 2020-07-24 13:21:41 -07:00
parent 562af18129
commit 5de524a8a8
4 changed files with 98 additions and 21 deletions

View File

@ -18,7 +18,7 @@ func main() {
type GnomeScreenStater struct {
}
func (s GnomeScreenStater) GetScreenStateChannel() (chan bool, error) {
func (s GnomeScreenStater) GetScreenStateChannel() (chan csminer.ScreenState, error) {
bus, err := dbus.ConnectSessionBus()
if err != nil {
crylog.Fatal("dbus connection failed")
@ -34,7 +34,7 @@ func (s GnomeScreenStater) GetScreenStateChannel() (chan bool, error) {
dChan := make(chan *dbus.Message, 128)
bus.Eavesdrop(dChan)
ret := make(chan bool)
ret := make(chan csminer.ScreenState)
go func() {
defer bus.Close()
@ -47,11 +47,11 @@ func (s GnomeScreenStater) GetScreenStateChannel() (chan bool, error) {
str := fmt.Sprintf("%v", m.Body[0])
if str == "true" {
crylog.Info("Gnome screensaver turned on")
ret <- true
ret <- csminer.ScreenState(csminer.SCREEN_ACTIVE)
continue
} else if str == "false" {
crylog.Info("Gnome screensaver turned off")
ret <- false
ret <- csminer.ScreenState(csminer.SCREEN_IDLE)
continue
}
}

View File

@ -35,23 +35,34 @@ var (
lastStatsUpdateTime time.Time
screenIdle int32 // only mine when this is > 0
batteryPower int32
manualMinerToggle int32
SCREEN_IDLE_POKE client.MultiClientJob
SCREEN_ON_POKE client.MultiClientJob
PRINT_STATS_POKE client.MultiClientJob
ENTER_HIT_POKE client.MultiClientJob
SCREEN_IDLE_POKE client.MultiClientJob
SCREEN_ON_POKE client.MultiClientJob
BATTERY_POWER_POKE client.MultiClientJob
AC_POWER_POKE client.MultiClientJob
PRINT_STATS_POKE client.MultiClientJob
ENTER_HIT_POKE client.MultiClientJob
)
const (
HANDLED = 1
USE_CACHED = 2
// Valid screen states
SCREEN_IDLE = 0
SCREEN_ACTIVE = 1
BATTERY_POWER = 2
AC_POWER = 3
)
type ScreenState int
type ScreenStater interface {
// Returns a channel that produces true when state changes from screen off to screen on,
// and false when it changes from on to off.
GetScreenStateChannel() (chan bool, error)
GetScreenStateChannel() (chan ScreenState, error)
}
func Mine(s ScreenStater, threads int, uname, rigid string, saver bool, excludeHrStart int, excludeHrEnd int, startDiff int, useTLS bool) error {
@ -65,6 +76,8 @@ func Mine(s ScreenStater, threads int, uname, rigid string, saver bool, excludeH
seed := []byte{}
screenIdle = 1
batteryPower = 0
manualMinerToggle = 0
if saver {
ch, err := s.GetScreenStateChannel()
@ -295,14 +308,21 @@ func startKeyboardScanning() {
}()
}
func monitorScreenSaver(ch chan bool) {
func monitorScreenSaver(ch chan ScreenState) {
for state := range ch {
if state {
switch state {
case SCREEN_IDLE:
crylog.Info("Screen off")
kickJobDispatcher(&SCREEN_IDLE_POKE)
} else {
case SCREEN_ACTIVE:
crylog.Info("Screen on")
kickJobDispatcher(&SCREEN_ON_POKE)
case BATTERY_POWER:
crylog.Info("Battery power")
kickJobDispatcher(&BATTERY_POWER_POKE)
case AC_POWER:
crylog.Info("AC power")
kickJobDispatcher(&AC_POWER_POKE)
}
}
}
@ -320,6 +340,9 @@ func kickJobDispatcher(job *client.MultiClientJob) bool {
}
func miningActive(excludeHrStart, excludeHrEnd int) bool {
if atomic.LoadInt32(&batteryPower) > 0 {
return false
}
if atomic.LoadInt32(&manualMinerToggle) > 0 {
// keyboard override to always mine no matter what
return true
@ -336,10 +359,16 @@ func miningActive(excludeHrStart, excludeHrEnd int) bool {
}
func getActivityMessage(excludeHrStart, excludeHrEnd, threads int) string {
battery := atomic.LoadInt32(&batteryPower) > 0
if battery {
return "PAUSED due to running on battery power"
}
saver := atomic.LoadInt32(&screenIdle) > 0
toggled := atomic.LoadInt32(&manualMinerToggle) > 0
onoff := ""
if timeExcluded(excludeHrStart, excludeHrEnd) {
if !toggled {
onoff = "PAUSED due to -exclude hour range. <enter> to mine anyway"
@ -360,7 +389,11 @@ func getActivityMessage(excludeHrStart, excludeHrEnd, threads int) string {
func handlePoke(wasMining bool, job *client.MultiClientJob, excludeHrStart, excludeHrEnd int) int {
var isMiningNow bool
if job == &SCREEN_ON_POKE {
if job == &BATTERY_POWER_POKE {
atomic.StoreInt32(&batteryPower, 1)
} else if job == &AC_POWER_POKE {
atomic.StoreInt32(&batteryPower, 0)
} else if job == &SCREEN_ON_POKE {
atomic.StoreInt32(&screenIdle, 0) // mark the screen as no longer idle
} else if job == &SCREEN_IDLE_POKE {
atomic.StoreInt32(&screenIdle, 1) // mark screen as idle

View File

@ -7,8 +7,8 @@ package main
import (
"context"
"github.com/cryptonote-social/csminer/crylog"
"github.com/cryptonote-social/csminer"
"github.com/cryptonote-social/csminer/crylog"
"os/exec"
"strings"
"time"
@ -20,15 +20,14 @@ type OSXScreenStater struct {
// The OSX implementation of the screen state notification channel is based on polling
// the state every 10 seconds. It would be better to figure out how to get notified
// of state changes when they happen.
func (s OSXScreenStater) GetScreenStateChannel() (chan bool, error) {
ret := make(chan bool)
func (s OSXScreenStater) GetScreenStateChannel() (chan csminer.ScreenState, error) {
ret := make(chan csminer.ScreenState)
go func() {
// We assume the screen is active when the miner is started. This may
// not hold if someone is running the miner from an auto-start script?
screenActive := true
batteryPower := false
for {
time.Sleep(time.Second * 10)
time.Sleep(time.Second * 5)
screenActiveNow, err := getScreenActiveState()
if err != nil {
crylog.Error("getScreenActiveState failed:", err)
@ -36,7 +35,25 @@ func (s OSXScreenStater) GetScreenStateChannel() (chan bool, error) {
}
if screenActiveNow != screenActive {
screenActive = screenActiveNow
ret <- !screenActive
if screenActive {
ret <- csminer.ScreenState(SCREEN_ACTIVE)
} else {
ret <- csminer.ScreenState(SCREEN_IDLE)
}
}
time.Sleep(time.Second * 5)
batteryPowerNow, err := getBatteryPowerState()
if err != nil {
crylog.Error("getBatteryPowerState failed:", err)
continue
}
if batteryPower != batteryPowerNow {
batteryPoser = batterPowerNow
if batteryPower {
ret <- csminer.ScreenState(BATTERY_POWER)
} else {
ret <- csminer.ScreenState(AC_POWER)
}
}
}
}()
@ -67,6 +84,29 @@ func getScreenActiveState() (bool, error) {
return true, nil
}
// getBatteryPowerState returns true if the machine is running on battery power.
// Current implementation invokes "pmset -g ps"
func getBatteryPowerState() (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
cmd := exec.CommandContext(
ctx,
"pmset",
"-g",
"ps",
)
b, err := cmd.CombinedOutput()
if err != nil {
crylog.Error("Error in cmd.CombinedOutput:", err)
return false, err
}
if strings.Contains(string(b), "Battery") {
return true, nil
}
return false, nil
}
func main() {
csminer.MultiMain(OSXScreenStater{})
}

View File

@ -13,7 +13,11 @@ import (
type WinScreenStater struct {
}
func (s WinScreenStater) GetScreenStateChannel() (chan bool, error) {
// We assume the screen is active when the miner is started. This may
// not hold if someone is running the miner from an auto-start script?
// TODO: On startup check if someone is logged in and if not assume screen
// is locked.
func GetScreenStateChannel() (chan bool, error) {
ret := make(chan bool)
chanMessages := make(chan session_notifications.Message, 100)