@Lichtsignaal I liked your extract as it provides easy parsing of API calls without the normal additional json libraries. I was having trouble with cookies from wunderground.com which meant the index wasn’t constant.
Eventually got it running and the full sketch to parse sunrise and sunset times, without disconnecting from the Blynk server, is provided below.
/* Webhooksv2a.ino based on sketch extract by @Lichtsignaal
* http://community.blynk.cc/t/read-data-from-the-web-with-webhook/8334/6
* Terminal on V0 and button in PUSH mode on V2
*/
//#define BLYNK_DEBUG // enable for debugging Blynk problems
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h> // Essential for almost all sketches
SimpleTimer timer;
WidgetTerminal terminalW(V0);
char server[] = "api.wunderground.com"; // same as: const char* server = "api.wunderground.com";
WiFiClient client;
#define debug 0 // reduced Serial Monitor output
bool validData = false; // assume bad data until validated
unsigned int sunriseseconds;
unsigned int sunsetseconds;
String sunrise;
String sunset;
int foundsunrise;
int foundsunset;
unsigned int numberofattempts = 3; // set maximum number of attempts to try to get valid data from webservice
// will try 4 times from V2 but 1 attempt is ok now
char OTAhost[] = "Webhook"; // Optional, but very useful
char ssidstr[] = "OfficeGargoyle"; // enter your Router SSID
char passstr[] = "1234567890"; // enter your Router AP password
char authstr[] = "AB012345678901234567890123456789"; // enter your Blynk token
char serverstr[] = "blynk-cloud.com"; // change to IP for local server connection
char WUNDERGROUND_REQ[] =
"GET /api/API_KEY/astronomy/q/COUNTRY/CITY.json HTTP/1.1\r\n" // enter your WUNDERGROUD API_KEY, COUNTRY and CITY
"User-Agent: ESP8266/0.1\r\n"
"Accept: */*\r\n"
"Host:api.wunderground.com\r\n"
"Connection: close\r\n"
"\r\n";
BLYNK_WRITE(V2){
int getWUsunrise = param.asInt();
terminalW.println();
if(getWUsunrise == 1){
int datachecks = 0;
while(validData == false){
getrawdata(); // keep checking for valid data
if(validData == false){ // rechecked after calling getrawdata();
terminalW.println("Invalid data, will try again");
terminalW.flush();
}
datachecks++;
if(datachecks > numberofattempts){
Serial.println("Check API");
terminalW.println("Check API");
terminalW.flush();
break; // tried enough times so bail out of while loop
}
}
gotValidData();
}
}
void gotValidData(){
if(validData == true){
terminalW.println("Data check passed");
terminalW.print("Sunrise seconds ");
terminalW.println(sunriseseconds);
terminalW.print("Sunset seconds ");
terminalW.println(sunsetseconds);
terminalW.flush();
validData = false; // resetting flag for further use
}
}
void reconnectBlynk() { // reconnect to server if we get disconnected
if (!Blynk.connected()) {
if(Blynk.connect()) {
BLYNK_LOG("Reconnected");
terminalW.print("Reconnected with local IP of ");
terminalW.println(WiFi.localIP());
terminalW.flush();
} else {
BLYNK_LOG("Not reconnected");
}
}
}
void getrawdata()
{
if(debug) { Serial.println("Disconnecting Blynk"); }
//Blynk.disconnect(); // Disconnect Blynk, cause API call has to be made
//delay(750);
int i=0;
String contents[65]; // maximum number of lines, not characters per line
String inputString = "";
foundsunrise = 0;
foundsunset = 0;
inputString.reserve(1400); // actual data approx 662 plus headers say 438 (measured size is around 1071 characters BEFORE trim
int countcharacters = 0;
if(debug) {
Serial.print("connecting to ");
Serial.println(server);
}
WiFiClient client; // Use WiFiClient class to create TCP connections
const int httpPort = 80;
if (!client.connect(server, httpPort)) {
if(debug) { Serial.println("connection failed"); }
return;
}
String url = "/api/527c5df849ee9364/astronomy/q/Cyprus/Paralimni.json HTTP/1.1\r\n"; // We now create a URI for the request
if(debug) {
Serial.print("Requesting URL: ");
Serial.println(url);
}
client.print(String("GET ") + url + " HTTP/1.1\r\n" + // This will send the request to the server
"Host: " + server + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
if(debug) { Serial.println(">>> Client Timeout !"); }
client.stop();
return;
}
}
while(client.available()){ // Read all the lines of the reply from server and print them to Serial
char c = client.read();
inputString += c;
countcharacters++;
if (c == '\n')
{
inputString.trim(); // Remove dumbass whitespaces and too much CR, LF etc.
//if(inputString.startsWith("Set-Cookie:") == false){ // skip any lines that refer to setting cookies as they are once / session
if(debug) {
Serial.print(i);
Serial.print(": Received: ");
Serial.println(inputString);
}
contents[i] = inputString;
i++;
yield();
if(foundsunrise == 0){ // ensures we only search for 1st instance
if(inputString.substring(1, 8) == "sunrise"){ // sunrise
foundsunrise = i;
if(debug) {
Serial.print("Found sunrise at index ");
Serial.println(foundsunrise);
}
}
}
if(foundsunset == 0){ // ensures we only search for 1st instance
if(inputString.substring(1, 7) == "sunset"){ // sunset
foundsunset = i;
if(debug) {
Serial.print("Found sunset at index ");
Serial.println(foundsunset);
}
}
}
inputString = "";
}
}
if(debug) {
Serial.println();
Serial.println("closing connection");
}
if((foundsunrise != 0) && (foundsunset != 0)){
validData = true;
if(debug) {
Serial.println("Data is valid");
Serial.println(contents[foundsunrise]);
Serial.println(contents[foundsunrise + 1]);
Serial.println(contents[foundsunset ]);
Serial.println(contents[foundsunset + 1]);
}
int risehourlength = (contents[foundsunrise].length()); // length 11 means before 10am i.e. single digit number
int riseminutelength = (contents[foundsunrise + 1].length()); // length 12 means less than 10 minutes passed the hour i.e. single digit number
int sethourlength = (contents[foundsunset].length()); // length 11 means before 10am i.e. single digit number
int setminutelength = (contents[foundsunset + 1].length()); // length 12 means less than 10 minutes passed the hour i.e. single digit number
if(debug) { Serial.print("Sunrise at "); }
if(risehourlength == 11){
if(debug) {
Serial.print("0");
Serial.print(contents[foundsunrise].charAt(8));
}
sunriseseconds = ((contents[foundsunrise].charAt(8) - '0') * 3600);
}
else{
if(debug) {
Serial.print(contents[foundsunrise].charAt(8));
Serial.print(contents[foundsunrise].charAt(9));
}
sunriseseconds = ((contents[foundsunrise].charAt(8) - '0') * 10 * 3600) + ((contents[33].charAt(9) - '0') * 3600);
}
if(debug) { Serial.print(":"); }
if(riseminutelength == 12){
if(debug) {
Serial.print("0");
Serial.println(contents[foundsunrise + 1].charAt(10));
}
sunriseseconds = sunriseseconds + ((contents[foundsunrise + 1].charAt(10) - '0') * 60);
}
else{
if(debug) {
Serial.print(contents[foundsunrise + 1].charAt(10));
Serial.println(contents[foundsunrise + 1].charAt(11));
}
sunriseseconds = sunriseseconds + ((contents[foundsunrise + 1].charAt(10) - '0') * 10 * 60) + ((contents[foundsunrise + 1].charAt(11) - '0') * 60);
}
if(debug) {
Serial.print("Seconds from midnight to SUNRISE: ");
Serial.println(sunriseseconds);
}
if(debug) { Serial.print("Sunset at "); }
if(sethourlength == 11){
if(debug) {
Serial.print("0");
Serial.print(contents[foundsunset].charAt(8));
}
sunsetseconds = ((contents[foundsunset].charAt(8) - '0') * 3600);
}
else{
if(debug) {
Serial.print(contents[foundsunset].charAt(8));
Serial.print(contents[foundsunset].charAt(9));
}
sunsetseconds = ((contents[foundsunset].charAt(8) - '0') * 10 * 3600) + ((contents[foundsunset].charAt(9) - '0') * 3600);
}
if(debug) { Serial.print(":"); }
if(setminutelength == 12){
if(debug) {
Serial.print("0");
Serial.println(contents[foundsunset + 1].charAt(10));
}
sunsetseconds = sunsetseconds + ((contents[foundsunset + 1].charAt(10) - '0') * 60);
}
else{
if(debug) {
Serial.print(contents[foundsunset + 1].charAt(10));
Serial.println(contents[foundsunset + 1].charAt(11));
}
sunsetseconds = sunsetseconds + ((contents[foundsunset + 1].charAt(10) - '0') * 10 * 60) + ((contents[foundsunset + 1].charAt(11) - '0') * 60);
}
if(debug) {
Serial.print("Seconds from midnight to SUNSET: ");
Serial.println(sunsetseconds);
}
//validData = false; // reset flag not needed here as it is done in V2
}
else{
validData = false;
if(debug) { Serial.println("Data is INVALID, check API"); }
}
if(debug) { Serial.println("Connecting Blynk"); }
//Blynk.connect();
}
void setup() {
Serial.begin(115200);
Serial.println("\nStarting");
Blynk.begin(authstr, ssidstr, passstr, serverstr);
int mytimeout = millis() / 1000;
while (Blynk.connect() == false) { // wait here for upto 10s until connected to the server
if((millis() / 1000) > mytimeout + 8){ // try to connect to the server for less than 9 seconds
break; // continue with the sketch regardless of connection to the server
}
}
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
ArduinoOTA.setHostname(OTAhost); // for local OTA updates
ArduinoOTA.begin();
timer.setInterval(5000L, reconnectBlynk); // check every 5s if still connected to server
terminalW.println();
terminalW.print("Local IP: ");
terminalW.println(WiFi.localIP());
terminalW.flush();
getrawdata(); // now also done with V2 momentary switch
gotValidData();
}
void loop() {
if (Blynk.connected()) { // to ensure that Blynk.run() function is only called if we are still connected to the server
Blynk.run();
}
timer.run();
ArduinoOTA.handle(); // for local OTA updates
yield();
}