获取Android手机电池电流值

27

我正在尝试收集Android G1手机的电源使用统计数据。 我想知道电压和电流的值,以便能够按照此PDF中所述的报告收集统计数据。

通过注册意图接收器以接收ACTION_BATTERY_CHANGED广播,我能够获取电池电压的值。 但问题在于,Android不通过该SDK接口公开电流值。

我尝试的一种方法是通过sysfs接口,在adb shell中使用以下命令查看电池电流值:

$cat /sys/class/power_supply/battery/batt_current
449 

但是仅当手机通过USB接口连接时才能起作用。如果我断开手机,我会看到batt_current的值为“0”。我不确定为什么报告的电流值为零。它应该大于零,对吧?

有没有关于获取电池电流值的建议/指针?如果我错了,请您纠正我。


2
你可能想在YouTube上观看那个演示。我当时在场,好像记得Sharkey先生提到了关于使用特殊硬件进行这些测量的事情。 - CommonsWare
这里有一些你可以尝试的示例代码:http://androidcommunity.com/forums/f7/battery-value-in-andriod-22236/ - Jay Askren
谢谢提供链接,我正在使用类似的函数来读取电池电压。但是Android没有通过该接口公开电流值。因此,如果您知道在内核/较低层有什么解决方法,请告诉我。 - Chintan Parikh
是的,在演示的最后,他提到测量电流需要通过硬件电子设备完成,软件无法帮助。您知道sysfs接口的工作原理吗?如果可能的话,我们能否从中获取数据。感谢您指向视频。 - Chintan Parikh
嗨@Chintan Parikh,你找到了获取当前值的好方法吗?有一个应用程序可以获取当前值,但我不知道它是如何工作的。https://play.google.com/store/apps/details?id=com.gombosdev.ampere - DàChún
@User9527 实际上,它似乎是从这些文件中读取数据。 - trolley813
8个回答

13

你可以查看当前小部件的源代码。它已经硬编码了特定平台存储当前值的路径。

/*
 *  Copyright (c) 2010-2011 Ran Manor
 *  
 *  This file is part of CurrentWidget.
 *    
 *  CurrentWidget 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  CurrentWidget is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with CurrentWidget.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.manor.currentwidget.library;

import java.io.File;

import android.os.Build;
import android.util.Log;

public class CurrentReaderFactory {

    static public Long getValue() {

        File f = null;      

        // htc desire hd / desire z / inspire?
        if (Build.MODEL.toLowerCase().contains("desire hd") ||
                Build.MODEL.toLowerCase().contains("desire z") ||
                Build.MODEL.toLowerCase().contains("inspire")) {

            f = new File("/sys/class/power_supply/battery/batt_current");
            if (f.exists()) {
                return OneLineReader.getValue(f, false);
            }
        }

        // nexus one cyangoenmod
        f = new File("/sys/devices/platform/ds2784-battery/getcurrent");
        if (f.exists()) {
            return OneLineReader.getValue(f, true);
        }

        // sony ericsson xperia x1
        f = new File("/sys/devices/platform/i2c-adapter/i2c-0/0-0036/power_supply/ds2746-battery/current_now");
        if (f.exists()) {
            return OneLineReader.getValue(f, false);
        }

        // xdandroid
        /*if (Build.MODEL.equalsIgnoreCase("MSM")) {*/
            f = new File("/sys/devices/platform/i2c-adapter/i2c-0/0-0036/power_supply/battery/current_now");
            if (f.exists()) {
                return OneLineReader.getValue(f, false);
            }
        /*}*/

        // droid eris
        f = new File("/sys/class/power_supply/battery/smem_text");      
        if (f.exists()) {
            Long value = SMemTextReader.getValue();
            if (value != null)
                return value;
        }

        // htc sensation / evo 3d
        f = new File("/sys/class/power_supply/battery/batt_attr_text");
        if (f.exists())
        {
            Long value = BattAttrTextReader.getValue();
            if (value != null)
                return value;
        }

        // some htc devices
        f = new File("/sys/class/power_supply/battery/batt_current");
        if (f.exists())
            return OneLineReader.getValue(f, false);

        // nexus one
        f = new File("/sys/class/power_supply/battery/current_now");
        if (f.exists())
            return OneLineReader.getValue(f, true);

        // samsung galaxy vibrant       
        f = new File("/sys/class/power_supply/battery/batt_chg_current");
        if (f.exists())
            return OneLineReader.getValue(f, false);

        // sony ericsson x10
        f = new File("/sys/class/power_supply/battery/charger_current");
        if (f.exists())
            return OneLineReader.getValue(f, false);

        // Nook Color
        f = new File("/sys/class/power_supply/max17042-0/current_now");
        if (f.exists())
            return OneLineReader.getValue(f, false);

        return null;
    }
}

1
我的GNex运行Slimkat系统,电池电量在/sys/class/power_supply/battery/capacity中显示,但由于它是百分比值而不是电流值,因此可能在此处未被使用。有趣的是,您列出的文件在我的设备上都没有。 - user169771
这是GNU许可证。有没有更好的许可证适用于类似的代码?此外,是否有一种方式可以覆盖所有设备? - android developer

11

从API 21开始,我们可以获取瞬时电池电流,单位为微安,以整数形式表示。开发者文档

BatteryManager mBatteryManager = (BatteryManager) getSystemService(Context.BATTERY_SERVICE);
    Long avgCurrent = null, currentNow = null;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        avgCurrent = mBatteryManager.getLongProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE);
        currentNow = mBatteryManager.getLongProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW);
    }
    Log.d(TAG, "BATTERY_PROPERTY_CURRENT_AVERAGE = " + avgCurrent + "mAh");
    Log.d(TAG, "BATTERY_PROPERTY_CURRENT_NOW =  " + currentNow + "mAh");

使用 mBatteryManager 您可以获取瞬时电流读数。

测量设备的电力和读取 NEXUS 设备上可用的属性来了解能量消耗。 Android 开放源代码文档


3
-9223372036854775808 毫安时。这总是我得到的结果。 - Hitesh Danidhariya
正如@HiteshDanidhariya所提到的,此API可能会提供当前值,但并不保证在所有设备上都是准确的。 - Darpan
1
正如 Android 开源文档中所提到的,设备需要具备燃油计硬件才能获得精确读数,否则输出值将会是任意值。目前只有极少数设备配备了这种硬件。 - LokiDroid

5
使用此函数在所有设备中获取电压、温度和电流信息。
在OnCreate函数中注册广播接收器。
    this.registerReceiver(this.BatteryInfo, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

并创建广播接收器

    private BroadcastReceiver BatteryInfo = new BroadcastReceiver() {
    @Override
    public void onReceive(Context ctxt, Intent intent) {
        int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
        int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);

        boolean isPresent = intent.getBooleanExtra("present", false);

        Bundle bundle = intent.getExtras();
        String str = bundle.toString();
        Log.i("Battery Info", str);

        if (isPresent) {
            int percent = (level * 100) / scale;

            technology.setText("Technology: "+bundle.getString("technology"));
            voltage.setText("Voltage: "+bundle.getInt("voltage")+"mV");
            temp.setText("Temperature: "+bundle.getInt("temperature"));
            curent.setText("Current: "+bundle.getInt("current_avg"));
            health.setText("Health: "+getHealthString(health_));
            charging.setText("Charging: "+getStatusString(status) + "(" +getPlugTypeString(pluggedType)+")");
            battery_percentage.setText("" + percent + "%");


        } else {
            battery_percentage.setText("Battery not present!!!");
        }
    }   
};


 private String getPlugTypeString(int plugged) {
    String plugType = "Unknown";

    switch (plugged) {
    case BatteryManager.BATTERY_PLUGGED_AC:
        plugType = "AC";
        break;
    case BatteryManager.BATTERY_PLUGGED_USB:
        plugType = "USB";
        break;
    }
    return plugType;
}

private String getHealthString(int health) {
    String healthString = "Unknown";
    switch (health) {
    case BatteryManager.BATTERY_HEALTH_DEAD:
        healthString = "Dead";
        break;
    case BatteryManager.BATTERY_HEALTH_GOOD:
        healthString = "Good Condition";
        break;
    case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
        healthString = "Over Voltage";
        break;
    case BatteryManager.BATTERY_HEALTH_OVERHEAT:
        healthString = "Over Heat";
        break;
    case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
        healthString = "Failure";
        break;
    }
    return healthString;
}
private String getStatusString(int status) {
    String statusString = "Unknown";

    switch (status) {
    case BatteryManager.BATTERY_STATUS_CHARGING:
        statusString = "Charging";
        break;
    case BatteryManager.BATTERY_STATUS_DISCHARGING:
        statusString = "Discharging";
        break;
    case BatteryManager.BATTERY_STATUS_FULL:
        statusString = "Full";
        break;
    case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
        statusString = "Not Charging";
        break;
    }
    return statusString;
}

谢谢。您能否回答其他问题?我还注意到对于我的设备,“current”值始终为0。这是为什么? - android developer
由于你已经将“str”写入日志,我发现“current_avg”不在那里... :( - android developer
你能在展示“电池信息”时拍一张logcat的截图吗? - Sumit
也许有一种方法可以通过其他可用的变量来获取“current”吗? - android developer
在我的情况下,isPresent 始终为 false,即使实际上它是存在的 :) - djdance
显示剩余8条评论

3

我在英特尔安卓开发者网站上找到了这段代码。

public class BatteryActivity extends Activity {

    private final String TAG = "SDP_BATTERY";
    private final String DEGREE_UNICODE = "\u00B0";

    private StringBuffer textBuffer = new StringBuffer();

    // a text view to show the status of the battery
    private TextView mStatusTextView;
    // a text view to display the battery status icon
    private TextView mBatteryStatusIcon;

    /** Called when the activity is first created. */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.battery);

        mBatteryStatusIcon = (TextView) this.findViewById(R.id.statusBattIcon);
        mStatusTextView = (TextView) this.findViewById(R.id.statusEditText);
    }

    /**
     * Once onResume is called, the activity has become visible (it is now "resumed"). Comes after onCreate
     */
    protected void onResume() {
        super.onResume();

        IntentFilter filter = new IntentFilter();

        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        Log.d(TAG, "Register battery status receiver.");
        registerReceiver(mBroadcastReceiver, filter);
    }

    /**
     * Another activity takes focus, so this activity goes to "paused" state
     */
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "Unegister battery status receiver.");
        unregisterReceiver(mBroadcastReceiver);
    }

    /**
     * BroadcastReceiver is used for receiving intents (broadcasted messages) from the BatteryManager
     */
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

        private boolean isHealth = false;

        public void onReceive(Context context, Intent intent) {
            DecimalFormat formatter = new DecimalFormat();

            String action = intent.getAction();

            // store battery information received from BatteryManager
            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                Log.d(TAG, "Received battery status information.");
                int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 0);
                int health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH, 0);
                boolean present = intent.getBooleanExtra(
                        BatteryManager.EXTRA_PRESENT, false);
                int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
                int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
                int icon_small = intent.getIntExtra(
                        BatteryManager.EXTRA_ICON_SMALL, 0);
                int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED,
                        0);
                int voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE,
                        0);
                int temperature = intent.getIntExtra(
                        BatteryManager.EXTRA_TEMPERATURE, 0);
                String technology = intent
                        .getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);

                // display the battery icon that fits the current battery status (charging/discharging)
                mBatteryStatusIcon.setCompoundDrawablesWithIntrinsicBounds(icon_small, 0, 0, 0);

                // create TextView of the remaining information , to display to screen.
                String statusString = "";

                switch (status) {
                case BatteryManager.BATTERY_STATUS_UNKNOWN:
                    statusString = "unknown";
                    break;
                case BatteryManager.BATTERY_STATUS_CHARGING:
                    statusString = "charging";
                    break;
                case BatteryManager.BATTERY_STATUS_DISCHARGING:
                    statusString = "discharging";
                    break;
                case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
                    statusString = "not charging";
                    break;
                case BatteryManager.BATTERY_STATUS_FULL:
                    statusString = "full";
                    break;
                }

                String healthString = "";

                switch (health) {
                case BatteryManager.BATTERY_HEALTH_UNKNOWN:
                    healthString = "unknown";
                    break;
                case BatteryManager.BATTERY_HEALTH_GOOD:
                    healthString = "good";
                    isHealth = true;
                    break;
                case BatteryManager.BATTERY_HEALTH_OVERHEAT:
                    healthString = "overheat";
                    break;
                case BatteryManager.BATTERY_HEALTH_DEAD:
                    healthString = "dead";
                    break;
                case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
                    healthString = "over voltage";
                    break;
                case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
                    healthString = "unspecified failure";
                    break;
                }

                String acString = "";

                switch (plugged) {
                case BatteryManager.BATTERY_PLUGGED_AC:
                    acString = "plugged AC";
                    break;
                case BatteryManager.BATTERY_PLUGGED_USB:
                    acString = "plugged USB";
                    break;
                default:
                    acString = "not plugged";
                }

                textBuffer =  new StringBuffer();
                textBuffer.append("status:" + statusString + "\n");

                formatter.applyPattern("#");
                String levelStr = formatter.format( (float)level/scale * 100 );
                textBuffer.append("level:" + levelStr + "% (out of 100)\n");
                textBuffer.append("health:" + healthString + "\n");

                textBuffer.append("present?:" + String.valueOf(present) + "\n");

                textBuffer.append("plugged?:" + acString + "\n");

                // voltage is reported in millivolts
                formatter.applyPattern(".##");
                String voltageStr = formatter.format( (float)voltage/1000 );
                textBuffer.append("voltage:" + voltageStr + "V\n");

                // temperature is reported in tenths of a degree Centigrade (from BatteryService.java)
                formatter.applyPattern(".#");
                String temperatureStr = formatter.format( (float)temperature/10 );
                textBuffer.append("temperature:" + temperatureStr
                        + "C" + DEGREE_UNICODE + "\n");

                textBuffer.append("technology:" + String.valueOf(technology)
                        + "\n");

                mStatusTextView.setText(textBuffer.toString());

                if (isHealth) {
                    Log.d(TAG, "Battery health: " + healthString);
                    Log.d(TAG, "UMSE_BATTERY_SUCCESSFULLY");
                } else {
                    Log.d(TAG, "UMSE_BATTERY_FAILED");
                }

                Log.d(TAG, textBuffer.toString());

                //finish();
            }
        }
    };

3

经过数次实验和其他团体的帮助,我发现无法通过仅使用软件获取电池电流值(因为此功能不受硬件支持)。唯一的方法是通过万用表测量电流流入电池的方式来获得电池电流值。


这个做不了任务吗?http://developer.android.com/training/monitoring-device-state/battery-monitoring.html#CurrentLevel - fredcrs
可以先看一下@Kevin(和voss)的答案。;) - Old McStopher
难道没有一个 current_now 吗? - neverMind9

1

尝试这段代码,可能对您有帮助:

private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver(){
      @Override
      public void onReceive(Context arg0, Intent intent) {
        // TODO Auto-generated method stub
          //this will give you battery current status
        int level = intent.getIntExtra("level", 0);

        contentTxt.setText(String.valueOf(level) + "%");

        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        textView2.setText("status:"+status);
        boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                            status == BatteryManager.BATTERY_STATUS_FULL;
        textView3.setText("is Charging:"+isCharging);
        int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
        textView4.setText("is Charge plug:"+chargePlug);
        boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;

        boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
        textView5.setText("USB Charging:"+usbCharge+" AC charging:"+acCharge);

      }
    };

在主类中注册这个使用:

 this.registerReceiver(this.mBatInfoReceiver, 
          new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

0

关于电池电流百分比充电,您可以使用以下方法

IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = this.registerReceiver(null, ifilter);

int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

float batteryPct = level / (float)scale;

TextView tView = (TextView) findViewById(R.id.textView2);
tView.setText("Battery Status " + batteryPct);

0

大多数电池使用从电池流出的电流来确定百分比,但开发人员很少能够使用它!

这需要在这些设备上修改内核。

Galaxy S2也是如此,它有测量这种电流流动的芯片!但是,在原始内核中,“停用”了它。这意味着它已从sysfs接口中删除,并仅由电池内部使用。

尽管如此,您可以尝试从市场下载应用程序“电池监视器小部件”,它支持许多手机,并将在不可用时估算mA电流。为了改善读数,定期添加对新手机和方法的支持。

在Galaxy Nexus上,电流芯片已完全删除,因为电池现在使用先进的计算来确定百分比,不需要电流数据。结果是该手机没有学习曲线(


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接