mirror of
https://github.com/NotAShelf/batmon.git
synced 2024-11-22 21:31:08 +00:00
commit
2b94d2eda1
21 changed files with 437 additions and 552 deletions
22
.gitignore
vendored
22
.gitignore
vendored
|
@ -1 +1,21 @@
|
||||||
/target
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
||||||
|
|
||||||
|
# Go workspace file
|
||||||
|
go.work
|
||||||
|
|
||||||
|
# Config file
|
||||||
|
config.json
|
||||||
|
|
351
Cargo.lock
generated
351
Cargo.lock
generated
|
@ -1,351 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "batmon"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"glob",
|
|
||||||
"notify",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-channel"
|
|
||||||
version = "0.5.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "filetime"
|
|
||||||
version = "0.2.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fsevent-sys"
|
|
||||||
version = "4.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glob"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inotify"
|
|
||||||
version = "0.9.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"inotify-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inotify-sys"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kqueue"
|
|
||||||
version = "1.0.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
|
|
||||||
dependencies = [
|
|
||||||
"kqueue-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kqueue-sys"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.152"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mio"
|
|
||||||
version = "0.8.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"wasi",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "notify"
|
|
||||||
version = "6.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.1",
|
|
||||||
"crossbeam-channel",
|
|
||||||
"filetime",
|
|
||||||
"fsevent-sys",
|
|
||||||
"inotify",
|
|
||||||
"kqueue",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"mio",
|
|
||||||
"walkdir",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_syscall"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "same-file"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "walkdir"
|
|
||||||
version = "2.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
|
||||||
dependencies = [
|
|
||||||
"same-file",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.48.5",
|
|
||||||
"windows_aarch64_msvc 0.48.5",
|
|
||||||
"windows_i686_gnu 0.48.5",
|
|
||||||
"windows_i686_msvc 0.48.5",
|
|
||||||
"windows_x86_64_gnu 0.48.5",
|
|
||||||
"windows_x86_64_gnullvm 0.48.5",
|
|
||||||
"windows_x86_64_msvc 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.52.0",
|
|
||||||
"windows_aarch64_msvc 0.52.0",
|
|
||||||
"windows_i686_gnu 0.52.0",
|
|
||||||
"windows_i686_msvc 0.52.0",
|
|
||||||
"windows_x86_64_gnu 0.52.0",
|
|
||||||
"windows_x86_64_gnullvm 0.52.0",
|
|
||||||
"windows_x86_64_msvc 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "batmon"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
notify = "6.1"
|
|
||||||
glob = "0.3"
|
|
70
README.md
Normal file
70
README.md
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# 🔋 Batmon
|
||||||
|
|
||||||
|
> **Batmon** is a dead-simple battery monitor for Linux written in Go. It
|
||||||
|
> provides real-time monitoring of battery status and adjusts the power profile
|
||||||
|
> accordingly to optimize battery life.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Real-time monitoring of battery status
|
||||||
|
- Adjustment of power profile based on battery status
|
||||||
|
- Support for custom commands and extra commands
|
||||||
|
- Configuration via a JSON file
|
||||||
|
- Not written in Rust (the codebase is _readable_)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Upower
|
||||||
|
- powerprofilesctl
|
||||||
|
- Nix or Go
|
||||||
|
|
||||||
|
### Nix
|
||||||
|
|
||||||
|
**Batmon** is primarily distributed through a Nix flake. You may install it
|
||||||
|
manually using `nix profile install github:NotAShelf/batmon`
|
||||||
|
|
||||||
|
### Manually
|
||||||
|
|
||||||
|
```console
|
||||||
|
go install . # this will install Batmon in your $GOPATH
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
To start using Batmon, use the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
batmon
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, Gomon will load the configuration from config.json in the current
|
||||||
|
directory. You can specify a different configuration file using the `--config`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
```console
|
||||||
|
gomon -c /path/to/config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
The configuration file should contain a list of batteries to monitor, along
|
||||||
|
with any custom commands or extra commands to execute. Here's an example of
|
||||||
|
a configuration file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"batPaths": [
|
||||||
|
{
|
||||||
|
"path": "/sys/class/power_supply/BAT0",
|
||||||
|
"command": "powerprofilesctl set performance",
|
||||||
|
"extraCommand": "echo 'Battery is charging' | wall"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- You can leave `command` empty to use the default behaviour - which will
|
||||||
|
switch active powerprofile using `powerprofiles set performance | balanced`
|
||||||
|
|
||||||
|
- `extraCommand`, if provided, will be executed in addition to the `command`
|
||||||
|
value.
|
4
TODO
4
TODO
|
@ -1,4 +0,0 @@
|
||||||
- nix integration
|
|
||||||
- unit tests
|
|
||||||
- use the battery crate
|
|
||||||
- rewrite in Go as soon as rust frustrates me enough
|
|
23
default.nix
23
default.nix
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
rustPlatform,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
pname = "batmon";
|
|
||||||
version = "unstable-2024-01-08";
|
|
||||||
in
|
|
||||||
rustPlatform.buildRustPackage {
|
|
||||||
inherit pname version;
|
|
||||||
|
|
||||||
src = lib.cleanSource ./.;
|
|
||||||
cargoHash = "sha256-d9wWr17BnlRwa3CLcfDeby60a2BPwpBy1xjY6oTgyG0=";
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "Nananananananana batmon";
|
|
||||||
homepage = "https://github.com/NotAShelf/batmon.git";
|
|
||||||
license = lib.licenses.gpl3Only;
|
|
||||||
maintainers = with lib.maintainers; [NotAShelf];
|
|
||||||
mainProgram = "batmon";
|
|
||||||
platforms = lib.platforms.linux;
|
|
||||||
};
|
|
||||||
}
|
|
8
example.config.json
Normal file
8
example.config.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"batPaths": [
|
||||||
|
{
|
||||||
|
"path": "/sys/class/power_supply/BAT0",
|
||||||
|
"extraCommand": "notify-send 'hello'"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
26
flake.lock
26
flake.lock
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1704796538,
|
|
||||||
"narHash": "sha256-uRMWOijfPGHzLXMqiYGoAitkq1beLfg2JAmGLdTjmvQ=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "792a7ddec9e0fe05aed934160eb75f1a821eb69b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
11
flake.nix
11
flake.nix
|
@ -1,8 +1,6 @@
|
||||||
{
|
{
|
||||||
description = "Batmon - battery monitor service";
|
description = "Batmon - battery monitor";
|
||||||
inputs = {
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs";
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
self,
|
self,
|
||||||
|
@ -13,11 +11,12 @@
|
||||||
pkgsForEach = nixpkgs.legacyPackages;
|
pkgsForEach = nixpkgs.legacyPackages;
|
||||||
in {
|
in {
|
||||||
packages = forEachSystem (system: {
|
packages = forEachSystem (system: {
|
||||||
default = pkgsForEach.${system}.callPackage ./default.nix {};
|
batmon = pkgsForEach.${system}.callPackage ./nix/package.nix {};
|
||||||
|
default = self.${system}.batmon;
|
||||||
});
|
});
|
||||||
|
|
||||||
devShells = forEachSystem (system: {
|
devShells = forEachSystem (system: {
|
||||||
default = pkgsForEach.${system}.callPackage ./shell.nix {};
|
default = pkgsForEach.${system}.callPackage ./nix/shell.nix {};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
29
go.mod
Normal file
29
go.mod
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
module gomon
|
||||||
|
|
||||||
|
go 1.21.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
|
github.com/spf13/cobra v1.8.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/spf13/viper v1.18.2 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
|
golang.org/x/sys v0.16.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
62
go.sum
Normal file
62
go.sum
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
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.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||||
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||||
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||||
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
|
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||||
|
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||||
|
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
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/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||||
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
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=
|
71
internal/battery/battery.go
Normal file
71
internal/battery/battery.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package battery
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gomon/internal/exec"
|
||||||
|
"gomon/internal/logger"
|
||||||
|
"gomon/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// battery monitor service
|
||||||
|
func Monitor(bat model.Battery, profiles ...string) error {
|
||||||
|
// wait a while if needed
|
||||||
|
startupWait := os.Getenv("STARTUP_WAIT")
|
||||||
|
if startupWait != "" {
|
||||||
|
duration, err := time.ParseDuration(startupWait)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Invalid STARTUP_WAIT duration")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the monitor loop
|
||||||
|
var prevProfile string
|
||||||
|
for {
|
||||||
|
// read the current state
|
||||||
|
batteryStatus, err := os.ReadFile(bat.Path + "/status")
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to read battery status")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
currentProfile := "performance"
|
||||||
|
if strings.TrimSpace(string(batteryStatus)) == "Discharging" {
|
||||||
|
currentProfile = "balanced"
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the new profile
|
||||||
|
if currentProfile != prevProfile {
|
||||||
|
logger.Info("Setting power profile to %s for battery %s", currentProfile, bat.Path)
|
||||||
|
var commandArgs []string
|
||||||
|
if bat.Command != "" {
|
||||||
|
commandArgs = strings.Split(bat.Command, " ")
|
||||||
|
} else {
|
||||||
|
commandArgs = []string{"powerprofilesctl", "set", currentProfile}
|
||||||
|
}
|
||||||
|
err = exec.ExecCommand(commandArgs[0], commandArgs[1:]...)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to execute command")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute the extra command
|
||||||
|
// if any
|
||||||
|
if bat.ExtraCommand != "" {
|
||||||
|
extraCommandArgs := strings.Split(bat.ExtraCommand, " ")
|
||||||
|
err = exec.ExecCommand(extraCommandArgs[0], extraCommandArgs[1:]...)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to execute extra command")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevProfile = currentProfile
|
||||||
|
|
||||||
|
// wait for the next power change event
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
29
internal/config/config.go
Normal file
29
internal/config/config.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"gomon/internal/logger"
|
||||||
|
"gomon/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Load loads the battery configuration from a file.
|
||||||
|
func Load(filename string) (model.BatteryConfig, error) {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to open file")
|
||||||
|
return model.BatteryConfig{}, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var config model.BatteryConfig
|
||||||
|
decoder := json.NewDecoder(file)
|
||||||
|
err = decoder.Decode(&config)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to decode JSON")
|
||||||
|
return model.BatteryConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
21
internal/exec/exec.go
Normal file
21
internal/exec/exec.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package exec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"gomon/internal/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// execute a command with args and returns its output
|
||||||
|
// this will be used primarily for executing external commands if configured
|
||||||
|
// or executing bash commands verbatim
|
||||||
|
func ExecCommand(name string, arg ...string) error {
|
||||||
|
cmd := exec.Command(name, arg...)
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to execute command")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
24
internal/logger/logger.go
Normal file
24
internal/logger/logger.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Log *logrus.Logger
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Log = logrus.New()
|
||||||
|
Log.SetFormatter(&logrus.JSONFormatter{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Info(format string, v ...interface{}) {
|
||||||
|
Log.Infof(format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(format string, v ...interface{}) {
|
||||||
|
Log.Errorf(format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatal(format string, v ...interface{}) {
|
||||||
|
Log.Fatalf(format, v...)
|
||||||
|
}
|
11
internal/model/model.go
Normal file
11
internal/model/model.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
type Battery struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Command string `json:"command"`
|
||||||
|
ExtraCommand string `json:"extraCommand"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatteryConfig struct {
|
||||||
|
BatPaths []Battery `json:"batPaths"`
|
||||||
|
}
|
60
main.go
Normal file
60
main.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"gomon/internal/battery"
|
||||||
|
"gomon/internal/config"
|
||||||
|
"gomon/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "gomon",
|
||||||
|
Short: "TODO",
|
||||||
|
Long: `TODO`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
// load the battery configuration
|
||||||
|
config, err := config.Load(viper.GetString("config"))
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Fatal("Failed to load configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a WaitGroup to wait for all goroutines to finish
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(len(config.BatPaths))
|
||||||
|
|
||||||
|
// start a goroutine for each battery
|
||||||
|
for _, bat := range config.BatPaths {
|
||||||
|
go func(bat model.Battery) {
|
||||||
|
defer wg.Done()
|
||||||
|
err := battery.Monitor(bat)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
"battery": bat.Path,
|
||||||
|
}).Error("Failed to monitor battery")
|
||||||
|
}
|
||||||
|
}(bat)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for all goroutines to finish
|
||||||
|
wg.Wait()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCmd.PersistentFlags().StringP("config", "c", "config.json", "Path to the configuration file")
|
||||||
|
viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
|
||||||
|
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Fatal("Failed to execute root command")
|
||||||
|
}
|
||||||
|
}
|
11
nix/package.nix
Normal file
11
nix/package.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{buildGoModule}:
|
||||||
|
buildGoModule {
|
||||||
|
pname = "sample-go";
|
||||||
|
version = "0.0.1";
|
||||||
|
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
vendorHash = null;
|
||||||
|
|
||||||
|
ldflags = ["-s" "-w"];
|
||||||
|
}
|
15
nix/shell.nix
Normal file
15
nix/shell.nix
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
callPackage,
|
||||||
|
gopls,
|
||||||
|
go,
|
||||||
|
}: let
|
||||||
|
mainPkg = callPackage ./default.nix {};
|
||||||
|
in
|
||||||
|
mainPkg.overrideAttrs (oa: {
|
||||||
|
nativeBuildInputs =
|
||||||
|
(oa.nativeBuildInputs or [])
|
||||||
|
++ [
|
||||||
|
gopls
|
||||||
|
go
|
||||||
|
];
|
||||||
|
})
|
20
shell.nix
20
shell.nix
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
callPackage,
|
|
||||||
rust-analyzer,
|
|
||||||
rustfmt,
|
|
||||||
clippy,
|
|
||||||
cargo,
|
|
||||||
}: let
|
|
||||||
mainPkg = callPackage ./default.nix {};
|
|
||||||
in
|
|
||||||
mainPkg.overrideAttrs (oa: {
|
|
||||||
nativeBuildInputs =
|
|
||||||
[
|
|
||||||
# Additional rust tooling
|
|
||||||
rust-analyzer
|
|
||||||
rustfmt
|
|
||||||
clippy
|
|
||||||
cargo
|
|
||||||
]
|
|
||||||
++ (oa.nativeBuildInputs or []);
|
|
||||||
})
|
|
111
src/main.rs
111
src/main.rs
|
@ -1,111 +0,0 @@
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
use std::sync::mpsc::channel;
|
|
||||||
use std::process::Command;
|
|
||||||
use std::error::Error;
|
|
||||||
use notify::{RecommendedWatcher, RecursiveMode, Watcher, Config};
|
|
||||||
use glob::glob;
|
|
||||||
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
|
|
||||||
// check if the current user has read permissions for a given path
|
|
||||||
fn has_read_permission<P: AsRef<Path>>(path: P) -> Result<bool, Box<dyn Error>> {
|
|
||||||
let metadata = fs::metadata(path.as_ref())?;
|
|
||||||
let permissions = metadata.permissions();
|
|
||||||
let mode = permissions.mode();
|
|
||||||
Ok(mode & 0o444 != 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
println!("Starting the battery monitor...");
|
|
||||||
|
|
||||||
let bat_base_paths = glob("/sys/class/power_supply/BAT*")?.filter_map(Result::ok);
|
|
||||||
|
|
||||||
let mut bat_status_path = String::new();
|
|
||||||
let mut bat_capacity_path = String::new();
|
|
||||||
|
|
||||||
for path in bat_base_paths {
|
|
||||||
println!("Found battery path: {:?}", path.display());
|
|
||||||
bat_status_path = format!("{}/status", path.display());
|
|
||||||
bat_capacity_path = format!("{}/capacity", path.display());
|
|
||||||
// break after finding the first match.
|
|
||||||
// FIXME: this is assuming there's only one battery, account for multiple?
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if bat_status_path.is_empty() || bat_capacity_path.is_empty() {
|
|
||||||
return Err("Battery path not found".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we have read permissions for the battery status and capacity paths
|
|
||||||
// TODO: I'm pretty sure there's a better and faster way to do this
|
|
||||||
if !has_read_permission(&bat_status_path)? {
|
|
||||||
println!("No read permission for the battery status path");
|
|
||||||
return Err("Permission denied".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has_read_permission(&bat_capacity_path)? {
|
|
||||||
println!("No read permission for the battery capacity path");
|
|
||||||
return Err("Permission denied".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Battery status path: {}", bat_status_path);
|
|
||||||
println!("Battery capacity path: {}", bat_capacity_path);
|
|
||||||
|
|
||||||
let ac_profile = "performance";
|
|
||||||
let bat_profile = "balanced";
|
|
||||||
|
|
||||||
if let Ok(wait_time_str) = std::env::var("STARTUP_WAIT") {
|
|
||||||
println!("STARTUP_WAIT is set, waiting for {} seconds", wait_time_str);
|
|
||||||
if let Ok(wait_time) = wait_time_str.parse::<u64>() {
|
|
||||||
thread::sleep(Duration::from_secs(wait_time));
|
|
||||||
} else {
|
|
||||||
println!("Invalid STARTUP_WAIT value: {}", wait_time_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut prev_profile = String::new();
|
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
let mut watcher = RecommendedWatcher::new(tx, Config::default())?;
|
|
||||||
|
|
||||||
println!("Watching battery status and capacity paths for changes...");
|
|
||||||
watcher.watch(Path::new(&bat_status_path), RecursiveMode::NonRecursive)?;
|
|
||||||
watcher.watch(Path::new(&bat_capacity_path), RecursiveMode::NonRecursive)?;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match rx.recv() {
|
|
||||||
Ok(_) => {
|
|
||||||
println!("Change detected in battery status or capacity.");
|
|
||||||
let current_status = fs::read_to_string(&bat_status_path)?.trim().to_string();
|
|
||||||
println!("Current battery status: {}", current_status);
|
|
||||||
|
|
||||||
let profile = if current_status == "Discharging" {
|
|
||||||
bat_profile
|
|
||||||
} else {
|
|
||||||
ac_profile
|
|
||||||
};
|
|
||||||
|
|
||||||
if prev_profile != profile {
|
|
||||||
println!("Setting power profile to {}", profile);
|
|
||||||
let output = Command::new("powerprofilesctl")
|
|
||||||
.arg("set")
|
|
||||||
.arg(profile)
|
|
||||||
.output()?;
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
println!("Failed to set power profile: {}", stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prev_profile = profile.to_string();
|
|
||||||
},
|
|
||||||
Err(e) => println!("Watch error: {:?}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue