commit
abf551023a
|
|
@ -34,6 +34,7 @@ SOFTWARE.
|
||||||
* Screen turns on when printer is Operational or connected
|
* Screen turns on when printer is Operational or connected
|
||||||
* Option to display a clock screen instead of sleep mode
|
* Option to display a clock screen instead of sleep mode
|
||||||
* Option to display 24 hour clock or AM/PM style
|
* Option to display 24 hour clock or AM/PM style
|
||||||
|
* Option to display Current Weather when printer is off
|
||||||
* Sample rate is every 60 seconds when not printing
|
* Sample rate is every 60 seconds when not printing
|
||||||
* Sample rate is every 10 seconds when printing
|
* Sample rate is every 10 seconds when printing
|
||||||
* Fully configurable from the web interface (not required to update Settings.h)
|
* Fully configurable from the web interface (not required to update Settings.h)
|
||||||
|
|
@ -79,8 +80,9 @@ ArduinoOTA.h --> Arduino OTA Library
|
||||||
"OLEDDisplayUi.h"
|
"OLEDDisplayUi.h"
|
||||||
|
|
||||||
## Initial Configuration
|
## Initial Configuration
|
||||||
You will can update the **Settings.h** file with your OctoPrint API Key or do it from the web interface.
|
All settings may be managed from the Web Interface, however, you may update the **Settings.h** file manually -- but it is not required. There is also an option to display current weather when the print is off-line.
|
||||||
* Your OctoPrint API Key from your OctoPrint -> User Settings -> Current API Key
|
* Your OctoPrint API Key from your OctoPrint -> User Settings -> Current API Key
|
||||||
|
* Optional OpenWeatherMap API Key -- if you want current weather when not printing. Get the api key from: https://openweathermap.org/
|
||||||
|
|
||||||
NOTE: The settings in the Settings.h are the default settings for the first loading. After loading you will manage changes to the settings via the Web Interface. If you want to change settings again in the settings.h, you will need to erase the file system on the Wemos or use the “Reset Settings” option in the Web Interface.
|
NOTE: The settings in the Settings.h are the default settings for the first loading. After loading you will manage changes to the settings via the Web Interface. If you want to change settings again in the settings.h, you will need to erase the file system on the Wemos or use the “Reset Settings” option in the Web Interface.
|
||||||
|
|
||||||
|
|
@ -89,7 +91,7 @@ The Printer Monitor uses the **WiFiManager** so when it can't find the last netw
|
||||||
it will become a **AP Hotspot** -- connect to it with your phone and you can then enter your WiFi connection information.
|
it will become a **AP Hotspot** -- connect to it with your phone and you can then enter your WiFi connection information.
|
||||||
|
|
||||||
After connected to your WiFi network it will display the IP addressed assigned to it and that can be
|
After connected to your WiFi network it will display the IP addressed assigned to it and that can be
|
||||||
used to open a browser to the Web Interface. Everything can be configured there.
|
used to open a browser to the Web Interface. **Everything** can be configured there.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="/images/shot_01.png" width="200"/>
|
<img src="/images/shot_01.png" width="200"/>
|
||||||
|
|
|
||||||
|
|
@ -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 <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
|
|
@ -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,72 @@ 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>OpenWeatherMap 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>) "
|
||||||
"<option>blue</option>"
|
"or full <a href='http://openweathermap.org/help/city_list.txt' target='_BLANK'>city list</a></label>"
|
||||||
"<option>light-blue</option>"
|
"<input class='w3-input w3-border w3-margin-bottom' type='text' name='city1' value='%CITY1%' onkeypress='return isNumberKey(event)'></p>"
|
||||||
"<option>cyan</option>"
|
"<p><input name='metric' class='w3-check w3-margin-top' type='checkbox' %METRIC%> Use Metric (Celsius)</p>"
|
||||||
"<option>teal</option>"
|
"<button class='w3-button w3-block w3-grey w3-section w3-padding' type='submit'>Save</button></form>"
|
||||||
"<option>green</option>"
|
"<script>function isNumberKey(e){var h=e.which?e.which:event.keyCode;return!(h>31&&(h<48||h>57))}</script>";
|
||||||
"<option>light-green</option>"
|
|
||||||
"<option>lime</option>"
|
String COLOR_THEMES = "<option>red</option>"
|
||||||
"<option>khaki</option>"
|
"<option>pink</option>"
|
||||||
"<option>yellow</option>"
|
"<option>purple</option>"
|
||||||
"<option>amber</option>"
|
"<option>deep-purple</option>"
|
||||||
"<option>orange</option>"
|
"<option>indigo</option>"
|
||||||
"<option>deep-orange</option>"
|
"<option>blue</option>"
|
||||||
"<option>blue-grey</option>"
|
"<option>light-blue</option>"
|
||||||
"<option>brown</option>"
|
"<option>cyan</option>"
|
||||||
"<option>grey</option>"
|
"<option>teal</option>"
|
||||||
"<option>dark-grey</option>"
|
"<option>green</option>"
|
||||||
"<option>black</option>"
|
"<option>light-green</option>"
|
||||||
"<option>w3schools</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
|
// Change the externalLight to the pin you wish to use if other than the Built-in LED
|
||||||
|
|
@ -197,6 +213,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 +257,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 +359,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 +384,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 +438,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 +494,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 +515,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 +565,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,9 +665,33 @@ 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 Weather</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("");
|
||||||
server.client().stop();
|
server.client().stop();
|
||||||
|
|
@ -683,6 +786,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 = "°" + 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 +875,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 +926,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 +1009,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 +1081,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) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue