Track battery percentage history; skip poll write when value unchanged
This commit is contained in:
@@ -364,5 +364,109 @@ def test_manual_battery_percentage_edit(ha_client_f):
|
||||
# Clear via edit form
|
||||
ha_client_f.post("/battery/1/edit-details", data={"battery_percentage": ""})
|
||||
resp2 = ha_client_f.get("/battery/1")
|
||||
# percentage display row should not appear when None
|
||||
assert b"Battery %" not in resp2.data or b"55%" not in resp2.data
|
||||
# "55%" still appears once in history; the info-table row is gone (current value is None)
|
||||
assert resp2.data.count(b"55%") == 1
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Group 3 additions — skip-on-no-change + history logging (poller)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_poll_skips_update_when_percentage_unchanged(ha_app, ha_client_f):
|
||||
"""No write and no pct_log entry when the polled value matches the stored value."""
|
||||
ha_client_f.post("/device/add", data={"name": "Dev NoCh", "battery_slots": "1"})
|
||||
ha_client_f.post("/battery/add", data={"brand": "X", "count": "1"})
|
||||
ha_client_f.post("/battery/1/assign", data={"device_id": "1"})
|
||||
ha_client_f.post("/device/1/edit", data={
|
||||
"name": "Dev NoCh", "battery_slots": "1", "ha_entity_id": "sensor.noch"
|
||||
})
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from models import Battery, BatteryPctLog
|
||||
engine = create_engine(ha_app.config["SQLALCHEMY_DATABASE_URI"])
|
||||
s = sessionmaker(bind=engine)()
|
||||
s.get(Battery, 1).battery_percentage = 50
|
||||
s.commit(); s.close()
|
||||
|
||||
from ha_client import HomeAssistantClient
|
||||
from ha_poller import HaPoller
|
||||
mock_ha = MagicMock(spec=HomeAssistantClient)
|
||||
mock_ha.enabled = True
|
||||
mock_ha.get_state.return_value = 50 # same value — should be a no-op
|
||||
|
||||
Session = _make_session_factory(ha_app)
|
||||
HaPoller(mock_ha, Session, interval=300)._poll_once()
|
||||
|
||||
s2 = sessionmaker(bind=engine)()
|
||||
assert s2.query(BatteryPctLog).count() == 0
|
||||
s2.close()
|
||||
|
||||
|
||||
def test_poll_creates_pct_log_on_change(ha_app, ha_client_f):
|
||||
"""A pct_log entry with source='poll' is written when the value changes."""
|
||||
ha_client_f.post("/device/add", data={"name": "Dev Chg", "battery_slots": "1"})
|
||||
ha_client_f.post("/battery/add", data={"brand": "X", "count": "1"})
|
||||
ha_client_f.post("/battery/1/assign", data={"device_id": "1"})
|
||||
ha_client_f.post("/device/1/edit", data={
|
||||
"name": "Dev Chg", "battery_slots": "1", "ha_entity_id": "sensor.chg"
|
||||
})
|
||||
|
||||
from ha_client import HomeAssistantClient
|
||||
from ha_poller import HaPoller
|
||||
from models import BatteryPctLog
|
||||
mock_ha = MagicMock(spec=HomeAssistantClient)
|
||||
mock_ha.enabled = True
|
||||
mock_ha.get_state.return_value = 72
|
||||
|
||||
Session = _make_session_factory(ha_app)
|
||||
HaPoller(mock_ha, Session, interval=300)._poll_once()
|
||||
|
||||
s = Session()
|
||||
logs = s.query(BatteryPctLog).filter_by(battery_id=1).all()
|
||||
assert len(logs) == 1
|
||||
assert logs[0].percentage == 72
|
||||
assert logs[0].source == "poll"
|
||||
s.close()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Group 4 additions — history logging (routes / UI)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_charge_log_creates_pct_log_entry(ha_app, ha_client_f):
|
||||
"""Logging a charge creates a pct_log entry with percentage=100, source='charge'."""
|
||||
ha_client_f.post("/battery/add", data={"brand": "X", "count": "1"})
|
||||
ha_client_f.post("/battery/1/charge-log/add", data={"charged_date": "2026-04-13"})
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from models import BatteryPctLog
|
||||
engine = create_engine(ha_app.config["SQLALCHEMY_DATABASE_URI"])
|
||||
s = sessionmaker(bind=engine)()
|
||||
logs = s.query(BatteryPctLog).filter_by(battery_id=1).all()
|
||||
assert len(logs) == 1
|
||||
assert logs[0].percentage == 100
|
||||
assert logs[0].source == "charge"
|
||||
s.close()
|
||||
|
||||
|
||||
def test_manual_edit_creates_pct_log_entry(ha_client_f):
|
||||
"""Saving a new battery_percentage via edit-details creates a history entry."""
|
||||
ha_client_f.post("/battery/add", data={"brand": "X", "count": "1"})
|
||||
ha_client_f.post("/battery/1/edit-details", data={"battery_percentage": "65"})
|
||||
|
||||
resp = ha_client_f.get("/battery/1")
|
||||
assert b"65%" in resp.data
|
||||
assert b"manual" in resp.data # source shown in history table
|
||||
|
||||
|
||||
def test_manual_edit_no_log_when_unchanged(ha_client_f):
|
||||
"""Saving the same percentage twice produces only one history entry."""
|
||||
ha_client_f.post("/battery/add", data={"brand": "X", "count": "1"})
|
||||
ha_client_f.post("/battery/1/edit-details", data={"battery_percentage": "40"})
|
||||
ha_client_f.post("/battery/1/edit-details", data={"battery_percentage": "40"})
|
||||
|
||||
resp = ha_client_f.get("/battery/1")
|
||||
# "40%" appears once in the info section and once in history — not twice in history
|
||||
assert resp.data.count(b"40%") == 2
|
||||
|
||||
Reference in New Issue
Block a user