Piehnat

01 Dez, 2025

Ich habe mir einen eigenen NBA-Stats-Server auf dem Raspberry 5 gebaut

Seit ich denken kann, bin ich NBA-Fan. Die 90er Jahre waren für mich die absolute Goldzeit. Jordan, Pippen, die Bulls-Dynastie, Shaq, Kobe… ich habe jede Minute verschlungen, jede Highlight-VHS zerlegt, jede Statistik ausgeschnitten und jedes Stickeralbum gefüttert. Basketball war damals nicht einfach nur ein Sport, es war meine Religion.

Ist es für mich heute irgendwie noch immer, aber heutzutage ist alles digital. Jede Bewegung wird getrackt, jede Aktion landet in Datenbanken von Apps oder Websites und dort nicht selten hinter Paywalls.

Da ich aber nun mal irgendwie ein Nerd bin und Wert auf Datenschutz lege, hab ich beschlossen, Statistiken und Analysen unter meine Kontrolle zu bringen und mir meine eigene kleine NBA-Statistikzentrale auf einem Raspberry Pi zu bauen.

 

Hardware & System

Der Raspberry Pi 5 ist ideal. Nicht nur, weil ich eh einen rumzufliegen habe. Er ist kompakt, stromsparend, leistungsfähig genug für Python, PostgreSQL und gelegentliche Analysen. Ich nutze Raspberry Pi OS Lite 64-Bit, weil es schlank ist, stabil läuft und genau das bietet, was ein Server-Setup braucht. Also kein Desktop-Schnickschnack.

 

Grundsetup

sudo apt update
sudo apt upgrade -y
sudo apt install postgresql postgresql-contrib git python3-pip -y

Diese Befehle aktualisieren das System, installieren PostgreSQL (die Datenbank), Git (für Codeverwaltung) und Python 3 mit Pip (damit ich Bibliotheken wie Requests oder SQLAlchemy installieren kann).

Dazu ein Python virtuelles Environment, um System-Pakete sauber zu halten:

python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install requests sqlalchemy psycopg2-binary pandas matplotlib

Damit erstelle ich eine isolierte Python-Umgebung, in der ich alle benötigten Bibliotheken installieren kann, ohne dass die System-Pakete durcheinander geraten.

 

PostgreSQL-Setup

sudo -i -u postgres
createuser pi -P          # Passwort eingeben (ggf. URL-kodiert, falls Sonderzeichen @, : etc.)
createdb nba
psql -c "GRANT ALL PRIVILEGES ON DATABASE nba TO pi;"
exit

Hier erstelle ich einen neuen Datenbank-User pi, lege eine Datenbank nba an und gebe dem volle Rechte. So sind meine Daten sauber getrennt und sicher.

 

Balldontlie API mit Pagination (next_cursor)

Die balldontlie API liefert JSON-Daten zu Spielern, Teams, Spielen und Statistiken. Bisschen nervig, aber seit kurzem braucht es einen API-Key (kostenlos nach Registrierung).

import requests

API_KEY = "DEIN_API_KEY"
headers = {"Authorization": f"Bearer {API_KEY}"}

url = "https://api.balldontlie.io/nba/v1/players?per_page=100"
cursor = None

while True:
    paged_url = url
    if cursor:
        paged_url += f"&cursor={cursor}"

    response = requests.get(paged_url, headers=headers)
    response.raise_for_status()  # Fehler sofort sichtbar
    data = response.json()

    # Hier die Daten speichern...

    cursor = data.get('meta', {}).get('next_cursor')
    if not cursor:
        break  # keine weiteren Seiten, Schleife beenden

Dieser Code ruft alle Spieler der NBA ab. Mit next_cursor hole ich sie Seite für Seite ab, bis keine mehr übrig ist. response.raise_for_status() sorgt dafür, dass Fehler wie ein falscher API-Key sofort angezeigt werden.

 

Daten in PostgreSQL speichern (SQLAlchemy 2.x-konform)

from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String

engine = create_engine('postgresql://pi:DEIN_PASSWORT@localhost/nba')
metadata = MetaData()

players = Table('players', metadata,
    Column('id', Integer, primary_key=True),
    Column('first_name', String),
    Column('last_name', String),
    Column('team', String)
)
metadata.create_all(engine)

# Beispiel Insert
with engine.begin() as conn:
    for p in data['data']:
        conn.execute(
            players.insert().values(
                id=p['id'],
                first_name=p['first_name'],
                last_name=p['last_name'],
                team=p['team']['full_name']
            )
        )

Hier wird die Datenbanktabelle players angelegt und die Spielerdaten eingefügt. Das with engine.begin() sorgt dafür, dass die Daten sicher und atomar eingefügt werden. SQLAlchemy 2.x verwendet diese Schreibweise statt des alten engine.execute().

 

Automatische Updates per Cronjob

crontab -e

Öffnet die Cronjob-Liste für den User.

0 2 * * * /usr/bin/python3 /home/pi/nba_fetch.py >> /home/pi/nba_fetch.log 2>&1

Script ausführbar machen (chmod +x nba_fetch.py) oder explizit mit /usr/bin/python3 starten. Absolute Pfade verwenden, Cron kennt andere Umgebungsvariablen.

 

Grafana auf dem Raspberry Pi

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://apt.grafana.com/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/grafana.gpg
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y grafana
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
sudo systemctl status grafana-server

Diese Befehle fügen das offizielle Grafana-Repository hinzu, installieren die Software und sorgen dafür, dass sie automatisch startet. Grafana ist ein Tool, mit dem ich meine NBA-Daten in übersichtlichen Diagrammen und Dashboards anzeigen und interaktiv auswerten kann. Mit sudo systemctl status grafana-server kann ich prüfen, ob Grafana läuft.

 

Zugriff: http://IP_DEINES_PI:3000/
Login: admin / admin (Passwort sofort ändern!)

 

PostgreSQL als Datenquelle

  • Host: localhost:5432
  • Datenbank: nba
  • User: pi
  • Passwort: DEIN_PASSWORT

Damit kann Grafana direkt auf die NBA-Daten zugreifen.

 

Erstes Dashboard – Spieler pro Team

SELECT team, COUNT(*) AS player_count
FROM players
GROUP BY team
ORDER BY player_count DESC;

Diese SQL-Abfrage zählt, wie viele Spieler jedes Team hat. In Grafana wähle ich den Panel-Typ „Bar chart“ und kann die Daten interaktiv anzeigen. Optional: im Query inspector prüfen, ob Daten zurückkommen, falls das Diagramm leer bleibt.

 

Ready

Jetzt habe ich ne vollständige, lokale NBA-Statistikzentrale

  • Daten automatisch per API abrufen (inkl. next_cursor Pagination)
  • In PostgreSQL speichern (SQLAlchemy 2.x-konform)
  • Automatisch aktualisieren per Cronjob
  • Interaktiv visualisieren mit Grafana

Endlich mein eigener NBA-Stats-Server, genau so, wie ich ihn will.

Hinterlasse einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Pflichtfelder sind mit * markiert. Deine Daten werden ausschließlich lokal gespeichert.