publish eve_rock_watcher.py
This commit is contained in:
parent
a728b529c5
commit
82b9ef3605
1 changed files with 29 additions and 13 deletions
|
|
@ -352,13 +352,16 @@ def main():
|
||||||
pytesseract.pytesseract.tesseract_cmd = tcmd
|
pytesseract.pytesseract.tesseract_cmd = tcmd
|
||||||
|
|
||||||
poll = max(poll, 8) # full-window OCR is heavy; don't spin
|
poll = max(poll, 8) # full-window OCR is heavy; don't spin
|
||||||
|
MAX_DROP_PS = 4000 / 60.0 # units/sec ceiling — a faster "drop" than this is a misread
|
||||||
print(f"[rock] started; switch<{switch_secs}s, poll {poll}s (waits for !mining on)")
|
print(f"[rock] started; switch<{switch_secs}s, poll {poll}s (waits for !mining on)")
|
||||||
hist = deque() # (t, units) for the currently-selected rock
|
hist = deque() # accepted (t, units), cleaned of OCR outliers
|
||||||
|
pending = None # a jumped value awaiting a confirming second read
|
||||||
last_status = 0.0
|
last_status = 0.0
|
||||||
last_alert = 0.0
|
last_alert = 0.0
|
||||||
|
last_ore = "rock"
|
||||||
while True:
|
while True:
|
||||||
if not w.bot_mining(cp): # only during a mining session
|
if not w.bot_mining(cp): # only during a mining session
|
||||||
hist.clear()
|
hist.clear(); pending = None
|
||||||
time.sleep(15)
|
time.sleep(15)
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
|
@ -367,26 +370,39 @@ def main():
|
||||||
if units is None: # no rock selected / popup not shown
|
if units is None: # no rock selected / popup not shown
|
||||||
time.sleep(poll)
|
time.sleep(poll)
|
||||||
continue
|
continue
|
||||||
# quantity jumped UP -> you locked a fresh rock; restart the measurement
|
if ore and ore != "rock":
|
||||||
if hist and units > hist[-1][1] + 50:
|
last_ore = ore
|
||||||
hist.clear()
|
# ---- reject OCR misreads (a stray digit makes 34,569 read as ~234,000) ----
|
||||||
hist.append((now, units))
|
if not hist:
|
||||||
|
hist.append((now, units)); pending = None
|
||||||
|
else:
|
||||||
|
lt, lu = hist[-1]
|
||||||
|
dt = max(1.0, now - lt)
|
||||||
|
if (lu - units) <= MAX_DROP_PS * dt + 400 and units <= lu + 40:
|
||||||
|
hist.append((now, units)); pending = None # normal depletion / flat
|
||||||
|
elif pending is not None and abs(units - pending) <= max(400, units * 0.03):
|
||||||
|
hist.clear(); hist.append((now, units)); pending = None # new rock, confirmed
|
||||||
|
else:
|
||||||
|
pending = units # outlier or jump — wait for confirmation
|
||||||
|
time.sleep(poll); continue
|
||||||
while hist and now - hist[0][0] > 180: # keep a ~3 min window
|
while hist and now - hist[0][0] > 180: # keep a ~3 min window
|
||||||
hist.popleft()
|
hist.popleft()
|
||||||
# true depletion rate from the number falling — captures ALL miners on the rock
|
# ---- depletion rate from the cleaned series (captures ALL miners on the rock) ----
|
||||||
rate = 0.0 # units/sec
|
rate = 0.0 # units/sec
|
||||||
if len(hist) >= 2 and (hist[-1][0] - hist[0][0]) >= 20:
|
if len(hist) >= 3 and (hist[-1][0] - hist[0][0]) >= 30:
|
||||||
du, dt = hist[0][1] - hist[-1][1], hist[-1][0] - hist[0][0]
|
du, dt = hist[0][1] - hist[-1][1], hist[-1][0] - hist[0][0]
|
||||||
rate = du / dt if du > 0 else 0.0
|
r = du / dt if du > 0 else 0.0
|
||||||
|
if 0 < r <= MAX_DROP_PS: # ignore impossible rates
|
||||||
|
rate = r
|
||||||
tleft = units / rate if rate > 0 else None
|
tleft = units / rate if rate > 0 else None
|
||||||
# live readout (edit-in-place, no spam)
|
# live readout (edit-in-place, no spam)
|
||||||
if post_rock and not w.bot_muted(cp) and now - last_status >= status_secs:
|
if post_rock and not w.bot_muted(cp) and now - last_status >= status_secs:
|
||||||
if tleft:
|
if tleft:
|
||||||
empty_at = int(now + tleft)
|
empty_at = int(now + tleft)
|
||||||
line = (f"🪨 {ore.title()} {units:,} u · ~{_fmt_dur(tleft)} left "
|
line = (f"🪨 {last_ore.title()} {units:,} u · ~{_fmt_dur(tleft)} left "
|
||||||
f"(empties <t:{empty_at}:R>) · {rate*60:,.0f} u/min")
|
f"(empties <t:{empty_at}:R>) · {rate*60:,.0f} u/min")
|
||||||
else:
|
else:
|
||||||
line = f"🪨 {ore.title()} {units:,} u · measuring rate…"
|
line = f"🪨 {last_ore.title()} {units:,} u · measuring rate…"
|
||||||
w._discord_live(cp, "rock", f"⛏️ {socket.gethostname()} current rock", line)
|
w._discord_live(cp, "rock", f"⛏️ {socket.gethostname()} current rock", line)
|
||||||
last_status = now
|
last_status = now
|
||||||
# switch-rocks alert when it's genuinely about to empty
|
# switch-rocks alert when it's genuinely about to empty
|
||||||
|
|
@ -394,10 +410,10 @@ def main():
|
||||||
last_alert = now
|
last_alert = now
|
||||||
empty_at = int(now + tleft)
|
empty_at = int(now + tleft)
|
||||||
w.notify(cp, "Switch rocks",
|
w.notify(cp, "Switch rocks",
|
||||||
f"{ore.title()} rock empties in ~{_fmt_dur(tleft)} "
|
f"{last_ore.title()} rock empties in ~{_fmt_dur(tleft)} "
|
||||||
f"(<t:{empty_at}:R>) — {units:,} u left. Lock a new rock.",
|
f"(<t:{empty_at}:R>) — {units:,} u left. Lock a new rock.",
|
||||||
priority="high", tags="pick,gem")
|
priority="high", tags="pick,gem")
|
||||||
print(f"[rock] ALERT {ore} {units} u, ~{_fmt_dur(tleft)} left")
|
print(f"[rock] ALERT {last_ore} {units} u, ~{_fmt_dur(tleft)} left")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[rock] error: {e}")
|
print(f"[rock] error: {e}")
|
||||||
time.sleep(poll)
|
time.sleep(poll)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue