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 <SPI.h>
|
||||
#include "MiniGrafx.h"
|
||||
#include "Carousel.h"
|
||||
#include "ILI9341_SPI.h"
|
||||
#include "ArialRounded.h"
|
||||
#include "moonphases.h"
|
||||
#include "weathericons.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 <WundergroundConditions.h>
|
||||
#include <WundergroundForecast.h>
|
||||
#include <WundergroundAstronomy.h>
|
||||
#include <TimeClient.h>
|
||||
#include "CalendarParser.h"
|
||||
#include <MiniGrafx.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_WHITE 1
|
||||
@@ -58,26 +63,24 @@ uint16_t palette[] = {ILI9341_BLACK, // 0
|
||||
|
||||
int SCREEN_WIDTH = 240;
|
||||
int SCREEN_HEIGHT = 320;
|
||||
// Limited to 4 colors due to memory constraints
|
||||
int BITS_PER_PIXEL = 2; // 2^2 = 4 colors
|
||||
|
||||
// HOSTNAME for OTA update
|
||||
#define HOSTNAME "ESP8266-OTA-"
|
||||
|
||||
/*****************************
|
||||
* Important: see settings.h to configure your settings!!!
|
||||
* ***************************/
|
||||
|
||||
ILI9341_SPI tft = ILI9341_SPI(TFT_CS, TFT_DC);
|
||||
MiniGrafx gfx = MiniGrafx(&tft, BITS_PER_PIXEL, palette);
|
||||
Carousel carousel(&gfx, 0, 0, 240, 100);
|
||||
|
||||
TimeClient timeClient(UTC_OFFSET);
|
||||
|
||||
|
||||
WGConditions conditions;
|
||||
WGForecast forecasts[MAX_FORECASTS];
|
||||
WGAstronomy astronomy;
|
||||
|
||||
// Setup simpleDSTadjust Library rules
|
||||
simpleDSTadjust dstAdjusted(StartRule, EndRule);
|
||||
|
||||
void updateData();
|
||||
void drawProgress(uint8_t percentage, String text);
|
||||
void drawTime();
|
||||
@@ -96,6 +99,8 @@ long lastDownloadUpdate = millis();
|
||||
|
||||
void updateCalendar();
|
||||
|
||||
String moonAgeImage = "";
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
@@ -112,10 +117,9 @@ void setup() {
|
||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
gfx.drawString(120, 160, "Connecting to WiFi");
|
||||
gfx.commit();
|
||||
|
||||
carousel.setFrames(frames, frameCount);
|
||||
//WiFiManager
|
||||
Serial.print("Free heap: ");
|
||||
Serial.println(ESP.getFreeHeap());
|
||||
carousel.disableAllIndicators();
|
||||
|
||||
//Manual Wifi
|
||||
WiFi.begin("yourssid", "yourpassw0rd");
|
||||
@@ -123,12 +127,9 @@ void setup() {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println(ESP.getFreeHeap());
|
||||
//calendar.updateCalendar(G_SCRIPT_ID);
|
||||
//updateCalendar();
|
||||
|
||||
|
||||
// load the weather information
|
||||
// update the weather information
|
||||
updateData();
|
||||
}
|
||||
|
||||
@@ -137,7 +138,6 @@ void loop() {
|
||||
gfx.fillBuffer(MINI_BLACK);
|
||||
drawTime();
|
||||
drawCurrentWeather();
|
||||
//drawForecast();
|
||||
int remainingTimeBudget = carousel.update();
|
||||
|
||||
if (remainingTimeBudget > 0) {
|
||||
@@ -159,58 +159,32 @@ void loop() {
|
||||
|
||||
// Update the internet based information and update screen
|
||||
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.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...");
|
||||
timeClient.updateTime();
|
||||
drawProgress(10, "Updating time...");
|
||||
configTime(UTC_OFFSET * 3600, 0, NTP_SERVERS);
|
||||
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
WundergroundAstronomy *astronomyClient = new WundergroundAstronomy(STYLE_12HR);
|
||||
astronomyClient->updateAstronomy(&astronomy, WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
|
||||
delete astronomyClient;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -226,90 +200,65 @@ void drawProgress(uint8_t percentage, String text) {
|
||||
gfx.drawRect(10, 165, 240 - 20, 15);
|
||||
gfx.setColor(MINI_BLUE);
|
||||
gfx.fillRect(12, 167, 216 * percentage / 100, 11);
|
||||
//ui.drawProgressBar(10, 165, 240 - 20, 15, percentage, ILI9341_WHITE, ILI9341_BLUE);
|
||||
|
||||
gfx.commit();
|
||||
}
|
||||
|
||||
// draws the clock
|
||||
void drawTime() {
|
||||
|
||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
/*gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
gfx.setColor(MINI_WHITE);
|
||||
gfx.setFont(ArialRoundedMTBold_14);
|
||||
String date = conditions->date;
|
||||
String date = conditions.date;
|
||||
gfx.drawString(120, 6, date);
|
||||
|
||||
gfx.setFont(ArialRoundedMTBold_36);
|
||||
String time = timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds();
|
||||
gfx.drawString(120, 20, time);
|
||||
}
|
||||
|
||||
void updateCalendar() {
|
||||
Serial.print("Free heap: ");
|
||||
Serial.println(ESP.getFreeHeap());
|
||||
const char* host = "script.google.com";
|
||||
// Replace with your own script id to make server side changes
|
||||
const char *GScriptId = "AKfycbwdOi6zab7cLU5fEr0AL6KrAMpygUoFHOtSrgnKfccyHHkpZPo";
|
||||
gfx.drawString(120, 20, time);*/
|
||||
char *dstAbbrev;
|
||||
char time_str[11];
|
||||
time_t now = dstAdjusted.time(&dstAbbrev);
|
||||
struct tm * timeinfo = localtime (&now);
|
||||
|
||||
const int httpsPort = 443;
|
||||
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";
|
||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
gfx.setFont(ArialRoundedMTBold_14);
|
||||
String date = ctime(&now);
|
||||
date = date.substring(0,11) + String(1900 + timeinfo->tm_year);
|
||||
gfx.drawString(120, 6, date);
|
||||
|
||||
// Use HTTPSRedirect class to create a new TLS connection
|
||||
HTTPSRedirect *client = new HTTPSRedirect(httpsPort);
|
||||
client->setPrintResponseBody(true);
|
||||
client->setContentTypeHeader("application/json");
|
||||
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;
|
||||
}
|
||||
gfx.setFont(ArialRoundedMTBold_36);
|
||||
|
||||
if (client->verify(fingerprint, host)) {
|
||||
Serial.println("Certificate match.");
|
||||
if (STYLE_12HR) {
|
||||
int hour = (timeinfo->tm_hour+11)%12+1; // take care of noon and midnight
|
||||
sprintf(time_str, "%2d:%02d:%02d\n",hour, timeinfo->tm_min, timeinfo->tm_sec);
|
||||
gfx.drawString(120, 20, time_str);
|
||||
} 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
|
||||
client->GET(url, host);
|
||||
|
||||
|
||||
delete client;
|
||||
client = nullptr;
|
||||
gfx.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
gfx.setFont(ArialMT_Plain_10);
|
||||
gfx.setColor(MINI_BLUE);
|
||||
if (STYLE_12HR) {
|
||||
sprintf(time_str, "%s\n%s", dstAbbrev, timeinfo->tm_hour>=12?"PM":"AM");
|
||||
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
|
||||
void drawCurrentWeather() {
|
||||
// Weather Icon
|
||||
|
||||
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
|
||||
gfx.setFont(ArialRoundedMTBold_14);
|
||||
gfx.setColor(MINI_YELLOW);
|
||||
gfx.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
gfx.drawString(220, 76, conditions->weatherText);
|
||||
gfx.drawString(220, 76, conditions.weatherText);
|
||||
|
||||
gfx.setFont(ArialRoundedMTBold_36);
|
||||
gfx.setColor(MINI_WHITE);
|
||||
@@ -318,7 +267,7 @@ void drawCurrentWeather() {
|
||||
if (IS_METRIC) {
|
||||
degreeSign = "°C";
|
||||
}
|
||||
String temp = conditions->currentTemp + degreeSign;
|
||||
String temp = conditions.currentTemp + degreeSign;
|
||||
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 + 180, y + 165, 4);
|
||||
}
|
||||
|
||||
void drawForecast2(MiniGrafx *display, CarouselState* state, int16_t x, int16_t y) {
|
||||
drawForecastDetail(x + 10, y + 165, 6);
|
||||
drawForecastDetail(x + 95, y + 165, 8);
|
||||
drawForecastDetail(x + 180, y + 165, 10);
|
||||
}
|
||||
// draws the three forecast columns
|
||||
void drawForecast() {
|
||||
|
||||
}
|
||||
|
||||
// helper for the forecast columns
|
||||
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.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
|
||||
void drawAstronomy() {
|
||||
char moonAgeImage = 65 + 26 * astronomy->moonAge.toInt() / 30.0;
|
||||
|
||||
gfx.setFont(MoonPhases_Regular_36);
|
||||
gfx.setColor(MINI_WHITE);
|
||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
gfx.drawString(120, 270, String(moonAgeImage));
|
||||
//gfx.drawBmpFromFile("/moon" + String(moonAgeImage) + ".bmp", 120 - 30, 255);
|
||||
gfx.drawString(120, 275, moonAgeImage);
|
||||
|
||||
gfx.setColor(MINI_WHITE);
|
||||
gfx.setFont(ArialRoundedMTBold_14);
|
||||
gfx.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
gfx.setColor(MINI_YELLOW);
|
||||
gfx.drawString(120, 245, astronomy->moonPhase);
|
||||
gfx.drawString(120, 250, astronomy.moonPhase);
|
||||
gfx.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
gfx.setColor(MINI_YELLOW);
|
||||
gfx.drawString(10, 245, "Sun");
|
||||
gfx.drawString(5, 250, "Sun");
|
||||
gfx.setColor(MINI_WHITE);
|
||||
astronomy->sunriseTime.trim();
|
||||
astronomy->sunriseTime.trim();
|
||||
gfx.drawString(10, 276, astronomy->sunriseTime);
|
||||
gfx.drawString(10, 291, astronomy->sunsetTime);
|
||||
gfx.drawString(5, 276, astronomy.sunriseTime);
|
||||
gfx.drawString(5, 291, astronomy.sunsetTime);
|
||||
|
||||
gfx.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
gfx.setColor(MINI_YELLOW);
|
||||
gfx.drawString(230, 245, "Moon");
|
||||
gfx.drawString(235, 250, "Moon");
|
||||
gfx.setColor(MINI_WHITE);
|
||||
astronomy->moonriseTime.trim();
|
||||
astronomy->moonsetTime.trim();
|
||||
gfx.drawString(230, 276, astronomy->moonriseTime);
|
||||
gfx.drawString(230, 291, astronomy->moonsetTime);
|
||||
gfx.drawString(235, 276, astronomy.moonriseTime);
|
||||
gfx.drawString(235, 291, astronomy.moonsetTime);
|
||||
|
||||
}
|
||||
|
||||
@@ -438,8 +382,4 @@ const char* getMiniMeteoconIconFromProgmem(String iconText) {
|
||||
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
|
||||
*/
|
||||
|
||||
#include <simpleDSTadjust.h>
|
||||
|
||||
// Setup
|
||||
const int UPDATE_INTERVAL_SECS = 10 * 60; // Update every 10 minutes
|
||||
|
||||
// Pins for the ILI9341
|
||||
#define TFT_DC D2
|
||||
#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
|
||||
// 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 String WUNDERGRROUND_API_KEY = "808ba87ed77c4501";
|
||||
const String WUNDERGRROUND_LANGUAGE = "EN";
|
||||
const String WUNDERGROUND_COUNTRY = "CH";
|
||||
const String WUNDERGROUND_CITY = "Zurich";
|
||||
|
||||
//Thingspeak Settings
|
||||
const String THINGSPEAK_CHANNEL_ID = "67284";
|
||||
const String THINGSPEAK_API_READ_KEY = "L2VIW20QVNZJBLAK";
|
||||
#define UTC_OFFSET + 1
|
||||
struct dstRule StartRule = {"CEST", Last, Sun, Mar, 2, 3600}; // Central European Summer Time = UTC/GMT +2 hours
|
||||
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
|
||||
String wundergroundIcons [] = {"chanceflurries","chancerain","chancesleet","chancesnow","clear","cloudy","flurries","fog","hazy","mostlycloudy","mostlysunny","partlycloudy","partlysunny","rain","sleet","snow","sunny","tstorms","unknown"};
|
||||
// Settings for Boston
|
||||
// #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
|
||||
|
||||
Reference in New Issue
Block a user