ESP8266 Projects

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):

AZDelivery MAX7219 Led Modul 8 Bit 7-Segmentanzeige LED Display für Arduino und Raspberry Pi
✔️ Versorgungsspannung: 5V; ✔️ 0.5" 7-Segmentanzeige; ✔️ Driver IC: MAX7219;...
4,79 EUR
AZDelivery 5 x 5V RGB LED Ring WS2812B 12-Bit 37mm kompatibel mit Arduino inklusive E-Book!
✔️ 12 leuchtstarke LEDs. Einzeln adressierbar; ✔️ Für Arduino, Digispark u.v.m.;...
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 EUR
AZDelivery 3 x Jumper Wire Kabel 40 STK. je 20 cm M2M Male to Male kompatibel mit Arduino und Raspberry Pi Breadboard
✔️ Länge der Kabel: 20 cm / 120 Stück pro Einheit / 120 Stück insgesamt; ✔️...
4,66 EUR

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

[democracy id=”5″]

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; //Dein Breitengrad
const float longitude = 8.40; //Dein Längengrad
const float altitude = 115.00; //Deine Höhe über Normalnull – 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);

  //Die neuen Farben auf dem NeoPixel ausgeben
  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-Zugangsdaten
const char* ssid = "WLAN-NETZWERK";
const char* password =  "PASSWORT";

//Koordinaten und Höhe über NN
const float latitude = 00.00; //Dein Breitengrad
const float longitude = 00.00; //Dein Längengrad
const float altitude = 00.00; //Deine Höhe über Normalnull – Optional


#include <ESP8266WiFi.h> //WiFI
#include <ArduinoJson.h> //JSON
#include <ESP8266HTTPClient.h> //API-Abfrage

//LED-Ring
#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

//Zeiten und Dauer
long riseTime = 0;
long currentTime = 0;
int duration = 0;
long timeUntilRise = 0; //Differenz riseTime - currentTime

//Ziffern für das 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;

//LED-Ring initiieren
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(12, 14, NEO_GRB + NEO_KHZ800); //14=D5

//Status OK = LEDs leuchten grün auf
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 = LEDs leuchten rot auf
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 zur Zeitabfrage
  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(); //Die Verbindung beenden

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

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

void apiCall() {

  if ((WiFi.status() == WL_CONNECTED)) { //Netzwerkstatus checken

    getCurrentTime(); //aktuelle Zeit abfragen

    HTTPClient http; //Instanz von HTTPClient starten

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

    int httpCode = http.GET(); //Antwort des Servers abrufen
    Serial.println(httpCode); //Antwort im Seriellen Monitor ausgeben

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

      String payload = http.getString(); //Daten in eine Variable speichern

      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); //Größe des Speichers zur JSON-Verarbeitung festlegen
      DeserializationError error = deserializeJson(doc, payload); //JSON parsen

      http.end(); //Die Verbindung zum Server beenden

      if (error) { //Fehlermeldung bei fehlerhafter Verarbeitung der Daten
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
        return;
      }

      JsonArray response = doc["response"];
      duration = response[0]["duration"]; // Länge des Überflugs in Sekunden speichern
      riseTime = response[0]["risetime"]; // Zeitpunkt des Überflugs in UTC als Unix Time speichern

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

      timeUntilRise = riseTime - currentTime; //Zeit bis zum Überflug berechnen
      Serial.println(timeUntilRise);

      if (timeUntilRise < 0) { //Wenn letzter Überflug schon vorüber ist, den nächsten nehmen:
        duration = response[1]["duration"]; // Länge des Überflugs in Sekunden speichern
        riseTime = response[1]["risetime"]; // Zeitpunkt des Überflugs in UTC als Unix Time speichern
        Serial.print("Risetime [1]: ");
        Serial.println(riseTime);
        timeUntilRise = riseTime - currentTime; //Zeit bis zum Überflug berechnen
        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); //Helligkeit des NeoPixel-Rings: 0-255

  Serial.begin(115200); //Verbindung zum Seriellen Monitor

  lc.shutdown(0, false); //Display "aufwecken"

  lc.setIntensity(0, 8); //Helligkeit des Displays einstellen
  lc.clearDisplay(0);

  WiFi.begin(ssid, password); //Internet-Verbindung starten

  while (WiFi.status() != WL_CONNECTED) { //Statusnachricht "Verbindung herstellen" solange nicht verbunden
    delay(1000);
    Serial.println("Connecting...");
  }

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

void loop() {

  apiCall(); //Überflugsdaten abrufen

  while (timeUntilRise > 0) {

    //Countdown berechnen und anzeigen
    timeUntilRise--;
    intoDigitstimeUntilRise();
    displayCountdown();
    delay(1000);
    lc.clearDisplay(0);
  }

  //Wenn der Überflug startet:
  if (timeUntilRise == 0) {
    Serial.println("ISS is coming.");
    Serial.print("overflight duration = ");
    Serial.println(duration);

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

      //Farbverlauf auf Duration mappen
      int colorRed = map(i, 0, duration, 200, 0);
      int colorBlue = map(i, 0, duration, 0, 200);

      //NeoPixel anschalten, alle 12 LEDs
      for (int j = 0; j < 12; j++) {
        pixels.setPixelColor(j, pixels.Color(colorRed, 0, colorBlue));
        pixels.show();
      }
      delay(1000);
    }
    //NeoPixel ausschalten
    for (int j = 0; j < 12; j++) {
      pixels.setPixelColor(j, LOW);
      pixels.show();
    }
  }
}

Letzte Aktualisierung am 2020-11-26 / Affiliate Links / Bilder von der Amazon Product Advertising API

You may also like

Comments are closed.