Display battery charge value with LXDE and lxpanel
#1
In my opinion, Armbian with LXDE as window manager is a good fitting combination for the limited power of the Pinebook. LXDE provides only few visual effects, so the system can be used with acceptable performance. Unfortunately, I had an issue with the battery plugin of the lxpanel (the bar where all current windows/processes are stacked into). 

Indication: Battery plugin (batt) of lxpanel does not show the current "capacity" (charged value in percent) of Pinebook's battery. Instead, it displays "0% charged" and continuously fires the low-battery alarm.

Reason: The integrated functionality of the battery plugin calculates the charged value by using the coulomb-based counters "charge_now" and "charge_full" (or alternatively "energy_now" and "energy_full"). These counters are usually provided by the power management unit's Linux kernel module. The kernel module (axp20x) for the AXP803 power management unit of the Pinebook does not provide "charge_now" and "charge_full" information. Instead, a percentage value for the current charge is provided as "capacity" (try 'cat /sys/class/power_supply/axp20x-battery/capacity').

Solution: I have changed the source code for the batt plugin with respect to the above mentioned reasons. Now, the percentage value is directly read from the corresponding sysfs file and not longer calculated indirectly.

The original code (lxpanel version 0.10.0) that you can find in 'lxpanel-0.10.0/plugins/batt/batt_sys.c' looked like this: 

Code:
battery* battery_update(battery *b) {
   gchar *gctmp; int promille;

   /* [...] */

   /* read from sysfs */
   b->charge_now = get_gint_from_infofile(b, "charge_now");
   b->energy_now = get_gint_from_infofile(b, "energy_now");

   b->current_now = get_gint_from_infofile(b, "current_now");
   b->power_now   = get_gint_from_infofile(b, "power_now");

   if (b->current_now < -1)
           b->current_now = - b->current_now;

   b->charge_full = get_gint_from_infofile(b, "charge_full");
   b->energy_full = get_gint_from_infofile(b, "energy_full");

   b->charge_full_design = get_gint_from_infofile(b, "charge_full_design");
   b->energy_full_design = get_gint_from_infofile(b, "energy_full_design");

   b->voltage_now = get_gint_from_infofile(b, "voltage_now");

   gctmp = get_gchar_from_infofile(b, "type");
   b->type_battery = gctmp ? (strcasecmp(gctmp, "battery") == 0) : TRUE;
   g_free(gctmp);

   g_free(b->state);
   b->state = get_gchar_from_infofile(b, "status");
   if (!b->state)
       b->state = get_gchar_from_infofile(b, "state");
   if (!b->state) {
       if (b->charge_now != -1 || b->energy_now != -1
               || b->charge_full != -1 || b->energy_full != -1)
           b->state = g_strdup("available");
       else
           b->state = g_strdup("unavailable");
   }

   if (b->charge_now != -1 && b->charge_full != -1)
       promille = (b->charge_now * 1000) / b->charge_full;
   else if (b->energy_full != -1 && b->energy_now != -1)
       /* no charge data, let try energy instead */
       promille = (b->energy_now * 1000) / b->energy_full;
   else
       promille = 0;

   b->percentage = (promille + 5) / 10; /* round properly */
   if (b->percentage > 100)
       b->percentage = 100;

/* [...] */

   return b;
}

This code has been changed to the following:

Code:
battery* battery_update(battery *b) {
   gchar *gctmp; int promille;
    /* [...] */

   /* read from sysfs */
   b->charge_now = get_gint_from_infofile(b, "charge_now");
   b->energy_now = get_gint_from_infofile(b, "energy_now");

   b->current_now = get_gint_from_infofile(b, "current_now");
   b->power_now   = get_gint_from_infofile(b, "power_now");

   if (b->current_now < -1)
           b->current_now = - b->current_now;

   b->charge_full = get_gint_from_infofile(b, "charge_full");
   b->energy_full = get_gint_from_infofile(b, "energy_full");

   b->charge_full_design = get_gint_from_infofile(b, "charge_full_design");
   b->energy_full_design = get_gint_from_infofile(b, "energy_full_design");

   b->voltage_now = get_gint_from_infofile(b, "voltage_now");
   // changed to direct read of percentage value (supported by pinebook)
   b->percentage = get_norm_gint_from_infofile(b, "capacity");

   gctmp = get_gchar_from_infofile(b, "type");
   b->type_battery = gctmp ? (strcasecmp(gctmp, "battery") == 0) : TRUE;
   g_free(gctmp);

   /* [...] */
   
   if (b->charge_now != -1 && b->charge_full != -1)
       promille = (b->charge_now * 1000) / b->charge_full;
   else if (b->energy_full != -1 && b->energy_now != -1)
       /* no charge data, let try energy instead */
       promille = (b->energy_now * 1000) / b->energy_full;
   else
       promille = 0;

   // percentage was indirectly calculated, this has changed to direct read of value
   //b->percentage = (promille + 5) / 10; /* round properly */
   if (b->percentage > 100)
       b->percentage = 100;

   /* [...] */
   return b;
}

As this requires a new function for reading the numerical value as provided by '/sys/class/power_supply/axp20x-battery/capacity', I introduced the following function which was inserted below the existing function "static gint get_gint_from_infofile(battery *b, gchar *sys_file)" in the same source code file "batt_sys.c":

Code:
/* get_norm_gint_from_infofile():
*         If the sys_file exists, then its value is converted to an int,
*         and returned.
*         Failure is indicated by returning -1. */
static gint get_norm_gint_from_infofile(battery *b, gchar *sys_file) {
   gchar *file_content = parse_info_file(b, sys_file);
   gint value = -1;

   if (file_content != NULL)
       value = atoi(file_content);
   g_free(file_content);

   return value;
}

The most time consuming part of this change was building the plugin's shared library file 'batt.so' because of all the required dependencies. But finally, it worked and I could replace the original file in '/usr/lib/aarch64-linux-gnu/lxpanel/plugins/'. The charge indicator now works as it should (except that I see no practical way how to predict the remaining power-on time).

I provide to you my build of 'batt.so' here (together with the changed 'batt_sys.c'), so that you do not need to build it by yourself:
.zip   lxde-lxpanel_batt-plugin.zip (Size: 39.15 KB / Downloads: 4)  
I use it on Armbian 5.86 Debian stretch with LXDE 9.9 and lxpanel version 0.9.3. It may also work with other versions of LXDE/lxpanel and in combination with different Armbian versions. Please post your message on whether it worked for you by mentioning your system configuration. Thanks!
  Reply


Possibly Related Threads...
Thread Author Replies Views Last Post
  Improve the life of your Pinebook battery by setting charger's voltage limits wlad 0 91 06-11-2019, 02:27 PM
Last Post: wlad
  How can I reliably get battery status on pinebook tillea 5 1,172 06-11-2019, 10:10 AM
Last Post: wlad
  Failure in setting the display backlight with Armbian 5.86 [SOLVED] wlad 0 56 06-11-2019, 03:36 AM
Last Post: wlad
  Battery Status in Bionic X-Istence 3 238 03-11-2019, 03:52 PM
Last Post: soupbowl
  .bashrc to show battery percentage at prompt e-minguez 1 118 03-05-2019, 07:03 PM
Last Post: PatrickM
  No display options on Pinebook or Pineboard Fox7799 0 214 02-06-2019, 11:56 AM
Last Post: Fox7799
  Tips and Tricks for Ayufan's Bionic LXDE Image LeoLambda 8 678 01-22-2019, 06:22 PM
Last Post: binholz
  Battery drained while turned off amentis 6 555 07-17-2018, 02:38 AM
Last Post: pfeerick
  Splash But No Login After Low Battery robbiemacg 3 286 05-17-2018, 09:30 AM
Last Post: robbiemacg
Information i3wm xenial-i3 introduction -- mate terminal & battery monitor MarkHaysHarris777 4 1,379 08-31-2017, 04:47 AM
Last Post: shirman

Forum Jump:


Users browsing this thread: 1 Guest(s)