From 9766c7c23c1c462e1e9a52b26ecc7856253601c1 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 4 May 2019 21:37:39 -0600 Subject: [PATCH 1/2] Updated files to implement speed & pressure Implemented wind speed and barometric pressure display. --- marquee/OpenWeatherMapClient.cpp | 700 ++++++++++++++++--------------- marquee/OpenWeatherMapClient.h | 175 ++++---- marquee/marquee.ino | 26 +- 3 files changed, 472 insertions(+), 429 deletions(-) diff --git a/marquee/OpenWeatherMapClient.cpp b/marquee/OpenWeatherMapClient.cpp index ab95b3e..9a9608b 100644 --- a/marquee/OpenWeatherMapClient.cpp +++ b/marquee/OpenWeatherMapClient.cpp @@ -1,341 +1,359 @@ -/** 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); - weathers[0].cached = false; - weathers[0].error = ""; - 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(); - weathers[0].error = "Connection for weather data failed"; - 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); - weathers[0].error = "Weather Data Error: " + String(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); - - // 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"]; - - if (units == "metric") { - // convert to kph from m/s - float f = (weathers[inx].wind.toFloat() * 3.6); - weathers[inx].wind = String(f); - } - - 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::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::getWeekDay(int index, float offset) { - String rtnValue = ""; - long epoc = weathers[index].dt.toInt(); - long day = 0; - if (epoc != 0) { - day = (((epoc + (3600 * (int)offset)) / 86400) + 4) % 7; - switch (day) { - case 0: - rtnValue = "Sunday"; - break; - case 1: - rtnValue = "Monday"; - break; - case 2: - rtnValue = "Tuesday"; - break; - case 3: - rtnValue = "Wednesday"; - break; - case 4: - rtnValue = "Thursday"; - break; - case 5: - rtnValue = "Friday"; - break; - case 6: - rtnValue = "Saturday"; - break; - default: - break; - } - } - return rtnValue; -} - -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; -} +/** 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); + weathers[0].cached = false; + weathers[0].error = ""; + 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(); + weathers[0].error = "Connection for weather data failed"; + 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); + weathers[0].error = "Weather Data Error: " + String(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); + + // 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"]; + weathers[inx].pressure = (const char*)root["list"][inx]["main"]["pressure"]; + weathers[inx].direction = (const char*)root["list"][inx]["wind"]["deg"]; + + if (units == "metric") { + // convert to kph from m/s + float f = (weathers[inx].wind.toFloat() * 3.6); + weathers[inx].wind = String(f); + } + + 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("direction: " + weathers[inx].direction); + 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::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::getDirection(int index) +{ + return weathers[index].direction; +} + +String OpenWeatherMapClient::getDirectionRounded(int index) +{ + return roundValue(getDirection(index)); +} + +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::getPressure(int index) +{ + return weathers[index].pressure; +} + +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::getWeekDay(int index, float offset) { + String rtnValue = ""; + long epoc = weathers[index].dt.toInt(); + long day = 0; + if (epoc != 0) { + day = (((epoc + (3600 * (int)offset)) / 86400) + 4) % 7; + switch (day) { + case 0: + rtnValue = "Sunday"; + break; + case 1: + rtnValue = "Monday"; + break; + case 2: + rtnValue = "Tuesday"; + break; + case 3: + rtnValue = "Wednesday"; + break; + case 4: + rtnValue = "Thursday"; + break; + case 5: + rtnValue = "Friday"; + break; + case 6: + rtnValue = "Saturday"; + break; + default: + break; + } + } + return rtnValue; +} + +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; +} diff --git a/marquee/OpenWeatherMapClient.h b/marquee/OpenWeatherMapClient.h index 594e3f9..2b34a97 100644 --- a/marquee/OpenWeatherMapClient.h +++ b/marquee/OpenWeatherMapClient.h @@ -1,85 +1,90 @@ -/** 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 -#include "libs/ArduinoJson/ArduinoJson.h" - -class OpenWeatherMapClient { - -private: - String myCityIDs = ""; - String myApiKey = ""; - String units = ""; - - const char* servername = "api.openweathermap.org"; // remote server we will connect to - - 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 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(); - String getWeekDay(int index, float offset); -}; +/** 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 +#include "libs/ArduinoJson/ArduinoJson.h" + +class OpenWeatherMapClient { + +private: + String myCityIDs = ""; + String myApiKey = ""; + String units = ""; + + const char* servername = "api.openweathermap.org"; // remote server we will connect to + + 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; + String pressure; + String direction; + } 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 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 getDirection(int index); + String getDirectionRounded(int index); + String getPressure(int index); + String getWeatherId(int index); + String getDescription(int index); + String getIcon(int index); + boolean getCached(); + String getMyCityIDs(); + String getWeatherIcon(int index); + String getError(); + String getWeekDay(int index, float offset); +}; diff --git a/marquee/marquee.ino b/marquee/marquee.ino index 8d70b0b..ec4828f 100644 --- a/marquee/marquee.ino +++ b/marquee/marquee.ino @@ -79,6 +79,8 @@ boolean SHOW_CITY = true; boolean SHOW_CONDITION = true; boolean SHOW_HUMIDITY = true; boolean SHOW_WIND = true; +boolean SHOW_WINDDIR = true; +boolean SHOW_PRESSURE = true; // OctoPrint Client OctoPrintClient printerClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass); @@ -121,6 +123,7 @@ static const char CHANGE_FORM1[] PROGMEM = "
Display Weather Condition

" "

Display Humidity

" "

Display Wind

" + "

Display Barometric Pressure

" "

Use 24 Hour Clock (military time)

"; static const char CHANGE_FORM2[] PROGMEM = "

Show PM indicator (only 12h format)

" @@ -392,9 +395,14 @@ void loop() { msg += "Humidity:" + weatherClient.getHumidityRounded(0) + "% "; } if (SHOW_WIND) { - msg += "Wind:" + weatherClient.getWindRounded(0) + getSpeedSymbol() + " "; + msg += "Wind:" + weatherClient.getDirectionRounded(0) + " deg/"; + msg += weatherClient.getWindRounded(0) + " " + getSpeedSymbol() + " "; + } + //line to show barometric pressure + if (SHOW_PRESSURE) + { + msg += "Pressure:" + weatherClient.getPressure(0) + " mb "; } - msg += marqueeMessage + " "; if (NEWS_ENABLED) { @@ -567,6 +575,7 @@ void handleLocations() { SHOW_CONDITION = server.hasArg("showcondition"); SHOW_HUMIDITY = server.hasArg("showhumidity"); SHOW_WIND = server.hasArg("showwind"); + SHOW_PRESSURE = server.hasArg("showpressure"); IS_METRIC = server.hasArg("metric"); marqueeMessage = decodeHtmlString(server.arg("marqueeMsg")); timeDisplayTurnsOn = decodeHtmlString(server.arg("startTime")); @@ -825,6 +834,11 @@ void handleConfigure() { isWindChecked = "checked='checked'"; } form.replace("%WIND_CHECKED%", isWindChecked); + String isPressureChecked = ""; + if (SHOW_PRESSURE) { + isPressureChecked = "checked='checked'"; + } + form.replace("%PRESSURE_CHECKED%", isPressureChecked); String is24hourChecked = ""; if (IS_24HOUR) { is24hourChecked = "checked='checked'"; @@ -1080,7 +1094,8 @@ void displayWeatherData() { html += "
"; html += "" + weatherClient.getDescription(0) + "
"; html += weatherClient.getHumidity(0) + "% Humidity
"; - html += weatherClient.getWind(0) + " " + getSpeedSymbol() + " Wind
"; + html += weatherClient.getDirection(0) + " deg/" + weatherClient.getWind(0) + " " + getSpeedSymbol() + " Wind
"; + html += weatherClient.getPressure(0) + " Pressure
"; html += "
"; html += "

"; html += weatherClient.getCondition(0) + " (" + weatherClient.getDescription(0) + ")
"; @@ -1319,6 +1334,7 @@ String writeCityIds() { f.println("SHOW_CONDITION=" + String(SHOW_CONDITION)); f.println("SHOW_HUMIDITY=" + String(SHOW_HUMIDITY)); f.println("SHOW_WIND=" + String(SHOW_WIND)); + f.println("SHOW_PRESSURE=" + String(SHOW_PRESSURE)); f.println("SHOW_DATE=" + String(SHOW_DATE)); f.println("USE_PIHOLE=" + String(USE_PIHOLE)); f.println("PiHoleServer=" + PiHoleServer); @@ -1494,6 +1510,10 @@ void readCityIds() { SHOW_WIND = line.substring(line.lastIndexOf("SHOW_WIND=") + 10).toInt(); Serial.println("SHOW_WIND=" + String(SHOW_WIND)); } + if (line.indexOf("SHOW_PRESSURE=") >= 0) { + SHOW_PRESSURE = line.substring(line.lastIndexOf("SHOW_PRESSURE=") + 14).toInt(); + Serial.println("SHOW_PRESSURE=" + String(SHOW_PRESSURE)); + } if (line.indexOf("SHOW_DATE=") >= 0) { SHOW_DATE = line.substring(line.lastIndexOf("SHOW_DATE=") + 10).toInt(); Serial.println("SHOW_DATE=" + String(SHOW_DATE)); From 7206dec37ad669283817fff525a74110b621cf12 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sun, 5 May 2019 19:57:49 -0600 Subject: [PATCH 2/2] add additional weather features Support added for wind direction, barometric pressure, and daily high/low temperatures. --- marquee/OpenWeatherMapClient.cpp | 18 ++++++++++ marquee/OpenWeatherMapClient.h | 4 +++ marquee/marquee.ino | 57 ++++++++++++++++++++++++++------ 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/marquee/OpenWeatherMapClient.cpp b/marquee/OpenWeatherMapClient.cpp index 9a9608b..8d4e05b 100644 --- a/marquee/OpenWeatherMapClient.cpp +++ b/marquee/OpenWeatherMapClient.cpp @@ -114,6 +114,8 @@ void OpenWeatherMapClient::updateWeather() { weathers[inx].icon = (const char*)root["list"][inx]["weather"][0]["icon"]; weathers[inx].pressure = (const char*)root["list"][inx]["main"]["pressure"]; weathers[inx].direction = (const char*)root["list"][inx]["wind"]["deg"]; + weathers[inx].high = (const char*)root["list"][inx]["main"]["temp_max"]; + weathers[inx].low = (const char*)root["list"][inx]["main"]["temp_min"]; if (units == "metric") { // convert to kph from m/s @@ -121,6 +123,12 @@ void OpenWeatherMapClient::updateWeather() { weathers[inx].wind = String(f); } + if (units != "metric") + { + float p = (weathers[inx].pressure.toFloat() * 0.0295301); //convert millibars to inches + weathers[inx].pressure = String(p); + } + Serial.println("lat: " + weathers[inx].lat); Serial.println("lon: " + weathers[inx].lon); Serial.println("dt: " + weathers[inx].dt); @@ -236,6 +244,16 @@ String OpenWeatherMapClient::getPressure(int index) return weathers[index].pressure; } +String OpenWeatherMapClient::getHigh(int index) +{ + return weathers[index].high; +} + +String OpenWeatherMapClient::getLow(int index) +{ + return weathers[index].low; +} + String OpenWeatherMapClient::getIcon(int index) { return weathers[index].icon; } diff --git a/marquee/OpenWeatherMapClient.h b/marquee/OpenWeatherMapClient.h index 2b34a97..636acd0 100644 --- a/marquee/OpenWeatherMapClient.h +++ b/marquee/OpenWeatherMapClient.h @@ -51,6 +51,8 @@ class OpenWeatherMapClient { String error; String pressure; String direction; + String high; + String low; } weather; weather weathers[5]; @@ -79,6 +81,8 @@ class OpenWeatherMapClient { String getDirection(int index); String getDirectionRounded(int index); String getPressure(int index); + String getHigh(int index); + String getLow(int index); String getWeatherId(int index); String getDescription(int index); String getIcon(int index); diff --git a/marquee/marquee.ino b/marquee/marquee.ino index ec4828f..6f615d3 100644 --- a/marquee/marquee.ino +++ b/marquee/marquee.ino @@ -81,6 +81,7 @@ boolean SHOW_HUMIDITY = true; boolean SHOW_WIND = true; boolean SHOW_WINDDIR = true; boolean SHOW_PRESSURE = true; +boolean SHOW_HIGHLOW = true; // OctoPrint Client OctoPrintClient printerClient(OctoPrintApiKey, OctoPrintServer, OctoPrintPort, OctoAuthUser, OctoAuthPass); @@ -124,6 +125,7 @@ static const char CHANGE_FORM1[] PROGMEM = " Display Humidity

" "

Display Wind

" "

Display Barometric Pressure

" + "

Display Daily High/Low Temperatures

" "

Use 24 Hour Clock (military time)

"; static const char CHANGE_FORM2[] PROGMEM = "

Show PM indicator (only 12h format)

" @@ -382,17 +384,17 @@ void loop() { if (SHOW_DATE) { msg += TimeDB.getDayName() + ", "; - msg += TimeDB.getMonthName() + " " + day() + " "; + msg += TimeDB.getMonthName() + " " + day() + " "; } if (SHOW_CITY) { - msg += weatherClient.getCity(0) + " "; + msg += weatherClient.getCity(0) + " "; } - msg += temperature + getTempSymbol() + " "; + msg += temperature + getTempSymbol() + " "; if (SHOW_CONDITION) { - msg += description + " "; + msg += description + " "; } if (SHOW_HUMIDITY) { - msg += "Humidity:" + weatherClient.getHumidityRounded(0) + "% "; + msg += "Humidity:" + weatherClient.getHumidityRounded(0) + "% "; } if (SHOW_WIND) { msg += "Wind:" + weatherClient.getDirectionRounded(0) + " deg/"; @@ -401,23 +403,29 @@ void loop() { //line to show barometric pressure if (SHOW_PRESSURE) { - msg += "Pressure:" + weatherClient.getPressure(0) + " mb "; + msg += "Pressure:" + weatherClient.getPressure(0) + getPressureSymbol() + " "; } - msg += marqueeMessage + " "; + //show high/low temperature + if (SHOW_HIGHLOW) + { + msg += "Daily High/Low Temperatures:" + weatherClient.getHigh(0) + "/" + weatherClient.getLow(0) + " " + getTempSymbol() + " "; + } + msg += marqueeMessage + " "; + if (NEWS_ENABLED) { - msg += " " + NEWS_SOURCE + ": " + newsClient.getTitle(newsIndex) + " "; + msg += " " + NEWS_SOURCE + ": " + newsClient.getTitle(newsIndex) + " "; newsIndex += 1; if (newsIndex > 9) { newsIndex = 0; } } if (OCTOPRINT_ENABLED && printerClient.isPrinting()) { - msg += " " + printerClient.getFileName() + " "; - msg += "(" + printerClient.getProgressCompletion() + "%) "; + msg += " " + printerClient.getFileName() + " "; + msg += "(" + printerClient.getProgressCompletion() + "%) "; } if (BitcoinCurrencyCode != "NONE" && BitcoinCurrencyCode != "") { - msg += " Bitcoin: " + bitcoinClient.getRate() + " " + bitcoinClient.getCode() + " "; + msg += " Bitcoin: " + bitcoinClient.getRate() + " " + bitcoinClient.getCode() + " "; } if (USE_PIHOLE) { piholeClient.getPiHoleData(PiHoleServer, PiHolePort); @@ -576,6 +584,7 @@ void handleLocations() { SHOW_HUMIDITY = server.hasArg("showhumidity"); SHOW_WIND = server.hasArg("showwind"); SHOW_PRESSURE = server.hasArg("showpressure"); + SHOW_HIGHLOW = server.hasArg("showhighlow"); IS_METRIC = server.hasArg("metric"); marqueeMessage = decodeHtmlString(server.arg("marqueeMsg")); timeDisplayTurnsOn = decodeHtmlString(server.arg("startTime")); @@ -839,6 +848,14 @@ void handleConfigure() { isPressureChecked = "checked='checked'"; } form.replace("%PRESSURE_CHECKED%", isPressureChecked); + + String isHighlowChecked = ""; + if (SHOW_HIGHLOW) { + isHighlowChecked = "checked='checked'"; + } + form.replace("%HIGHLOW_CHECKED%", isHighlowChecked); + + String is24hourChecked = ""; if (IS_24HOUR) { is24hourChecked = "checked='checked'"; @@ -1100,6 +1117,7 @@ void displayWeatherData() { html += "

"; html += weatherClient.getCondition(0) + " (" + weatherClient.getDescription(0) + ")
"; html += temperature + " " + getTempSymbol() + "
"; + html += weatherClient.getHigh(0) + "/" + weatherClient.getLow(0) + " " + getTempSymbol() + "
"; html += time + "
"; html += " Map It!
"; html += "


"; @@ -1212,6 +1230,16 @@ String getSpeedSymbol() { return rtnValue; } +String getPressureSymbol() +{ + String rtnValue = ""; + if (IS_METRIC) + { + rtnValue = "mb"; + } + return rtnValue; +} + // converts the dBm to a range between 0 and 100% int8_t getWifiQuality() { int32_t dbm = WiFi.RSSI(); @@ -1335,6 +1363,7 @@ String writeCityIds() { f.println("SHOW_HUMIDITY=" + String(SHOW_HUMIDITY)); f.println("SHOW_WIND=" + String(SHOW_WIND)); f.println("SHOW_PRESSURE=" + String(SHOW_PRESSURE)); + f.println("SHOW_HIGHLOW=" + String(SHOW_HIGHLOW)); f.println("SHOW_DATE=" + String(SHOW_DATE)); f.println("USE_PIHOLE=" + String(USE_PIHOLE)); f.println("PiHoleServer=" + PiHoleServer); @@ -1514,6 +1543,12 @@ void readCityIds() { SHOW_PRESSURE = line.substring(line.lastIndexOf("SHOW_PRESSURE=") + 14).toInt(); Serial.println("SHOW_PRESSURE=" + String(SHOW_PRESSURE)); } + + if (line.indexOf("SHOW_HIGHLOW=") >= 0) { + SHOW_HIGHLOW = line.substring(line.lastIndexOf("SHOW_HIGHLOW=") + 13).toInt(); + Serial.println("SHOW_HIGHLOW=" + String(SHOW_HIGHLOW)); + } + if (line.indexOf("SHOW_DATE=") >= 0) { SHOW_DATE = line.substring(line.lastIndexOf("SHOW_DATE=") + 10).toInt(); Serial.println("SHOW_DATE=" + String(SHOW_DATE));