Skip to content

Instantly share code, notes, and snippets.

@gomako
Created May 15, 2019 15:07
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save gomako/4bcd3731af11896e7985f0d88a0af0a5 to your computer and use it in GitHub Desktop.
Save gomako/4bcd3731af11896e7985f0d88a0af0a5 to your computer and use it in GitHub Desktop.
// Wifi Credentials
const WIFI_NAME = "YOURSSID";
const WIFI_PASS = "YOURPASS";
// Your location latitude and longitude
const lat = 'YOURLAT';
const lon = 'YOURLON';
// Required libs
const http = require("http");
const np = require("neopixel");
// Variable to store the time
let now;
// Variable to store ISS pass info
let iss;
// Variable to set the interval so we can clear it
let intervalId;
// Setup Wifi Shim according to instructions found here:
// https://www.espruino.com/ESP8266
digitalWrite(B9, 1); // enable on Pico Shim V2
Serial2.setup(115200, { rx: A3, tx: A2 });
// Turn LED off
np.write(B5, [0,0,0]);
/**
* Connect to WIFI
*/
var wifi = require("ESP8266WiFi_0v25").connect(Serial2, function (err) {
if (err) throw err;
console.log("Connecting to WiFi");
wifi.connect(WIFI_NAME, WIFI_PASS, err => {
if (err) throw err;
console.log("Connected");
// Once we have connected, set the UTC time
setTime();
});
});
/**
* Set the UTC time to sync with the ISS API
*/
function setTime() {
console.log("Setting Time");
http.get('http://worldclockapi.com/api/json/utc/now', res => {
let contents = '';
res.on("data", data => contents += data);
res.on("close", () => {
let timeJson = JSON.parse(contents);
now = new Date(timeJson.currentDateTime);
// Now we have set the time, let's get the ISS pass data
fetchData();
});
}).on("error", e => console.log("Error getting time: ", e));
}
/**
* Fetch the ISS Pass Data
*/
function fetchData() {
console.log("Fetching Data");
let url = `http://api.open-notify.org/iss-pass.json?lat=${lat}&lon=${lon}`;
http.get(url, res => {
let contents = '';
res.on("data", data => contents += data);
res.on("close", () => {
try {
iss = JSON.parse(contents);
// If we didn't have an error, all is good
if (iss.hasOwnProperty('message') && iss.message == 'success') {
// Calculate the interval between request time and next rise
let interval = (iss.response[0].risetime * 1000) - now.getTime();
let duration = iss.response[0].duration;
showDebug(iss);
// Set the timeout function (multiply the duration by 1k to convert to ms)
setTimeout(flashLED, interval, duration * 1000);
} else {
// Something went wrong, we'll try again in 30 seconds
setTimeout(fetchData, 30 * 1000);
}
} catch (e) {
// There was an error parsing the data, let's try again in 30 seconds
console.log("ERROR parsing ISS json", e);
setTimeout(fetchData, 30 * 1000);
}
});
}).on("error", (e) => {
// There was an error fetching the data, let's try again in 30 seconds
console.log("ERROR fetching data: ", e);
setTimeout(fetchData, 30 * 1000);
});
}
/**
* Flash the LED to notify us of the
*/
function flashLED(duration) {
console.log('ISS Overhead!');
let state = true;
intervalId = setInterval(() => {
if(state) np.write(B5, [100, 10, 10])
else np.write(B5, [10, 30, 100])
state = !state
}, 1000);
setTimeout(() => {
// Clear the interval
clearInterval(intervalId);
// Turn off LED
np.write(B5, [0,0,0]);
// Fetch more data!
setTime();
}, duration);
}
/**
* Show debug information in terminal
*/
function showDebug() {
console.log("Current time: ", now);
console.log("Next rise: ", new Date(iss.response[0].risetime * 1000));
console.log("Pass duration: ", iss.response[0].duration + " seconds. Or " + iss.response[0].duration / 60 + " minutes. ");
}
@gomako
Copy link
Author

gomako commented Jun 10, 2019

If you visit your api url you should be able to see that the json consists of the following:

{
    message: "success",
    request: {
        altitude: 230,
        datetime: 1560180377,
        latitude: 47.03453,
        longitude: 8.756765,
        passes: 5
    },
    response: [
        {
            duration: 649,
            risetime: 1560183385
        },
        {
            duration: 596,
            risetime: 1560189194
        },
        ...
    ]
}

So there are three top level properties in the json object, message, request and response

Really the only one you are interested in is response and I would think you access it like this response[0].risetime to just get the first one.

Looking at your code, you set your number of passes to const int n = 1; then you declare an array with one element, but then try and assign the second index of the response array to it. I've commented your code below:

    JsonObject& root = jsonBuffer.parseObject(http.getString());
    const char* message = root["message"]; 
    const int passes = root["passes"];

    const char* response[n] = {root["response[${n}]"]}; 
    /* 
    Here you are saying that you want to create an array with a single index (char* response[1]) and assign
    the index of the response that corresponds to n, which is this case is 1, or the second index, as the first index number is 0. 
    So as you have only asked for one pass, response[1] does not exist!
    You should say:
        const char* response[n-1] = {root["response[${n-1}]"]};
    Or to be explicit
        const char* response[0] = {root["response[0]"]};

    // What is this? There is no dayOfTheWeek in the JSON, I would get rid of it
    const char* dayOfTheWeek = root["dayOfTheWeek"];

Keep trying! It's very rewarding once you figure it all out. I would also try out one of the ArduinoJSON examples to make sure that everything is working correctly and that there isn't a bug with your Wemos. It'll help you figure out the syntax, and if in doubt, println it out!

@wooghee
Copy link

wooghee commented Jun 13, 2019

thank you so much for helping me!
with some help of the ArduinoJSON examples i got it to work (edit: no it does not, it seems i just programmed a converter, to deserialize a char, not actually pulling it from the API). even better I figured out that i do not need to connect to the worldclock API since the ISS one does already provide an accurate enough time (edit: thats still something I got right I think)

working code: see next comment

@gomako
Copy link
Author

gomako commented Jun 13, 2019

Excellent, glad to hear it's working!

@wooghee
Copy link

wooghee commented Jun 13, 2019

fixed some stuff; now it really works:


#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>


// Wifi Credentials
const char* ssid = "ssid";
const char* password = "password";

//API server                                                 lat           lon      
const String iss = "http://api.open-notify.org/iss-pass.json?lat=47.0532452&lon=8.356456&alt=";

//number of passes requested
int p = 2;
int i = 2;
int alt = 100;

//long nowtime;
long interval;
int duration;

void setup() 
{
  Serial.begin(115200);
  while (!Serial) continue;
  WiFi.begin(ssid, password);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);    // turn the LED off by making the voltage LOW
  
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(1000);
    Serial.println("Connecting...");
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED on
    delay(1000);                        
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED off by making the voltage LOW                       // 
  }
  
}

void loop() 
{
  if (WiFi.status() == WL_CONNECTED)
  {
    HTTPClient http;                                //Object of class HTTPClient
    http.begin(iss+alt);
    int httpCode = http.GET();
    Serial.print("\n\n\n\n\n\n\n================================================================================");
    Serial.print("\nconnected to:      ");
    Serial.println(iss+alt);
    if (httpCode > 0) 
    {
      const size_t capacity = JSON_ARRAY_SIZE(2) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(5) + 200;
      DynamicJsonBuffer jsonBuffer(capacity);

      String json = http.getString();
      
      JsonObject& root = jsonBuffer.parseObject(json);

      // test if parsing succeeded
      if (!root.success()) 
      {
        Serial.println("parseObject() failed");
        return;
      }

      String message = root["message"];                                           // "success"

      JsonObject& request = root["request"];
      int request_altitude = request["altitude"];                                 // 437
      long request_datetime = request["datetime"];                         // 1560370729
      float request_latitude = request["latitude"];                             // 47.0243543
      float request_longitude = request["longitude"];                      // 8.3034321
      int request_passes = request["passes"];                                   // 5
      
      int response_0_duration = root["response"][0]["duration"];           // 491
      long response_0_risetime = root["response"][0]["risetime"];          // 1560416345

      //save to global variables
      duration = response_0_duration;
      interval = ((response_0_risetime)-request_datetime);

      int response_1_duration = root["response"][1]["duration"];           // 639
      long response_1_risetime = root["response"][1]["risetime"];          // 1560422032
      
      Serial.print("\nstatus:            ");
      Serial.println(message);

      Serial.print("\nrequest time:      ");
      Serial.print(request_datetime);
      Serial.println(" unix timestamp");

      Serial.print("\nrequested passes:  ");
      Serial.println(request_passes);
      
       
      Serial.print("\nnext risetime:     ");
      Serial.print(response_0_risetime);
      Serial.println(" unix timestamp");

      Serial.print("\nnext flyover in:   ");
      Serial.print(interval);
      Serial.println(" seconds");

      Serial.print("\nduration:          ");
      Serial.print(duration);
      Serial.println(" seconds");

      json = "";                       // delete stored data
    }
    http.end(); //Close connection
  }

  while(interval<=duration) // check if ISS will come up within a the duration of next pass or is already up at this very moment
  {
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED on
    delay(250);                        
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED off by making the voltage LOW
    delay(250);                        
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED on
    delay(250);                        
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED off by making the voltage LOW
    delay(250);                              // that makes total 1 second delay
    interval--;
    if(interval==0)
    {
      interval=10000;
    }
  }
  if(interval>=duration)                    // if not, generate new request
  {
   alt++;
   if(alt==10000){  // increase altitude up to 10000
    alt=100;        // reset altitude
   }
  }
  //run setup again if connection is lost
  if (WiFi.status() != WL_CONNECTED) 
  {
    setup();
  }
  delay(60000);                        // wait 1 minute until next request.
}


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment