battery.c 3.08 KB
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#if defined(__FreeBSD__)
#include <sys/sysctl.h>
#endif

// maximum number of batteries supported
#define MAXBAT 2

// const char *icon[] = {  FIXME: sometimes do now show up on freebsd kitty
//     "\uf58d",                                         /* 0% */
//     "\uf579", "\uf57a", "\uf57b", "\uf57c", "\uf57d", /* 50% */
//     "\uf57e", "\uf57f", "\uf580", "\uf581", "\uf578", /* 100% */
// };

const char *icon[] = {
    "󰂎",                     /* 0% */
    "󰁺", "󰁻", "󰁼", "󰁽", "󰁾", /* 50% */
    "󰁿", "󰂀", "󰂁", "󰂂", "󰁹", /* 100% */
};
const char charging[] = "󰂄";
const char disconnected[] = "-";
const char unknown[] = "󰂑";

typedef enum {
  CHARGED = 0,
  DISCHARGING = 1,
  CHARGING = 2,
  DISCONNECTED = 7,
  UNKNOWN = -1
} State;

const char separator[] = "  "; // space between battery indicators

void battery_state(int *nbats, int bat[], State state[]) {
#if defined(__linux__)
  FILE *fd;
  int i;

  for (i = 0; i < MAXBAT; i++) {
    char filename[50], status[50];

    // get current capacity
    sprintf(filename, "/sys/class/power_supply/BAT%d/capacity", i);
    fd = fopen(filename, "rb");
    if (fd == NULL)
      break;
    fscanf(fd, "%d", &bat[i]);
    fclose(fd);
    // battery status (charging...)
    sprintf(filename, "/sys/class/power_supply/BAT%d/status", i);
    fd = fopen(filename, "rb");
    fgets(status, 50, fd);
    // puts(status);
    fclose(fd);
    if (!strcmp(status, "Not charging\n"))
      state[i] = CHARGED;
    else if (!strcmp(status, "Discharging\n"))
      state[i] = DISCHARGING;
    else if (!strcmp(status, "Charging\n"))
      state[i] = CHARGING;
    else
      state[i] = UNKNOWN;
  }
  *nbats = i;
#elif defined(__FreeBSD__)
  size_t len = sizeof(int);
  int status, life = 0;

  *nbats = 1; // FIXME: deal with multiple batteries

  if (sysctlbyname("hw.acpi.battery.state", &status, &len, NULL, 0) ||
      sysctlbyname("hw.acpi.battery.life", &life, &len, NULL, 0)) {
    state[0] = UNKNOWN;
    bat[0] = 0;
  } else {
    bat[0] = life;
    state[0] = status;
  }
#else
#error "Unsupported"
#endif
}

int main() {
  char *color;
  int life[2], nbats;
  State state[2];

  battery_state(&nbats, life, state);

  for (int i = 0; i < nbats; i++) {
    if (i > 0)
      printf("%s", separator);

    switch (state[i]) {
    case CHARGED: /* fully charged  */
      printf("%s %d%%", icon[life[i] / 10], life[i]);
      break;
    case DISCHARGING: /* discharging */
      if (life[i] >= 50)
        color = "colour028"; /* green */
      else if (life[i] >= 25)
        color = "colour172"; /* yellow */
      else
        color = "colour196"; /* red */

      printf("#[fg=%s]%s#[fg=default] %d%%", color, icon[life[i] / 10],
             life[i]);
      break;
    case CHARGING: /* charging */
      printf("#[fg=yellow]%s#[fg=default] %d%%", charging, life[i]);
      break;
    case DISCONNECTED: /* disconnected */
      printf("%s", disconnected);
      break;
    default: /* unknown code */
      printf("%s", unknown);
    }
  }

  return EXIT_SUCCESS;
}