Du venter på en pakke, og du gidder ikke å laste sporingssiden om og om igjen som en nervøs katt. Transportøren har et status-API. Da kan du sette et lite script til å gjøre kjedejobben: sjekk med jevne mellomrom, oppdag når noe endrer seg, send et varsel. Så er du ferdig.
Mønsteret

Det samme mønsteret dukker opp overalt der noe eksponerer en status: pakkesporing, en byggejobb i CI, en ordre, en sensor på loftet. Du poller periodisk, sammenligner mot forrige verdi, og varsler bare når noe faktisk har endret seg. Det henger sammen av tre deler:
- En tilstandsfil som husker siste kjente status per pakke.
- Et diff-steg som holder det nye svaret opp mot det som står i filen.
- En varselkanal. Her bruker jeg en Discord-webhook.
Det kritiske her er idempotens. Kjører scriptet hver tredje time, vil du ikke ha det samme varselet dundrende inn fire ganger på rad. Regelen er grei nok: varsle kun ved reell endring, og skriv den nye statusen til filen etter at varselet er ute.
Tilstandsfilen
En enkel JSON-fil holder rede på siste status per sporingsnummer. Ingen database, ingen tabeller, ingenting å drifte.
{
"NO123456789": "Sendt fra terminal",
"NO987654321": "Levert"
}
Scriptet
Gangen er den samme hver gang: poll API-et, bygg opp den nye tilstanden, diff mot den lagrede, send varsel på det som har endret seg, og lagre helt til slutt.
import json, os, requests
STATE = os.path.expanduser("~/pakker/state.json")
WEBHOOK = os.environ["DISCORD_WEBHOOK"]
PAKKER = ["NO123456789", "NO987654321"]
def hent_status(nr):
r = requests.get(f"https://api.transportoer.example/track/{nr}", timeout=30)
r.raise_for_status()
return r.json()["events"][0]["status"]
def varsle(tekst):
requests.post(WEBHOOK, json={"content": tekst}, timeout=30)
gammel = json.load(open(STATE)) if os.path.exists(STATE) else {}
ny = {}
for nr in PAKKER:
try:
ny[nr] = hent_status(nr)
except Exception:
ny[nr] = gammel.get(nr) # behold forrige ved feil
for nr, status in ny.items():
if status and status != gammel.get(nr):
varsle(f"Pakke {nr}: {status}")
json.dump(ny, open(STATE, "w"), ensure_ascii=False, indent=2)
Legg merke til feilhåndteringen. Feiler et kall, beholder vi forrige status i stedet for å skrive None over den. Uten det ville en kortvarig API-hikke gitt deg et falskt varsel ved neste vellykkede kjøring, og da er vi like langt.
Cron

Hver tredje time holder i massevis. Oftere er bortkastet: transportøren oppdaterer uansett ikke i sanntid, og du slipper å mase på API-et med kall som ikke gir deg noe nytt.
0 */3 * * * DISCORD_WEBHOOK=https://discord.com/api/webhooks/xxx \
/usr/bin/python3 /home/bruker/pakker/track.py >> /home/bruker/pakker/track.log 2>&1
Oppsummering
Rundt 25 linjer kode og én linje cron. Ingen app, ingen server, ingen push-tjeneste å abonnere på. Poenget er egentlig ikke pakkesporing i seg selv, men mønsteret bak: har noe et status-API, kan du polle det, diffe mot forrige tilstand og varsle på endring. Hold det idempotent, så plager det deg aldri med duplikater.



