cover LEGO ISS

Beleuchte deine LEGO ISS im Rhythmus der echten Raumstation

Inhalt

Update April 2026: Dieses Projekt ist zurück! Nachdem die alte Open-Notify-API leider offline gegangen ist, haben wir bei Pollux Labs einen Nachfolger gebaut: die ISS Pass API. Sie liefert dir zuverlässig die nächsten Überflüge der ISS über deinem Standort. Der Sketch läuft weiterhin auf dem bewährten NodeMCU (ESP8266) – nur der Aufruf der API und das Parsen der Antwort haben sich geändert.

Das wirst du bauen

Deine LEGO ISS bekommt eine Unterkonstruktion mit einem NeoPixel-Ring und einem 8-stelligen 7-Segment-Display. Solange kein Überflug ansteht, zählt das Display die Sekunden bis zum nächsten Vorbeiflug der ISS herunter. Sobald die Station über dir erscheint, beginnt der Ring im Rhythmus des Überflugs zu leuchten – mit einem Farbverlauf von Blau zu Rot, während die ISS über den Himmel zieht.

YouTube

Mit dem Laden des Videos akzeptieren Sie die Datenschutzerklärung von YouTube.
Mehr erfahren

Video laden

Für dieses Projekt benötigst du – abgesehen von der LEGO ISS – nur wenige Bauteile. Damit das Projekt gut aussieht, kannst du zwei Boxen aus dem 3D-Drucker verwenden – eine für den ESP8266 und den NeoPixel, die andere für das 7-Segment-Display.

Für dieses Projekt benötigst du:

  • LEGO ISS-Set (21321)
  • NodeMCU ESP8266
  • NeoPixel-Ring mit 12 LEDs (37mm Durchmesser)
  • 8-stelliges 7-Segment-Display (MAX7219)
  • Breadboard & Kabel

Hinweis: Meistens werden die NeoPixel LED-Ringe unverlötet verkauft – du benötigst also noch einen Lötkolben plus Zubehör. Wenn du unsere Vorlagen für die Boxen verwenden möchtest, benötigst du auch einen 3D-Drucker und Filament.

Der Aufbau unter der LEGO ISS

Da die LEGO ISS auf einer Art Sockel steht, unter dem noch viel Platz ist, eignet sich dieser Ort besonders, um sie von unten zu beleuchten. Hier platzierst du also deinen ESP8266 und den NeoPixel-Ring. Das 7-Segment-Display für den Countdown bis zum nächsten Überflug liegt etwas abseits.

Aufbau ESP8266, Neopixel, Display unter der LEGO ISS

Auf dem Breadboard

Die Bauteile miteinander zu verbinden, dauert nur wenige Minuten. Verbinde deine Bauteile folgendermaßen:

NodeMCU → NeoPixel-Ring

ESP8266NeoPixel
3V3VCC
GNDGND
D5DIN

NodeMCU → 7-Segment-Display (MAX7219)

ESP82667-Segment-Display
3V3VCC
GNDGND
D6DIN
D7CS
D8CLK

Noch zwei Hinweise: Wenn du die Vorlagen für die Boxen aus dem 3D-Drucker verwendest, achte darauf, deinen ESP8266 an den glatten Rand des Mini-Breadboards zu setzen – die Seite, die keine Feder hat. Dann kannst du das USB-Kabel bequem durch ein Loch in der Box mit dem ESP8266 verbinden.

Unsere Box hat einen Innendurchmesser von 39 mm. Achte darauf, einen NeoPixel-Ring mit 37 mm Durchmesser zu verwenden. Diese werden jedoch teilweise fälschlicherweise mit einem Durchmesser von 39 mm verkauft. Egal wie, beide passen in die Box. 😉

So ungefähr sollte es aussehen, wenn du alles miteinander verbunden hast.

Die passenden Boxen

Natürlich kannst du dein Projekt auch „nackt“ unter deine LEGO ISS stellen. Allerdings sieht es aufgeräumter aus, wenn du deine Bauteile in Boxen unterbringst. Wenn du möchtest, kannst du unsere Vorlagen verwenden und sie mit einem 3D-Drucker ausdrucken. Hier findest du je zwei Boxen mit Deckel – eine für den ESP8266 samt NeoPixel und eine für das 7-Segment-Display.

Hinweis: Du kannst die Boxen natürlich in deiner Lieblingsfarbe ausdrucken – der Deckel der Box für den ESP8266 plus NeoPixel sollte jedoch transparent sein, damit das Licht durchscheinen und deine LEGO ISS von unten beleuchten kann.

Du findest unsere Vorlagen hier bei uns als Download.

Und so sehen die Bauteile in den Boxen aus. Wie du siehst führt ein Kabelstrang aus der Box für den ESP8266 zum 7-Segment-Display in der anderen Box. Wir haben hierfür 10 cm lange Kabel verwendet, aber die Wahl liegt natürlich bei dir.

Alle Bauteile in den passenden Boxen

Und das war es auch schon mit der Hardware. Weiter geht es mit dem Sketch.

Der passende Sketch

Nun also weiter zum Herzstück des Projekts: Der Code, mit dem du deine ISS zum Leuten bringst. Der folgende Sketch ruft die nächsten Überflugsdaten für deinen Standort von unserer API ab und steuert entsprechend das 7-Segment-Display und den NeoPixel-Ring.

___STEADY_PAYWALL___

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <Adafruit_NeoPixel.h>
#include <LedControl.h>
#include <time.h>

// ===== WLAN =====
const char* WIFI_SSID = "DEIN WLAN-NETZ";
const char* WIFI_PASS = "DEIN PASSWORT";

// ===== Dein Standort (Beispiel: Karlsruhe) =====
const float LATITUDE  = 49.00;
const float LONGITUDE =  8.40;
const float ALTITUDE  = 115.0;  // Meter über NN

// ===== Pollux Labs ISS Pass API =====
const char* API_HOST = "https://iss-api.polluxlabs.io/iss-pass";

// ===== Pins (NodeMCU) =====
#define NEOPIXEL_PIN  D5
#define NUMPIXELS     12
#define SEG_DIN       D6
#define SEG_CS        D7
#define SEG_CLK       D8

Adafruit_NeoPixel pixels(NUMPIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
LedControl lc = LedControl(SEG_DIN, SEG_CLK, SEG_CS, 1);

time_t passStart = 0;
time_t passEnd   = 0;

// ----- ISO 8601 (UTC) -> Unix-Zeit, zeitzonenunabhängig -----
time_t parseISO8601UTC(const char* iso) {
  int Y, M, D, h, m, s;
  if (sscanf(iso, "%d-%d-%dT%d:%d:%dZ", &Y, &M, &D, &h, &m, &s) != 6) return 0;
  static const int dim[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  long days = 0;
  for (int y = 1970; y < Y; y++)
    days += ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) ? 366 : 365;
  for (int mo = 0; mo < M - 1; mo++) {
    days += dim[mo];
    if (mo == 1 && ((Y % 4 == 0 && Y % 100 != 0) || Y % 400 == 0)) days++;
  }
  days += D - 1;
  return days * 86400L + h * 3600L + m * 60L + s;
}

// ----- Nächsten Überflug von der API holen -----
bool fetchNextPass() {
  WiFiClientSecure client;
  client.setInsecure();            // Hobbyprojekt: kein Zertifikatscheck

  HTTPClient http;
  String url = String(API_HOST)
             + "?lat=" + String(LATITUDE, 4)
             + "&lon=" + String(LONGITUDE, 4)
             + "&alt=" + String(ALTITUDE, 0)
             + "&n=1";

  if (!http.begin(client, url)) return false;

  int code = http.GET();
  if (code != 200) {
    Serial.printf("HTTP-Fehler: %d\n", code);
    http.end();
    return false;
  }

  JsonDocument doc;
  DeserializationError err = deserializeJson(doc, http.getStream());
  http.end();
  if (err) { Serial.println("JSON-Fehler"); return false; }

  JsonArray passes = doc["passes"].as<JsonArray>();
  if (passes.isNull() || passes.size() == 0) {
    Serial.println("Kein Überflug gefunden.");
    return false;
  }

  const char* startStr = passes[0]["rise"]["time"];
  const char* endStr   = passes[0]["set"]["time"];
  if (!startStr || !endStr) return false;

  passStart = parseISO8601UTC(startStr);
  passEnd   = parseISO8601UTC(endStr);

  Serial.printf("Nächster Überflug: %s -> %s\n", startStr, endStr);
  return true;
}

// ----- Sekunden rechtsbündig auf 8-stelligem Display anzeigen -----
void showSecondsCountdown(long secs) {
  if (secs < 0) secs = 0;
  for (int i = 0; i < 8; i++) lc.setChar(0, i, ' ', false);  // alle leer
  if (secs == 0) { lc.setDigit(0, 0, 0, false); return; }
  int pos = 0;
  while (secs > 0 && pos < 8) {
    lc.setDigit(0, pos, secs % 10, false);
    secs /= 10;
    pos++;
  }
}

// ----- NeoPixel-Animation während des Überflugs -----
void animatePass() {
  long total = passEnd - passStart;
  if (total <= 0) return;

  time_t now = time(nullptr);
  while (now < passEnd) {
    long remaining = passEnd - now;
    int red  = map(remaining, 0, total, 200, 0);
    int blue = map(remaining, 0, total,   0, 200);
    for (int j = 0; j < NUMPIXELS; j++) {
      pixels.setPixelColor(j, pixels.Color(red, 0, blue));
    }
    pixels.show();
    delay(1000);
    now = time(nullptr);
  }
  pixels.clear();
  pixels.show();
}

void setup() {
  Serial.begin(115200);

  pixels.begin();
  pixels.clear();
  pixels.show();

  lc.shutdown(0, false);
  lc.setIntensity(0, 4);
  lc.clearDisplay(0);

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.print("Verbinde mit WLAN");
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
  Serial.println("\nWLAN verbunden");

  configTime(0, 0, "pool.ntp.org", "time.nist.gov");  // UTC reicht uns
  while (time(nullptr) < 1700000000L) delay(200);
  Serial.println("Zeit synchronisiert");
}

void loop() {
  if (passStart == 0) {
    if (!fetchNextPass()) { delay(60000); return; }
  }

  time_t now = time(nullptr);

  if (now < passStart) {
    // Countdown in Sekunden bis zum nächsten Überflug
    showSecondsCountdown(passStart - now);
    delay(1000);
  } else if (now < passEnd) {
    // ISS ist gerade über uns: Ring animieren
    lc.clearDisplay(0);
    animatePass();
    passStart = 0;  // danach neu laden
  } else {
    passStart = 0;
    lc.clearDisplay(0);
  }
}

Die benötigten Bibliotheken

Für dieses Projekt benötigst du einige Bibliotheken, um z.B. das 7-Segment-Display, den NeoPixel-Ring zu steuern und die aktuelle Uhrzeit abzufragen. Installiere die folgenden Bibliotheken in deinem Bibliotheksmanager, falls sie noch nicht in deiner Arduino IDE verfügbar sind:

  • ArduinoJson (v7) von Benoît Blanchon
  • Adafruit NeoPixel
  • LedControl von Eberhard Fahle

Den ESP8266 mit dem Internet verbinden

Für dieses Projekt muss dein ESP8266 mit dem Internet verbunden sein. Zu diesem Thema haben wir ein eigenes Tutorial, in dem du lernst, wie das geht. Übrigens: Solltest du noch nie einen ESP8266 mit der Arduino IDE programmiert haben, lies hier nach, wie du die beiden verbindest.

Den nächsten Überflug der ISS ermitteln

Damit die Beleuchtung deiner LEGO ISS im Rhythmus der echten funktioniert, benötigst du zuerst die Überflugsdaten. Hier kommt die API von Pollux Labs ins Spiel. Mit ihr kannst du den nächsten Transit für deinen Standort mit deinem ESP8266 abfragen.

Trage deshalb zu Beginn des Sketchs deine Koordinaten ein. Falls du diese nicht kennst, kannst du sie z.B bei geoplaner.de ermitteln. Deine Höhe ist optional – wenn du sie weißt, wird das Ergebnis ein klein wenig genauer, wenn nicht, rechnet die API einfach mit einer Höhe von 100 Metern. Allerdings muss die Höhenangabe größer als Null sein – sonst funktioniert die API-Abfrage nicht.

Hier sind die Daten für Karlsruhe eingetragen:

const float LATITUDE = 49.00; //Dein Breitengrad
const float LONGITUDE = 8.40; //Dein Längengrad
const float ALTITUDE = 115.00; //Deine Höhe über Normalnull

Die fertige URL für das Beispiel Karlsruhe lautet dann wie folgt. Der Parameter n=5 bestimmt die Anzahl der nächsten Überflüge, die berechnet werden soll – hier also 5.

https://iss-api.polluxlabs.io/iss-pass?lat=49.00&lon=8.40&alt=115&n=1

Die Antwort der API auswerten

Wenn du diese Adresse testweise in deinem Browser öffnest, erhältst du ungefähr folgende Antwort:

Pollux Labs ISS API Antwort

Hierbei handelt es sich um Daten im JSON-Format, mit denen du noch nichts anfangen kannst.

Wie der Code arbeitet

Nach dem Verbinden mit dem WLAN synchronisieren wir die Uhrzeit per NTP in UTC. Für reine Zeit-Differenzen brauchen wir keine Zeitzone – wir vergleichen nur Unix-Sekundenwerte miteinander.

Anfrage an die API

Da die API HTTPS nutzt, verwenden wir `WiFiClientSecure` mit `setInsecure()`. Für ein Hobbyprojekt völlig ausreichend: wir vertrauen dem Server, prüfen aber sein Zertifikat nicht. Das Paar `setBufferSizes(512, 512)` hält den TLS-RAM-Verbrauch auf dem ESP8266 klein – sonst wird’s beim Parsen knapp.

Mit `n=1` fragen wir gezielt den nächsten Überflug ab, egal ob sichtbar oder nicht.

ISO-8601 parsen

Die alte API lieferte `risetime` als Unix-Zeit. Die neue gibt uns Strings wie `2026-04-22T19:32:04Z`. Die Funktion `parseISO8601UTC()` rechnet diese manuell in Unix-Sekunden um – zeitzonenunabhängig, damit die Umrechnung unter jeder gesetzten `TZ` sauber funktioniert.

Anzeige und Animation

  • Vor dem Überflug: das 8-stellige Display zählt die Sekunden bis zum nächsten Überflug herunter.
  • Während des Überflugs: der NeoPixel-Ring wechselt die Farbe von Blau zu Rot, synchron zur verbleibenden Überflugsdauer.
  • Nach dem Überflug: der ESP8266 fragt automatisch den nächsten Überflug ab.

Anpassungsmöglichkeiten

  • Andere Farben: Die RGB-Werte in `animatePass()` kannst du beliebig ändern.
  • Nur sichtbare Überflüge: Die API kennt einen zusätzlichen Filter für Überflüge, die tatsächlich mit bloßem Auge zu sehen sind (Sonne beleuchtet die ISS, Beobachter in Dämmerung oder Nacht). Hänge dazu `&visible_only=true` an die URL in `fetchNextPass()` an und lies statt `rise.time`/`set.time` die Felder `visible_start` und `visible_end` aus. Dann leuchtet die Lampe nur noch bei Überflügen, die du auch tatsächlich am Himmel sehen könntest.
  • Zusatzinfos: Statt des Countdowns könntest du auch die Himmelsrichtung (`rise.compass`) oder die maximale Elevation (`culmination.elevation_deg`) anzeigen.

Der Countdown

Apropos nächster Transit: Auf dem 7-Segment-Display soll ja ein Countdown bis zum nächsten Überflug erscheinen. Auch diesen Teil sparen wir hier aus, da du in diesem Tutorial nachlesen kannst, wie du ein 7-Segment-Display im Sketch ansteuerst. In diesem Projekt erfährst du alles zum Thema Countdown mit diesem Display.

Die LEGO ISS beleuchten

Nun hast du alle Bestandteile zusammen – laden den für deinen Standort angepassten auf deinen ESP8266. Wenn die echte ISS über den Horizont steigt, sollte deine LEGO ISS beleuchtet werden.

Die beleuchtete LEGO ISS

Speichere diesen Artikel auf deinem Computer

Auch interessant

Projekt ESP32 Internetradio

ESP32 Internetradio

Radio übers Internet zu hören, ist heute natürlich nichts Besonderes mehr – mit einem selbstgebauten ESP32 Internetradio allerdings schon! In diesem Tutorial baust du dir

Artikel lesen
Mehr Projekte für Arduino, ESP32, Raspi & Co
Werde Mitglied bei Pollux Labs und finde dein nächstes Projekt. Zum Beispiel:
Über 100 Maker sind bereits Mitglied bei Pollux Labs
  • ESP32 Internetradio
  • Arduino Wetterstation
  • ESP8266 & Raspi Webserver
  • Automatische Bewässerung
  • ... und viele mehr!