-
-
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. "); | |
} |
Hmm, I'm not sure. This part http://api.open-notify.org/iss-pass.json?lat=${lat}&lon=${lon}&alt=${alt}&n=${n}
Doesn't look like it should work with Arduino? I may be wrong. Have you tried putting the vars directly into the url?
thank you, it did not occur to me that the issue my be in the url itself,
I tried inserting the variables directly into the url but this did not work.
what seems to work is the following:
//initate the variables
const String iss = "http://api.open-notify.org/iss-pass.json?lat=";
const String lati = "47.03453&lon=";
const String longi = "8.756765&alt=";
const String alti = "230&n=";
const int p = 1;
//call api
http.begin(iss + lati + longi + alti + p);
writing this I think you meant i could just write the url as one single string, since it needs no changing during the program... i feel like an idiot now haha.
I will do this now:
const String iss = "http://api.open-notify.org/iss-pass.json?lat=47.03453&lon=8.756765&alt=230&n=1"
but i still cannot use the data coming from de server in my program.
I try to print everything to serial but it comes back empty:
status:
passes: 0
writing this I think you meant i could just write the url as one single string, since it needs no changing during the program... i feel like an idiot now haha.
This is what I feel like 99% of the time! Sometimes I explain the things I'm trying to do aloud to inanimate objects and that helps!
I had issues when setting the number of passes to 1 as it would sometimes return zero, or the pass that had already happened, so I just left that off, got the next 5 passes (the default I think) and took the first element in the pass array.
Unfortunately, I don't have a Wemos/ESP8x to test out the code with so I can't really help in terms of the JSON returned etc.
yeah I will try this for my next project :)
do you know if the JSON passes returned is a array with two dimensions? maybe if i try to run a for loop that choses an element and then saves it in its own array?
thank you for your help! really appreciate it :)
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!
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
Excellent, glad to hear it's working!
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.
}
:) Thank you for you fast and elaborate reply!
I looked into loading Espruino onto my board but did get it to work...
So I tried translating it into arduino code.
This is my first try at API and json stuff...
I got it to read out UTC time/date and store that in a char, but got stuck at json arrays for the passes form the open-notify server.
I think the array is two dimensional, I tried narrowing it down into a single dimension array by asking only for the next pass (n=1).
can you point me in the right direction?
this is what i got so far:
''
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
// Wifi Credentials
const char* ssid = "networkname";
const char* password = "password";
// Your location latitude, longitude, altitude and number of passes
const int lat = 47.0000;
const int lon = 8.0000;
const int alt = 450;
const int n = 1;
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("Connecting...");
}
}
void loop()
{
if (WiFi.status() == WL_CONNECTED)
{
HTTPClient http; //Object of class HTTPClient
http.begin("http://worldclockapi.com/api/json/utc/now");
int httpCode = http.GET();
}
delay(1000);
//run setup again if connection is lost
if (WiFi.status() != WL_CONNECTED) {
setup();
}
}
''