diff --git a/README.md b/README.md index a936a48..8e63d56 100644 --- a/README.md +++ b/README.md @@ -85,14 +85,19 @@ Datasheets Battery Life ------------ -I tested 22 sensors connecting every minute in my house: the room temperature -sensors lasted 17-18 days, a sensor placed outdoors which saw daily temps -30F - 55F lasted 10 days, a sensor in my 40F refrigerator lasted 12 days, and a -sensor in my -5F freezer lasted 6 days. - -With the new code that stores readings in NVS and turns the wifi on much less -frequently, the battery life will be much longer: hopefully it will scale more -or less linearly, I'm currently testing 5-minute reporting intervals. +Connecting every single minute: + + * 17-18 days at room temperature + * 12 days at 40F + * 6 days at -5F + +Connecting every six minutes: + + * 68-70 days at room temperature + * 60 days at 40F + * 28 days at -5F + +I'm currently testing 60-minute reporting intervals. TODO ---- diff --git a/backend/http_sensor.py b/backend/http_sensor.py index 06b7c03..9b02866 100755 --- a/backend/http_sensor.py +++ b/backend/http_sensor.py @@ -86,11 +86,17 @@ def do_POST(self): rjsond = { "next_epoch": (rxtime // 60 + 1) * 60, "queue_interval": 60, - "queue_count": 5, + "queue_count": 60, } location, want_send_delay_us = self.server.lookup_location(ser) + if "outdoor" in location.lower(): + rjsond["queue_count"] = 5 + + if location.startswith("(") and location.endswith(")"): + rjsond["queue_count"] = 0 + if send_delay_us != want_send_delay_us: rjsond["next_send_delay_us"] = want_send_delay_us diff --git a/backend/http_ui.py b/backend/http_ui.py index 9473e89..ae51805 100755 --- a/backend/http_ui.py +++ b/backend/http_ui.py @@ -18,6 +18,7 @@ import urllib.parse from http.server import HTTPServer, BaseHTTPRequestHandler +import missing import plots class UIRequestHandler(BaseHTTPRequestHandler): @@ -155,6 +156,15 @@ def do_GET(self): self.send_error(500, explain=traceback.format_exc().encode('utf-8')) return + elif self.path == "/missing": + ret = missing.get_missing_text().encode('utf-8') + self.send_response(200) + self.send_header("Content-Length", len(ret)) + self.send_header("Content-Type", "text/plain;charset=utf-8") + self.end_headers() + self.wfile.write(ret) + return + self.send_error(403) def do_POST(self): diff --git a/backend/missing.py b/backend/missing.py new file mode 100755 index 0000000..a57d156 --- /dev/null +++ b/backend/missing.py @@ -0,0 +1,53 @@ +#!/usr/bin/python3 + +import sqlite3 +import itertools +import time + +def get_missing_text(): + txt = "" + con = sqlite3.connect("data.db") + cur = con.cursor() + + def to_ranges(iterable): + iterable = sorted(set(iterable)) + for key, group in itertools.groupby(enumerate(iterable), + lambda t: t[1] - t[0]): + group = list(group) + yield group[0][1], group[-1][1] + + def date_parse(epoch): + return time.strftime("%c", time.localtime(epoch)) + + locs = [x[0] for x in cur.execute( + "select location from data group by location;" + )] + ts = [x[0] for x in cur.execute( + "select (c_epoch / 60) as c_epoch_base from data " + "where c_epoch > 0 group by c_epoch_base;" + )] + + txt += f"Earliest entry: {date_parse(min(ts) * 60)}\n\n" + + for location in locs: + if location.startswith("(") and location.endswith(")"): + continue + + got_ts = set(x[0] for x in cur.execute( + f"select (c_epoch / 60) as c_epoch_base from data where location='{location}' order by c_epoch_base;" + )) + missing = [] + + for timestamp in ts: + if timestamp not in got_ts: + missing.append(timestamp) + + txt += f"{location} missing {len(missing)} entries:\n" + for miss_start, miss_end in to_ranges(missing): + miss_len = miss_end - miss_start + 1 + txt += f"\t{date_parse(miss_start * 60)} --- " + txt += f"{date_parse(miss_end * 60)}\t{miss_len}min!\n" + txt += "\n" + + con.close() + return txt