Pakkesporing med et Python-script, cron og Discord-varsel

Transportøren har et status-API, så et script kan sjekke pakken i stedet for at du laster sporingssiden på nytt. Scriptet poller API-et, oppdager endringer og sender varsel til Discord.

Mønsteret

Skjematisk flytdiagram: cron utløser scriptet, som poller transportørens status-API, sammenligner mot tilstandsfilen, og sender varsel til Discord kun ved endring

Mønsteret passer for alt som har en status: pakkesporing, en byggejobb i CI, en ordre, en sensor på loftet. Poll periodisk, sammenlign med forrige verdi, og varsle bare ved endring. Det har tre deler:

  • En tilstandsfil som husker siste kjente status per pakke.
  • Et diff-steg som sammenligner det nye svaret med det som står i filen.
  • En varselkanal. Her er det en Discord-webhook.

Scriptet må være idempotent. Kjører det hver tredje time, skal samme status ikke gi fire like varsler. Varsle bare ved reell endring, og skriv den nye statusen til filen etter at varselet er sendt.

Tilstandsfilen

En JSON-fil holder siste status per sporingsnummer. Det trengs ingen database.

{
"NO123456789": "Sendt fra terminal",
"NO987654321": "Levert"
}
ScriptetRekkefølgen er: poll API-et, bygg ny tilstand, sammenlign med den lagrede, varsle om endringer og lagre 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)
Feiler et kall, beholder scriptet forrige status i stedet for å skrive None over den. Ellers ville en kortvarig feil i API-et gitt et falskt varsel ved neste vellykkede kjøring.

Cron

Skjematisk tidslinje: scriptet kjøres hver tredje time gjennom døgnet, med markerte kjøretidspunkter og idempotent tilstandssjekk mellom hver kjøring

Hver tredje time er nok. Transportøren oppdaterer ikke i sanntid, så hyppigere kall gir ingen ny informasjon.

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
Scriptet er rundt 25 linjer, og crontab trenger én linje.