Qrome - Added Weather display and some cleanup

pull/22/head
Chrome Legion 2018-06-15 23:16:17 -07:00
parent b1fa89a492
commit f0562880e8
5 changed files with 1929 additions and 57 deletions

View File

@ -0,0 +1,303 @@
/** The MIT License (MIT)
Copyright (c) 2018 David Payne
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.
*/
#include "OpenWeatherMapClient.h"
OpenWeatherMapClient::OpenWeatherMapClient(String ApiKey, int CityIDs[], int cityCount, boolean isMetric) {
updateCityIdList(CityIDs, cityCount);
myApiKey = ApiKey;
setMetric(isMetric);
}
void OpenWeatherMapClient::updateWeatherApiKey(String ApiKey) {
myApiKey = ApiKey;
}
void OpenWeatherMapClient::updateWeather() {
WiFiClient weatherClient;
String apiGetData = "GET /data/2.5/group?id=" + myCityIDs + "&units=" + units + "&cnt=1&APPID=" + myApiKey + " HTTP/1.1";
Serial.println("Getting Weather Data");
Serial.println(apiGetData);
result = "";
if (weatherClient.connect(servername, 80)) { //starts client connection, checks for connection
weatherClient.println(apiGetData);
weatherClient.println("Host: " + String(servername));
weatherClient.println("User-Agent: ArduinoWiFi/1.1");
weatherClient.println("Connection: close");
weatherClient.println();
}
else {
Serial.println("connection for weather data failed"); //error message if no client connect
Serial.println();
return;
}
while(weatherClient.connected() && !weatherClient.available()) delay(1); //waits for data
Serial.println("Waiting for data");
// Check HTTP status
char status[32] = {0};
weatherClient.readBytesUntil('\r', status, sizeof(status));
Serial.println("Response Header: " + String(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(status);
return;
}
// Skip HTTP headers
char endOfHeaders[] = "\r\n\r\n";
if (!weatherClient.find(endOfHeaders)) {
Serial.println(F("Invalid response"));
return;
}
const size_t bufferSize = 710;
DynamicJsonBuffer jsonBuffer(bufferSize);
weathers[0].cached = false;
weathers[0].error = "";
// Parse JSON object
JsonObject& root = jsonBuffer.parseObject(weatherClient);
if (!root.success()) {
Serial.println(F("Weather Data Parsing failed!"));
weathers[0].error = "Weather Data Parsing failed!";
return;
}
weatherClient.stop(); //stop client
if (root.measureLength() <= 150) {
Serial.println("Error Does not look like we got the data. Size: " + String(root.measureLength()));
weathers[0].cached = true;
weathers[0].error = (const char*)root["message"];
Serial.println("Error: " + weathers[0].error);
return;
}
int count = root["cnt"];
for (int inx = 0; inx < count; inx++) {
weathers[inx].lat = (const char*)root["list"][inx]["coord"]["lat"];
weathers[inx].lon = (const char*)root["list"][inx]["coord"]["lon"];
weathers[inx].dt = (const char*)root["list"][inx]["dt"];
weathers[inx].city = (const char*)root["list"][inx]["name"];
weathers[inx].country = (const char*)root["list"][inx]["sys"]["country"];
weathers[inx].temp = (const char*)root["list"][inx]["main"]["temp"];
weathers[inx].humidity = (const char*)root["list"][inx]["main"]["humidity"];
weathers[inx].condition = (const char*)root["list"][inx]["weather"][0]["main"];
weathers[inx].wind = (const char*)root["list"][inx]["wind"]["speed"];
weathers[inx].weatherId = (const char*)root["list"][inx]["weather"][0]["id"];
weathers[inx].description = (const char*)root["list"][inx]["weather"][0]["description"];
weathers[inx].icon = (const char*)root["list"][inx]["weather"][0]["icon"];
Serial.println("lat: " + weathers[inx].lat);
Serial.println("lon: " + weathers[inx].lon);
Serial.println("dt: " + weathers[inx].dt);
Serial.println("city: " + weathers[inx].city);
Serial.println("country: " + weathers[inx].country);
Serial.println("temp: " + weathers[inx].temp);
Serial.println("humidity: " + weathers[inx].humidity);
Serial.println("condition: " + weathers[inx].condition);
Serial.println("wind: " + weathers[inx].wind);
Serial.println("weatherId: " + weathers[inx].weatherId);
Serial.println("description: " + weathers[inx].description);
Serial.println("icon: " + weathers[inx].icon);
Serial.println();
}
}
String OpenWeatherMapClient::roundValue(String value) {
float f = value.toFloat();
int rounded = (int)(f+0.5f);
return String(rounded);
}
void OpenWeatherMapClient::updateCityIdList(int CityIDs[], int cityCount) {
myCityIDs = "";
for (int inx = 0; inx < cityCount; inx++) {
if (CityIDs[inx] > 0) {
if (myCityIDs != "") {
myCityIDs = myCityIDs + ",";
}
myCityIDs = myCityIDs + String(CityIDs[inx]);
}
}
}
void OpenWeatherMapClient::setMetric(boolean isMetric) {
if (isMetric) {
units = "metric";
} else {
units = "imperial";
}
}
String OpenWeatherMapClient::getWeatherResults() {
return result;
}
String OpenWeatherMapClient::getLat(int index) {
return weathers[index].lat;
}
String OpenWeatherMapClient::getLon(int index) {
return weathers[index].lon;
}
String OpenWeatherMapClient::getDt(int index) {
return weathers[index].dt;
}
String OpenWeatherMapClient::getCity(int index) {
return weathers[index].city;
}
String OpenWeatherMapClient::getCountry(int index) {
return weathers[index].country;
}
String OpenWeatherMapClient::getTemp(int index) {
return weathers[index].temp;
}
String OpenWeatherMapClient::getTempRounded(int index) {
return roundValue(getTemp(index));
}
String OpenWeatherMapClient::getHumidity(int index) {
return weathers[index].humidity;
}
String OpenWeatherMapClient::getHumidityRounded(int index) {
return roundValue(getHumidity(index));
}
String OpenWeatherMapClient::getCondition(int index) {
return weathers[index].condition;
}
String OpenWeatherMapClient::getWind(int index) {
return weathers[index].wind;
}
String OpenWeatherMapClient::getWindRounded(int index) {
return roundValue(getWind(index));
}
String OpenWeatherMapClient::getWeatherId(int index) {
return weathers[index].weatherId;
}
String OpenWeatherMapClient::getDescription(int index) {
return weathers[index].description;
}
String OpenWeatherMapClient::getIcon(int index) {
return weathers[index].icon;
}
boolean OpenWeatherMapClient::getCached() {
return weathers[0].cached;
}
String OpenWeatherMapClient::getMyCityIDs() {
return myCityIDs;
}
String OpenWeatherMapClient::getError() {
return weathers[0].error;
}
String OpenWeatherMapClient::getWeatherIcon(int index)
{
int id = getWeatherId(index).toInt();
String W = ")";
switch(id)
{
case 800: W = "B"; break;
case 801: W = "Y"; break;
case 802: W = "H"; break;
case 803: W = "H"; break;
case 804: W = "Y"; break;
case 200: W = "0"; break;
case 201: W = "0"; break;
case 202: W = "0"; break;
case 210: W = "0"; break;
case 211: W = "0"; break;
case 212: W = "0"; break;
case 221: W = "0"; break;
case 230: W = "0"; break;
case 231: W = "0"; break;
case 232: W = "0"; break;
case 300: W = "R"; break;
case 301: W = "R"; break;
case 302: W = "R"; break;
case 310: W = "R"; break;
case 311: W = "R"; break;
case 312: W = "R"; break;
case 313: W = "R"; break;
case 314: W = "R"; break;
case 321: W = "R"; break;
case 500: W = "R"; break;
case 501: W = "R"; break;
case 502: W = "R"; break;
case 503: W = "R"; break;
case 504: W = "R"; break;
case 511: W = "R"; break;
case 520: W = "R"; break;
case 521: W = "R"; break;
case 522: W = "R"; break;
case 531: W = "R"; break;
case 600: W = "W"; break;
case 601: W = "W"; break;
case 602: W = "W"; break;
case 611: W = "W"; break;
case 612: W = "W"; break;
case 615: W = "W"; break;
case 616: W = "W"; break;
case 620: W = "W"; break;
case 621: W = "W"; break;
case 622: W = "W"; break;
case 701: W = "M"; break;
case 711: W = "M"; break;
case 721: W = "M"; break;
case 731: W = "M"; break;
case 741: W = "M"; break;
case 751: W = "M"; break;
case 761: W = "M"; break;
case 762: W = "M"; break;
case 771: W = "M"; break;
case 781: W = "M"; break;
default:break;
}
return W;
}

View File

@ -0,0 +1,88 @@
/** The MIT License (MIT)
Copyright (c) 2018 David Payne
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.
*/
#pragma once
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
class OpenWeatherMapClient {
private:
String myCityIDs = "";
String myApiKey = "";
String units = "";
const char* servername = "api.openweathermap.org"; // remote server we will connect to
String result;
typedef struct {
String lat;
String lon;
String dt;
String city;
String country;
String temp;
String humidity;
String condition;
String wind;
String weatherId;
String description;
String icon;
boolean cached;
String error;
} weather;
weather weathers[5];
String roundValue(String value);
public:
OpenWeatherMapClient(String ApiKey, int CityIDs[], int cityCount, boolean isMetric);
void updateWeather();
void updateWeatherApiKey(String ApiKey);
void updateCityIdList(int CityIDs[], int cityCount);
void setMetric(boolean isMetric);
String getWeatherResults();
String getLat(int index);
String getLon(int index);
String getDt(int index);
String getCity(int index);
String getCountry(int index);
String getTemp(int index);
String getTempRounded(int index);
String getHumidity(int index);
String getHumidityRounded(int index);
String getCondition(int index);
String getWind(int index);
String getWindRounded(int index);
String getWeatherId(int index);
String getDescription(int index);
String getIcon(int index);
boolean getCached();
String getMyCityIDs();
String getWeatherIcon(int index);
String getError();
};

View File

@ -42,6 +42,8 @@ SOFTWARE.
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#include "TimeClient.h" #include "TimeClient.h"
#include "OctoPrintClient.h" #include "OctoPrintClient.h"
#include "OpenWeatherMapClient.h"
#include "WeatherStationFonts.h"
#include "FS.h" #include "FS.h"
#include "SH1106Wire.h" #include "SH1106Wire.h"
#include "SSD1306Wire.h" #include "SSD1306Wire.h"
@ -59,13 +61,20 @@ int OctoPrintPort = 80; // the port you are running your OctoPrint server
String OctoAuthUser = ""; // only used if you have haproxy or basic athentintication turned on (not default) String OctoAuthUser = ""; // only used if you have haproxy or basic athentintication turned on (not default)
String OctoAuthPass = ""; // only used with haproxy or basic auth (only needed if you must authenticate) String OctoAuthPass = ""; // only used with haproxy or basic auth (only needed if you must authenticate)
// Weather Configuration
boolean DISPLAYWEATHER = true; // true = show weather when not printing / false = no weather
String WeatherApiKey = ""; // Your API Key from http://openweathermap.org/
// Default City Location (use http://openweathermap.org/find to find city ID)
int CityIDs[] = { 5304391 }; //Only USE ONE for weather marquee
boolean IS_METRIC = false; // false = Imperial and true = Metric
const int WEBSERVER_PORT = 80; // The port you can access this device on over HTTP const int WEBSERVER_PORT = 80; // The port you can access this device on over HTTP
const boolean WEBSERVER_ENABLED = true; // Device will provide a web interface via http://[ip]:[port]/ const boolean WEBSERVER_ENABLED = true; // Device will provide a web interface via http://[ip]:[port]/
char* www_username = "admin"; // User account for the Web Interface char* www_username = "admin"; // User account for the Web Interface
char* www_password = "password"; // Password for the Web Interface char* www_password = "password"; // Password for the Web Interface
float UtcOffset = -7; // Hour offset from GMT for your timezone float UtcOffset = -7; // Hour offset from GMT for your timezone
boolean IS_24HOUR = false; // 23:00 millitary 24 hour clock boolean IS_24HOUR = false; // 23:00 millitary 24 hour clock
int minutesBetweenDataRefresh = 60; int minutesBetweenDataRefresh = 15;
boolean DISPLAYCLOCK = true; // true = Show Clock when not printing / false = turn off display when not printing boolean DISPLAYCLOCK = true; // true = Show Clock when not printing / false = turn off display when not printing
// Display Settings // Display Settings

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@ SOFTWARE.
#include "Settings.h" #include "Settings.h"
#define VERSION "1.7" #define VERSION "2.0"
#define HOSTNAME "OctMon-" #define HOSTNAME "OctMon-"
#define CONFIG "/conf.txt" #define CONFIG "/conf.txt"
@ -60,12 +60,13 @@ void drawScreen2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int
void drawScreen3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); void drawScreen3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state); void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
void drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); void drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state); void drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
// Set the number of Frames supported // Set the number of Frames supported
const int numberOfFrames = 3; const int numberOfFrames = 3;
FrameCallback frames[numberOfFrames]; FrameCallback frames[numberOfFrames];
FrameCallback clockFrame[1]; FrameCallback clockFrame[2];
boolean isClockOn = false; boolean isClockOn = false;
OverlayCallback overlays[] = { drawHeaderOverlay }; OverlayCallback overlays[] = { drawHeaderOverlay };
@ -86,57 +87,71 @@ boolean displayOn = true;
OctoPrintClient printerClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass); OctoPrintClient printerClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass);
int printerCount = 0; int printerCount = 0;
// Weather Client
OpenWeatherMapClient weatherClient(WeatherApiKey, CityIDs, 1, IS_METRIC);
//declairing prototypes //declairing prototypes
void configModeCallback (WiFiManager *myWiFiManager); void configModeCallback (WiFiManager *myWiFiManager);
int8_t getWifiQuality(); int8_t getWifiQuality();
ESP8266WebServer server(WEBSERVER_PORT); ESP8266WebServer server(WEBSERVER_PORT);
const String WEB_ACTIONS = "<a class='w3-bar-item w3-button' href='/'><i class='fa fa-home'></i> Home</a>" String WEB_ACTIONS = "<a class='w3-bar-item w3-button' href='/'><i class='fa fa-home'></i> Home</a>"
"<a class='w3-bar-item w3-button' href='/configure'><i class='fa fa-cog'></i> Configure</a>" "<a class='w3-bar-item w3-button' href='/configure'><i class='fa fa-cog'></i> Configure</a>"
"<a class='w3-bar-item w3-button' href='/systemreset' onclick='return confirm(\"Do you want to reset to default settings?\")'><i class='fa fa-undo'></i> Reset Settings</a>" "<a class='w3-bar-item w3-button' href='/configureweather'><i class='fa fa-cloud'></i> Weather</a>"
"<a class='w3-bar-item w3-button' href='/forgetwifi' onclick='return confirm(\"Do you want to forget to WiFi connection?\")'><i class='fa fa-wifi'></i> Forget WiFi</a>" "<a class='w3-bar-item w3-button' href='/systemreset' onclick='return confirm(\"Do you want to reset to default settings?\")'><i class='fa fa-undo'></i> Reset Settings</a>"
"<a class='w3-bar-item w3-button' href='https://github.com/Qrome' target='_blank'><i class='fa fa-question-circle'></i> About</a>"; "<a class='w3-bar-item w3-button' href='/forgetwifi' onclick='return confirm(\"Do you want to forget to WiFi connection?\")'><i class='fa fa-wifi'></i> Forget WiFi</a>"
"<a class='w3-bar-item w3-button' href='https://github.com/Qrome' target='_blank'><i class='fa fa-question-circle'></i> About</a>";
const String CHANGE_FORM = "<form class='w3-container' action='/updateconfig' method='get'><h2>Station Config:</h2>" String CHANGE_FORM = "<form class='w3-container' action='/updateconfig' method='get'><h2>Station Config:</h2>"
"<p><label>OctoPrint API Key (get from your server)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoPrintApiKey' value='%OCTOKEY%' maxlength='60'></p>" "<p><label>OctoPrint API Key (get from your server)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoPrintApiKey' value='%OCTOKEY%' maxlength='60'></p>"
"<p><label>OctoPrint Host Name (usually octopi)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoPrintHostName' value='%OCTOHOST%' maxlength='60'></p>" "<p><label>OctoPrint Host Name (usually octopi)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoPrintHostName' value='%OCTOHOST%' maxlength='60'></p>"
"<p><label>OctoPrint Address (do not include http://)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoPrintAddress' value='%OCTOADDRESS%' maxlength='60'></p>" "<p><label>OctoPrint Address (do not include http://)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoPrintAddress' value='%OCTOADDRESS%' maxlength='60'></p>"
"<p><label>OctoPrint Port</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoPrintPort' value='%OCTOPORT%' maxlength='5' onkeypress='return isNumberKey(event)'></p>" "<p><label>OctoPrint Port</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoPrintPort' value='%OCTOPORT%' maxlength='5' onkeypress='return isNumberKey(event)'></p>"
"<p><label>OctoPrint User (only needed if you have haproxy or basic auth turned on)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoUser' value='%OCTOUSER%' maxlength='30'></p>" "<p><label>OctoPrint User (only needed if you have haproxy or basic auth turned on)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='octoUser' value='%OCTOUSER%' maxlength='30'></p>"
"<p><label>OctoPrint Password </label><input class='w3-input w3-border w3-margin-bottom' type='password' name='octoPass' value='%OCTOPASS%'></p><hr>" "<p><label>OctoPrint Password </label><input class='w3-input w3-border w3-margin-bottom' type='password' name='octoPass' value='%OCTOPASS%'></p><hr>"
"<p><input name='isClockEnabled' class='w3-check w3-margin-top' type='checkbox' %IS_CLOCK_CHECKED%> Display Clock when printer is off</p>" "<p><input name='isClockEnabled' class='w3-check w3-margin-top' type='checkbox' %IS_CLOCK_CHECKED%> Display Clock when printer is off</p>"
"<p><input name='is24hour' class='w3-check w3-margin-top' type='checkbox' %IS_24HOUR_CHECKED%> Use 24 Hour Clock (military time)</p>" "<p><input name='is24hour' class='w3-check w3-margin-top' type='checkbox' %IS_24HOUR_CHECKED%> Use 24 Hour Clock (military time)</p>"
"<p>Time Refresh (minutes) <select class='w3-option w3-padding' name='refresh'>%OPTIONS%</select></p>" "<p>Clock Sync / Weather Refresh (minutes) <select class='w3-option w3-padding' name='refresh'>%OPTIONS%</select></p>"
"<p>Theme Color <select class='w3-option w3-padding' name='theme'>%THEME_OPTIONS%</select></p>" "<p>Theme Color <select class='w3-option w3-padding' name='theme'>%THEME_OPTIONS%</select></p>"
"<p><label>UTC Time Offset</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='utcoffset' value='%UTCOFFSET%' maxlength='12'></p><hr>" "<p><label>UTC Time Offset</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='utcoffset' value='%UTCOFFSET%' maxlength='12'></p><hr>"
"<p><label>User ID (for this interface)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='userid' value='%USERID%' maxlength='20'></p>" "<p><label>User ID (for this interface)</label><input class='w3-input w3-border w3-margin-bottom' type='text' name='userid' value='%USERID%' maxlength='20'></p>"
"<p><label>Password </label><input class='w3-input w3-border w3-margin-bottom' type='password' name='stationpassword' value='%STATIONPASSWORD%'></p>" "<p><label>Password </label><input class='w3-input w3-border w3-margin-bottom' type='password' name='stationpassword' value='%STATIONPASSWORD%'></p>"
"<button class='w3-button w3-block w3-grey w3-section w3-padding' type='submit'>Save</button></form>"; "<button class='w3-button w3-block w3-grey w3-section w3-padding' type='submit'>Save</button></form>";
const String COLOR_THEMES = "<option>red</option>" String WEATHER_FORM = "<form class='w3-container' action='/updateweatherconfig' method='get'><h2>Weather Config:</h2>"
"<option>pink</option>" "<p><input name='isWeatherEnabled' class='w3-check w3-margin-top' type='checkbox' %IS_WEATHER_CHECKED%> Display Weather when printer is off</p>"
"<option>purple</option>" "<label>OpenWeahterMap API Key (get from <a href='https://openweathermap.org/' target='_BLANK'>here</a>)</label>"
"<option>deep-purple</option>" "<input class='w3-input w3-border w3-margin-bottom' type='text' name='openWeatherMapApiKey' value='%WEATHERKEY%' maxlength='60'>"
"<option>indigo</option>" "<p><label>%CITYNAME1% (<a href='http://openweathermap.org/find' target='_BLANK'><i class='fa fa-search'></i> Search for City ID</a>)</label>"
"<option>blue</option>" "<input class='w3-input w3-border w3-margin-bottom' type='text' name='city1' value='%CITY1%' onkeypress='return isNumberKey(event)'></p>"
"<option>light-blue</option>" "<p><input name='metric' class='w3-check w3-margin-top' type='checkbox' %METRIC%> Use Metric (Celsius)</p>"
"<option>cyan</option>" "<button class='w3-button w3-block w3-grey w3-section w3-padding' type='submit'>Save</button></form>"
"<option>teal</option>" "<script>function isNumberKey(e){var h=e.which?e.which:event.keyCode;return!(h>31&&(h<48||h>57))}</script>";
"<option>green</option>"
"<option>light-green</option>" String COLOR_THEMES = "<option>red</option>"
"<option>lime</option>" "<option>pink</option>"
"<option>khaki</option>" "<option>purple</option>"
"<option>yellow</option>" "<option>deep-purple</option>"
"<option>amber</option>" "<option>indigo</option>"
"<option>orange</option>" "<option>blue</option>"
"<option>deep-orange</option>" "<option>light-blue</option>"
"<option>blue-grey</option>" "<option>cyan</option>"
"<option>brown</option>" "<option>teal</option>"
"<option>grey</option>" "<option>green</option>"
"<option>dark-grey</option>" "<option>light-green</option>"
"<option>black</option>" "<option>lime</option>"
"<option>w3schools</option>"; "<option>khaki</option>"
"<option>yellow</option>"
"<option>amber</option>"
"<option>orange</option>"
"<option>deep-orange</option>"
"<option>blue-grey</option>"
"<option>brown</option>"
"<option>grey</option>"
"<option>dark-grey</option>"
"<option>black</option>"
"<option>w3schools</option>";
// Change the externalLight to the pin you wish to use if other than the Built-in LED // Change the externalLight to the pin you wish to use if other than the Built-in LED
@ -197,6 +212,7 @@ void setup() {
frames[1] = drawScreen2; frames[1] = drawScreen2;
frames[2] = drawScreen3; frames[2] = drawScreen3;
clockFrame[0] = drawClock; clockFrame[0] = drawClock;
clockFrame[1] = drawWeather;
ui.setOverlays(overlays, numberOfOverlays); ui.setOverlays(overlays, numberOfOverlays);
// Inital UI takes care of initalising the display too. // Inital UI takes care of initalising the display too.
@ -240,7 +256,9 @@ void setup() {
server.on("/systemreset", handleSystemReset); server.on("/systemreset", handleSystemReset);
server.on("/forgetwifi", handleWifiReset); server.on("/forgetwifi", handleWifiReset);
server.on("/updateconfig", handleUpdateConfig); server.on("/updateconfig", handleUpdateConfig);
server.on("/updateweatherconfig", handleUpdateWeather);
server.on("/configure", handleConfigure); server.on("/configure", handleConfigure);
server.on("/configureweather", handleWeatherConfigure);
server.onNotFound(redirectHome); server.onNotFound(redirectHome);
// Start the server // Start the server
server.begin(); server.begin();
@ -340,6 +358,11 @@ void getUpdateTime() {
digitalWrite(externalLight, LOW); // turn on the LED digitalWrite(externalLight, LOW); // turn on the LED
Serial.println(); Serial.println();
if (displayOn && DISPLAYWEATHER) {
Serial.println("Getting Weather Data...");
weatherClient.updateWeather();
}
Serial.println("Updating Time..."); Serial.println("Updating Time...");
//Update the Time //Update the Time
timeClient.updateTime(); timeClient.updateTime();
@ -360,6 +383,21 @@ void handleSystemReset() {
} }
} }
void handleUpdateWeather() {
if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication();
}
DISPLAYWEATHER = server.hasArg("isWeatherEnabled");
WeatherApiKey = server.arg("openWeatherMapApiKey");
CityIDs[0] = server.arg("city1").toInt();
IS_METRIC = server.hasArg("metric");
writeSettings();
isClockOn = false; // this will force a check for the display
checkDisplay();
lastEpoch = 0;
redirectHome();
}
void handleUpdateConfig() { void handleUpdateConfig() {
if (!server.authenticate(www_username, www_password)) { if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication(); return server.requestAuthentication();
@ -399,6 +437,46 @@ void handleWifiReset() {
ESP.restart(); ESP.restart();
} }
void handleWeatherConfigure() {
if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication();
}
digitalWrite(externalLight, LOW);
String html = "";
server.sendHeader("Cache-Control", "no-cache, no-store");
server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1");
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(200, "text/html", "");
html = getHeader();
server.sendContent(html);
String form = WEATHER_FORM;
String isWeatherChecked = "";
if (DISPLAYWEATHER) {
isWeatherChecked = "checked='checked'";
}
form.replace("%IS_WEATHER_CHECKED%", isWeatherChecked);
form.replace("%WEATHERKEY%", WeatherApiKey);
form.replace("%CITYNAME1%", weatherClient.getCity(0));
form.replace("%CITY1%", String(CityIDs[0]));
String checked = "";
if (IS_METRIC) {
checked = "checked='checked'";
}
form.replace("%METRIC%", checked);
server.sendContent(form);
html = getFooter();
server.sendContent(html);
server.sendContent("");
server.client().stop();
digitalWrite(externalLight, HIGH);
}
void handleConfigure() { void handleConfigure() {
if (!server.authenticate(www_username, www_password)) { if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication(); return server.requestAuthentication();
@ -415,7 +493,7 @@ void handleConfigure() {
html = getHeader(); html = getHeader();
server.sendContent(html); server.sendContent(html);
String form = String(CHANGE_FORM); String form = CHANGE_FORM;
form.replace("%OCTOKEY%", OctoPrintApiKey); form.replace("%OCTOKEY%", OctoPrintApiKey);
form.replace("%OCTOHOST%", OctoPrintHostName); form.replace("%OCTOHOST%", OctoPrintHostName);
@ -436,14 +514,14 @@ void handleConfigure() {
String options = "<option>10</option><option>15</option><option>20</option><option>30</option><option>60</option>"; String options = "<option>10</option><option>15</option><option>20</option><option>30</option><option>60</option>";
options.replace(">"+String(minutesBetweenDataRefresh)+"<", " selected>"+String(minutesBetweenDataRefresh)+"<"); options.replace(">"+String(minutesBetweenDataRefresh)+"<", " selected>"+String(minutesBetweenDataRefresh)+"<");
form.replace("%OPTIONS%", options); form.replace("%OPTIONS%", options);
String themeOptions = String(COLOR_THEMES); String themeOptions = COLOR_THEMES;
themeOptions.replace(">"+String(themeColor)+"<", " selected>"+String(themeColor)+"<"); themeOptions.replace(">"+String(themeColor)+"<", " selected>"+String(themeColor)+"<");
form.replace("%THEME_OPTIONS%", themeOptions); form.replace("%THEME_OPTIONS%", themeOptions);
form.replace("%UTCOFFSET%", String(UtcOffset)); form.replace("%UTCOFFSET%", String(UtcOffset));
form.replace("%USERID%", String(www_username)); form.replace("%USERID%", String(www_username));
form.replace("%STATIONPASSWORD%", String(www_password)); form.replace("%STATIONPASSWORD%", String(www_password));
server.sendContent(String(form)); server.sendContent(form);
html = getFooter(); html = getFooter();
server.sendContent(html); server.sendContent(html);
@ -486,7 +564,7 @@ String getHeader() {
} }
String getHeader(boolean refresh) { String getHeader(boolean refresh) {
String menu = String(WEB_ACTIONS); String menu = WEB_ACTIONS;
String html = "<!DOCTYPE HTML>"; String html = "<!DOCTYPE HTML>";
html += "<html><head><title>Printer Monitor</title><link rel='icon' href='data:;base64,='>"; html += "<html><head><title>Printer Monitor</title><link rel='icon' href='data:;base64,='>";
@ -586,8 +664,32 @@ void displayPrinterStatus() {
html += "<div id=\"myProgress\"><div id=\"myBar\" class=\"w3-medium w3-center\">" + printerClient.getProgressCompletion() + "%</div></div>"; html += "<div id=\"myProgress\"><div id=\"myBar\" class=\"w3-medium w3-center\">" + printerClient.getProgressCompletion() + "%</div></div>";
html += "</p></div></div>"; html += "</p></div></div>";
server.sendContent(String(html)); // spit out what we got server.sendContent(html); // spit out what we got
html = "";
if (DISPLAYWEATHER) {
if (weatherClient.getCity(0) == "") {
html += "<p>Please <a href='/configureweather'>Configure Weahter</a> API</p>";
if (weatherClient.getError() != "") {
html += "<p>Weather Error: <strong>" + weatherClient.getError() + "</strong></p>";
}
} else {
html += "<div class='w3-cell-row' style='width:100%'><h2>" + weatherClient.getCity(0) + ", " + weatherClient.getCountry(0) + "</h2></div><div class='w3-cell-row'>";
html += "<div class='w3-cell w3-left w3-medium' style='width:120px'>";
html += "<img src='http://openweathermap.org/img/w/" + weatherClient.getIcon(0) + ".png' alt='" + weatherClient.getDescription(0) + "'><br>";
html += weatherClient.getHumidity(0) + "% Humidity<br>";
html += weatherClient.getWind(0) + " <span class='w3-tiny'>" + getSpeedSymbol() + "</span> Wind<br>";
html += "</div>";
html += "<div class='w3-cell w3-container' style='width:100%'><p>";
html += weatherClient.getCondition(0) + " (" + weatherClient.getDescription(0) + ")<br>";
html += weatherClient.getTempRounded(0) + getTempSymbol(true) + "<br>";
html += "<a href='https://www.google.com/maps/@" + weatherClient.getLat(0) + "," + weatherClient.getLon(0) + ",10000m/data=!3m1!1e3' target='_BLANK'><i class='fa fa-map-marker' style='color:red'></i> Map It!</a><br>";
html += "</p></div></div>";
}
server.sendContent(html); // spit out what we got
html = ""; // fresh start
}
server.sendContent(String(getFooter())); server.sendContent(String(getFooter()));
server.sendContent(""); server.sendContent("");
@ -683,6 +785,44 @@ void drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16
display->drawString(64 + x, 10 + y, displayTime); display->drawString(64 + x, 10 + y, displayTime);
} }
void drawWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_24);
display->drawString(0 + x, 0 + y, weatherClient.getTempRounded(0) + getTempSymbol());
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_24);
display->setFont(ArialMT_Plain_16);
display->drawString(0 + x, 24 + y, weatherClient.getCondition(0));
display->setFont((const uint8_t*)Meteocons_Plain_42);
display->drawString(86 + x, 0 + y, weatherClient.getWeatherIcon(0));
}
String getTempSymbol() {
return getTempSymbol(false);
}
String getTempSymbol(boolean forHTML) {
String rtnValue = "F";
if (IS_METRIC) {
rtnValue = "C";
}
if (forHTML) {
rtnValue = "&#176;" + rtnValue;
} else {
rtnValue = "°" + rtnValue;
}
return rtnValue;
}
String getSpeedSymbol() {
String rtnValue = "mph";
if (IS_METRIC) {
rtnValue = "kph";
}
return rtnValue;
}
String zeroPad(int value) { String zeroPad(int value) {
String rtnValue = String(value); String rtnValue = String(value);
if (value < 10) { if (value < 10) {
@ -734,7 +874,7 @@ void drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
display->drawString(64, 48, "offline"); display->drawString(64, 48, "offline");
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawRect(0, 41, 128, 2); display->drawRect(0, 43, 128, 2);
drawRssi(display); drawRssi(display);
} }
@ -785,6 +925,10 @@ void writeSettings() {
f.println("www_password=" + String(www_password)); f.println("www_password=" + String(www_password));
f.println("DISPLAYCLOCK=" + String(DISPLAYCLOCK)); f.println("DISPLAYCLOCK=" + String(DISPLAYCLOCK));
f.println("is24hour=" + String(IS_24HOUR)); f.println("is24hour=" + String(IS_24HOUR));
f.println("isWeather=" + String(DISPLAYWEATHER));
f.println("weatherKey=" + WeatherApiKey);
f.println("CityID=" + String(CityIDs[0]));
f.println("isMetric=" + String(IS_METRIC));
} }
f.close(); f.close();
readSettings(); readSettings();
@ -864,9 +1008,29 @@ void readSettings() {
IS_24HOUR = line.substring(line.lastIndexOf("is24hour=") + 9).toInt(); IS_24HOUR = line.substring(line.lastIndexOf("is24hour=") + 9).toInt();
Serial.println("IS_24HOUR=" + String(IS_24HOUR)); Serial.println("IS_24HOUR=" + String(IS_24HOUR));
} }
if (line.indexOf("isWeather=") >= 0) {
DISPLAYWEATHER = line.substring(line.lastIndexOf("isWeather=") + 10).toInt();
Serial.println("DISPLAYWEATHER=" + String(DISPLAYWEATHER));
}
if (line.indexOf("weatherKey=") >= 0) {
WeatherApiKey = line.substring(line.lastIndexOf("weatherKey=") + 11);
WeatherApiKey.trim();
Serial.println("WeatherApiKey=" + WeatherApiKey);
}
if (line.indexOf("CityID=") >= 0) {
CityIDs[0] = line.substring(line.lastIndexOf("CityID=") + 7).toInt();
Serial.println("CityID: " + String(CityIDs[0]));
}
if (line.indexOf("isMetric=") >= 0) {
IS_METRIC = line.substring(line.lastIndexOf("isMetric=") + 9).toInt();
Serial.println("IS_METRIC=" + String(IS_METRIC));
}
} }
fr.close(); fr.close();
printerClient.updateOctoPrintClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass); printerClient.updateOctoPrintClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass);
weatherClient.updateWeatherApiKey(WeatherApiKey);
weatherClient.setMetric(IS_METRIC);
weatherClient.updateCityIdList(CityIDs, 1);
timeClient.setUtcOffset(UtcOffset); timeClient.setUtcOffset(UtcOffset);
} }
@ -916,9 +1080,16 @@ void checkDisplay() {
} else if (DISPLAYCLOCK) { } else if (DISPLAYCLOCK) {
if (!printerClient.isOperational() && !isClockOn) { if (!printerClient.isOperational() && !isClockOn) {
Serial.println("Clock Mode is turned on."); Serial.println("Clock Mode is turned on.");
ui.disableAutoTransition(); if (!DISPLAYWEATHER) {
ui.setFrames(clockFrame, 1); ui.disableAutoTransition();
clockFrame[0] = drawClock; ui.setFrames(clockFrame, 1);
clockFrame[0] = drawClock;
} else {
ui.enableAutoTransition();
ui.setFrames(clockFrame, 2);
clockFrame[0] = drawClock;
clockFrame[1] = drawWeather;
}
ui.setOverlays(clockOverlay, numberOfOverlays); ui.setOverlays(clockOverlay, numberOfOverlays);
isClockOn = true; isClockOn = true;
} else if (printerClient.isOperational() && isClockOn) { } else if (printerClient.isOperational() && isClockOn) {