Battery level from OwnTracks GPS data via PostgreSQL. Red = heavy drain (>30%), orange = moderate, green = light. Dashed lines at 20% and 80%.
import psycopg2, datetime
BST = datetime.timezone(datetime.timedelta(hours=1))
conn = psycopg2.connect(host='/home/john/tmp', port=5432, dbname='owntracks', user='owntracks_ro')
cur = conn.cursor()
cur.execute("""
WITH day_batt AS (
SELECT (to_timestamp(tst) AT TIME ZONE 'Europe/London')::date AS day,
batt, tst, bs
FROM locations
WHERE tst >= extract(epoch FROM now() - interval '7 days')
AND batt IS NOT NULL
)
SELECT day,
(array_agg(batt ORDER BY tst ASC))[1] AS first_batt,
(array_agg(batt ORDER BY tst DESC))[1] AS last_batt,
MIN(batt), MAX(batt),
COUNT(*) FILTER (WHERE bs IN (2,3)),
COUNT(*),
array_agg(batt ORDER BY tst),
array_agg(tst ORDER BY tst)
FROM day_batt GROUP BY day ORDER BY day
""")
rows = cur.fetchall()
conn.close()
print(f"Fetched {len(rows)} days")
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import seaborn as sns
def plot_day(row):
day, first_b, last_b, min_b, max_b, chrg_fixes, total_fixes, batt_series, tst_series = row
times = [datetime.datetime.fromtimestamp(t, tz=BST) for t in tst_series]
charging = chrg_fixes > total_fixes * 0.1
drop = first_b - last_b
colour = '#e05050' if drop > 30 else '#e09030' if drop > 10 else '#50a050'
sns.set_theme(style='whitegrid')
fig, ax = plt.subplots(figsize=(14, 2.5))
ax.plot(times, batt_series, color=colour, linewidth=1.5)
ax.fill_between(times, batt_series, alpha=0.2, color=colour)
ax.set_ylim(0, 105)
ax.set_ylabel('%', fontsize=9)
ax.set_title(
f"start={first_b}% end={last_b}% min={min_b}% drop={drop:+d}%"
+ (' [charging]' if charging else ''),
fontsize=9, loc='right'
)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
ax.xaxis.set_major_locator(mdates.AutoDateLocator())
ax.axhline(20, color='#bbb', linewidth=0.6, linestyle='--')
ax.axhline(80, color='#bbb', linewidth=0.6, linestyle='--')
fig.tight_layout()
show(fig)
plt.close(fig)
print("plot_day() defined")
plot_day(rows[0])
plot_day(rows[1])
plot_day(rows[2])
plot_day(rows[3])
plot_day(rows[4])
plot_day(rows[5])
plot_day(rows[6])
plot_day(rows[7])