// #include <FastLED.h>
// #include <WiFi.h>
// #include <HTTPClient.h>
// #include <ArduinoJson.h>
// // How many leds in your strip?
// #define NUM_LEDS 8
// // For led chips like Neopixels, which have a data line, ground, and power, you just
// // need to define DATA_PIN.
// #define DATA_PIN 2
// // Define the array of leds
// CRGB leds[NUM_LEDS];
// // Airport list
// String icao[] = {"KRPH", "KBKD", "K6P9", "KETN", "KGZN", "KABI", "KDYS", "KSWW"};
// void setup() {
// Serial.begin(115200);
// Serial.println("resetting");
// FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
// FastLED.setBrightness(100);
// fetchMetars(DATA_PIN, icao, NUM_LEDS);
// }
// void fetchMetars(int pin, String icao[], int numIcao) {
// WiFiClientSecure client;
// client.setInsecure();
// HTTPClient http;
// http.useHTTP10(true);
// // String url = "https://aviationweather.gov/api/data/metar?ids=" + icao[0] + delim + icao[1] + delim + icao[2] + "&format=json";
// String url = "https://aviationweather.gov/api/data/metar?ids=";
// for (int i = 0; i < numIcao; i++) {
// if (i < numIcao - 1) {
// url += icao[i] + "%2C";
// } else {
// url += icao[i];
// }
// }
// url += "&format=json";
// Serial.println("Pulling METARs from: " + url);
// http.begin(client, url);
// // http.begin(url);
// int responseCode = http.GET();
// String result = http.getString();
// Serial.println("JSON Recieved: " + result);
// DynamicJsonDocument doc(16384);
// DeserializationError error = deserializeJson(doc, result);
// // Serial.println("METAR: " + doc[0]["rawOb"]);
// // Test if parsing succeeds.
// if (error) {
// Serial.print(F("deserializeJson() failed: "));
// Serial.println(error.f_str());
// return;
// }
// // Note this implementation only chceks the lowest reported clouds
// for (int i = 0; i < numIcao; i++) {
// JsonObject root = doc[i];
// String metarRaw = root["rawOb"];
// // Serial.println(metarRaw);
// String lowest_cover = root["clouds"][0]["cover"];
// String lowest_base = root["clouds"][0]["base"];
// String visib = root["visib"];
// Serial.println(icao[i] + " ceiling: " + lowest_cover + " @ " + lowest_base + " ft\tVisibility: " + visib + " mi");
// bool ceiling = false;
// int ceiling_num = -1;
// // if clouds > 0:
// // for x in range(len(clouds)):
// // cloud = clouds[x]
// if (isDigit(lowest_base[0])) {
// if (lowest_cover == "BKN" || lowest_cover == "OVC") {
// // lowest_cover = cloud['cover']
// // lowest_base = cloud['base']
// ceiling = true;
// // ceiling_num = x;
// // break
// }
// } else {
// Serial.println("No clouds!");
// }
// float vis = 0;
// if (visib == "10+") {
// vis = 10;
// } else {
// vis = visib.toInt();
// }
// int base = lowest_base.toInt();
// if (lowest_cover == "CLR") {
// Serial.println("CLR WX!");
// leds[i] = CRGB(0, 255, 0);
// Serial.println(icao[i] + " is VFR");
// } else {
// // Serial.println("CEILING!");
// if (base < 500 || vis < 1) {
// leds[i] = CRGB(255, 0, 255);
// Serial.println(icao[i] + " is LIFR");
// } else if (base < 1000 || vis < 3) {
// leds[i] = CRGB(255, 0, 0);
// Serial.println(icao[i] + " is IFR");
// } else if (base < 3000 || vis < 5) {
// leds[i] = CRGB(0, 0, 255);
// Serial.println(icao[i] + " is MVFR");
// // }
// } else {
// Serial.println("NO CEILING!");
// leds[i] = CRGB(0, 255, 0);
// Serial.println(icao[i] + " is VFR");
// }
// }
// Serial.println("\n");
// FastLED.show();
// }
// }
// void loop() {
// // Loop through each LED and set it to blue
// // for (int dot = 0; dot < NUM_LEDS; dot++) {
// // leds[dot] = CRGB::Blue; // Set the current LED to blue
// // FastLED.show(); // Update LEDs
// // leds[dot] = CRGB::Black; // Clear the current LED
// // delay(100); // Wait for a short period before moving to the next LED
// // }
// }
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <FastLED.h> // Include FastLED library
const char* ssid = "Wokwi-GUEST";
const char* password = "";
#define DATA_PIN_1 2
#define NUM_ICAO 8
#define NUM_LEDS 8 // Number of LEDs in the chain
#define BRIGHTNESS 8
#define UPDATE_IN_SEC 300 // Update interval in seconds (Default is 5 min)
unsigned long lastMillis;
CRGB leds[NUM_LEDS]; // Array to hold LED color data
String ICAOS[NUM_ICAO] = {"KBVY", "KLWM", "KASH", "KFIT", "KBED", "KBOS", "KGHG", "KPYM"};
void setup() {
Serial.begin(115200);
FastLED.addLeds<NEOPIXEL, DATA_PIN_1>(leds, NUM_LEDS); // Initialize LEDs
FastLED.setBrightness(BRIGHTNESS); // Set LED brightness
for (int n = 0; n < NUM_ICAO; n++) {
leds[n] = CRGB::White;
}
FastLED.show();
WiFi.begin(ssid, password);
Serial.println("");
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.print("\nOK! IP=");
Serial.println(WiFi.localIP());
fetchMetars(ICAOS, NUM_ICAO);
lastMillis = millis();
}
void fetchMetars(String icao[], int n) {
// Set up WiFi and HTTP clients
// WiFiClientSecure client;
// client.setInsecure(); // Yeah this is not ideal but this shouldn't be a securty issue for this project...
WiFiClient client;
HTTPClient http;
http.useHTTP10(true);
// Construct URL based off ICAOs supplied above
String delim = "%2C";
String url = "https://aviationweather.gov/api/data/metar?ids=";
for (int k = 0; k < NUM_ICAO; k++) {
url += icao[k] + delim;
}
url += "&format=json";
Serial.println("Pulling METARs from: " + url);
// Fetch JSON based off url
http.begin(client, url);
int responseCode = http.GET();
String result = http.getString();
Serial.println(result);
// Setup JSON doc for storage and parsing
JsonDocument doc;
DeserializationError error = deserializeJson(doc, result);
// Test if JSON parsing succeeds.
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
// Note this implementation only chceks the lowest reported clouds
for (int i = 0; i < n; i++) {
JsonObject root = doc[i];
String metarRaw = root["rawOb"];
// Serial.println(metarRaw);
String lowest_cover = root["clouds"][0]["cover"];
String lowest_base = root["clouds"][0]["base"];
String visib = root["visib"];
Serial.println(icao[i] + " ceiling: " + lowest_cover + " @ " + lowest_base + " ft\tVisibility: " + visib + " mi");
bool ceiling = false;
int ceiling_num = -1;
// if clouds > 0:
// for x in range(len(clouds)):
// cloud = clouds[x]
if (isDigit(lowest_base[0])) {
if (lowest_cover == "BKN" || lowest_cover == "OVC") {
// lowest_cover = cloud['cover']
// lowest_base = cloud['base']
ceiling = true;
// ceiling_num = x;
// break
}
} else {
Serial.println("No clouds!");
}
float vis = 0;
if (visib == "10+") {
vis = 10;
} else {
vis = visib.toInt();
}
int base = lowest_base.toInt();
if (lowest_cover == "CLR") {
Serial.println("NO CEILING!");
leds[i] = CRGB::Green;
Serial.println(icao[i] + " is VFR");
} else {
// Serial.println("CEILING!");
if (base < 500 || vis < 1) {
leds[i] = CRGB::Purple;
Serial.println(icao[i] + " is LIFR");
} else if (base < 1000 || vis < 3) {
leds[i] = CRGB::Red;
Serial.println(icao[i] + " is IFR");
} else if (base < 3000 || vis < 5) {
leds[i] = CRGB::Blue;
Serial.println(icao[i] + " is MVFR");
// }
} else {
Serial.println("NO CEILING!");
leds[i] = CRGB::Green;
Serial.println(icao[i] + " is VFR");
}
FastLED.show();
}
// Add a delay for a fun effect???
delay(100);
}
}
void loop() {
// Update METARs according to the time set in UPDATE_IN_SEC
if (millis() - lastMillis >= UPDATE_IN_SEC * 1000UL) {
lastMillis = millis(); //get ready for the next iteration
Serial.println("UPDATING METARS!!!");
// Dim and set LEDs to white
FastLED.setBrightness(1);
for (int n = 0; n < NUM_ICAO; n++) {
leds[n] = CRGB::White;
}
FastLED.show();
// Refresh METARS
fetchMetars(ICAOS, NUM_ICAO);
// Return LEDS to normal brightness
FastLED.setBrightness(BRIGHTNESS);
FastLED.show();
Serial.println("UPDATED!!!");
}
}