Cleaning up sample code
This commit is contained in:
@@ -1,165 +0,0 @@
|
|||||||
|
|
||||||
/**The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2017 by Daniel Eichhorn
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
See more at http://blog.squix.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <WiFiClient.h>
|
|
||||||
#include "CalendarParser.h"
|
|
||||||
|
|
||||||
CalendarParser::CalendarParser() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::updateCalendar(String GScriptId) {
|
|
||||||
|
|
||||||
|
|
||||||
const char* host = "script.google.com";
|
|
||||||
String url = String("/macros/s/") + GScriptId + "/exec";
|
|
||||||
JsonStreamingParser parser;
|
|
||||||
parser.setListener(this);
|
|
||||||
|
|
||||||
/*const int httpPort = 80;
|
|
||||||
if (!client.connect("api.wunderground.com", httpPort)) {
|
|
||||||
Serial.println("connection failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.print("Requesting URL: ");
|
|
||||||
Serial.println(url);
|
|
||||||
|
|
||||||
// This will send the request to the server
|
|
||||||
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
|
|
||||||
"Host: api.wunderground.com\r\n" +
|
|
||||||
"Connection: close\r\n\r\n");
|
|
||||||
int retryCounter = 0;
|
|
||||||
while(!client.available()) {
|
|
||||||
delay(1000);
|
|
||||||
retryCounter++;
|
|
||||||
if (retryCounter > 10) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
// Use HTTPSRedirect class to create a new TLS connection
|
|
||||||
int httpsPort = 443;
|
|
||||||
HTTPSRedirect *client = new HTTPSRedirect();
|
|
||||||
client->setPrintResponseBody(true);
|
|
||||||
client->setContentTypeHeader("application/json");
|
|
||||||
|
|
||||||
Serial.print("Connecting to ");
|
|
||||||
Serial.println(url);
|
|
||||||
|
|
||||||
// Try to connect for a maximum of 5 times
|
|
||||||
bool flag = false;
|
|
||||||
for (int i=0; i<5; i++){
|
|
||||||
yield();
|
|
||||||
Serial.print("X");
|
|
||||||
int retval = client->connect("blog.squix.org", httpsPort);
|
|
||||||
Serial.print("x");
|
|
||||||
if (retval == 1) {
|
|
||||||
flag = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Serial.println("Connection failed. Retrying...");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!flag){
|
|
||||||
Serial.print("Could not connect to server: ");
|
|
||||||
Serial.println(host);
|
|
||||||
Serial.println("Exiting...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*if (client->verify(fingerprint, host)) {
|
|
||||||
Serial.println("Certificate match.");
|
|
||||||
} else {
|
|
||||||
Serial.println("Certificate mis-match");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
// fetch spreadsheet data
|
|
||||||
client->GET(url, host);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int pos = 0;
|
|
||||||
boolean isBody = false;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
int size = 0;
|
|
||||||
client->setNoDelay(false);
|
|
||||||
while(client->connected()) {
|
|
||||||
while((size = client->available()) > 0) {
|
|
||||||
c = client->read();
|
|
||||||
if (c == '{' || c == '[') {
|
|
||||||
isBody = true;
|
|
||||||
}
|
|
||||||
if (isBody) {
|
|
||||||
parser.parse(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::whitespace(char c) {
|
|
||||||
Serial.println("whitespace");
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::startDocument() {
|
|
||||||
Serial.println("start document");
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::key(String key) {
|
|
||||||
currentKey = String(key);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::value(String value) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::endArray() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CalendarParser::startObject() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::endObject() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::endDocument() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalendarParser::startArray() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/**The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2017 by Daniel Eichhorn
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
See more at http://blog.squix.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <JsonListener.h>
|
|
||||||
#include <JsonStreamingParser.h>
|
|
||||||
#include "HTTPSRedirect.h"
|
|
||||||
|
|
||||||
class CalendarParser: public JsonListener {
|
|
||||||
private:
|
|
||||||
String currentKey;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CalendarParser();
|
|
||||||
void updateCalendar(String GScriptId);
|
|
||||||
|
|
||||||
virtual void whitespace(char c);
|
|
||||||
|
|
||||||
virtual void startDocument();
|
|
||||||
|
|
||||||
virtual void key(String key);
|
|
||||||
|
|
||||||
virtual void value(String value);
|
|
||||||
|
|
||||||
virtual void endArray();
|
|
||||||
|
|
||||||
virtual void endObject();
|
|
||||||
|
|
||||||
virtual void endDocument();
|
|
||||||
|
|
||||||
virtual void startArray();
|
|
||||||
|
|
||||||
virtual void startObject();
|
|
||||||
};
|
|
||||||
@@ -1,486 +0,0 @@
|
|||||||
/* HTTPS on ESP8266 with follow redirects, chunked encoding support
|
|
||||||
* Version 2.1
|
|
||||||
* Author: Sujay Phadke
|
|
||||||
* Github: @electronicsguy
|
|
||||||
* Copyright (C) 2017 Sujay Phadke <electronicsguy123@gmail.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "HTTPSRedirect.h"
|
|
||||||
|
|
||||||
HTTPSRedirect::HTTPSRedirect(void) : _httpsPort(443){
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
HTTPSRedirect::HTTPSRedirect(const int p) : _httpsPort(p){
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
HTTPSRedirect::~HTTPSRedirect(){
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSRedirect::Init(void){
|
|
||||||
_keepAlive = true;
|
|
||||||
_printResponseBody = false;
|
|
||||||
_maxRedirects = 10;
|
|
||||||
_contentTypeHeader = "application/x-www-form-urlencoded";
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the main function which is similar to the method
|
|
||||||
// print() from WifiClient or WifiClientSecure
|
|
||||||
bool HTTPSRedirect::printRedir(void){
|
|
||||||
unsigned int httpStatus;
|
|
||||||
|
|
||||||
// Check if connection to host is alive
|
|
||||||
if (!connected()){
|
|
||||||
Serial.println("Error! Not connected to host.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the input stream of any junk data before making the request
|
|
||||||
while(available())
|
|
||||||
read();
|
|
||||||
|
|
||||||
// Create HTTP/1.1 compliant request string
|
|
||||||
// HTTP/1.1 complaint request packet must exist
|
|
||||||
|
|
||||||
DPRINTLN(_Request);
|
|
||||||
|
|
||||||
// Make the actual HTTPS request using the method
|
|
||||||
// print() from the WifiClientSecure class
|
|
||||||
// Make sure the input stream is cleared (as above) before making the call
|
|
||||||
print(_Request);
|
|
||||||
|
|
||||||
// Read HTTP Response Status lines
|
|
||||||
while (connected()) {
|
|
||||||
|
|
||||||
httpStatus = getResponseStatus();
|
|
||||||
|
|
||||||
// Only some HTTP response codes are checked for
|
|
||||||
// http://www.restapitutorial.com/httpstatuscodes.html
|
|
||||||
switch (httpStatus){
|
|
||||||
// Success. Fetch final response body
|
|
||||||
case 200:
|
|
||||||
case 201:
|
|
||||||
{
|
|
||||||
// final header is discarded
|
|
||||||
fetchHeader();
|
|
||||||
|
|
||||||
#ifdef EXTRA_FNS
|
|
||||||
printHeaderFields();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (_hF.transferEncoding == "chunked")
|
|
||||||
fetchBodyChunked();
|
|
||||||
else
|
|
||||||
fetchBodyUnChunked(_hF.contentLength);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 301:
|
|
||||||
case 302:
|
|
||||||
{
|
|
||||||
// Get re-direction URL from the 'Location' field in the header
|
|
||||||
if (getLocationURL()){
|
|
||||||
//stop(); // may not be required
|
|
||||||
|
|
||||||
_myResponse.redirected = true;
|
|
||||||
|
|
||||||
// Make a new connection to the re-direction server
|
|
||||||
if (!connect(_redirHost.c_str(), _httpsPort)) {
|
|
||||||
Serial.println("Connection to re-directed URL failed!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursive call to the requested URL on the server
|
|
||||||
return printRedir();
|
|
||||||
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
Serial.println("Unable to retrieve redirection URL!");
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Serial.print("Error with request. Response status code: ");
|
|
||||||
Serial.println(httpStatus);
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
} // end of switch
|
|
||||||
|
|
||||||
} // end of while
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a HTTP GET request packet
|
|
||||||
// GET headers must be terminated with a "\r\n\r\n"
|
|
||||||
// http://stackoverflow.com/questions/6686261/what-at-the-bare-minimum-is-required-for-an-http-request
|
|
||||||
void HTTPSRedirect::createGetRequest(const String& url, const char* host){
|
|
||||||
_Request = String("GET ") + url + " HTTP/1.1\r\n" +
|
|
||||||
"Host: " + host + "\r\n" +
|
|
||||||
"User-Agent: ESP8266\r\n" +
|
|
||||||
(_keepAlive ? "" : "Connection: close\r\n") +
|
|
||||||
"\r\n\r\n";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a HTTP POST request packet
|
|
||||||
// POST headers must be terminated with a "\r\n\r\n"
|
|
||||||
// POST requests have 1 single blank like between the end of the header fields and the body payload
|
|
||||||
void HTTPSRedirect::createPostRequest(const String& url, const char* host, const String& payload){
|
|
||||||
// Content-Length is mandatory in POST requests
|
|
||||||
// Body content will include payload and a newline character
|
|
||||||
unsigned int len = payload.length() + 1;
|
|
||||||
|
|
||||||
_Request = String("POST ") + url + " HTTP/1.1\r\n" +
|
|
||||||
"Host: " + host + "\r\n" +
|
|
||||||
"User-Agent: ESP8266\r\n" +
|
|
||||||
(_keepAlive ? "" : "Connection: close\r\n") +
|
|
||||||
"Content-Type: " + _contentTypeHeader + "\r\n" +
|
|
||||||
"Content-Length: " + len + "\r\n" +
|
|
||||||
"\r\n" +
|
|
||||||
payload +
|
|
||||||
"\r\n\r\n";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool HTTPSRedirect::getLocationURL(void){
|
|
||||||
|
|
||||||
bool flag;
|
|
||||||
|
|
||||||
// Keep reading from the input stream till we get to
|
|
||||||
// the location field in the header
|
|
||||||
flag = find("Location: ");
|
|
||||||
|
|
||||||
if (flag){
|
|
||||||
// Skip URI protocol (http, https, etc. till '//')
|
|
||||||
// This assumes that the location field will be containing
|
|
||||||
// a URL of the form: http<s>://<hostname>/<url>
|
|
||||||
readStringUntil('/');
|
|
||||||
readStringUntil('/');
|
|
||||||
// get hostname
|
|
||||||
_redirHost = readStringUntil('/');
|
|
||||||
// get remaining url
|
|
||||||
_redirUrl = String('/') + readStringUntil('\n');
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
DPRINT("No valid 'Location' field found in header!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a GET request for the new location
|
|
||||||
createGetRequest(_redirUrl, _redirHost.c_str());
|
|
||||||
|
|
||||||
DPRINT("_redirHost: ");
|
|
||||||
DPRINTLN(_redirHost);
|
|
||||||
DPRINT("_redirUrl: ");
|
|
||||||
DPRINTLN(_redirUrl);
|
|
||||||
|
|
||||||
return flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSRedirect::fetchHeader(void){
|
|
||||||
String line = "";
|
|
||||||
int pos = -1;
|
|
||||||
int pos2 = -1;
|
|
||||||
int pos3 = -1;
|
|
||||||
|
|
||||||
_hF.transferEncoding = "";
|
|
||||||
_hF.contentLength = 0;
|
|
||||||
|
|
||||||
#ifdef EXTRA_FNS
|
|
||||||
_hF.contentType = "";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (connected()) {
|
|
||||||
line = readStringUntil('\n');
|
|
||||||
|
|
||||||
DPRINTLN(line);
|
|
||||||
|
|
||||||
// HTTP headers are terminated by a CRLF ('\r\n')
|
|
||||||
// Hence the final line will contain only '\r'
|
|
||||||
// since we have already till the end ('\n')
|
|
||||||
if (line == "\r")
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (pos < 0){
|
|
||||||
pos = line.indexOf("Transfer-Encoding: ");
|
|
||||||
if (!pos)
|
|
||||||
// get string & remove trailing '\r' character to facilitate string comparisons
|
|
||||||
_hF.transferEncoding = line.substring(19, line.length()-1);
|
|
||||||
}
|
|
||||||
if (pos2 < 0){
|
|
||||||
pos2 = line.indexOf("Content-Length: ");
|
|
||||||
if (!pos2)
|
|
||||||
_hF.contentLength = line.substring(16).toInt();
|
|
||||||
}
|
|
||||||
#ifdef EXTRA_FNS
|
|
||||||
if (pos3 < 0){
|
|
||||||
pos3 = line.indexOf("Content-Type: ");
|
|
||||||
if (!pos3)
|
|
||||||
// get string & remove trailing '\r' character to facilitate string comparisons
|
|
||||||
_hF.contentType = line.substring(14, line.length()-1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSRedirect::fetchBodyUnChunked(unsigned len){
|
|
||||||
String line;
|
|
||||||
DPRINTLN("Body:");
|
|
||||||
|
|
||||||
while ((connected()) && (len > 0)) {
|
|
||||||
line = readStringUntil('\n');
|
|
||||||
len -= line.length();
|
|
||||||
// Content length will include all '\n' terminating characters
|
|
||||||
// Decrement once more to account for the '\n' line ending character
|
|
||||||
--len;
|
|
||||||
|
|
||||||
if (_printResponseBody)
|
|
||||||
Serial.println(line);
|
|
||||||
|
|
||||||
_myResponse.body += line;
|
|
||||||
_myResponse.body += '\n';
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ref: http://mihai.ibanescu.net/chunked-encoding-and-python-requests
|
|
||||||
// http://fssnip.net/2t
|
|
||||||
void HTTPSRedirect::fetchBodyChunked(void){
|
|
||||||
String line;
|
|
||||||
int chunkSize;
|
|
||||||
|
|
||||||
while (connected()){
|
|
||||||
line = readStringUntil('\n');
|
|
||||||
|
|
||||||
// Skip any empty lines
|
|
||||||
if (line == "\r")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Chunk sizes are in hexadecimal so convert to integer
|
|
||||||
chunkSize = (uint32_t) strtol((const char *) line.c_str(), NULL, 16);
|
|
||||||
DPRINT("Chunk Size: ");
|
|
||||||
DPRINTLN(chunkSize);
|
|
||||||
|
|
||||||
// Terminating chunk is of size 0
|
|
||||||
if (chunkSize == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
while (chunkSize > 0){
|
|
||||||
line = readStringUntil('\n');
|
|
||||||
if (_printResponseBody)
|
|
||||||
Serial.println(line);
|
|
||||||
|
|
||||||
_myResponse.body += line;
|
|
||||||
_myResponse.body += '\n';
|
|
||||||
|
|
||||||
chunkSize -= line.length();
|
|
||||||
// The line above includes the '\r' character
|
|
||||||
// which is not part of chunk size, so account for it
|
|
||||||
--chunkSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip over chunk trailer
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int HTTPSRedirect::getResponseStatus(void){
|
|
||||||
// Read response status line
|
|
||||||
// ref: https://www.tutorialspoint.com/http/http_responses.htm
|
|
||||||
|
|
||||||
unsigned int statusCode;
|
|
||||||
String reasonPhrase;
|
|
||||||
String line;
|
|
||||||
|
|
||||||
unsigned int pos = -1;
|
|
||||||
unsigned int pos2 = -1;
|
|
||||||
|
|
||||||
// Skip any empty lines
|
|
||||||
do{
|
|
||||||
line = readStringUntil('\n');
|
|
||||||
}while(line.length() == 0);
|
|
||||||
|
|
||||||
pos = line.indexOf("HTTP/1.1 ");
|
|
||||||
pos2 = line.indexOf(" ", 9);
|
|
||||||
|
|
||||||
if (!pos){
|
|
||||||
statusCode = line.substring(9, pos2).toInt();
|
|
||||||
reasonPhrase = line.substring(pos2+1, line.length()-1);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
DPRINTLN("Error! No valid Status Code found in HTTP Response.");
|
|
||||||
statusCode = 0;
|
|
||||||
reasonPhrase = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
_myResponse.statusCode = statusCode;
|
|
||||||
_myResponse.reasonPhrase = reasonPhrase;
|
|
||||||
|
|
||||||
DPRINT("Status code: ");
|
|
||||||
DPRINTLN(statusCode);
|
|
||||||
DPRINT("Reason phrase: ");
|
|
||||||
DPRINTLN(reasonPhrase);
|
|
||||||
|
|
||||||
return statusCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HTTPSRedirect::GET(const String& url, const char* host){
|
|
||||||
return GET(url, host, _printResponseBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HTTPSRedirect::GET(const String& url, const char* host, const bool& disp){
|
|
||||||
bool retval;
|
|
||||||
bool oldval;
|
|
||||||
|
|
||||||
// set _printResponseBody temporarily to argument passed
|
|
||||||
oldval = _printResponseBody;
|
|
||||||
_printResponseBody = disp;
|
|
||||||
|
|
||||||
// redirected Host and Url need to be initialized in case a
|
|
||||||
// reConnectFinalEndpoint() request is made after an initial request
|
|
||||||
// which did not have redirection
|
|
||||||
_redirHost = host;
|
|
||||||
_redirUrl = url;
|
|
||||||
|
|
||||||
InitResponse();
|
|
||||||
|
|
||||||
// Create request packet
|
|
||||||
createGetRequest(url, host);
|
|
||||||
|
|
||||||
// Calll request handler
|
|
||||||
retval = printRedir();
|
|
||||||
|
|
||||||
_printResponseBody = oldval;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HTTPSRedirect::POST(const String& url, const char* host, const String& payload){
|
|
||||||
return POST(url, host, payload, _printResponseBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HTTPSRedirect::POST(const String& url, const char* host, const String& payload, const bool& disp){
|
|
||||||
bool retval;
|
|
||||||
bool oldval;
|
|
||||||
|
|
||||||
// set _printResponseBody temporarily to argument passed
|
|
||||||
oldval = _printResponseBody;
|
|
||||||
_printResponseBody = disp;
|
|
||||||
|
|
||||||
// redirected Host and Url need to be initialized in case a
|
|
||||||
// reConnectFinalEndpoint() request is made after an initial request
|
|
||||||
// which did not have redirection
|
|
||||||
_redirHost = host;
|
|
||||||
_redirUrl = url;
|
|
||||||
|
|
||||||
InitResponse();
|
|
||||||
|
|
||||||
// Create request packet
|
|
||||||
createPostRequest(url, host, payload);
|
|
||||||
|
|
||||||
// Call request handler
|
|
||||||
retval = printRedir();
|
|
||||||
|
|
||||||
_printResponseBody = oldval;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSRedirect::InitResponse(void){
|
|
||||||
// Init response data
|
|
||||||
_myResponse.body = "";
|
|
||||||
_myResponse.statusCode = 0;
|
|
||||||
_myResponse.reasonPhrase = "";
|
|
||||||
_myResponse.redirected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int HTTPSRedirect::getStatusCode(void){
|
|
||||||
return _myResponse.statusCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
String HTTPSRedirect::getReasonPhrase(void){
|
|
||||||
return _myResponse.reasonPhrase;
|
|
||||||
}
|
|
||||||
|
|
||||||
String HTTPSRedirect::getResponseBody(void){
|
|
||||||
return _myResponse.body;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSRedirect::setPrintResponseBody(bool disp){
|
|
||||||
_printResponseBody = disp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSRedirect::setMaxRedirects(const unsigned int n){
|
|
||||||
_maxRedirects = n; // to-do: use this in code above
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSRedirect::setContentTypeHeader(const char *type){
|
|
||||||
_contentTypeHeader = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef OPTIMIZE_SPEED
|
|
||||||
bool HTTPSRedirect::reConnectFinalEndpoint(void){
|
|
||||||
// disconnect if connection already exists
|
|
||||||
if (connected())
|
|
||||||
stop();
|
|
||||||
|
|
||||||
DPRINT("_redirHost: ");
|
|
||||||
DPRINTLN(_redirHost);
|
|
||||||
DPRINT("_redirUrl: ");
|
|
||||||
DPRINTLN(_redirUrl);
|
|
||||||
|
|
||||||
// Connect to stored final endpoint
|
|
||||||
if (!connect(_redirHost.c_str(), _httpsPort)) {
|
|
||||||
DPRINTLN("Connection to final URL failed!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valid request packed must already be
|
|
||||||
// present at this point in the member variable _Request
|
|
||||||
// from the previous GET() or POST() request
|
|
||||||
|
|
||||||
// Make call to final endpoint
|
|
||||||
return printRedir();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef EXTRA_FNS
|
|
||||||
void HTTPSRedirect::fetchBodyRaw(void){
|
|
||||||
String line;
|
|
||||||
|
|
||||||
while (connected()){
|
|
||||||
line = readStringUntil('\n');
|
|
||||||
if (_printResponseBody)
|
|
||||||
Serial.println(line);
|
|
||||||
|
|
||||||
_myResponse.body += line;
|
|
||||||
_myResponse.body += '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPSRedirect::printHeaderFields(void){
|
|
||||||
DPRINT("Transfer Encoding: ");
|
|
||||||
DPRINTLN(_hF.transferEncoding);
|
|
||||||
DPRINT("Content Length: ");
|
|
||||||
DPRINTLN(_hF.contentLength);
|
|
||||||
DPRINT("Content Type: ");
|
|
||||||
DPRINTLN(_hF.contentType);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
/* HTTPS on ESP8266 with follow redirects, chunked encoding support
|
|
||||||
* Version 2.1
|
|
||||||
* Author: Sujay Phadke
|
|
||||||
* Github: @electronicsguy
|
|
||||||
* Copyright (C) 2017 Sujay Phadke <electronicsguy123@gmail.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <WiFiClientSecure.h>
|
|
||||||
|
|
||||||
#define DPRINT(...)
|
|
||||||
#define DPRINTLN(...)
|
|
||||||
|
|
||||||
// Un-comment for extra functionality
|
|
||||||
//#define EXTRA_FNS
|
|
||||||
#define OPTIMIZE_SPEED
|
|
||||||
|
|
||||||
class HTTPSRedirect : public WiFiClientSecure {
|
|
||||||
private:
|
|
||||||
const int _httpsPort;
|
|
||||||
bool _keepAlive;
|
|
||||||
String _redirUrl;
|
|
||||||
String _redirHost;
|
|
||||||
unsigned int _maxRedirects; // to-do
|
|
||||||
const char* _contentTypeHeader;
|
|
||||||
|
|
||||||
struct headerFields{
|
|
||||||
String transferEncoding;
|
|
||||||
unsigned int contentLength;
|
|
||||||
#ifdef EXTRA_FNS
|
|
||||||
String contentType;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
headerFields _hF;
|
|
||||||
|
|
||||||
String _Request;
|
|
||||||
|
|
||||||
struct Response{
|
|
||||||
int statusCode;
|
|
||||||
String reasonPhrase;
|
|
||||||
bool redirected;
|
|
||||||
String body;
|
|
||||||
};
|
|
||||||
|
|
||||||
Response _myResponse;
|
|
||||||
bool _printResponseBody;
|
|
||||||
|
|
||||||
void Init(void);
|
|
||||||
bool printRedir(void);
|
|
||||||
void fetchHeader(void);
|
|
||||||
bool getLocationURL(void);
|
|
||||||
void fetchBodyUnChunked(unsigned);
|
|
||||||
void fetchBodyChunked(void);
|
|
||||||
unsigned int getResponseStatus(void);
|
|
||||||
void InitResponse(void);
|
|
||||||
void createGetRequest(const String&, const char*);
|
|
||||||
void createPostRequest(const String&, const char*, const String&);
|
|
||||||
|
|
||||||
#ifdef EXTRA_FNS
|
|
||||||
void fetchBodyRaw(void);
|
|
||||||
void printHeaderFields(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
HTTPSRedirect(void);
|
|
||||||
HTTPSRedirect(const int);
|
|
||||||
~HTTPSRedirect();
|
|
||||||
|
|
||||||
bool GET(const String&, const char*);
|
|
||||||
bool GET(const String&, const char*, const bool&);
|
|
||||||
bool POST(const String&, const char*, const String&);
|
|
||||||
bool POST(const String&, const char*, const String&, const bool&);
|
|
||||||
|
|
||||||
int getStatusCode(void);
|
|
||||||
String getReasonPhrase(void);
|
|
||||||
String getResponseBody(void);
|
|
||||||
|
|
||||||
void setPrintResponseBody(bool);
|
|
||||||
void setMaxRedirects(const unsigned int);
|
|
||||||
|
|
||||||
void setContentTypeHeader(const char *);
|
|
||||||
#ifdef OPTIMIZE_SPEED
|
|
||||||
bool reConnectFinalEndpoint(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/**The MIT License (MIT)
|
|
||||||
Copyright (c) 2017 by Daniel Eichhorn
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
See more at https://blog.squix.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
WeatherApp:WeatherApp() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void WeatherApp::updateWeatherData() {
|
|
||||||
|
|
||||||
Serial.println("Allocated");
|
|
||||||
delay(1000);
|
|
||||||
WundergroundConditions *conditionsClient = new WundergroundConditions(IS_METRIC);
|
|
||||||
conditionsClient->updateConditions(conditions, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
|
||||||
delete conditionsClient;
|
|
||||||
conditionsClient = nullptr;
|
|
||||||
|
|
||||||
drawProgress(70, "Updating forecasts...");
|
|
||||||
forecasts = (WGForecast*) malloc(sizeof(WGForecast) * MAX_FORECASTS);
|
|
||||||
WundergroundForecast *forecastClient = new WundergroundForecast(IS_METRIC);
|
|
||||||
forecastClient->updateForecast(forecasts, MAX_FORECASTS, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
|
||||||
delete forecastClient;
|
|
||||||
forecastClient = nullptr;
|
|
||||||
drawProgress(80, "Updating astronomy...");
|
|
||||||
|
|
||||||
astronomy = (WGAstronomy*) malloc(sizeof(WGAstronomy));
|
|
||||||
WundergroundAstronomy *astronomyClient = new WundergroundAstronomy(USE_PM);
|
|
||||||
astronomyClient->updateAstronomy(astronomy, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
|
||||||
delete astronomyClient;
|
|
||||||
astronomyClient = nullptr;
|
|
||||||
|
|
||||||
drawProgress(100, "Done...");
|
|
||||||
Serial.print("Free heap, before bit change: ");
|
|
||||||
Serial.println(ESP.getFreeHeap());
|
|
||||||
gfx.changeBitDepth(2, palette);
|
|
||||||
|
|
||||||
Serial.print("Free heap, after bit change: ");
|
|
||||||
Serial.println(ESP.getFreeHeap());
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
40
WeatherApp.h
40
WeatherApp.h
@@ -1,40 +0,0 @@
|
|||||||
/**The MIT License (MIT)
|
|
||||||
Copyright (c) 2017 by Daniel Eichhorn
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
See more at https://blog.squix.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <JsonListener.h>
|
|
||||||
#include <JsonStreamingParser.h>
|
|
||||||
#include "HTTPSRedirect.h"
|
|
||||||
|
|
||||||
#define MAX_FORECASTS 12
|
|
||||||
|
|
||||||
class WeatherApp {
|
|
||||||
private:
|
|
||||||
WGConditions conditions;
|
|
||||||
WGForecast forecasts[MAX_FORECASTS];
|
|
||||||
WGAstronomy astronomy;
|
|
||||||
|
|
||||||
public:
|
|
||||||
WeatherApp();
|
|
||||||
void updateWeatherData();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -19,29 +19,34 @@ See more at https://blog.squix.org
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include "MiniGrafx.h"
|
|
||||||
#include "Carousel.h"
|
|
||||||
#include "ILI9341_SPI.h"
|
|
||||||
#include "ArialRounded.h"
|
|
||||||
#include "moonphases.h"
|
|
||||||
#include "weathericons.h"
|
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Install the following libraries through Arduino Library Manager
|
||||||
|
* - Mini Grafx by Daniel Eichhorn
|
||||||
|
* - ESP8266 WeatherStation by Daniel Eichhorn
|
||||||
|
* - Json Streaming Parser by Daniel Eichhorn
|
||||||
|
* - simpleDSTadjust by neptune2
|
||||||
|
***/
|
||||||
|
|
||||||
#include "settings.h"
|
|
||||||
#include <JsonListener.h>
|
#include <JsonListener.h>
|
||||||
#include <WundergroundConditions.h>
|
#include <WundergroundConditions.h>
|
||||||
#include <WundergroundForecast.h>
|
#include <WundergroundForecast.h>
|
||||||
#include <WundergroundAstronomy.h>
|
#include <WundergroundAstronomy.h>
|
||||||
#include <TimeClient.h>
|
#include <MiniGrafx.h>
|
||||||
#include "CalendarParser.h"
|
#include <Carousel.h>
|
||||||
|
#include <ILI9341_SPI.h>
|
||||||
|
|
||||||
|
#include "ArialRounded.h"
|
||||||
|
#include "moonphases.h"
|
||||||
|
#include "weathericons.h"
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* Important: see settings.h to configure your settings!!!
|
||||||
|
* ***************************/
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
#define TFT_DC D2
|
|
||||||
#define TFT_CS D1
|
|
||||||
#define TFT_LED D8
|
|
||||||
|
|
||||||
#define MINI_BLACK 0
|
#define MINI_BLACK 0
|
||||||
#define MINI_WHITE 1
|
#define MINI_WHITE 1
|
||||||
@@ -58,26 +63,24 @@ uint16_t palette[] = {ILI9341_BLACK, // 0
|
|||||||
|
|
||||||
int SCREEN_WIDTH = 240;
|
int SCREEN_WIDTH = 240;
|
||||||
int SCREEN_HEIGHT = 320;
|
int SCREEN_HEIGHT = 320;
|
||||||
|
// Limited to 4 colors due to memory constraints
|
||||||
int BITS_PER_PIXEL = 2; // 2^2 = 4 colors
|
int BITS_PER_PIXEL = 2; // 2^2 = 4 colors
|
||||||
|
|
||||||
// HOSTNAME for OTA update
|
// HOSTNAME for OTA update
|
||||||
#define HOSTNAME "ESP8266-OTA-"
|
#define HOSTNAME "ESP8266-OTA-"
|
||||||
|
|
||||||
/*****************************
|
|
||||||
* Important: see settings.h to configure your settings!!!
|
|
||||||
* ***************************/
|
|
||||||
|
|
||||||
ILI9341_SPI tft = ILI9341_SPI(TFT_CS, TFT_DC);
|
ILI9341_SPI tft = ILI9341_SPI(TFT_CS, TFT_DC);
|
||||||
MiniGrafx gfx = MiniGrafx(&tft, BITS_PER_PIXEL, palette);
|
MiniGrafx gfx = MiniGrafx(&tft, BITS_PER_PIXEL, palette);
|
||||||
Carousel carousel(&gfx, 0, 0, 240, 100);
|
Carousel carousel(&gfx, 0, 0, 240, 100);
|
||||||
|
|
||||||
TimeClient timeClient(UTC_OFFSET);
|
|
||||||
|
|
||||||
|
|
||||||
WGConditions conditions;
|
WGConditions conditions;
|
||||||
WGForecast forecasts[MAX_FORECASTS];
|
WGForecast forecasts[MAX_FORECASTS];
|
||||||
WGAstronomy astronomy;
|
WGAstronomy astronomy;
|
||||||
|
|
||||||
|
// Setup simpleDSTadjust Library rules
|
||||||
|
simpleDSTadjust dstAdjusted(StartRule, EndRule);
|
||||||
|
|
||||||
void updateData();
|
void updateData();
|
||||||
void drawProgress(uint8_t percentage, String text);
|
void drawProgress(uint8_t percentage, String text);
|
||||||
void drawTime();
|
void drawTime();
|
||||||
@@ -96,6 +99,8 @@ long lastDownloadUpdate = millis();
|
|||||||
|
|
||||||
void updateCalendar();
|
void updateCalendar();
|
||||||
|
|
||||||
|
String moonAgeImage = "";
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
@@ -112,10 +117,9 @@ void setup() {
|
|||||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
gfx.drawString(120, 160, "Connecting to WiFi");
|
gfx.drawString(120, 160, "Connecting to WiFi");
|
||||||
gfx.commit();
|
gfx.commit();
|
||||||
|
|
||||||
carousel.setFrames(frames, frameCount);
|
carousel.setFrames(frames, frameCount);
|
||||||
//WiFiManager
|
carousel.disableAllIndicators();
|
||||||
Serial.print("Free heap: ");
|
|
||||||
Serial.println(ESP.getFreeHeap());
|
|
||||||
|
|
||||||
//Manual Wifi
|
//Manual Wifi
|
||||||
WiFi.begin("yourssid", "yourpassw0rd");
|
WiFi.begin("yourssid", "yourpassw0rd");
|
||||||
@@ -123,12 +127,9 @@ void setup() {
|
|||||||
delay(500);
|
delay(500);
|
||||||
Serial.print(".");
|
Serial.print(".");
|
||||||
}
|
}
|
||||||
Serial.println(ESP.getFreeHeap());
|
|
||||||
//calendar.updateCalendar(G_SCRIPT_ID);
|
|
||||||
//updateCalendar();
|
|
||||||
|
|
||||||
|
|
||||||
// load the weather information
|
// update the weather information
|
||||||
updateData();
|
updateData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +138,6 @@ void loop() {
|
|||||||
gfx.fillBuffer(MINI_BLACK);
|
gfx.fillBuffer(MINI_BLACK);
|
||||||
drawTime();
|
drawTime();
|
||||||
drawCurrentWeather();
|
drawCurrentWeather();
|
||||||
//drawForecast();
|
|
||||||
int remainingTimeBudget = carousel.update();
|
int remainingTimeBudget = carousel.update();
|
||||||
|
|
||||||
if (remainingTimeBudget > 0) {
|
if (remainingTimeBudget > 0) {
|
||||||
@@ -159,58 +159,32 @@ void loop() {
|
|||||||
|
|
||||||
// Update the internet based information and update screen
|
// Update the internet based information and update screen
|
||||||
void updateData() {
|
void updateData() {
|
||||||
Serial.print("Free heap, before bit change: ");
|
|
||||||
Serial.println(ESP.getFreeHeap());
|
|
||||||
gfx.changeBitDepth(1, palette);
|
|
||||||
Serial.print("Free heap, after bit change: ");
|
|
||||||
Serial.println(ESP.getFreeHeap());
|
|
||||||
gfx.fillBuffer(MINI_BLACK);
|
gfx.fillBuffer(MINI_BLACK);
|
||||||
gfx.setFont(ArialRoundedMTBold_14);
|
gfx.setFont(ArialRoundedMTBold_14);
|
||||||
free(conditions);
|
|
||||||
free(forecasts);
|
|
||||||
free(astronomy);
|
|
||||||
drawProgress(10, "Updating calendar...");
|
|
||||||
/*CalendarParser calendar = new Calendar();
|
|
||||||
calendar->updateCalendar(G_SCRIPT_ID);
|
|
||||||
calendar = nullptr;*/
|
|
||||||
//updateCalendar();
|
|
||||||
|
|
||||||
drawProgress(20, "Updating time...");
|
drawProgress(10, "Updating time...");
|
||||||
timeClient.updateTime();
|
configTime(UTC_OFFSET * 3600, 0, NTP_SERVERS);
|
||||||
|
|
||||||
drawProgress(50, "Updating conditions...");
|
drawProgress(50, "Updating conditions...");
|
||||||
conditions = (WGConditions *) malloc(sizeof(WGConditions));
|
|
||||||
Serial.println("Allocating");
|
|
||||||
delay(1000);
|
|
||||||
conditions->currentTemp = "hello";
|
|
||||||
Serial.println("Allocated");
|
|
||||||
delay(1000);
|
|
||||||
WundergroundConditions *conditionsClient = new WundergroundConditions(IS_METRIC);
|
WundergroundConditions *conditionsClient = new WundergroundConditions(IS_METRIC);
|
||||||
conditionsClient->updateConditions(conditions, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
conditionsClient->updateConditions(&conditions, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
||||||
delete conditionsClient;
|
delete conditionsClient;
|
||||||
conditionsClient = nullptr;
|
conditionsClient = nullptr;
|
||||||
|
|
||||||
drawProgress(70, "Updating forecasts...");
|
drawProgress(70, "Updating forecasts...");
|
||||||
forecasts = (WGForecast*) malloc(sizeof(WGForecast) * MAX_FORECASTS);
|
|
||||||
WundergroundForecast *forecastClient = new WundergroundForecast(IS_METRIC);
|
WundergroundForecast *forecastClient = new WundergroundForecast(IS_METRIC);
|
||||||
forecastClient->updateForecast(forecasts, MAX_FORECASTS, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
forecastClient->updateForecast(forecasts, MAX_FORECASTS, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
||||||
delete forecastClient;
|
delete forecastClient;
|
||||||
forecastClient = nullptr;
|
forecastClient = nullptr;
|
||||||
drawProgress(80, "Updating astronomy...");
|
drawProgress(80, "Updating astronomy...");
|
||||||
|
|
||||||
astronomy = (WGAstronomy*) malloc(sizeof(WGAstronomy));
|
WundergroundAstronomy *astronomyClient = new WundergroundAstronomy(STYLE_12HR);
|
||||||
WundergroundAstronomy *astronomyClient = new WundergroundAstronomy(USE_PM);
|
astronomyClient->updateAstronomy(&astronomy, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
||||||
astronomyClient->updateAstronomy(astronomy, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
|
||||||
delete astronomyClient;
|
delete astronomyClient;
|
||||||
astronomyClient = nullptr;
|
astronomyClient = nullptr;
|
||||||
|
moonAgeImage = String((char) (65 + 26 * (((15 + astronomy.moonAge.toInt()) % 30) / 30.0)));
|
||||||
|
|
||||||
drawProgress(100, "Done...");
|
|
||||||
Serial.print("Free heap, before bit change: ");
|
|
||||||
Serial.println(ESP.getFreeHeap());
|
|
||||||
gfx.changeBitDepth(2, palette);
|
|
||||||
|
|
||||||
Serial.print("Free heap, after bit change: ");
|
|
||||||
Serial.println(ESP.getFreeHeap());
|
|
||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,90 +200,65 @@ void drawProgress(uint8_t percentage, String text) {
|
|||||||
gfx.drawRect(10, 165, 240 - 20, 15);
|
gfx.drawRect(10, 165, 240 - 20, 15);
|
||||||
gfx.setColor(MINI_BLUE);
|
gfx.setColor(MINI_BLUE);
|
||||||
gfx.fillRect(12, 167, 216 * percentage / 100, 11);
|
gfx.fillRect(12, 167, 216 * percentage / 100, 11);
|
||||||
//ui.drawProgressBar(10, 165, 240 - 20, 15, percentage, ILI9341_WHITE, ILI9341_BLUE);
|
|
||||||
gfx.commit();
|
gfx.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// draws the clock
|
// draws the clock
|
||||||
void drawTime() {
|
void drawTime() {
|
||||||
|
|
||||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
/*gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
gfx.setColor(MINI_WHITE);
|
gfx.setColor(MINI_WHITE);
|
||||||
gfx.setFont(ArialRoundedMTBold_14);
|
gfx.setFont(ArialRoundedMTBold_14);
|
||||||
String date = conditions->date;
|
String date = conditions.date;
|
||||||
gfx.drawString(120, 6, date);
|
gfx.drawString(120, 6, date);
|
||||||
|
|
||||||
gfx.setFont(ArialRoundedMTBold_36);
|
gfx.setFont(ArialRoundedMTBold_36);
|
||||||
String time = timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds();
|
String time = timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds();
|
||||||
gfx.drawString(120, 20, time);
|
gfx.drawString(120, 20, time);*/
|
||||||
}
|
char *dstAbbrev;
|
||||||
|
char time_str[11];
|
||||||
|
time_t now = dstAdjusted.time(&dstAbbrev);
|
||||||
|
struct tm * timeinfo = localtime (&now);
|
||||||
|
|
||||||
void updateCalendar() {
|
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
Serial.print("Free heap: ");
|
gfx.setFont(ArialRoundedMTBold_14);
|
||||||
Serial.println(ESP.getFreeHeap());
|
String date = ctime(&now);
|
||||||
const char* host = "script.google.com";
|
date = date.substring(0,11) + String(1900 + timeinfo->tm_year);
|
||||||
// Replace with your own script id to make server side changes
|
gfx.drawString(120, 6, date);
|
||||||
const char *GScriptId = "AKfycbwdOi6zab7cLU5fEr0AL6KrAMpygUoFHOtSrgnKfccyHHkpZPo";
|
|
||||||
|
|
||||||
const int httpsPort = 443;
|
gfx.setFont(ArialRoundedMTBold_36);
|
||||||
String url = String("/macros/s/") + GScriptId + "/exec";
|
|
||||||
// echo | openssl s_client -connect script.google.com:443 |& openssl x509 -fingerprint -noout
|
|
||||||
const char* fingerprint = "08:9E:B2:B8:77:37:3E:85:26:09:CA:29:13:D2:B0:57:26:DE:C4:6D";
|
|
||||||
|
|
||||||
// Use HTTPSRedirect class to create a new TLS connection
|
if (STYLE_12HR) {
|
||||||
HTTPSRedirect *client = new HTTPSRedirect(httpsPort);
|
int hour = (timeinfo->tm_hour+11)%12+1; // take care of noon and midnight
|
||||||
client->setPrintResponseBody(true);
|
sprintf(time_str, "%2d:%02d:%02d\n",hour, timeinfo->tm_min, timeinfo->tm_sec);
|
||||||
client->setContentTypeHeader("application/json");
|
gfx.drawString(120, 20, time_str);
|
||||||
Serial.print("Connecting to ");
|
|
||||||
Serial.println(host);
|
|
||||||
|
|
||||||
// Try to connect for a maximum of 5 times
|
|
||||||
bool flag = false;
|
|
||||||
for (int i=0; i<5; i++){
|
|
||||||
Serial.println(".");
|
|
||||||
delay(1000);
|
|
||||||
int retval = client->connect(host, httpsPort);
|
|
||||||
if (retval == 1) {
|
|
||||||
flag = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Serial.println("Connection failed. Retrying...");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!flag){
|
|
||||||
Serial.print("Could not connect to server: ");
|
|
||||||
Serial.println(host);
|
|
||||||
Serial.println("Exiting...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client->verify(fingerprint, host)) {
|
|
||||||
Serial.println("Certificate match.");
|
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Certificate mis-match");
|
sprintf(time_str, "%02d:%02d:%02d\n",timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
|
||||||
|
gfx.drawString(120, 20, time_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch spreadsheet data
|
gfx.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
client->GET(url, host);
|
gfx.setFont(ArialMT_Plain_10);
|
||||||
|
gfx.setColor(MINI_BLUE);
|
||||||
|
if (STYLE_12HR) {
|
||||||
delete client;
|
sprintf(time_str, "%s\n%s", dstAbbrev, timeinfo->tm_hour>=12?"PM":"AM");
|
||||||
client = nullptr;
|
gfx.drawString(195, 27, time_str);
|
||||||
|
} else {
|
||||||
|
sprintf(time_str, "%s", dstAbbrev);
|
||||||
|
gfx.drawString(195, 27, time_str); // Known bug: Cuts off 4th character of timezone abbreviation
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// draws current weather information
|
// draws current weather information
|
||||||
void drawCurrentWeather() {
|
void drawCurrentWeather() {
|
||||||
// Weather Icon
|
|
||||||
|
|
||||||
gfx.setTransparentColor(MINI_BLACK);
|
gfx.setTransparentColor(MINI_BLACK);
|
||||||
//gfx.drawBmpFromFile(weatherIcon + ".bmp", 0, 55);
|
gfx.drawPalettedBitmapFromPgm(0, 55, getMeteoconIconFromProgmem(conditions.weatherIcon));
|
||||||
gfx.drawPalettedBitmapFromPgm(0, 55, getMeteoconIconFromProgmem(conditions->weatherIcon));
|
|
||||||
// Weather Text
|
// Weather Text
|
||||||
gfx.setFont(ArialRoundedMTBold_14);
|
gfx.setFont(ArialRoundedMTBold_14);
|
||||||
gfx.setColor(MINI_YELLOW);
|
gfx.setColor(MINI_YELLOW);
|
||||||
gfx.setTextAlignment(TEXT_ALIGN_RIGHT);
|
gfx.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||||
gfx.drawString(220, 76, conditions->weatherText);
|
gfx.drawString(220, 76, conditions.weatherText);
|
||||||
|
|
||||||
gfx.setFont(ArialRoundedMTBold_36);
|
gfx.setFont(ArialRoundedMTBold_36);
|
||||||
gfx.setColor(MINI_WHITE);
|
gfx.setColor(MINI_WHITE);
|
||||||
@@ -318,7 +267,7 @@ void drawCurrentWeather() {
|
|||||||
if (IS_METRIC) {
|
if (IS_METRIC) {
|
||||||
degreeSign = "°C";
|
degreeSign = "°C";
|
||||||
}
|
}
|
||||||
String temp = conditions->currentTemp + degreeSign;
|
String temp = conditions.currentTemp + degreeSign;
|
||||||
gfx.drawString(220, 89, temp);
|
gfx.drawString(220, 89, temp);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -328,15 +277,13 @@ void drawForecast1(MiniGrafx *display, CarouselState* state, int16_t x, int16_t
|
|||||||
drawForecastDetail(x + 95, y + 165, 2);
|
drawForecastDetail(x + 95, y + 165, 2);
|
||||||
drawForecastDetail(x + 180, y + 165, 4);
|
drawForecastDetail(x + 180, y + 165, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawForecast2(MiniGrafx *display, CarouselState* state, int16_t x, int16_t y) {
|
void drawForecast2(MiniGrafx *display, CarouselState* state, int16_t x, int16_t y) {
|
||||||
drawForecastDetail(x + 10, y + 165, 6);
|
drawForecastDetail(x + 10, y + 165, 6);
|
||||||
drawForecastDetail(x + 95, y + 165, 8);
|
drawForecastDetail(x + 95, y + 165, 8);
|
||||||
drawForecastDetail(x + 180, y + 165, 10);
|
drawForecastDetail(x + 180, y + 165, 10);
|
||||||
}
|
}
|
||||||
// draws the three forecast columns
|
|
||||||
void drawForecast() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper for the forecast columns
|
// helper for the forecast columns
|
||||||
void drawForecastDetail(uint16_t x, uint16_t y, uint8_t dayIndex) {
|
void drawForecastDetail(uint16_t x, uint16_t y, uint8_t dayIndex) {
|
||||||
@@ -351,39 +298,36 @@ void drawForecastDetail(uint16_t x, uint16_t y, uint8_t dayIndex) {
|
|||||||
gfx.drawString(x + 25, y, forecasts[dayIndex].forecastLowTemp + "|" + forecasts[dayIndex].forecastHighTemp);
|
gfx.drawString(x + 25, y, forecasts[dayIndex].forecastLowTemp + "|" + forecasts[dayIndex].forecastHighTemp);
|
||||||
|
|
||||||
gfx.drawPalettedBitmapFromPgm(x, y + 15, getMiniMeteoconIconFromProgmem(forecasts[dayIndex].forecastIcon));
|
gfx.drawPalettedBitmapFromPgm(x, y + 15, getMiniMeteoconIconFromProgmem(forecasts[dayIndex].forecastIcon));
|
||||||
|
gfx.setColor(MINI_BLUE);
|
||||||
|
gfx.drawString(x + 25, y + 60, forecasts[dayIndex].PoP + "%");
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw moonphase and sunrise/set and moonrise/set
|
// draw moonphase and sunrise/set and moonrise/set
|
||||||
void drawAstronomy() {
|
void drawAstronomy() {
|
||||||
char moonAgeImage = 65 + 26 * astronomy->moonAge.toInt() / 30.0;
|
|
||||||
gfx.setFont(MoonPhases_Regular_36);
|
gfx.setFont(MoonPhases_Regular_36);
|
||||||
gfx.setColor(MINI_WHITE);
|
gfx.setColor(MINI_WHITE);
|
||||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
gfx.drawString(120, 270, String(moonAgeImage));
|
gfx.drawString(120, 275, moonAgeImage);
|
||||||
//gfx.drawBmpFromFile("/moon" + String(moonAgeImage) + ".bmp", 120 - 30, 255);
|
|
||||||
|
|
||||||
gfx.setColor(MINI_WHITE);
|
gfx.setColor(MINI_WHITE);
|
||||||
gfx.setFont(ArialRoundedMTBold_14);
|
gfx.setFont(ArialRoundedMTBold_14);
|
||||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
gfx.setColor(MINI_YELLOW);
|
gfx.setColor(MINI_YELLOW);
|
||||||
gfx.drawString(120, 245, astronomy->moonPhase);
|
gfx.drawString(120, 250, astronomy.moonPhase);
|
||||||
gfx.setTextAlignment(TEXT_ALIGN_LEFT);
|
gfx.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
gfx.setColor(MINI_YELLOW);
|
gfx.setColor(MINI_YELLOW);
|
||||||
gfx.drawString(10, 245, "Sun");
|
gfx.drawString(5, 250, "Sun");
|
||||||
gfx.setColor(MINI_WHITE);
|
gfx.setColor(MINI_WHITE);
|
||||||
astronomy->sunriseTime.trim();
|
gfx.drawString(5, 276, astronomy.sunriseTime);
|
||||||
astronomy->sunriseTime.trim();
|
gfx.drawString(5, 291, astronomy.sunsetTime);
|
||||||
gfx.drawString(10, 276, astronomy->sunriseTime);
|
|
||||||
gfx.drawString(10, 291, astronomy->sunsetTime);
|
|
||||||
|
|
||||||
gfx.setTextAlignment(TEXT_ALIGN_RIGHT);
|
gfx.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||||
gfx.setColor(MINI_YELLOW);
|
gfx.setColor(MINI_YELLOW);
|
||||||
gfx.drawString(230, 245, "Moon");
|
gfx.drawString(235, 250, "Moon");
|
||||||
gfx.setColor(MINI_WHITE);
|
gfx.setColor(MINI_WHITE);
|
||||||
astronomy->moonriseTime.trim();
|
gfx.drawString(235, 276, astronomy.moonriseTime);
|
||||||
astronomy->moonsetTime.trim();
|
gfx.drawString(235, 291, astronomy.moonsetTime);
|
||||||
gfx.drawString(230, 276, astronomy->moonriseTime);
|
|
||||||
gfx.drawString(230, 291, astronomy->moonsetTime);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,8 +382,4 @@ const char* getMiniMeteoconIconFromProgmem(String iconText) {
|
|||||||
return miniunknown;
|
return miniunknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if you want separators, uncomment the tft-line
|
|
||||||
void drawSeparator(uint16_t y) {
|
|
||||||
//tft.drawFastHLine(10, y, 240 - 2 * 10, 0x4228);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
31
settings.h
31
settings.h
@@ -18,34 +18,45 @@ SOFTWARE.
|
|||||||
See more at http://blog.squix.ch
|
See more at http://blog.squix.ch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <simpleDSTadjust.h>
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
const int UPDATE_INTERVAL_SECS = 10 * 60; // Update every 10 minutes
|
const int UPDATE_INTERVAL_SECS = 10 * 60; // Update every 10 minutes
|
||||||
|
|
||||||
// Pins for the ILI9341
|
// Pins for the ILI9341
|
||||||
#define TFT_DC D2
|
#define TFT_DC D2
|
||||||
#define TFT_CS D1
|
#define TFT_CS D1
|
||||||
#define LED_PIN D8
|
#define TFT_LED D8
|
||||||
|
|
||||||
|
|
||||||
String G_SCRIPT_ID = "AKfycbwdOi6zab7cLU5fEr0AL6KrAMpygUoFHOtSrgnKfccyHHkpZPo";
|
|
||||||
#define USE_PM false
|
|
||||||
|
|
||||||
// TimeClient settings
|
|
||||||
const float UTC_OFFSET = 2;
|
|
||||||
|
|
||||||
// Wunderground Settings
|
// Wunderground Settings
|
||||||
|
// To check your settings first try them out in your browser:
|
||||||
|
// http://api.wunderground.com/api/WUNDERGROUND_API_KEY/conditions/q/WUNDERGROUND_COUNTTRY/WUNDERGROUND_CITY.json
|
||||||
|
// e.g. http://api.wunderground.com/api/808ba87ed77c4511/conditions/q/CH/Zurich.json
|
||||||
|
// e.g. http://api.wunderground.com/api/808ba87ed77c4511/conditions/q/CA/SAN_FRANCISCO.json <- note that in the US you use the state instead of country code
|
||||||
const boolean IS_METRIC = true;
|
const boolean IS_METRIC = true;
|
||||||
const String WUNDERGRROUND_API_KEY = "808ba87ed77c4501";
|
const String WUNDERGRROUND_API_KEY = "808ba87ed77c4501";
|
||||||
const String WUNDERGRROUND_LANGUAGE = "EN";
|
const String WUNDERGRROUND_LANGUAGE = "EN";
|
||||||
const String WUNDERGROUND_COUNTRY = "CH";
|
const String WUNDERGROUND_COUNTRY = "CH";
|
||||||
const String WUNDERGROUND_CITY = "Zurich";
|
const String WUNDERGROUND_CITY = "Zurich";
|
||||||
|
|
||||||
//Thingspeak Settings
|
#define UTC_OFFSET + 1
|
||||||
const String THINGSPEAK_CHANNEL_ID = "67284";
|
struct dstRule StartRule = {"CEST", Last, Sun, Mar, 2, 3600}; // Central European Summer Time = UTC/GMT +2 hours
|
||||||
const String THINGSPEAK_API_READ_KEY = "L2VIW20QVNZJBLAK";
|
struct dstRule EndRule = {"CET", Last, Sun, Oct, 2, 0}; // Central European Time = UTC/GMT +1 hour
|
||||||
|
|
||||||
// List, so that the downloader knows what to fetch
|
// Settings for Boston
|
||||||
String wundergroundIcons [] = {"chanceflurries","chancerain","chancesleet","chancesnow","clear","cloudy","flurries","fog","hazy","mostlycloudy","mostlysunny","partlycloudy","partlysunny","rain","sleet","snow","sunny","tstorms","unknown"};
|
// #define UTC_OFFSET -5
|
||||||
|
// struct dstRule StartRule = {"EDT", Second, Sun, Mar, 2, 3600}; // Eastern Daylight time = UTC/GMT -4 hours
|
||||||
|
// struct dstRule EndRule = {"EST", First, Sun, Nov, 1, 0}; // Eastern Standard time = UTC/GMT -5 hour
|
||||||
|
|
||||||
|
// Change for 12 Hour/ 24 hour style clock
|
||||||
|
#define STYLE_12HR false
|
||||||
|
|
||||||
|
// change for different ntp (time servers)
|
||||||
|
#define NTP_SERVERS "0.ch.pool.ntp.org", "1.ch.pool.ntp.org", "2.ch.pool.ntp.org"
|
||||||
|
// #define NTP_SERVERS "us.pool.ntp.org", "time.nist.gov", "pool.ntp.org"
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
* End Settings
|
* End Settings
|
||||||
|
|||||||
Reference in New Issue
Block a user