Qrome - Added Weather display and some cleanup
parent
b1fa89a492
commit
f0562880e8
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
@ -42,6 +42,8 @@ SOFTWARE.
|
|||
#include <ArduinoOTA.h>
|
||||
#include "TimeClient.h"
|
||||
#include "OctoPrintClient.h"
|
||||
#include "OpenWeatherMapClient.h"
|
||||
#include "WeatherStationFonts.h"
|
||||
#include "FS.h"
|
||||
#include "SH1106Wire.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 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 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_password = "password"; // Password for the Web Interface
|
||||
float UtcOffset = -7; // Hour offset from GMT for your timezone
|
||||
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
|
||||
|
||||
// Display Settings
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -27,7 +27,7 @@ SOFTWARE.
|
|||
|
||||
#include "Settings.h"
|
||||
|
||||
#define VERSION "1.7"
|
||||
#define VERSION "2.0"
|
||||
|
||||
#define HOSTNAME "OctMon-"
|
||||
#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 drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
|
||||
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);
|
||||
|
||||
// Set the number of Frames supported
|
||||
const int numberOfFrames = 3;
|
||||
FrameCallback frames[numberOfFrames];
|
||||
FrameCallback clockFrame[1];
|
||||
FrameCallback clockFrame[2];
|
||||
boolean isClockOn = false;
|
||||
|
||||
OverlayCallback overlays[] = { drawHeaderOverlay };
|
||||
|
|
@ -86,57 +87,71 @@ boolean displayOn = true;
|
|||
OctoPrintClient printerClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass);
|
||||
int printerCount = 0;
|
||||
|
||||
// Weather Client
|
||||
OpenWeatherMapClient weatherClient(WeatherApiKey, CityIDs, 1, IS_METRIC);
|
||||
|
||||
//declairing prototypes
|
||||
void configModeCallback (WiFiManager *myWiFiManager);
|
||||
int8_t getWifiQuality();
|
||||
|
||||
ESP8266WebServer server(WEBSERVER_PORT);
|
||||
|
||||
const 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='/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='/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>";
|
||||
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='/configureweather'><i class='fa fa-cloud'></i> Weather</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='/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>"
|
||||
"<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 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 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><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>Time 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><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>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>";
|
||||
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 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 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 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='is24hour' class='w3-check w3-margin-top' type='checkbox' %IS_24HOUR_CHECKED%> Use 24 Hour Clock (military time)</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><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>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>";
|
||||
|
||||
const String COLOR_THEMES = "<option>red</option>"
|
||||
"<option>pink</option>"
|
||||
"<option>purple</option>"
|
||||
"<option>deep-purple</option>"
|
||||
"<option>indigo</option>"
|
||||
"<option>blue</option>"
|
||||
"<option>light-blue</option>"
|
||||
"<option>cyan</option>"
|
||||
"<option>teal</option>"
|
||||
"<option>green</option>"
|
||||
"<option>light-green</option>"
|
||||
"<option>lime</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>";
|
||||
String WEATHER_FORM = "<form class='w3-container' action='/updateweatherconfig' method='get'><h2>Weather Config:</h2>"
|
||||
"<p><input name='isWeatherEnabled' class='w3-check w3-margin-top' type='checkbox' %IS_WEATHER_CHECKED%> Display Weather when printer is off</p>"
|
||||
"<label>OpenWeahterMap API Key (get from <a href='https://openweathermap.org/' target='_BLANK'>here</a>)</label>"
|
||||
"<input class='w3-input w3-border w3-margin-bottom' type='text' name='openWeatherMapApiKey' value='%WEATHERKEY%' maxlength='60'>"
|
||||
"<p><label>%CITYNAME1% (<a href='http://openweathermap.org/find' target='_BLANK'><i class='fa fa-search'></i> Search for City ID</a>)</label>"
|
||||
"<input class='w3-input w3-border w3-margin-bottom' type='text' name='city1' value='%CITY1%' onkeypress='return isNumberKey(event)'></p>"
|
||||
"<p><input name='metric' class='w3-check w3-margin-top' type='checkbox' %METRIC%> Use Metric (Celsius)</p>"
|
||||
"<button class='w3-button w3-block w3-grey w3-section w3-padding' type='submit'>Save</button></form>"
|
||||
"<script>function isNumberKey(e){var h=e.which?e.which:event.keyCode;return!(h>31&&(h<48||h>57))}</script>";
|
||||
|
||||
String COLOR_THEMES = "<option>red</option>"
|
||||
"<option>pink</option>"
|
||||
"<option>purple</option>"
|
||||
"<option>deep-purple</option>"
|
||||
"<option>indigo</option>"
|
||||
"<option>blue</option>"
|
||||
"<option>light-blue</option>"
|
||||
"<option>cyan</option>"
|
||||
"<option>teal</option>"
|
||||
"<option>green</option>"
|
||||
"<option>light-green</option>"
|
||||
"<option>lime</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
|
||||
|
|
@ -197,6 +212,7 @@ void setup() {
|
|||
frames[1] = drawScreen2;
|
||||
frames[2] = drawScreen3;
|
||||
clockFrame[0] = drawClock;
|
||||
clockFrame[1] = drawWeather;
|
||||
ui.setOverlays(overlays, numberOfOverlays);
|
||||
|
||||
// Inital UI takes care of initalising the display too.
|
||||
|
|
@ -240,7 +256,9 @@ void setup() {
|
|||
server.on("/systemreset", handleSystemReset);
|
||||
server.on("/forgetwifi", handleWifiReset);
|
||||
server.on("/updateconfig", handleUpdateConfig);
|
||||
server.on("/updateweatherconfig", handleUpdateWeather);
|
||||
server.on("/configure", handleConfigure);
|
||||
server.on("/configureweather", handleWeatherConfigure);
|
||||
server.onNotFound(redirectHome);
|
||||
// Start the server
|
||||
server.begin();
|
||||
|
|
@ -340,6 +358,11 @@ void getUpdateTime() {
|
|||
digitalWrite(externalLight, LOW); // turn on the LED
|
||||
Serial.println();
|
||||
|
||||
if (displayOn && DISPLAYWEATHER) {
|
||||
Serial.println("Getting Weather Data...");
|
||||
weatherClient.updateWeather();
|
||||
}
|
||||
|
||||
Serial.println("Updating Time...");
|
||||
//Update the Time
|
||||
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() {
|
||||
if (!server.authenticate(www_username, www_password)) {
|
||||
return server.requestAuthentication();
|
||||
|
|
@ -399,6 +437,46 @@ void handleWifiReset() {
|
|||
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() {
|
||||
if (!server.authenticate(www_username, www_password)) {
|
||||
return server.requestAuthentication();
|
||||
|
|
@ -415,7 +493,7 @@ void handleConfigure() {
|
|||
html = getHeader();
|
||||
server.sendContent(html);
|
||||
|
||||
String form = String(CHANGE_FORM);
|
||||
String form = CHANGE_FORM;
|
||||
|
||||
form.replace("%OCTOKEY%", OctoPrintApiKey);
|
||||
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>";
|
||||
options.replace(">"+String(minutesBetweenDataRefresh)+"<", " selected>"+String(minutesBetweenDataRefresh)+"<");
|
||||
form.replace("%OPTIONS%", options);
|
||||
String themeOptions = String(COLOR_THEMES);
|
||||
String themeOptions = COLOR_THEMES;
|
||||
themeOptions.replace(">"+String(themeColor)+"<", " selected>"+String(themeColor)+"<");
|
||||
form.replace("%THEME_OPTIONS%", themeOptions);
|
||||
form.replace("%UTCOFFSET%", String(UtcOffset));
|
||||
form.replace("%USERID%", String(www_username));
|
||||
form.replace("%STATIONPASSWORD%", String(www_password));
|
||||
|
||||
server.sendContent(String(form));
|
||||
server.sendContent(form);
|
||||
|
||||
html = getFooter();
|
||||
server.sendContent(html);
|
||||
|
|
@ -486,7 +564,7 @@ String getHeader() {
|
|||
}
|
||||
|
||||
String getHeader(boolean refresh) {
|
||||
String menu = String(WEB_ACTIONS);
|
||||
String menu = WEB_ACTIONS;
|
||||
|
||||
String html = "<!DOCTYPE HTML>";
|
||||
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 += "</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("");
|
||||
|
|
@ -683,6 +785,44 @@ void drawClock(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16
|
|||
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 = "°" + rtnValue;
|
||||
} else {
|
||||
rtnValue = "°" + rtnValue;
|
||||
}
|
||||
return rtnValue;
|
||||
}
|
||||
|
||||
String getSpeedSymbol() {
|
||||
String rtnValue = "mph";
|
||||
if (IS_METRIC) {
|
||||
rtnValue = "kph";
|
||||
}
|
||||
return rtnValue;
|
||||
}
|
||||
|
||||
String zeroPad(int value) {
|
||||
String rtnValue = String(value);
|
||||
if (value < 10) {
|
||||
|
|
@ -734,7 +874,7 @@ void drawClockHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
|
|||
display->drawString(64, 48, "offline");
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
display->drawRect(0, 41, 128, 2);
|
||||
display->drawRect(0, 43, 128, 2);
|
||||
|
||||
drawRssi(display);
|
||||
}
|
||||
|
|
@ -785,6 +925,10 @@ void writeSettings() {
|
|||
f.println("www_password=" + String(www_password));
|
||||
f.println("DISPLAYCLOCK=" + String(DISPLAYCLOCK));
|
||||
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();
|
||||
readSettings();
|
||||
|
|
@ -864,9 +1008,29 @@ void readSettings() {
|
|||
IS_24HOUR = line.substring(line.lastIndexOf("is24hour=") + 9).toInt();
|
||||
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();
|
||||
printerClient.updateOctoPrintClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass);
|
||||
weatherClient.updateWeatherApiKey(WeatherApiKey);
|
||||
weatherClient.setMetric(IS_METRIC);
|
||||
weatherClient.updateCityIdList(CityIDs, 1);
|
||||
timeClient.setUtcOffset(UtcOffset);
|
||||
}
|
||||
|
||||
|
|
@ -916,9 +1080,16 @@ void checkDisplay() {
|
|||
} else if (DISPLAYCLOCK) {
|
||||
if (!printerClient.isOperational() && !isClockOn) {
|
||||
Serial.println("Clock Mode is turned on.");
|
||||
ui.disableAutoTransition();
|
||||
ui.setFrames(clockFrame, 1);
|
||||
clockFrame[0] = drawClock;
|
||||
if (!DISPLAYWEATHER) {
|
||||
ui.disableAutoTransition();
|
||||
ui.setFrames(clockFrame, 1);
|
||||
clockFrame[0] = drawClock;
|
||||
} else {
|
||||
ui.enableAutoTransition();
|
||||
ui.setFrames(clockFrame, 2);
|
||||
clockFrame[0] = drawClock;
|
||||
clockFrame[1] = drawWeather;
|
||||
}
|
||||
ui.setOverlays(clockOverlay, numberOfOverlays);
|
||||
isClockOn = true;
|
||||
} else if (printerClient.isOperational() && isClockOn) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue