HTML5: Access Battery status through javascript

Update 19-01-2014: Well the adoption rate is very small. Firefox still supports this, but support has still not landed in Chrome (see here: https://code.google.com/p/chromium/issues/detail?id=122593). I updated the article so the example works again for firefox users.

The HTML5 specification is maturing and slowly APIs surface that allow you to access more information from the device the browser is running on. One of the latest submissions is the "Battery Status API". As the name implies the API allows you to access the battery status through javascript. So you could use this API to disable heavy animations on your web page, warn the user to sync its data, or proactively store the data in local storage. If you want to test this for yourself you can find a working example here. Note that the "Battery time left" property, at least for me, isn't available when I open the page. It updates after a couple of minutes.

I tested this API with the latest betas of mozilla. And it doesn't work yet on Mac (does work on iOS, Android and windows). I also didn't get a good result for the charging time, but discharging and level worked nicely. For this small example we'll just display information from the API in a simple webpage, like this (screenshot from my tablet):

Screenshot_2012-06-08-12-20-53.png

We'll look at the following in this article:

  • How to use the Battery API
  • Create a couple of text fields to show information from the API
  • Create a battery image that shows how much power we have left
  • Use event listeners to update the information

Lets start with a quick look at the API

How to use the Battery API

Using the API is very simple, it has only a couple of properties you can access (from the spec):

[NoInterfaceObject]
interface BatteryManager : EventTarget {
    readonly attribute boolean   charging;
    readonly attribute double    chargingTime;
    readonly attribute double    dischargingTime;
    readonly attribute double    level;
};

The charging property indicates whether we're connected to a charger, chargingTime returns the amount of time it will take to completely charge the device, the dischargingTime returns the time it will take to approximately run out of power, and the level shows a percentage of how much power you've got left. Very straightforward.

Besides these properties the API also defines a couple of callbacks.

    [TreatNonCallableAsNull]
             attribute Function? onchargingchange;
    [TreatNonCallableAsNull]
             attribute Function? onchargingtimechange;
    [TreatNonCallableAsNull]
             attribute Function? ondischargingtimechange;
    [TreatNonCallableAsNull]
             attribute Function? onlevelchange;

You can register functions for these callbacks that will be called whenever one of the properties changes.

Create a couple of text fields to show information from the API

Lets beging with a couple of simple text fields that show information on the battery. We use the following HTML:

<div id="box">
    <div id="battery"></div>
    <div id="text">
        <span style="display: block;margin-bottom:15px;font-size: xx-large;"><strong>Battery
            specifications</strong></span>
        <span style="display: block" id="level">Battery level: unknown</span>
        <span style="display: block" id="status">Charging status: unknown</span>
        <span style="display: block" id="charged">Battery charged: unknown</span>
    </div>
</div>

And to make sure they have the correct battery value, we fill these with the following javascript:

    // get the battery information
    var battery = navigator.battery || navigator.webkitBattery || navigator.mozBattery;
 
    // get the battery information to be displayed
    $('#level').text("Battery level: " + Math.round(battery.level * 100) + "%");
    $('#status').text("Charging status: " + ((battery.charging) ? "true" : "false"));
    if (battery.charging) {
        $('#charged').text("Battery time to charge: " + battery.chargingTime);
    } else {
        $('#charged').text("Battery time left: " + (Math.round(battery.dischargingTime / 60)) + " minutes");
    }

As you can see in the code, couldn't be much simpler. We also show an image that reflects the level.

Create a battery image that shows how much power we have left

I won't go into the details since that isn't that interesting. If you want to see the details look at the source code from the example . For this example I created a simple battery object (based on example from nokia) and with an updateBattery call I can set how full the battery is. To initialize this, use the following:

  var b = new Battery("assets/bat_empty.png", "assets/bat_full.png", 96, 168);
    $("#battery").append(b.domElement);
    b.updateBattery(battery.level * 100);

Use event listeners to update the information

And finally we add a couple of event listeners that are called whenever one of the properties of the battery changes:

   // when the loader is connected
    battery.addEventListener("chargingchange", function (e) {
        $('#status').text("Charging status: " + ((battery.charging) ? "true" : "false"));
    }, false);
 
    // when charging time changes update the time to charge / time left
    battery.addEventListener("chargingtimechange", function (e) {
        if (battery.charging) {
            $('#charged').text("Battery time to charge: " + battery.chargingTime);
        } else {
            $('#charged').text("Battery time left: " + (Math.round(battery.dischargingTime / 60)) + " minutes");
        }
 
    }, false);
 
    // when dischargingtime changes update the time to charge / time left
    battery.addEventListener("dischargingtimechange", function (e) {
        if (battery.charging) {
            $('#charged').text("Battery time to charge: " + (Math.round(battery.dischargingTime / 60)) + " minutes");
        } else {
            $('#charged').text("Battery time left: " + (Math.round(battery.dischargingTime / 60)) + " minutes");
        }
    }, false);
 
    // listener that is notified when the level changes
    battery.addEventListener("levelchange", function (e) {
        $('#level').text("Battery level: " + Math.round(battery.level * 100) + "%");
        b.updateBattery(100 * battery.level)
    }, false);

Easy isn't it? The really good thing about this, is that this works across devices. On my mobile phone it looks like this:

2012-06-08_11-35-31.jpg

And on windows (running in a VM) it shows me this:

Windows 7 - Ultimate [Running].png