Edit: this program contains a bug; the up to date version can be found here.

This program reads battery level every five minutes and executes a script whenever it changes.

--once execute this program (and the script) just once
--first execute the script after reading battery level for the first time (normally the initial value is kept only as a reference to detect a change)
The name of the script is made after the name of the program, so if you have /home/fred/gnobatmon the script is /home/fred/gnobatmon.script you can have symbolic links or you change the source!

Note: some phones send a battery full message well before stopping charger (and writing to the display).
Note2: some lines in the following source are wrapped by the editor

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Copyright (C) 2006 by Daniele Forsi

  An utility program that using libgnokii checks for battery level and executes a script
  when it changes.
  Script name is derived after the name of this program with ".script" appended; if you
  want more scripts
  make a symbolic link to the main program.
  Sample script gnobatmon.script:
  echo "$(date) battery charge $1 (previous $2)"
  compile with
  gcc -Wall -o gnobatmon gnobatmon.c `pkg-config --libs gnokii`




/* prepare for i18n */
#define _(x) x

struct gn_statemachine *state;
int quit = 0;
char *program_name;

void businit(void) {
	gn_error	error;
	error = gn_lib_phoneprofile_load(NULL, &state);
	if (GN_ERR_NONE == error) {
		error = gn_lib_phone_open(state);
	if (GN_ERR_NONE != error) {
		fprintf(stderr, "%s\n", gn_error_print(error));
void busterminate(void) {

void signal_handler(int signal) {
	quit = 1;

void execute_script(float battery_level, float previous_level) {
	char buf[128];
	snprintf(buf, sizeof(buf), "%s.script %d %d", program_name, (int)battery_level, (int)previous_level);
	fprintf(stdout,"executing %s\n", buf);

gn_error battery_monitor(int first, int once) {
	gn_data		data;
	gn_error	error;
	float		battery_level = 0, previous_percent = -1, percent_level;
	gn_battery_unit	battery_unit = GN_BU_Arbitrary;
	data.battery_unit = &battery_unit;
	data.battery_level = &battery_level;
	error = gn_sm_functions(GN_OP_GetBatteryLevel, &data, state);
	if (error != GN_ERR_NONE) {
		fprintf(stderr, _("Error getting battery level\n"));
		fprintf(stderr, "%s\n", gn_error_print(error));
		return error;
	fprintf(stdout, _("Ready.\n"));
	percent_level = battery_level * 100 / state->driver.phone.max_battery_level;
	if (once) {
		execute_script(percent_level, previous_percent);
		return GN_ERR_NONE;
	if (!first) previous_percent = percent_level;
	while (!quit) {
		error = gn_sm_functions(GN_OP_GetBatteryLevel, &data, state);
		switch (error) {
		case GN_ERR_NONE:
			percent_level = battery_level * 100 / state->driver.phone.max_battery_level;
			fprintf(stderr, _("Battery: %s\n"), gn_error_print(error));
			percent_level = -1;
		if (previous_percent != percent_level) {;
			execute_script(percent_level, previous_percent);
			previous_percent = percent_level;
	return GN_ERR_NONE;

int main(int argc, char *argv[]) {
	gn_error	error;
	int		first = 0, once = 0;
	program_name = argv[0];
	if ((argc != 1) && (argc != 2)) {
		fprintf(stderr, _("gnobatmon 0.1 by Daniele Forsi\nUsage: %s [--first|--once]\nPurpose:
 monitor battery level and run a script when it changes\n\t--first : run script also on the first value
 read\n\t--once  : run script once then exit\n"), argv[0]);
	if (argc == 2) {
		first = !strcmp(argv[1], "--first");
		once = !strcmp(argv[1], "--once");
	fprintf(stdout, _("Initializing...\n"));
	signal(SIGINT, signal_handler);
	error = battery_monitor(first, once);
	if (error == GN_ERR_NONE) return 0; else return error;