cover LEGO ISS

Light up your LEGO ISS in the rhythm of the real space station

How about if your LEGO ISS lights up as soon as the real International Space Station flies over it? In this project, you make that happen. You will learn how to find out the time of the next flyover so that you can program a countdown and then light up a NeoPixel LED ring at the right moment. Let’s go! 🙂

YouTube

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

Video laden

For this project you need – apart from the LEGO ISS – only a few parts. To make the project look reasonably good, we use two boxes from the 3D printer – one for the ESP8266 and the NeoPixel, the other for the 7-segment display.

Advanced

1 – 2 hours– without setting up the LEGO ISS 😉

approx. $20 plus costs for the LEGO ISS and 3D printing

For this project you need(quantities see description):

Angebot
LEGO 21321 Ideas Internationale Raumstation
LEGO 21321 Ideas Internationale Raumstation
Verpackungsabmessungen (L x B x H): 6.9 x 26.2 x 38.2 Zm; Beschreibung der Altersgruppe:...
80,99 €
AZDelivery MAX7219 LED Modul TM1637 8 Bit 7-Segmentanzeige LED Display kompatibel mit Raspberry Pi inklusive E-Book!
AZDelivery MAX7219 LED Modul TM1637 8 Bit 7-Segmentanzeige LED Display kompatibel mit Raspberry Pi inklusive E-Book!
✅ Versorgungsspannung: 5V; ✅ 0.5" 7-Segmentanzeige; ✅ Driver IC: MAX7219; ✅...
4,79 €
AZDelivery 5 x 5V RGB LED Ring WS2812B 12-Bit 38mm kompatibel mit Arduino inklusive E-Book!
AZDelivery 5 x 5V RGB LED Ring WS2812B 12-Bit 38mm kompatibel mit Arduino inklusive E-Book!
✅ 12 leuchtstarke LEDs. Einzeln adressierbar; ✅ Kompatibel mit Digispark u.v.m.; ✅...
15,99 €
ELEGOO 6er Set 170 Tie Points Mini Breadboard Kit fĂŒr Arduino
ELEGOO 6er Set 170 Tie Points Mini Breadboard Kit fĂŒr Arduino
Diese Teile sind gut um ganz kleine Schaltungen oder nur einen Chip zu verdraten.; 6...
7,99 €
AZDelivery 3 x Jumper Wire Kabel 40 STK. je 20 cm M2M Male to Male kompatibel mit Raspberry Pi Breadboard
AZDelivery 3 x Jumper Wire Kabel 40 STK. je 20 cm M2M Male to Male kompatibel mit Raspberry Pi Breadboard
✅ LĂ€nge der Kabel: 20 cm / 120 StĂŒck pro Einheit / 120 StĂŒck insgesamt; ✅...
4,66 €

Note:Most of the NeoPixel LED rings are sold unsoldered – so you will need a soldering iron plus accessories. If you want to use our templates for the boxes, you will need a 3D printer and filament.

The set up beneath the LEGO ISS

Since the LEGO ISS stands on a kind of pedestal, under which there is still plenty of space, this place is particularly suitable for lighting it from below. So this is where your ESP8266 and NeoPixel ring goes. The 7-segment display for the countdown to the next overflight is a bit aside.

Set up ESP8266, neopixel, display under the LEGO ISS

On the Breadboard

It only takes a few minutes to assemble the components. Use the following table to set up the system:

ESP8266NeoPixel
3v3VCC
GNDGND
D5IN
ESP82667-Segment Display
3v3VCC
GNDGND
D6DIN
D7CLK
D8CS

Two more notes: If you use our template for the boxes from the 3D printer, make sure to place your ESP8266 on the smooth edge of the mini breadboard, which means it has no spring. Then you can easily connect the USB cable to ESP8266 through a hole in the box.

Our box has an inner diameter of 39 mm. Make sure to use a NeoPixel ring with 37 mm diameter. However, some of these are wrongly sold with a diameter of 39 mm. No matter how, both fit into the box 😉

It should look something like this when you have it all connected.

The right boxes

Of course you can also put your project “naked” under your LEGO ISS. However, it will look tidier if you put your components in boxes. If you like, you can use our templates and print them out with a 3D printer. Here you’ll find two lidded boxes – one for the ESP8266 with NeoPixel and one for the 7-segment display.

Note: You can of course print the boxes in your favorite color – but the lid of the box for ESP8266 plus NeoPixel should be transparent so that the light can shine through and illuminate your LEGO ISS from below.

You can find our templates here as download.

And this is what the components in the boxes look like. As you can see, some wires lead from the box for the ESP8266 to the 7-segment display in the other box. We used 10 cm long cables for this, but the choice is of course yours.

All components in the appropriate boxes

And that was it with the hardware. Now we continue with the sketch.

The right sketch

You can find the complete sketch here on Github and at the end of this post. Let’s take a closer look at the most important parts of the code.

The required libraries

For this project you will need some libraries to control the 7-segment display and the NeoPixel Ring, for example. Install the following libraries in your Library Manager if they are not already available in your Arduino IDE:

ArduinoJson.h
ESP8266HTTPClient.h
Adafruit_NeoPixel.h
LedControl.h

Connecting the ESP8266 to the Internet

For this project, your ESP8266 must be connected to the Internet. We have a separate tutorial on this topic, where you can learn how to connect your ESP8266 to your Wi-Fi. By the way: Read this tutorial, if you’ve never programmed an ESP8266 with the Arduino IDE before.

Determine the next ISS overflight

In order for the lighting on your LEGO ISS to work at the rhythm of the real one, you first need the flyover data. This is where the API of open-notify.org comes into play. With it you can request the next transit for your location with your ESP8266 for free.

Therefore enter your coordinates at the beginning of the sketch. If you don’t know them, you can find them e.g. at geoplaner.de Your altitude is optional – if you know it, the result will be a little bit more accurate, if not, the API simply calculates an altitude of 100 meters. Here are the data for Karlsruhe, Germany:

const float latitude = 49.00; //Your Latitude
const float longitude = 8.40; //Your Longitude
const float altitude = 115.00; //Height above sea level – Optional

The sketch contains the function apiCall() – here the overflight data of the ISS for your location at the API of open-notify.org are retrieved and processed. First the request: With the function http.begin() you retrieve the data from the API address. For this you need the latitude and longitude and optionally the altitude, which you have already stored in the respective constants above. The URL within the function can be easily extended with this data:

http.begin("http://api.open-notify.org/iss-pass.json?lat=" + String(latitude) + "&lon=" + String(longitude) + "&alt=" + String(altitude) + "&n=5");

The finished URL for the example Karlsruhe is then as follows. The parameter n=5 determines the number of next overflights to be calculated – in this case 5.

http://api.open-notify.org/iss-pass.json?lat=49&lon=8.4&alt=115&n=5

Interpreting the response of the API

If you open this address in your browser as a test, you will receive the following answer:

Answer of the API

These are data in JSON format, which you can’t do anything with yet. What you need is the data contained in the key response: duration and risetime (the time when the ISS rises above the horizon and becomes theoretically visible from your location).

The pair duration-risetime is included 5 times in the response, because you requested it with n=5. All 5 together are an array and represent the value of the key response. The first pair is the next overflight, the second the next but one and so on. Later we will pick the needed pair from the array.

But first you store this JSON data as a whole in the variable payload:

String payload = http.getString();

Then the library ArduinoJson comes into play. We also have a tutorial for this, so we skip the parsing of the JSON data here.

Rather, we jump right to the part where you save the duration and time of the next flyover. As you can see in the code right below, we pick the first entry of the above mentioned array with [0].

duration = response[0]["duration"];
riseTime = response[0]["risetime"];

But what if the risetime has already passed, but the API still outputs this time as the next overflight? In this case you take the second entry, which you select with [1].

How long will it take until the ISS comes?

You now have the time of the next pass, but your ESP8266 does not know how long it will take until then. There is another function in the sketch for this: getCurrentTime()

This works in principle very similar to the function apiCall() above, except that it uses a different API to determine the current time and store it in the variable currentTime.

You then calculate the time until the ISS appears as follows:

timeUntilRise = riseTime - currentTime;

The variable timeUntilRise now contains the duration until the next flyover – in seconds. One more hint: Both the present time currentTime and the time of the flyover riseTime are retrieved as Unix time. These are the seconds that have passed since January 1, 1970. This has the advantage that you are independent of time shift, summer and winter time: Simply enter the seconds until the next transit of the ISS into the variable timeUntilRise and you are done 😉

The Countdown

Speaking of the next transit: The 7-segment display should show a countdown until the next pass. We will also leave this part out here, because you can read in this tutorial how to control a 7-segment-display in a sketch. In this project you will learn everything about countdown with this display.

Illuminating the LEGO ISS

Now it is time for some light. So when the real ISS rises above the horizon, the LEGO ISS should be illuminated.

The illuminated LEGO ISS

This is where the NeoPixel-Ring with its LEDs comes into play. You will have guessed it, also for this we already have a tutorial where you can read how to use a NeoPixel-Ring.

But in this project you go one step further: The LED ring should not only light up, but also change its color for the duration of the flyover. For this you need the variable duration, which you have filled with the duration of the flyover.

This variable is now used in the function map(). Here you calculate every second a new color value that all 12 LEDs on the ring should have – from blue at the beginning of the flyover to a deep red just before the ISS disappears behind the horizon again.

for (int i = duration; i >= 0; i--) {
  int colorRed = map(i, 0, duration, 200, 0);
  int colorBlue = map(i, 0, duration, 0, 200);

  //Show colors on NeoPixel
  for (int j = 0; j < 12; j++) {
    pixels.setPixelColor(j, pixels.Color(colorRed, 0, colorBlue));
    pixels.show();
  }
  delay(1000);
}

The map() function is not easy to understand at first sight, but the official Arduino documentation illuminates this topic quite well.

Experiment a bit with the RGB values for the NeoPixel to adjust the gradient to your taste. Or delete this function completely to illuminate the ISS in just one color.

And that’s it! 🙂 Here is the whole sketch:

/*********
  Frederik Kumbartzki
  Complete project details at https://polluxlabs.net
*********/

// WIFI Credentials
const char* ssid = "NETWORK";
const char* password =  "PASSWORD";

//Coordinates
const float latitude = 00.00; //Your Latitude
const float longitude = 00.00; //Your Longitued
const float altitude = 00.00; //Height above sea level – Optional


#include <ESP8266WiFi.h> //WiFi
#include <ArduinoJson.h> //JSON
#include <ESP8266HTTPClient.h> //API request

//NeoPixel
#include <Adafruit_NeoPixel.h>

//7-Segment Display
#include <LedControl.h>
LedControl lc = LedControl(12, 15, 13, 1); //12=D6=DIN, 15=D8=CLK, 13=D7=CS

//Times and duration
long riseTime = 0;
long currentTime = 0;
int duration = 0;
long timeUntilRise = 0; //Difference riseTime - currentTime

//Digits for the 7-Segment Display
int a = 8;
int b = 7;
int c = 6;
int d = 5;
int e = 4;
int f = 3;
int g = 2;
int h = 1;

//Initiate NeoPixel
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(12, 14, NEO_GRB + NEO_KHZ800); //14=D5

//Status OK
void success() {
  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 255, 0));
    pixels.show();
  }
  delay(100);

  for (int i = 11; i >= 0; i--) {
    pixels.setPixelColor(i, LOW);
    pixels.show();
  }
}

//Status Failed
void fail() {
  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, pixels.Color(255, 0, 0));
    pixels.show();
    delay(100);
  }

  for (int i = 11; i >= 0; i--) {
    pixels.setPixelColor(i, LOW);
    pixels.show();
    delay(100);
  }
}

void getCurrentTime() {

  HTTPClient http;
  http.begin("http://worldtimeapi.org/api/timezone/Europe/Berlin"); //URL for time request
  int httpCode = http.GET();

  if (httpCode == 200) { //200 = OK

    success();

    String payload = http.getString();

    const size_t capacity = JSON_OBJECT_SIZE(15) + 550;
    DynamicJsonDocument doc(capacity);
    DeserializationError error = deserializeJson(doc, payload);
    http.end(); //Close connection

    if (error) {
      Serial.print(F("deserializeJson() failed(current time): "));
      Serial.println(error.c_str());
      return;
    }
    currentTime = doc["unixtime"]; //Save current time in UTC as Unix Time
    Serial.print("current time= ");
    Serial.println(currentTime);

  } else {
    Serial.println("Error on HTTP request");
    fail();
  }
}

void apiCall() {

  if ((WiFi.status() == WL_CONNECTED)) { //Check network status

    getCurrentTime(); //Get current time

    HTTPClient http; //Instance of HTTPClient

    http.begin("http://api.open-notify.org/iss-pass.json?lat=" + String(latitude) + "&lon=" + String(longitude) + "&alt=" + String(altitude) + "&n=5"); //URL for request

    int httpCode = http.GET();
    Serial.println(httpCode);
    if (httpCode == 200) { //200 = OK

      String payload = http.getString(); //Save data in variable

      const size_t capacity = JSON_ARRAY_SIZE(5) + 5 * JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(5) + 190;
      DynamicJsonDocument doc(capacity); //Set memory
      DeserializationError error = deserializeJson(doc, payload); //Parse JSON

      http.end(); //Close connection

      if (error) {
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
        return;
      }

      JsonArray response = doc["response"];
      duration = response[0]["duration"]; // Duration of fly-by
      riseTime = response[0]["risetime"]; // Time of next fly-by

      Serial.print("Risetime [0]: ");
      Serial.println(riseTime);

      timeUntilRise = riseTime - currentTime; //Calculate time until fly-by
      Serial.println(timeUntilRise);

      if (timeUntilRise < 0) {
        duration = response[1]["duration"];
        riseTime = response[1]["risetime"];
        Serial.print("Risetime [1]: ");
        Serial.println(riseTime);
        timeUntilRise = riseTime - currentTime;
        Serial.println(timeUntilRise);
      }
    }
    else {
      Serial.println("Error on HTTP request");
    }
  }
}

void intoDigitstimeUntilRise() {

  h = timeUntilRise % 10;
  Serial.println(timeUntilRise);

  if (timeUntilRise > 9) {
    g = (timeUntilRise / 10) % 10;
  }
  if (timeUntilRise > 99) {
    f = (timeUntilRise / 100) % 10;
  }
  if (timeUntilRise > 999) {
    e = (timeUntilRise / 1000) % 10;
  }
  if (timeUntilRise > 9999) {
    d = (timeUntilRise / 10000) % 10;
  }
  if (timeUntilRise > 99999) {
    c = (timeUntilRise / 100000) % 10;
  }
  if (timeUntilRise > 999999) {
    b = (timeUntilRise / 1000000) % 10;
  }
  if (timeUntilRise > 9999999) {
    a = (timeUntilRise / 10000000) % 10;
  }
}

void displayCountdown() {

  lc.setDigit(0, 0, h, false);

  if (timeUntilRise > 9) {
    lc.setDigit(0, 1, g, false);
  }
  if (timeUntilRise > 99) {
    lc.setDigit(0, 2, f, false);
  }
  if (timeUntilRise > 999) {
    lc.setDigit(0, 3, e, false);
  }
  if (timeUntilRise > 9999) {
    lc.setDigit(0, 4, d, false);
  }
  if (timeUntilRise > 99999) {
    lc.setDigit(0, 5, c, false);
  }
  if (timeUntilRise > 999999) {
    lc.setDigit(0, 6, b, false);
  }
  if (timeUntilRise > 9999999) {
    lc.setDigit(0, 7, a, false);
  }
}

void setup() {

  pixels.begin();
  pixels.setBrightness(250); //Brightness of NeoPixel: 0-255

  Serial.begin(115200);

  lc.shutdown(0, false);

  lc.setIntensity(0, 8);
  lc.clearDisplay(0);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting...");
  }

  delay(1000);
  Serial.println("Hello, world!");
}

void loop() {

  apiCall(); //Get ISS fly-by data

  while (timeUntilRise > 0) {

    //Calculate and show countdown
    timeUntilRise--;
    intoDigitstimeUntilRise();
    displayCountdown();
    delay(1000);
    lc.clearDisplay(0);
  }

  if (timeUntilRise == 0) {
    Serial.println("ISS is coming.");
    Serial.print("overflight duration = ");
    Serial.println(duration);

    for (int i = duration; i >= 0; i--) {

      int colorRed = map(i, 0, duration, 200, 0);
      int colorBlue = map(i, 0, duration, 0, 200);

      //Start NeoPixel
      for (int j = 0; j < 12; j++) {
        pixels.setPixelColor(j, pixels.Color(colorRed, 0, colorBlue));
        pixels.show();
      }
      delay(1000);
    }
    //Turn off NeoPixel
    for (int j = 0; j < 12; j++) {
      pixels.setPixelColor(j, LOW);
      pixels.show();
    }
  }
}

Letzte Aktualisierung am 2021-06-23 / Affiliate Links / Bilder von der Amazon Product Advertising API

Also interesting