Compare commits
5 Commits
ee6dfc9ac6
...
master
Author | SHA1 | Date | |
---|---|---|---|
8d676a2167
|
|||
c89bcb4d68
|
|||
323cef6e35 | |||
22fcfcdba9 | |||
afa4e48757 |
28
README.md
28
README.md
@@ -3,13 +3,32 @@ My custom event handler for battery related things. Here's a brief rundown of
|
|||||||
all the features:
|
all the features:
|
||||||
|
|
||||||
When the percentage gets below a specified percentage it will blink the
|
When the percentage gets below a specified percentage it will blink the
|
||||||
specified led at any rate defined by the config file.
|
specified led at any rate defined by the config file. Example:
|
||||||
|

|
||||||
|
|
||||||
If the system is plugged in and a wayland session is running then the event
|
If the system is plugged in and a wayland session is running then the event
|
||||||
handler will place an idle inhibitor on the session to keep the computer from
|
handler will place an idle inhibitor on the session to keep the computer from
|
||||||
going to sleep. The inhibitor is removed when the system is unplugged.
|
going to sleep. The inhibitor is removed when the system is unplugged.
|
||||||
|
|
||||||
## Default Config
|
> [!WARNING]
|
||||||
|
> event-handler relies on [acpid](https://wiki.archlinux.org/title/Acpid) to
|
||||||
|
> monitor battery events ensure you have it installed and running before using
|
||||||
|
> event-handler
|
||||||
|
|
||||||
|
## Configuring
|
||||||
|
I built event-handler to be used as a service independent of my current user
|
||||||
|
and such event-handler does not read the configuration file from any default
|
||||||
|
path. Instead it's up to you to choose where it is and pass the file's full
|
||||||
|
path into event-handler like so:
|
||||||
|
```bash
|
||||||
|
eh -c ./config.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
The config is completely optional, however you will most likely need it as the
|
||||||
|
default is setup for my framework 13 system running Void Linux. Below are the
|
||||||
|
defaults:
|
||||||
|
|
||||||
|
### Default Config
|
||||||
```toml
|
```toml
|
||||||
[battery]
|
[battery]
|
||||||
status_path = "/sys/class/power_supply/BAT1"
|
status_path = "/sys/class/power_supply/BAT1"
|
||||||
@@ -25,3 +44,8 @@ timing_formula = "1.7 + 18.5 * exp(-0.29 * p)" # p is the percentage of the batt
|
|||||||
[acpi_daemon]
|
[acpi_daemon]
|
||||||
socket_path = "/run/acpid.socket"
|
socket_path = "/run/acpid.socket"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> The default formula may or may not work above 15 percent due to led
|
||||||
|
> shenanigans. If you wish to craft your own formula all relevant notation may
|
||||||
|
> be found in [this repo](https://github.com/codeplea/tinyexpr).
|
||||||
|
BIN
examples/blink.mp4
Normal file
BIN
examples/blink.mp4
Normal file
Binary file not shown.
@@ -3,6 +3,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -17,6 +18,11 @@ char
|
|||||||
/* open up the battery capacity for reading */
|
/* open up the battery capacity for reading */
|
||||||
d = concat(battery_status_path, "/capacity");
|
d = concat(battery_status_path, "/capacity");
|
||||||
f = fopen(d, "r");
|
f = fopen(d, "r");
|
||||||
|
if (!f) {
|
||||||
|
log_fatal("battery directory does not exist");
|
||||||
|
free(d);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
free(d);
|
free(d);
|
||||||
|
|
||||||
/* create enough space for the battery percentage */
|
/* create enough space for the battery percentage */
|
||||||
|
@@ -49,15 +49,12 @@ led_blink_timing_func(int percent)
|
|||||||
{
|
{
|
||||||
percentage = percent;
|
percentage = percent;
|
||||||
return te_eval(expr);
|
return te_eval(expr);
|
||||||
|
|
||||||
// return 1.7 + 18.5 * exp(-0.29 * percent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_eval(int sig)
|
free_eval(int sig)
|
||||||
{
|
{
|
||||||
te_free(expr);
|
te_free(expr);
|
||||||
exit(sig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -67,13 +64,13 @@ setup_led_formula(void)
|
|||||||
|
|
||||||
te_variable vars[] = { { "p", &percentage } };
|
te_variable vars[] = { { "p", &percentage } };
|
||||||
expr = te_compile(led_blink_timing_formula, vars, 1, &err);
|
expr = te_compile(led_blink_timing_formula, vars, 1, &err);
|
||||||
signal(SIGINT, free_eval);
|
|
||||||
if (!expr) {
|
if (!expr) {
|
||||||
log_fatal("%s", led_blink_timing_formula);
|
log_fatal("%s", led_blink_timing_formula);
|
||||||
log_fatal("%*s^ Error near here", err - 1, "");
|
log_fatal("%*s^ Error near here", err - 1, "");
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
signal(SIGINT, free_eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -86,6 +83,7 @@ parse_config_file(char *path)
|
|||||||
f = fopen(path, "r");
|
f = fopen(path, "r");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
log_fatal("Failed to open config file: %s", path);
|
log_fatal("Failed to open config file: %s", path);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
config = toml_parse_file(f, errbuf, sizeof(errbuf));
|
config = toml_parse_file(f, errbuf, sizeof(errbuf));
|
||||||
@@ -106,4 +104,6 @@ parse_config_file(char *path)
|
|||||||
set_int_conf(led_blink_trigger_level, led_blink, "power_source");
|
set_int_conf(led_blink_trigger_level, led_blink, "power_source");
|
||||||
set_str_conf(led_blink_timing_formula, led_blink, "timing_formula");
|
set_str_conf(led_blink_timing_formula, led_blink, "timing_formula");
|
||||||
set_str_conf(acpi_daemon_socket_path, acpi_daemon, "socket_path");
|
set_str_conf(acpi_daemon_socket_path, acpi_daemon, "socket_path");
|
||||||
|
|
||||||
|
toml_free(config);
|
||||||
}
|
}
|
||||||
|
10
src/led.c
10
src/led.c
@@ -6,6 +6,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
@@ -114,8 +115,6 @@ pre_exit(int signal)
|
|||||||
fclose(data->pfile);
|
fclose(data->pfile);
|
||||||
free(data->file_name);
|
free(data->file_name);
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -124,6 +123,13 @@ led_create_thread(char *file)
|
|||||||
int err;
|
int err;
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
static bool running;
|
static bool running;
|
||||||
|
struct stat s;
|
||||||
|
|
||||||
|
/* ensure that file exists */
|
||||||
|
err = stat(file, &s);
|
||||||
|
if (err < 0 || !S_ISREG(s.st_mode)) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* make sure the led thread cannot be created twice */
|
/* make sure the led thread cannot be created twice */
|
||||||
if (running) {
|
if (running) {
|
||||||
|
37
src/main.c
37
src/main.c
@@ -23,7 +23,13 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#define MAX_BUFLEN 1024
|
#define MAX_BUFLEN 1024
|
||||||
|
#define wrap(ok, func) do { \
|
||||||
|
if (ok) { \
|
||||||
|
func; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
bool led_ok, wayland_ok;
|
||||||
static struct cag_option options[] = {
|
static struct cag_option options[] = {
|
||||||
{
|
{
|
||||||
.identifier = 'c',
|
.identifier = 'c',
|
||||||
@@ -51,6 +57,7 @@ on_battery_event(char *percent, bool plugged)
|
|||||||
/* convert battery percentage to an int */
|
/* convert battery percentage to an int */
|
||||||
res = strtol(percent, &ep, 10);
|
res = strtol(percent, &ep, 10);
|
||||||
|
|
||||||
|
wrap(led_ok,
|
||||||
if (res <= led_blink_trigger_level) {
|
if (res <= led_blink_trigger_level) {
|
||||||
rate = led_blink_timing_func(res);
|
rate = led_blink_timing_func(res);
|
||||||
if (rate >= 1) {
|
if (rate >= 1) {
|
||||||
@@ -59,11 +66,12 @@ on_battery_event(char *percent, bool plugged)
|
|||||||
} else {
|
} else {
|
||||||
led_set_rate(0);
|
led_set_rate(0);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
wayland_set_idle_lock(false);
|
wrap(wayland_ok, wayland_set_idle_lock(false));
|
||||||
} else {
|
} else {
|
||||||
led_set_rate(0);
|
wrap(led_ok, led_set_rate(0));
|
||||||
wayland_set_idle_lock(true);
|
wrap(wayland_ok, wayland_set_idle_lock(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
free(percent);
|
free(percent);
|
||||||
@@ -74,9 +82,12 @@ main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
cag_option_context context;
|
cag_option_context context;
|
||||||
bool plugged = plugged_in(battery_power_source);
|
bool plugged = plugged_in(battery_power_source);
|
||||||
char buffer[MAX_BUFLEN], *out[4], *config_path;
|
char buffer[MAX_BUFLEN], *out[4], *config_path, *percent;
|
||||||
int sock_fd;
|
int sock_fd;
|
||||||
|
|
||||||
|
/* defaults to working */
|
||||||
|
led_ok = wayland_ok = true;
|
||||||
|
|
||||||
cag_option_init(&context, options, CAG_ARRAY_SIZE(options), argc, argv);
|
cag_option_init(&context, options, CAG_ARRAY_SIZE(options), argc, argv);
|
||||||
while (cag_option_fetch(&context)) {
|
while (cag_option_fetch(&context)) {
|
||||||
switch (cag_option_get_identifier(&context)) {
|
switch (cag_option_get_identifier(&context)) {
|
||||||
@@ -104,15 +115,22 @@ main(int argc, char *argv[])
|
|||||||
sock_fd = acpi_create_socket(acpi_daemon_socket_path);
|
sock_fd = acpi_create_socket(acpi_daemon_socket_path);
|
||||||
|
|
||||||
/* create the led thread */
|
/* create the led thread */
|
||||||
led_create_thread(led_brightness_path);
|
if (led_create_thread(led_brightness_path)) {
|
||||||
|
led_ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* create the wayland thread */
|
/* create the wayland thread */
|
||||||
wayland_create_thread();
|
if (wayland_create_thread()) {
|
||||||
|
wayland_ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* run events that need to be run on start to ensure that the current state
|
/* run events that need to be run on start to ensure that the current state
|
||||||
* inside the program reflects that that is outside the program
|
* inside the program reflects that that is outside the program
|
||||||
*/
|
*/
|
||||||
on_battery_event(battery_percent(), plugged);
|
percent = battery_percent();
|
||||||
|
if (percent == NULL) {
|
||||||
|
on_battery_event(percent, plugged);
|
||||||
|
}
|
||||||
|
|
||||||
/* zero buffer */
|
/* zero buffer */
|
||||||
memset(out, 0, sizeof(out));
|
memset(out, 0, sizeof(out));
|
||||||
@@ -145,7 +163,10 @@ main(int argc, char *argv[])
|
|||||||
if (strcmp(s, "PNP") == 0) {
|
if (strcmp(s, "PNP") == 0) {
|
||||||
if (strcmp(out[2], "00000080") == 0) {
|
if (strcmp(out[2], "00000080") == 0) {
|
||||||
if (strcmp(out[3], "00000001") == 0) {
|
if (strcmp(out[3], "00000001") == 0) {
|
||||||
on_battery_event(battery_percent(), plugged);
|
percent = battery_percent();
|
||||||
|
if (percent == NULL) {
|
||||||
|
on_battery_event(percent, plugged);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -118,16 +118,12 @@ pre_exit(int signal)
|
|||||||
|
|
||||||
zwp_idle_inhibit_manager_v1_destroy(data->inhibitmanager);
|
zwp_idle_inhibit_manager_v1_destroy(data->inhibitmanager);
|
||||||
wl_registry_destroy(data->registry);
|
wl_registry_destroy(data->registry);
|
||||||
|
// wl_display_destroy(data->display);
|
||||||
wl_compositor_destroy(data->compositor);
|
wl_compositor_destroy(data->compositor);
|
||||||
wl_surface_destroy(data->surface);
|
wl_surface_destroy(data->surface);
|
||||||
/* TODO: this causes a segfault
|
|
||||||
wl_display_destroy(data->display);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* make sure to cleanup the allocated data */
|
/* make sure to cleanup the allocated data */
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
Reference in New Issue
Block a user