-
Notifications
You must be signed in to change notification settings - Fork 5
/
batterylog.py
executable file
·144 lines (110 loc) · 4.41 KB
/
batterylog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/python
from decimal import Decimal
import glob
import os
import sqlite3
import sys
import time
# Paths
APP_DIR = os.path.dirname(__file__)
SCHEMA_FILE = APP_DIR + '/schema.sql'
DB_FILE = APP_DIR + '/batterylog.db'
# Connect to DB
con = sqlite3.connect(DB_FILE)
con.row_factory = sqlite3.Row
cur = con.cursor()
# Load schema if necessary - we use IF NOT EXISTS so this if fine to run for sanity checking
with open(SCHEMA_FILE) as f:
cur.executescript(f.read())
def main():
# This is used for logging
try:
event = sys.argv[1]
except:
event = None
# We write if there's an event being passed
if event:
# We only handle a single battery, but this should work fine for most laptops
batteries = glob.glob('/sys/class/power_supply/BAT*')
if batteries:
BAT = batteries[0]
name = os.path.basename(BAT)
else:
print('Sorry we couldn\'t find a battery in /sys/class/power_supply')
sys.exit()
# Timestamp
now = int(time.time())
with open(BAT + '/cycle_count') as f:
cycle_count = int(f.read())
with open(BAT + '/charge_now') as f:
charge_now = int(f.read())
with open(BAT + '/current_now') as f:
current_now = int(f.read())
with open(BAT + '/voltage_now') as f:
voltage_now = int(f.read())
with open(BAT + '/voltage_min_design') as f:
voltage_min_design = int(f.read())
# Energy = Wh
energy_now = charge_now * voltage_now # /1000000000000
energy_min = charge_now * voltage_min_design # what uPower uses
# Power = W
power_now = current_now * voltage_now
power_min = current_now * voltage_min_design
# Write to DB
con = sqlite3.connect(DB_FILE)
cur = con.cursor()
sql = "INSERT INTO log VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
values = (now, name, event, cycle_count, charge_now, current_now, voltage_now, voltage_min_design, energy_now, energy_min, power_now, power_min)
cur.execute(sql, values)
con.commit()
con.close()
# No event specified, we'll just do reporting
else:
# No argument - print last stats
con = sqlite3.connect(DB_FILE)
con.row_factory = sqlite3.Row
cur = con.cursor()
sql = """
SELECT * FROM log
WHERE event = 'resume'
ORDER BY TIME DESC
LIMIT 1
"""
res = cur.execute(sql)
resume = res.fetchone()
sql = """
SELECT * FROM log
WHERE event = 'suspend'
ORDER BY TIME DESC
LIMIT 1
"""
res = cur.execute(sql)
suspend = res.fetchone()
con.close()
if not resume:
print('No power data available. If this is your first time running batterylog, try suspending and resuming first.')
sys.exit()
# Get Time
delta_s = resume['time'] - suspend['time']
delta_h = Decimal(delta_s/3600)
# Get Power Used - we use min vs now since we don't have voltage_avg / smoothing, probably safer...
# energy_used_wh = Decimal((suspend['energy_now'] - resume['energy_now'])/1000000000000)
energy_used_wh = Decimal((suspend['energy_min'] - resume['energy_min'])/1000000000000)
# Average Power Use
power_use_w = energy_used_wh / delta_h
# Full Battery Power (presumably we should use min/nominal here?)
with open('/sys/class/power_supply/BAT1/charge_full') as f:
charge_full = int(f.read())
energy_full_wh = Decimal(charge_full/1000000000000) * resume['voltage_min_design']
# Percentage Battery Used / hour
percent_per_h = 100 * power_use_w / energy_full_wh
# Time left from resume
if power_use_w > 0:
until_empty_h = Decimal(resume['energy_min']/1000000000000)/ power_use_w
print('Slept for {:.2f} hours'.format(delta_h))
print('Used {:.2f} Wh, an average rate of {:.2f} W'.format(energy_used_wh, power_use_w))
if power_use_w > 0:
print('At {:.2f}/Wh drain you battery would be empty in {:.2f} hours'.format(power_use_w, until_empty_h))
print('For your {:.2f} Wh battery this is {:.2f}%/hr or {:.2f}%/day'.format(energy_full_wh, percent_per_h, percent_per_h*24))
if __name__ == '__main__':
main()