Only zero is empty, and the last day is worth reading

This commit is contained in:
2026-08-21 11:57:17 -04:00
parent bbda5cbfe9
commit 74392ccad2
7 changed files with 317 additions and 57 deletions

View File

@@ -74,12 +74,16 @@ MIN_DROP_FOR_ESTIMATE = 2
# precise-looking figure invites more trust than it has earned.
RATE_SPREAD_FACTOR = 5
# At or below this, the cartridge is done and the arithmetic stops being the
# useful answer. A supply sitting at 1% that drains a tenth of a point a day
# computes to ten days; a printer at 1% is out of toner as far as anyone
# standing at it is concerned, and it is what should be ordered first. Rate is
# still reported - only the days-left figure is floored.
EMPTY_LEVEL = 5
# Empty means empty. This was 5, on the reasoning that a printer at 1% is out
# of toner as far as anyone standing at it is concerned - but flooring the
# days-left of everything at or below 5% threw away the only number the row
# exists to give. A cartridge at 2% draining a point a day has two days left,
# and two days is worth knowing; reporting it as already gone puts it beside
# cartridges that genuinely are, and there is no way back to the difference.
#
# Anything above zero gets its real estimate, in hours if that is what it comes
# to. Only a reading of zero is empty.
EMPTY_LEVEL = 0
def _asfloat(value):
@@ -345,8 +349,8 @@ def analyse(points, rise=REPLACEMENT_RISE, currentlevel=None):
rate = burn_rate(run)
# Empty is empty. Ordering by a rate below this level ranks a dead
# cartridge behind a healthy one that happens to be draining faster.
# Empty is empty, and only zero is empty. Ordering by a rate at this level
# ranks a dead cartridge behind a healthy one that happens to drain faster.
if level <= EMPTY_LEVEL:
result['daysleft'] = 0
result['burnrateperday'] = round(rate, 2) if rate is not None else None
@@ -363,7 +367,13 @@ def analyse(points, rise=REPLACEMENT_RISE, currentlevel=None):
return result
result['burnrateperday'] = round(rate, 2)
result['daysleft'] = max(0, int(level / rate))
# Fractional, NOT int(). Truncating meant every cartridge with less than a
# full day left reported 0, which the bands read as empty and the view
# printed as "empty" - a cartridge with six hours in it was indistinguishable
# from one with nothing. Two decimal places is a quarter of an hour, which is
# finer than the estimate deserves but costs nothing and keeps the ordering
# of two nearly-spent cartridges meaningful.
result['daysleft'] = round(max(0.0, level / rate), 2)
# Say so when the intervals disagree wildly. The number is still the best
# estimate available; the flag stops it reading as a measurement.
result['rateunstable'] = rate_is_unstable(run)