diff --git a/README.md b/README.md
index 035081c6c..7da63593c 100644
--- a/README.md
+++ b/README.md
@@ -23,21 +23,19 @@ Here are two examples utilizing various configuration options:
-
## Contents
-- [Setup Guide](#setup-guide)
- - [Hardware](#hardware)
- - [Wiring](#wiring)
- - [Configuration, Compilation, and Upload](#configuration-compilation-and-upload)
- - [OpenWeatherMap API Key](#openweathermap-api-key)
-- [Error Messages and Troubleshooting](#error-messages-and-troubleshooting)
- - [Low Battery](#low-battery)
- - [WiFi Connection](#wifi-connection)
- - [API Error](#api-error)
- - [Time Server Error](#time-server-error)
-- [Licensing](#licensing)
-
+- [Setup Guide](#setup-guide)
+ - [Hardware](#hardware)
+ - [Wiring](#wiring)
+ - [Configuration, Compilation, and Upload](#configuration-compilation-and-upload)
+ - [OpenWeatherMap API Key](#openweathermap-api-key)
+- [Error Messages and Troubleshooting](#error-messages-and-troubleshooting)
+ - [Low Battery](#low-battery)
+ - [WiFi Connection](#wifi-connection)
+ - [API Error](#api-error)
+ - [Time Server Error](#time-server-error)
+- [Licensing](#licensing)
## Setup Guide
@@ -46,9 +44,11 @@ Here are two examples utilizing various configuration options:
7.5inch (800×480) E-Paper Display
- Advantages of E-Paper
+
- Ultra Low Power Consumption - E-Paper (aka E-Ink) displays are ideal for low-power applications that do not require frequent display refreshes. E-Paper displays only draw power when refreshing the display and do not have a backlight. Images will remain on the screen even when power is removed.
- Limitations of E-Paper:
+
- Colors - E-Paper has traditionally been limited to just black and white, but in recent years 3-color E-Paper screens have started showing up.
- Refresh Times and Ghosting - E-Paper displays are highly susceptible to ghosting effects if refreshed too quickly. To avoid this, E-Paper displays often take a few seconds to refresh(4s for the unit used in this project) and will alternate between black and white a few times, which can be distracting.
@@ -57,16 +57,16 @@ Here are two examples utilizing various configuration options:
Waveshare and Good Display make equivalent panels. Either variant will work.
- | Panel | Resolution | Colors | Notes |
- |-----------------------------------------|------------|-----------------|-----------------------------------------------------------------------------------------------------------------------|
- | Waveshare 7.5in e-paper (v2) | 800x480px | Black/White | Available [here](https://www.waveshare.com/product/7.5inch-e-paper.htm). (recommended) |
- | Good Display 7.5in e-paper (GDEY075T7) | 800x480px | Black/White | Available [here](https://www.aliexpress.com/item/3256802683908868.html). (recommended) |
- | Waveshare 7.5in e-Paper (B) | 800x480px | Red/Black/White | Available [here](https://www.waveshare.com/product/7.5inch-e-paper-b.htm). |
- | Good Display 7.5in e-paper (GDEY075Z08) | 800x480px | Red/Black/White | Available [here](https://www.aliexpress.com/item/3256803540460035.html). |
- | Waveshare 7.3in ACeP e-Paper (F) | 800x480px | 7-Color | Available [here](https://www.waveshare.com/product/displays/e-paper/epaper-1/7.3inch-e-paper-f.htm). |
- | Good Display 7.3in e-paper (GDEY073D46) | 800x480px | 7-Color | Available [here](https://www.aliexpress.com/item/3256805485098421.html). |
- | Waveshare 7.5in e-paper (v1) | 640x384px | Black/White | Limited support. Some information not displayed, see [image](showcase/demo-waveshare75-version1.jpg). |
- | Good Display 7.5in e-paper (GDEW075T8) | 640x384px | Black/White | Limited support. Some information not displayed, see [image](showcase/demo-waveshare75-version1.jpg). |
+ | Panel | Resolution | Colors | Notes |
+ | --------------------------------------- | ---------- | --------------- | ----------------------------------------------------------------------------------------------------- |
+ | Waveshare 7.5in e-paper (v2) | 800x480px | Black/White | Available [here](https://www.waveshare.com/product/7.5inch-e-paper.htm). (recommended) |
+ | Good Display 7.5in e-paper (GDEY075T7) | 800x480px | Black/White | Available [here](https://www.aliexpress.com/item/3256802683908868.html). (recommended) |
+ | Waveshare 7.5in e-Paper (B) | 800x480px | Red/Black/White | Available [here](https://www.waveshare.com/product/7.5inch-e-paper-b.htm). |
+ | Good Display 7.5in e-paper (GDEY075Z08) | 800x480px | Red/Black/White | Available [here](https://www.aliexpress.com/item/3256803540460035.html). |
+ | Waveshare 7.3in ACeP e-Paper (F) | 800x480px | 7-Color | Available [here](https://www.waveshare.com/product/displays/e-paper/epaper-1/7.3inch-e-paper-f.htm). |
+ | Good Display 7.3in e-paper (GDEY073D46) | 800x480px | 7-Color | Available [here](https://www.aliexpress.com/item/3256805485098421.html). |
+ | Waveshare 7.5in e-paper (v1) | 640x384px | Black/White | Limited support. Some information not displayed, see [image](showcase/demo-waveshare75-version1.jpg). |
+ | Good Display 7.5in e-paper (GDEW075T8) | 640x384px | Black/White | Limited support. Some information not displayed, see [image](showcase/demo-waveshare75-version1.jpg). |
This software has limited support for accent colors. E-paper panels with additional colors tend to have longer refresh times, which will reduce battery life.
@@ -77,10 +77,8 @@ DESPI-C02 Adapter Board
- The Waveshare HATs (rev 2.2/2.3) are not recommended. Their compatibility with this project is not regularly tested.
- https://www.e-paper-display.com/products_detail/productId=403.html
-
- https://www.aliexpress.us/item/3256804446769469.html
-
FireBeetle 2 ESP32-E Microcontroller
- Why the ESP32?
@@ -101,30 +99,25 @@ FireBeetle 2 ESP32-E Microcontroller
- FireBeetle ESP32 models include onboard circuitry to monitor battery voltage of a battery connected to its JST-PH2.0 connector.
-
-
-
BME280 - Pressure, Temperature, and Humidity Sensor
-
- Provides accurate indoor temperature and humidity.
- Much faster than the DHT22, which requires a 2-second wait before reading temperature and humidity samples.
-
-3.7V Lipo Battery w/ 2 Pin JST Connector
-
+ 3.7V Lipo Battery w/ 2 Pin JST Connector
- Size is up to you. I used a 5000mah battery so that the device can operate on a single charge for >6 months.
-
- The battery can be charged by plugging the FireBeetle ESP32 into the wall via the USB-C connector while the battery is plugged into the ESP32's JST connector.
> **Warning**
> The polarity of JST-PH2.0 connectors is not standardized! You may need to swap the order of the wires in the connector.
Stand/Frame
+
- You'll want a nice way to show off your project. Here are a few popular choices.
- DIY Wooden
- I made a small stand by hollowing out a piece of wood from the bottom. On the back, I used a short USB extension cable so that I can charge the battery without needing to remove the components from the stand. I also wired a small reset button to refresh the display manually. Additionally, I 3d printed a cover for the bottom, which is held on by magnets. The E-paper screen is very thin, so I used a thin piece of acrylic to support it.
@@ -135,10 +128,11 @@ Stand/Frame
screen angle = 80deg
screen is 15mm from the front
- 3D Printable
+
- Here is a list of community designs.
-
+
| Contributor | Link |
- |----------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
+ | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| [Kingfisher](https://www.printables.com/@Kingfisher_32821) | [Printables](https://www.printables.com/model/1139047-weather-station-e-ink-frame) |
| [Francois Allard](https://www.printables.com/@FrAllard_1585397) | [Printables](https://www.printables.com/model/791477-weather-station-using-a-esp32) |
| [3D Nate](https://www.printables.com/@3DNate_451157) | [Printables](https://www.printables.com/model/661183-e-ink-weather-station-frame) |
@@ -149,8 +143,8 @@ Stand/Frame
| [MPHarms](https://www.thingiverse.com/mpharms/designs) | [Thingiverse](https://www.thingiverse.com/thing:6666148) |
- If you want to share your own 3D printable designs, your contributions are highly encouraged and welcome!
-- Picture Frame
+- Picture Frame
### Wiring
@@ -184,7 +178,6 @@ Cut the low power pad for even longer battery life.
-
### Configuration, Compilation, and Upload
PlatformIO for VSCode is used for managing dependencies, code compilation, and uploading to ESP32.
@@ -203,9 +196,11 @@ PlatformIO for VSCode is used for managing dependencies, code compilation, and u
5. Configure Options.
- - Most configuration options are located in [config.cpp](platformio/src/config.cpp), with a few in [config.h](platformio/include/config.h). Locale/language options can also be found in include/locales/locale_*.inc.
+ - Most configuration options are located in [config.cpp](platformio/src/config.cpp), with a few in [config.h](platformio/include/config.h) and [credentials.h](platformio/include/credentials.h). Locale/language options can also be found in include/locales/locale\_\*.inc.
- - Important settings to configure in config.cpp:
+ - First copy `platformio/include/credentials.h.template` to `platformio/include/credentials.h`
+
+ - Important settings to configure in credentials.h:
- WiFi credentials (ssid, password).
@@ -213,6 +208,8 @@ PlatformIO for VSCode is used for managing dependencies, code compilation, and u
- Latitude and longitude.
+ - Important settings to configure in config.cpp:
+
- Time and date formats.
- Sleep duration.
@@ -231,11 +228,11 @@ PlatformIO for VSCode is used for managing dependencies, code compilation, and u
b. Click the upload arrow along the bottom of the VSCode window. (Should say "PlatformIO: Upload" if you hover over it.)
- - PlatformIO will automatically download the required third-party libraries, compile, and upload the code. :)
+ - PlatformIO will automatically download the required third-party libraries, compile, and upload the code. :)
- - You will only see this if you have the PlatformIO extension installed.
+ - You will only see this if you have the PlatformIO extension installed.
- - If you are getting errors during the upload process, you may need to install drivers to allow you to upload code to the ESP32.
+ - If you are getting errors during the upload process, you may need to install drivers to allow you to upload code to the ESP32.
### OpenWeatherMap API Key
@@ -246,25 +243,29 @@ This project will make calls to 2 different APIs ("One Call" and "Air Pollution"
- The One Call API 3.0 is only included in the "One Call by Call" subscription. This separate subscription includes 1,000 calls/day for free and allows you to pay only for the number of API calls made to this product.
Here's how to subscribe and avoid any credit card changes:
- - Go to
- - Follow the instructions to complete the subscription.
- - Go to and set the "Calls per day (no more than)" to 1,000. This ensures you will never overrun the free calls.
+
+- Go to
+- Follow the instructions to complete the subscription.
+- Go to and set the "Calls per day (no more than)" to 1,000. This ensures you will never overrun the free calls.
## Error Messages and Troubleshooting
### Low Battery
+
This error screen appears once the battery voltage has fallen below LOW_BATTERY_VOLTAGE (default = 3.20v). The display will not refresh again until it detects battery voltage above LOW_BATTERY_VOLTAGE. When battery voltage is between LOW_BATTERY_VOLTAGE and VERY_LOW_BATTERY_VOLTAGE (default = 3.10v) the esp32 will deep-sleep for periods of LOW_BATTERY_SLEEP_INTERVAL (default = 30min) before checking battery voltage again. If the battery voltage falls between LOW_BATTERY_SLEEP_INTERVAL and CRIT_LOW_BATTERY_VOLTAGE (default = 3.00v), then the display will deep-sleep for periods VERY_LOW_BATTERY_SLEEP_INTERVAL (default = 120min). If battery voltage falls below CRIT_LOW_BATTERY_VOLTAGE, then the esp32 will enter hibernate mode and will require a manual push of the reset (RST) button to begin updating again.
### WiFi Connection
+
This error screen appears when the ESP32 fails to connect to WiFi. If the message reads "WiFi Connection Failed" this might indicate an incorrect password. If the message reads "SSID Not Available" this might indicate that you mistyped the SSID or that the esp32 is out of the range of the access point. The esp32 will retry once every SLEEP_DURATION (default = 30min).
### API Error
+
This error screen appears if an error (client or server) occurs when making an API request to OpenWeatherMap. The second line will give the error code followed by a descriptor phrase. Positive error codes correspond to HTTP response status codes, while error codes <= 0 indicate a client(esp32) error. The esp32 will retry once every SLEEP_DURATION (default = 30min).
@@ -273,6 +274,7 @@ In the example shown to the left, "401: Unauthorized" may be the result of an in
### Time Server Error
+
This error screen appears when the esp32 fails to fetch the time from NTP_SERVER_1/NTP_SERVER_2. This error sometimes occurs immediately after uploading to the esp32; in this case, just hit the reset button or wait for SLEEP_DURATION (default = 30min) and the esp32 to automatically retry. If the error persists, try selecting closer/lower latency time servers or increasing NTP_TIMEOUT.
@@ -282,27 +284,26 @@ This error screen appears when the esp32 fails to fetch the time from NTP_SERVER
esp32-weather-epd is licensed under the [GNU General Public License v3.0](LICENSE) with tools, fonts, and icons whose licenses are as follows:
-| Name | License | Description |
-|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------|------------------------------------------------------------------------------------|
-| [Adafruit-GFX-Library: fontconvert](https://github.com/adafruit/Adafruit-GFX-Library/tree/master/fontconvert) | [BSD License](fonts/fontconvert/license.txt) | CLI tool for preprocessing fonts to be used with the Adafruit_GFX Arduino library. |
-| [pollutant-concentration-to-aqi](https://github.com/lmarzen/pollutant-concentration-to-aqi) | [GNU Lesser General Public License v2.1](platformio/lib/pollutant-concentration-to-aqi/LICENSE) | C library that converts pollutant concentrations to Air Quality Index(AQI). |
-| [GNU FreeFont](https://www.gnu.org/software/freefont/) | [GNU General Public License v3.0](https://www.gnu.org/software/freefont/license.html) | Font Family |
-| [Lato](https://fonts.google.com/specimen/Lato) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
-| [Montserrat](https://fonts.google.com/specimen/Montserrat) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
-| [Open Sans](https://fonts.google.com/specimen/Open+Sans) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
-| [Poppins](https://fonts.google.com/specimen/Poppins) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
-| [Quicksand](https://fonts.google.com/specimen/Quicksand) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
-| [Raleway](https://fonts.google.com/specimen/Raleway) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
-| [Roboto](https://fonts.google.com/specimen/Roboto) | [Apache License v2.0](https://www.apache.org/licenses/LICENSE-2.0) | Font Family |
-| [Roboto Mono](https://fonts.google.com/specimen/Roboto+Mono) | [Apache License v2.0](https://www.apache.org/licenses/LICENSE-2.0) | Font Family |
-| [Roboto Slab](https://fonts.google.com/specimen/Roboto+Slab) | [Apache License v2.0](https://www.apache.org/licenses/LICENSE-2.0) | Font Family |
-| [Ubuntu font](https://design.ubuntu.com/font) | [Ubuntu Font Licence v1.0](https://ubuntu.com/legal/font-licence) | Font Family |
-| [Weather Themed Icons](https://github.com/erikflowers/weather-icons) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | (wi-**.svg) Weather icon family by Lukas Bischoff/Erik Flowers. |
-| [Google Icons](https://fonts.google.com/icons) | [Apache License v2.0](https://www.apache.org/licenses/LICENSE-2.0) | (battery**.svg, visibility_icon.svg) Battery and visibility icons from Google Icons. |
-| [Biological Hazard Symbol](https://svgsilh.com/image/37775.html) | [CC0 v1.0](https://en.wikipedia.org/wiki/Public_domain) | (biological_hazard_symbol.svg) Biohazard icon. |
-| [House Icon](https://seekicon.com/free-icon/house_16) | [MIT License](http://opensource.org/licenses/mit-license.html) | (house.svg) House icon. |
-| [Indoor Temerature/Humidity Icons](icons/svg) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | (house_**.svg) Indoor temerature/humidity icons. |
-| [Ionizing Radiation Symbol](https://svgsilh.com/image/309911.html) | [CC0 v1.0](https://creativecommons.org/publicdomain/zero/1.0/) | (ionizing_radiation_symbol.svg) Ionizing radiation icons. |
-| [Phosphor Icons](https://github.com/phosphor-icons/homepage) | [MIT License](http://opensource.org/licenses/mit-license.html) | (wifi**.svg, warning_icon.svg, error_icon.svg) WiFi, Warning, and Error icons from Phosphor Icons. |
-| [Wind Direction Icon](https://www.onlinewebfonts.com/icon/251550) | [CC BY v3.0](http://creativecommons.org/licenses/by/3.0) | (meteorological_wind_direction_**deg.svg) Meteorological wind direction icon from Online Web Fonts. |
-
+| Name | License | Description |
+| ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
+| [Adafruit-GFX-Library: fontconvert](https://github.com/adafruit/Adafruit-GFX-Library/tree/master/fontconvert) | [BSD License](fonts/fontconvert/license.txt) | CLI tool for preprocessing fonts to be used with the Adafruit_GFX Arduino library. |
+| [pollutant-concentration-to-aqi](https://github.com/lmarzen/pollutant-concentration-to-aqi) | [GNU Lesser General Public License v2.1](platformio/lib/pollutant-concentration-to-aqi/LICENSE) | C library that converts pollutant concentrations to Air Quality Index(AQI). |
+| [GNU FreeFont](https://www.gnu.org/software/freefont/) | [GNU General Public License v3.0](https://www.gnu.org/software/freefont/license.html) | Font Family |
+| [Lato](https://fonts.google.com/specimen/Lato) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
+| [Montserrat](https://fonts.google.com/specimen/Montserrat) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
+| [Open Sans](https://fonts.google.com/specimen/Open+Sans) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
+| [Poppins](https://fonts.google.com/specimen/Poppins) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
+| [Quicksand](https://fonts.google.com/specimen/Quicksand) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
+| [Raleway](https://fonts.google.com/specimen/Raleway) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | Font Family |
+| [Roboto](https://fonts.google.com/specimen/Roboto) | [Apache License v2.0](https://www.apache.org/licenses/LICENSE-2.0) | Font Family |
+| [Roboto Mono](https://fonts.google.com/specimen/Roboto+Mono) | [Apache License v2.0](https://www.apache.org/licenses/LICENSE-2.0) | Font Family |
+| [Roboto Slab](https://fonts.google.com/specimen/Roboto+Slab) | [Apache License v2.0](https://www.apache.org/licenses/LICENSE-2.0) | Font Family |
+| [Ubuntu font](https://design.ubuntu.com/font) | [Ubuntu Font Licence v1.0](https://ubuntu.com/legal/font-licence) | Font Family |
+| [Weather Themed Icons](https://github.com/erikflowers/weather-icons) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | (wi-\*\*.svg) Weather icon family by Lukas Bischoff/Erik Flowers. |
+| [Google Icons](https://fonts.google.com/icons) | [Apache License v2.0](https://www.apache.org/licenses/LICENSE-2.0) | (battery\*\*.svg, visibility_icon.svg) Battery and visibility icons from Google Icons. |
+| [Biological Hazard Symbol](https://svgsilh.com/image/37775.html) | [CC0 v1.0](https://en.wikipedia.org/wiki/Public_domain) | (biological_hazard_symbol.svg) Biohazard icon. |
+| [House Icon](https://seekicon.com/free-icon/house_16) | [MIT License](http://opensource.org/licenses/mit-license.html) | (house.svg) House icon. |
+| [Indoor Temerature/Humidity Icons](icons/svg) | [SIL OFL v1.1](http://scripts.sil.org/OFL) | (house\_\*\*.svg) Indoor temerature/humidity icons. |
+| [Ionizing Radiation Symbol](https://svgsilh.com/image/309911.html) | [CC0 v1.0](https://creativecommons.org/publicdomain/zero/1.0/) | (ionizing_radiation_symbol.svg) Ionizing radiation icons. |
+| [Phosphor Icons](https://github.com/phosphor-icons/homepage) | [MIT License](http://opensource.org/licenses/mit-license.html) | (wifi\*\*.svg, warning_icon.svg, error_icon.svg) WiFi, Warning, and Error icons from Phosphor Icons. |
+| [Wind Direction Icon](https://www.onlinewebfonts.com/icon/251550) | [CC BY v3.0](http://creativecommons.org/licenses/by/3.0) | (meteorological*wind_direction*\*\*deg.svg) Meteorological wind direction icon from Online Web Fonts. |
diff --git a/platformio/.gitignore b/platformio/.gitignore
index b9f3806a2..bbba29c37 100644
--- a/platformio/.gitignore
+++ b/platformio/.gitignore
@@ -1,2 +1,3 @@
.pio
.vscode
+credentials.h
diff --git a/platformio/include/api_response.h b/platformio/include/api_response.h
index 8391dec2f..5da1e69e4 100644
--- a/platformio/include/api_response.h
+++ b/platformio/include/api_response.h
@@ -25,18 +25,18 @@
#include
#include
-#define OWM_NUM_MINUTELY 1 // 61
-#define OWM_NUM_HOURLY 48 // 48
-#define OWM_NUM_DAILY 8 // 8
-#define OWM_NUM_ALERTS 8 // OpenWeatherMaps does not specify a limit, but if you need more alerts you are probably doomed.
+#define OWM_NUM_MINUTELY 1 // 61
+#define OWM_NUM_HOURLY 48 // 48
+#define OWM_NUM_DAILY 8 // 8
+#define OWM_NUM_ALERTS 8 // OpenWeatherMaps does not specify a limit, but if you need more alerts you are probably doomed.
#define OWM_NUM_AIR_POLLUTION 24 // Depending on AQI scale, hourly concentrations will need to be averaged over a period of 1h to 24h
typedef struct owm_weather
{
- int id; // Weather condition id
- String main; // Group of weather parameters (Rain, Snow, Extreme etc.)
- String description; // Weather condition within the group (full list of weather conditions). Get the output in your language
- String icon; // Weather icon id.
+ int id; // Weather condition id
+ String main; // Group of weather parameters (Rain, Snow, Extreme etc.)
+ String description; // Weather condition within the group (full list of weather conditions). Get the output in your language
+ String icon; // Weather icon id.
} owm_weather_t;
/*
@@ -44,12 +44,12 @@ typedef struct owm_weather
*/
typedef struct owm_temp
{
- float morn; // Morning temperature.
- float day; // Day temperature.
- float eve; // Evening temperature.
- float night; // Night temperature.
- float min; // Min daily temperature.
- float max; // Max daily temperature.
+ float morn; // Morning temperature.
+ float day; // Day temperature.
+ float eve; // Evening temperature.
+ float night; // Night temperature.
+ float min; // Min daily temperature.
+ float max; // Max daily temperature.
} owm_temp_t;
/*
@@ -57,10 +57,10 @@ typedef struct owm_temp
*/
typedef struct owm_feels_like
{
- float morn; // Morning temperature.
- float day; // Day temperature.
- float eve; // Evening temperature.
- float night; // Night temperature.
+ float morn; // Morning temperature.
+ float day; // Day temperature.
+ float eve; // Evening temperature.
+ float night; // Night temperature.
} owm_owm_feels_like_t;
/*
@@ -68,23 +68,23 @@ typedef struct owm_feels_like
*/
typedef struct owm_current
{
- int64_t dt; // Current time, Unix, UTC
- int64_t sunrise; // Sunrise time, Unix, UTC
- int64_t sunset; // Sunset time, Unix, UTC
- float temp; // Temperature. Units - default: kelvin, metric: Celsius, imperial: Fahrenheit.
- float feels_like; // Temperature. This temperature parameter accounts for the human perception of weather. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
- int pressure; // Atmospheric pressure on the sea level, hPa
- int humidity; // Humidity, %
- float dew_point; // Atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
- int clouds; // Cloudiness, %
- float uvi; // Current UV index
- int visibility; // Average visibility, metres. The maximum value of the visibility is 10km
- float wind_speed; // Wind speed. Wind speed. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
- float wind_gust; // (where available) Wind gust. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
- int wind_deg; // Wind direction, degrees (meteorological)
- float rain_1h; // (where available) Rain volume for last hour, mm
- float snow_1h; // (where available) Snow volume for last hour, mm
- owm_weather_t weather;
+ int64_t dt; // Current time, Unix, UTC
+ int64_t sunrise; // Sunrise time, Unix, UTC
+ int64_t sunset; // Sunset time, Unix, UTC
+ float temp; // Temperature. Units - default: kelvin, metric: Celsius, imperial: Fahrenheit.
+ float feels_like; // Temperature. This temperature parameter accounts for the human perception of weather. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
+ int pressure; // Atmospheric pressure on the sea level, hPa
+ int humidity; // Humidity, %
+ float dew_point; // Atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
+ int clouds; // Cloudiness, %
+ float uvi; // Current UV index
+ int visibility; // Average visibility, metres. The maximum value of the visibility is 10km
+ float wind_speed; // Wind speed. Wind speed. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
+ float wind_gust; // (where available) Wind gust. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
+ int wind_deg; // Wind direction, degrees (meteorological)
+ float rain_1h; // (where available) Rain volume for last hour, mm
+ float snow_1h; // (where available) Snow volume for last hour, mm
+ owm_weather_t weather;
} owm_current_t;
/*
@@ -92,8 +92,8 @@ typedef struct owm_current
*/
typedef struct owm_minutely
{
- int64_t dt; // Time of the forecasted data, unix, UTC
- float precipitation; // Precipitation volume, mm
+ int64_t dt; // Time of the forecasted data, unix, UTC
+ float precipitation; // Precipitation volume, mm
} owm_minutely_t;
/*
@@ -101,22 +101,22 @@ typedef struct owm_minutely
*/
typedef struct owm_hourly
{
- int64_t dt; // Time of the forecasted data, unix, UTC
- float temp; // Temperature. Units - default: kelvin, metric: Celsius, imperial: Fahrenheit.
- float feels_like; // Temperature. This temperature parameter accounts for the human perception of weather. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
- int pressure; // Atmospheric pressure on the sea level, hPa
- int humidity; // Humidity, %
- float dew_point; // Atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
- int clouds; // Cloudiness, %
- float uvi; // Current UV index
- int visibility; // Average visibility, metres. The maximum value of the visibility is 10km
- float wind_speed; // Wind speed. Wind speed. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
- float wind_gust; // (where available) Wind gust. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
- int wind_deg; // Wind direction, degrees (meteorological)
- float pop; // Probability of precipitation. The values of the parameter vary between 0 and 1, where 0 is equal to 0%, 1 is equal to 100%
- float rain_1h; // (where available) Rain volume for last hour, mm
- float snow_1h; // (where available) Snow volume for last hour, mm
- owm_weather_t weather;
+ int64_t dt; // Time of the forecasted data, unix, UTC
+ float temp; // Temperature. Units - default: kelvin, metric: Celsius, imperial: Fahrenheit.
+ float feels_like; // Temperature. This temperature parameter accounts for the human perception of weather. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
+ int pressure; // Atmospheric pressure on the sea level, hPa
+ int humidity; // Humidity, %
+ float dew_point; // Atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
+ int clouds; // Cloudiness, %
+ float uvi; // Current UV index
+ int visibility; // Average visibility, metres. The maximum value of the visibility is 10km
+ float wind_speed; // Wind speed. Wind speed. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
+ float wind_gust; // (where available) Wind gust. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
+ int wind_deg; // Wind direction, degrees (meteorological)
+ float pop; // Probability of precipitation. The values of the parameter vary between 0 and 1, where 0 is equal to 0%, 1 is equal to 100%
+ float rain_1h; // (where available) Rain volume for last hour, mm
+ float snow_1h; // (where available) Snow volume for last hour, mm
+ owm_weather_t weather;
} owm_hourly_t;
/*
@@ -124,27 +124,27 @@ typedef struct owm_hourly
*/
typedef struct owm_daily
{
- int64_t dt; // Time of the forecasted data, unix, UTC
- int64_t sunrise; // Sunrise time, Unix, UTC
- int64_t sunset; // Sunset time, Unix, UTC
- int64_t moonrise; // The time of when the moon rises for this day, Unix, UTC
- int64_t moonset; // The time of when the moon sets for this day, Unix, UTC
- float moon_phase; // Moon phase. 0 and 1 are 'new moon', 0.25 is 'first quarter moon', 0.5 is 'full moon' and 0.75 is 'last quarter moon'. The periods in between are called 'waxing crescent', 'waxing gibous', 'waning gibous', and 'waning crescent', respectively.
- owm_temp_t temp;
- owm_owm_feels_like_t feels_like;
- int pressure; // Atmospheric pressure on the sea level, hPa
- int humidity; // Humidity, %
- float dew_point; // Atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
- int clouds; // Cloudiness, %
- float uvi; // Current UV index
- int visibility; // Average visibility, metres. The maximum value of the visibility is 10km
- float wind_speed; // Wind speed. Wind speed. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
- float wind_gust; // (where available) Wind gust. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
- int wind_deg; // Wind direction, degrees (meteorological)
- float pop; // Probability of precipitation. The values of the parameter vary between 0 and 1, where 0 is equal to 0%, 1 is equal to 100%
- float rain; // (where available) Precipitation volume, mm
- float snow; // (where available) Snow volume, mm
- owm_weather_t weather;
+ int64_t dt; // Time of the forecasted data, unix, UTC
+ int64_t sunrise; // Sunrise time, Unix, UTC
+ int64_t sunset; // Sunset time, Unix, UTC
+ int64_t moonrise; // The time of when the moon rises for this day, Unix, UTC
+ int64_t moonset; // The time of when the moon sets for this day, Unix, UTC
+ float moon_phase; // Moon phase. 0 and 1 are 'new moon', 0.25 is 'first quarter moon', 0.5 is 'full moon' and 0.75 is 'last quarter moon'. The periods in between are called 'waxing crescent', 'waxing gibous', 'waning gibous', and 'waning crescent', respectively.
+ owm_temp_t temp;
+ owm_owm_feels_like_t feels_like;
+ int pressure; // Atmospheric pressure on the sea level, hPa
+ int humidity; // Humidity, %
+ float dew_point; // Atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form. Units – default: kelvin, metric: Celsius, imperial: Fahrenheit.
+ int clouds; // Cloudiness, %
+ float uvi; // Current UV index
+ int visibility; // Average visibility, metres. The maximum value of the visibility is 10km
+ float wind_speed; // Wind speed. Wind speed. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
+ float wind_gust; // (where available) Wind gust. Units – default: metre/sec, metric: metre/sec, imperial: miles/hour.
+ int wind_deg; // Wind direction, degrees (meteorological)
+ float pop; // Probability of precipitation. The values of the parameter vary between 0 and 1, where 0 is equal to 0%, 1 is equal to 100%
+ float rain; // (where available) Precipitation volume, mm
+ float snow; // (where available) Snow volume, mm
+ owm_weather_t weather;
} owm_daily_t;
/*
@@ -152,12 +152,12 @@ typedef struct owm_daily
*/
typedef struct owm_alerts
{
- String sender_name; // Name of the alert source.
- String event; // Alert event name
- int64_t start; // Date and time of the start of the alert, Unix, UTC
- int64_t end; // Date and time of the end of the alert, Unix, UTC
- String description; // Description of the alert
- String tags; // Type of severe weather
+ String sender_name; // Name of the alert source.
+ String event; // Alert event name
+ int64_t start; // Date and time of the start of the alert, Unix, UTC
+ int64_t end; // Date and time of the end of the alert, Unix, UTC
+ String description; // Description of the alert
+ String tags; // Type of severe weather
} owm_alerts_t;
/*
@@ -167,15 +167,15 @@ typedef struct owm_alerts
*/
typedef struct owm_resp_onecall
{
- float lat; // Geographical coordinates of the location (latitude)
- float lon; // Geographical coordinates of the location (longitude)
- String timezone; // Timezone name for the requested location
- int timezone_offset; // Shift in seconds from UTC
- owm_current_t current;
+ float lat; // Geographical coordinates of the location (latitude)
+ float lon; // Geographical coordinates of the location (longitude)
+ String timezone; // Timezone name for the requested location
+ int timezone_offset; // Shift in seconds from UTC
+ owm_current_t current;
// owm_minutely_t minutely[OWM_NUM_MINUTELY];
- owm_hourly_t hourly[OWM_NUM_HOURLY];
- owm_daily_t daily[OWM_NUM_DAILY];
+ owm_hourly_t hourly[OWM_NUM_HOURLY];
+ owm_daily_t daily[OWM_NUM_DAILY];
std::vector alerts;
} owm_resp_onecall_t;
@@ -184,20 +184,20 @@ typedef struct owm_resp_onecall
*/
typedef struct owm_coord
{
- float lat;
- float lon;
+ float lat;
+ float lon;
} owm_coord_t;
typedef struct owm_components
{
- float co[OWM_NUM_AIR_POLLUTION]; // Сoncentration of CO (Carbon monoxide), μg/m^3
- float no[OWM_NUM_AIR_POLLUTION]; // Сoncentration of NO (Nitrogen monoxide), μg/m^3
- float no2[OWM_NUM_AIR_POLLUTION]; // Сoncentration of NO2 (Nitrogen dioxide), μg/m^3
- float o3[OWM_NUM_AIR_POLLUTION]; // Сoncentration of O3 (Ozone), μg/m^3
- float so2[OWM_NUM_AIR_POLLUTION]; // Сoncentration of SO2 (Sulphur dioxide), μg/m^3
- float pm2_5[OWM_NUM_AIR_POLLUTION]; // Сoncentration of PM2.5 (Fine particles matter), μg/m^3
- float pm10[OWM_NUM_AIR_POLLUTION]; // Сoncentration of PM10 (Coarse particulate matter), μg/m^3
- float nh3[OWM_NUM_AIR_POLLUTION]; // Сoncentration of NH3 (Ammonia), μg/m^3
+ float co[OWM_NUM_AIR_POLLUTION]; // Сoncentration of CO (Carbon monoxide), μg/m^3
+ float no[OWM_NUM_AIR_POLLUTION]; // Сoncentration of NO (Nitrogen monoxide), μg/m^3
+ float no2[OWM_NUM_AIR_POLLUTION]; // Сoncentration of NO2 (Nitrogen dioxide), μg/m^3
+ float o3[OWM_NUM_AIR_POLLUTION]; // Сoncentration of O3 (Ozone), μg/m^3
+ float so2[OWM_NUM_AIR_POLLUTION]; // Сoncentration of SO2 (Sulphur dioxide), μg/m^3
+ float pm2_5[OWM_NUM_AIR_POLLUTION]; // Сoncentration of PM2.5 (Fine particles matter), μg/m^3
+ float pm10[OWM_NUM_AIR_POLLUTION]; // Сoncentration of PM10 (Coarse particulate matter), μg/m^3
+ float nh3[OWM_NUM_AIR_POLLUTION]; // Сoncentration of NH3 (Ammonia), μg/m^3
} owm_components_t;
/*
@@ -205,17 +205,17 @@ typedef struct owm_components
*/
typedef struct owm_resp_air_pollution
{
- owm_coord_t coord;
- int main_aqi[OWM_NUM_AIR_POLLUTION]; // Air Quality Index. Possible values: 1, 2, 3, 4, 5. Where 1 = Good, 2 = Fair, 3 = Moderate, 4 = Poor, 5 = Very Poor.
+ owm_coord_t coord;
+ int main_aqi[OWM_NUM_AIR_POLLUTION]; // Air Quality Index. Possible values: 1, 2, 3, 4, 5. Where 1 = Good, 2 = Fair, 3 = Moderate, 4 = Poor, 5 = Very Poor.
owm_components_t components;
- int64_t dt[OWM_NUM_AIR_POLLUTION]; // Date and time, Unix, UTC;
+ int64_t dt[OWM_NUM_AIR_POLLUTION]; // Date and time, Unix, UTC;
} owm_resp_air_pollution_t;
DeserializationError deserializeOneCall(WiFiClient &json,
owm_resp_onecall_t &r);
DeserializationError deserializeAirQuality(WiFiClient &json,
owm_resp_air_pollution_t &r);
-
+DeserializationError deserializeOpenMeteoCall(WiFiClient &json,
+ owm_resp_onecall_t &r);
#endif
-
diff --git a/platformio/include/client_utils.h b/platformio/include/client_utils.h
index 6b84689e8..a157f3343 100644
--- a/platformio/include/client_utils.h
+++ b/platformio/include/client_utils.h
@@ -22,23 +22,24 @@
#include "api_response.h"
#include "config.h"
#ifdef USE_HTTP
- #include
+#include
#else
- #include
+#include
#endif
wl_status_t startWiFi(int &wifiRSSI);
void killWiFi();
bool waitForSNTPSync(tm *timeInfo);
bool printLocalTime(tm *timeInfo);
+
#ifdef USE_HTTP
- int getOWMonecall(WiFiClient &client, owm_resp_onecall_t &r);
- int getOWMairpollution(WiFiClient &client, owm_resp_air_pollution_t &r);
+int getOWMonecall(WiFiClient &client, owm_resp_onecall_t &r);
+int getOWMairpollution(WiFiClient &client, owm_resp_air_pollution_t &r);
+int getOMCall(WiFiClient &client, owm_resp_onecall_t &r);
#else
- int getOWMonecall(WiFiClientSecure &client, owm_resp_onecall_t &r);
- int getOWMairpollution(WiFiClientSecure &client, owm_resp_air_pollution_t &r);
-#endif
-
-
+int getOWMonecall(WiFiClientSecure &client, owm_resp_onecall_t &r);
+int getOWMairpollution(WiFiClientSecure &client, owm_resp_air_pollution_t &r);
+int getOMCall(WiFiClientSecure &client, owm_resp_onecall_t &r);
#endif
+#endif
\ No newline at end of file
diff --git a/platformio/include/config.h b/platformio/include/config.h
index b2dd7e8dc..698879dd1 100644
--- a/platformio/include/config.h
+++ b/platformio/include/config.h
@@ -21,6 +21,9 @@
#include
#include
+#define INDOOR 0
+#define AIR_POLLUTION 0
+
// E-PAPER PANEL
// This project supports the following E-Paper panels:
// DISP_BW_V2 - 7.5in e-Paper (v2) 800x480px Black/White
@@ -45,12 +48,12 @@
// 3 COLOR E-INK ACCENT COLOR
// Defines the 3rd color to be used when a 3+ color display is selected.
#if defined(DISP_3C_B) || defined(DISP_7C_F)
- // #define ACCENT_COLOR GxEPD_BLACK
- #define ACCENT_COLOR GxEPD_RED
- // #define ACCENT_COLOR GxEPD_GREEN
- // #define ACCENT_COLOR GxEPD_BLUE
- // #define ACCENT_COLOR GxEPD_YELLOW
- // #define ACCENT_COLOR GxEPD_ORANGE
+// #define ACCENT_COLOR GxEPD_BLACK
+#define ACCENT_COLOR GxEPD_RED
+// #define ACCENT_COLOR GxEPD_GREEN
+// #define ACCENT_COLOR GxEPD_BLUE
+// #define ACCENT_COLOR GxEPD_YELLOW
+// #define ACCENT_COLOR GxEPD_ORANGE
#endif
// LOCALE
@@ -69,6 +72,9 @@
// Portuguese (Brazil) pt_BR
#define LOCALE en_US
+#define USE_OPEN_WEATHER_MAP
+// #define USE_OPEN_METEO
+
// UNITS
// Define exactly one macro for each measurement type below.
@@ -247,7 +253,7 @@
// Extra information that can be displayed on the status bar. Set to 1 to
// enable.
#define STATUS_BAR_EXTRAS_BAT_VOLTAGE 0
-#define STATUS_BAR_EXTRAS_WIFI_RSSI 0
+#define STATUS_BAR_EXTRAS_WIFI_RSSI 0
// BATTERY MONITORING
// You may choose to power your weather display with or without a battery.
@@ -286,6 +292,7 @@ extern const unsigned HTTP_CLIENT_TCP_TIMEOUT;
extern const String OWM_APIKEY;
extern const String OWM_ENDPOINT;
extern const String OWM_ONECALL_VERSION;
+extern const String OM_ENDPOINT;
extern const String LAT;
extern const String LON;
extern const String CITY_STRING;
@@ -311,99 +318,59 @@ extern const uint32_t MAX_BATTERY_VOLTAGE;
extern const uint32_t MIN_BATTERY_VOLTAGE;
// CONFIG VALIDATION - DO NOT MODIFY
-#if !( defined(DISP_BW_V2) \
- ^ defined(DISP_3C_B) \
- ^ defined(DISP_7C_F) \
- ^ defined(DISP_BW_V1))
- #error Invalid configuration. Exactly one display panel must be selected.
+#if !(defined(DISP_BW_V2) ^ defined(DISP_3C_B) ^ defined(DISP_7C_F) ^ defined(DISP_BW_V1))
+#error Invalid configuration. Exactly one display panel must be selected.
#endif
-#if !( defined(DRIVER_WAVESHARE) \
- ^ defined(DRIVER_DESPI_C02))
- #error Invalid configuration. Exactly one driver board must be selected.
+#if !(defined(DRIVER_WAVESHARE) ^ defined(DRIVER_DESPI_C02))
+#error Invalid configuration. Exactly one driver board must be selected.
#endif
#if !(defined(LOCALE))
- #error Invalid configuration. Locale not selected.
+#error Invalid configuration. Locale not selected.
#endif
-#if !( defined(UNITS_TEMP_KELVIN) \
- ^ defined(UNITS_TEMP_CELSIUS) \
- ^ defined(UNITS_TEMP_FAHRENHEIT))
- #error Invalid configuration. Exactly one temperature unit must be selected.
+#if !(defined(UNITS_TEMP_KELVIN) ^ defined(UNITS_TEMP_CELSIUS) ^ defined(UNITS_TEMP_FAHRENHEIT))
+#error Invalid configuration. Exactly one temperature unit must be selected.
#endif
-#if !( defined(UNITS_SPEED_METERSPERSECOND) \
- ^ defined(UNITS_SPEED_FEETPERSECOND) \
- ^ defined(UNITS_SPEED_KILOMETERSPERHOUR) \
- ^ defined(UNITS_SPEED_MILESPERHOUR) \
- ^ defined(UNITS_SPEED_KNOTS) \
- ^ defined(UNITS_SPEED_BEAUFORT))
- #error Invalid configuration. Exactly one wind speed unit must be selected.
+#if !(defined(UNITS_SPEED_METERSPERSECOND) ^ defined(UNITS_SPEED_FEETPERSECOND) ^ defined(UNITS_SPEED_KILOMETERSPERHOUR) ^ defined(UNITS_SPEED_MILESPERHOUR) ^ defined(UNITS_SPEED_KNOTS) ^ defined(UNITS_SPEED_BEAUFORT))
+#error Invalid configuration. Exactly one wind speed unit must be selected.
#endif
-#if !( defined(UNITS_PRES_HECTOPASCALS) \
- ^ defined(UNITS_PRES_PASCALS) \
- ^ defined(UNITS_PRES_MILLIMETERSOFMERCURY) \
- ^ defined(UNITS_PRES_INCHESOFMERCURY) \
- ^ defined(UNITS_PRES_MILLIBARS) \
- ^ defined(UNITS_PRES_ATMOSPHERES) \
- ^ defined(UNITS_PRES_GRAMSPERSQUARECENTIMETER) \
- ^ defined(UNITS_PRES_POUNDSPERSQUAREINCH))
- #error Invalid configuration. Exactly one pressure unit must be selected.
+#if !(defined(UNITS_PRES_HECTOPASCALS) ^ defined(UNITS_PRES_PASCALS) ^ defined(UNITS_PRES_MILLIMETERSOFMERCURY) ^ defined(UNITS_PRES_INCHESOFMERCURY) ^ defined(UNITS_PRES_MILLIBARS) ^ defined(UNITS_PRES_ATMOSPHERES) ^ defined(UNITS_PRES_GRAMSPERSQUARECENTIMETER) ^ defined(UNITS_PRES_POUNDSPERSQUAREINCH))
+#error Invalid configuration. Exactly one pressure unit must be selected.
#endif
-#if !( defined(UNITS_DIST_KILOMETERS) \
- ^ defined(UNITS_DIST_MILES))
- #error Invalid configuration. Exactly one distance unit must be selected.
+#if !(defined(UNITS_DIST_KILOMETERS) ^ defined(UNITS_DIST_MILES))
+#error Invalid configuration. Exactly one distance unit must be selected.
#endif
-#if !( defined(UNITS_HOURLY_PRECIP_POP) \
- ^ defined(UNITS_HOURLY_PRECIP_MILLIMETERS) \
- ^ defined(UNITS_HOURLY_PRECIP_CENTIMETERS) \
- ^ defined(UNITS_HOURLY_PRECIP_INCHES))
- #error Invalid configuration. Exactly one houly precipitation measurement must be selected.
+#if !(defined(UNITS_HOURLY_PRECIP_POP) ^ defined(UNITS_HOURLY_PRECIP_MILLIMETERS) ^ defined(UNITS_HOURLY_PRECIP_CENTIMETERS) ^ defined(UNITS_HOURLY_PRECIP_INCHES))
+#error Invalid configuration. Exactly one houly precipitation measurement must be selected.
#endif
-#if !( defined(UNITS_DAILY_PRECIP_POP) \
- ^ defined(UNITS_DAILY_PRECIP_MILLIMETERS) \
- ^ defined(UNITS_DAILY_PRECIP_CENTIMETERS) \
- ^ defined(UNITS_DAILY_PRECIP_INCHES))
- #error Invalid configuration. Exactly one daily precipitation measurement must be selected.
+#if !(defined(UNITS_DAILY_PRECIP_POP) ^ defined(UNITS_DAILY_PRECIP_MILLIMETERS) ^ defined(UNITS_DAILY_PRECIP_CENTIMETERS) ^ defined(UNITS_DAILY_PRECIP_INCHES))
+#error Invalid configuration. Exactly one daily precipitation measurement must be selected.
#endif
-#if !( defined(USE_HTTP) \
- ^ defined(USE_HTTPS_NO_CERT_VERIF) \
- ^ defined(USE_HTTPS_WITH_CERT_VERIF))
- #error Invalid configuration. Exactly one HTTP mode must be selected.
+#if !(defined(USE_HTTP) ^ defined(USE_HTTPS_NO_CERT_VERIF) ^ defined(USE_HTTPS_WITH_CERT_VERIF))
+#error Invalid configuration. Exactly one HTTP mode must be selected.
#endif
-#if !( defined(WIND_INDICATOR_ARROW) \
- || ( \
- defined(WIND_INDICATOR_NUMBER) \
- ^ defined(WIND_INDICATOR_CPN_CARDINAL) \
- ^ defined(WIND_INDICATOR_CPN_INTERCARDINAL) \
- ^ defined(WIND_INDICATOR_CPN_SECONDARY_INTERCARDINAL) \
- ^ defined(WIND_INDICATOR_CPN_TERTIARY_INTERCARDINAL) \
- ) \
- ^ defined(WIND_INDICATOR_NONE))
- #error Invalid configuration. Illegal selction of wind indicator(s).
+#if !(defined(WIND_INDICATOR_ARROW) || (defined(WIND_INDICATOR_NUMBER) ^ defined(WIND_INDICATOR_CPN_CARDINAL) ^ defined(WIND_INDICATOR_CPN_INTERCARDINAL) ^ defined(WIND_INDICATOR_CPN_SECONDARY_INTERCARDINAL) ^ defined(WIND_INDICATOR_CPN_TERTIARY_INTERCARDINAL)) ^ defined(WIND_INDICATOR_NONE))
+#error Invalid configuration. Illegal selction of wind indicator(s).
#endif
-#if defined(WIND_INDICATOR_ARROW) \
- && !( defined(WIND_ICONS_CARDINAL) \
- ^ defined(WIND_ICONS_INTERCARDINAL) \
- ^ defined(WIND_ICONS_SECONDARY_INTERCARDINAL) \
- ^ defined(WIND_ICONS_TERTIARY_INTERCARDINAL) \
- ^ defined(WIND_ICONS_360))
- #error Invalid configuration. Exactly one wind direction icon precision level must be selected.
+#if defined(WIND_INDICATOR_ARROW) && !(defined(WIND_ICONS_CARDINAL) ^ defined(WIND_ICONS_INTERCARDINAL) ^ defined(WIND_ICONS_SECONDARY_INTERCARDINAL) ^ defined(WIND_ICONS_TERTIARY_INTERCARDINAL) ^ defined(WIND_ICONS_360))
+#error Invalid configuration. Exactly one wind direction icon precision level must be selected.
#endif
#if !(defined(FONT_HEADER))
- #error Invalid configuration. Font not selected.
+#error Invalid configuration. Font not selected.
#endif
#if !(defined(DISPLAY_DAILY_PRECIP))
- #error Invalid configuration. DISPLAY_DAILY_PRECIP not defined.
+#error Invalid configuration. DISPLAY_DAILY_PRECIP not defined.
#endif
#if !(defined(DISPLAY_HOURLY_ICONS))
- #error Invalid configuration. DISPLAY_HOURLY_ICONS not defined.
+#error Invalid configuration. DISPLAY_HOURLY_ICONS not defined.
#endif
#if !(defined(DISPLAY_ALERTS))
- #error Invalid configuration. DISPLAY_ALERTS not defined.
+#error Invalid configuration. DISPLAY_ALERTS not defined.
#endif
#if !(defined(BATTERY_MONITORING))
- #error Invalid configuration. BATTERY_MONITORING not defined.
+#error Invalid configuration. BATTERY_MONITORING not defined.
#endif
#if !(defined(DEBUG_LEVEL))
- #error Invalid configuration. DEBUG_LEVEL not defined.
+#error Invalid configuration. DEBUG_LEVEL not defined.
#endif
#endif
diff --git a/platformio/include/credentials.h.template b/platformio/include/credentials.h.template
new file mode 100644
index 000000000..7a1a241b7
--- /dev/null
+++ b/platformio/include/credentials.h.template
@@ -0,0 +1,14 @@
+// WIFI
+const char *WIFI_SSID = "ssid";
+const char *WIFI_PASSWORD = "password";
+
+// OPENWEATHERMAP API
+const String OWM_APIKEY = "abcdefghijklmnopqrstuvwxyz012345";
+
+// LOCATION
+// Set your latitude and longitude.
+// (used to get weather data as part of API requests to OpenWeatherMap)
+const String LAT = "40.7128";
+const String LON = "-74.0060";
+// City name that will be shown in the top-right corner of the display.
+const String CITY_STRING = "New York";
\ No newline at end of file
diff --git a/platformio/platformio.ini b/platformio/platformio.ini
index 2d34e8c5c..8dff51440 100644
--- a/platformio/platformio.ini
+++ b/platformio/platformio.ini
@@ -8,13 +8,9 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
-
[platformio]
default_envs = dfrobot_firebeetle2_esp32e
-; default_envs = firebeetle32
-
-; default options for each '[env:**]'
[env]
platform = espressif32 @ 6.9.0
framework = arduino
@@ -31,18 +27,25 @@ lib_deps =
[env:dfrobot_firebeetle2_esp32e]
board = dfrobot_firebeetle2_esp32e
monitor_speed = 115200
-; override default partition table
-; https://github.com/espressif/arduino-esp32/tree/master/tools/partitions
board_build.partitions = huge_app.csv
-; change MCU frequency, 240MHz -> 80MHz (for better power efficiency)
board_build.f_cpu = 80000000L
-
[env:firebeetle32]
board = firebeetle32
monitor_speed = 115200
; override default partition table
; https://github.com/espressif/arduino-esp32/tree/master/tools/partitions
board_build.partitions = huge_app.csv
-; change MCU frequency, 240MHz -> 80MHz (for better power efficiency)
board_build.f_cpu = 80000000L
+
+[env:esp32]
+board = esp32dev
+monitor_speed = 115200
+board_build.partitions = huge_app.csv
+board_build.f_cpu = 80000000L
+
+
+[env:esp32c3pico]
+board = lolin_c3_mini
+monitor_speed = 115200
+board_build.partitions = huge_app.csv
diff --git a/platformio/src/api_response.cpp b/platformio/src/api_response.cpp
index 27f7b9a32..f6c81f56d 100644
--- a/platformio/src/api_response.cpp
+++ b/platformio/src/api_response.cpp
@@ -26,68 +26,68 @@ DeserializationError deserializeOneCall(WiFiClient &json,
int i;
JsonDocument filter;
- filter["current"] = true;
+ filter["current"] = true;
filter["minutely"] = false;
- filter["hourly"] = true;
- filter["daily"] = true;
+ filter["hourly"] = true;
+ filter["daily"] = true;
#if !DISPLAY_ALERTS
- filter["alerts"] = false;
+ filter["alerts"] = false;
#else
// description can be very long so they are filtered out to save on memory
// along with sender_name
for (int i = 0; i < OWM_NUM_ALERTS; ++i)
{
filter["alerts"][i]["sender_name"] = false;
- filter["alerts"][i]["event"] = true;
- filter["alerts"][i]["start"] = true;
- filter["alerts"][i]["end"] = true;
+ filter["alerts"][i]["event"] = true;
+ filter["alerts"][i]["start"] = true;
+ filter["alerts"][i]["end"] = true;
filter["alerts"][i]["description"] = false;
- filter["alerts"][i]["tags"] = true;
+ filter["alerts"][i]["tags"] = true;
}
#endif
JsonDocument doc;
DeserializationError error = deserializeJson(doc, json,
- DeserializationOption::Filter(filter));
+ DeserializationOption::Filter(filter));
#if DEBUG_LEVEL >= 1
- Serial.println("[debug] doc.overflowed() : "
- + String(doc.overflowed()));
+ Serial.println("[debug] doc.overflowed() : " + String(doc.overflowed()));
#endif
#if DEBUG_LEVEL >= 2
serializeJsonPretty(doc, Serial);
#endif
- if (error) {
+ if (error)
+ {
return error;
}
- r.lat = doc["lat"] .as();
- r.lon = doc["lon"] .as();
- r.timezone = doc["timezone"] .as();
+ r.lat = doc["lat"].as();
+ r.lon = doc["lon"].as();
+ r.timezone = doc["timezone"].as();
r.timezone_offset = doc["timezone_offset"].as();
JsonObject current = doc["current"];
- r.current.dt = current["dt"] .as();
- r.current.sunrise = current["sunrise"] .as();
- r.current.sunset = current["sunset"] .as();
- r.current.temp = current["temp"] .as();
+ r.current.dt = current["dt"].as();
+ r.current.sunrise = current["sunrise"].as();
+ r.current.sunset = current["sunset"].as();
+ r.current.temp = current["temp"].as();
r.current.feels_like = current["feels_like"].as();
- r.current.pressure = current["pressure"] .as();
- r.current.humidity = current["humidity"] .as();
- r.current.dew_point = current["dew_point"] .as();
- r.current.clouds = current["clouds"] .as();
- r.current.uvi = current["uvi"] .as();
+ r.current.pressure = current["pressure"].as();
+ r.current.humidity = current["humidity"].as();
+ r.current.dew_point = current["dew_point"].as();
+ r.current.clouds = current["clouds"].as();
+ r.current.uvi = current["uvi"].as();
r.current.visibility = current["visibility"].as();
r.current.wind_speed = current["wind_speed"].as();
- r.current.wind_gust = current["wind_gust"] .as();
- r.current.wind_deg = current["wind_deg"] .as();
- r.current.rain_1h = current["rain"]["1h"].as();
- r.current.snow_1h = current["snow"]["1h"].as();
+ r.current.wind_gust = current["wind_gust"].as();
+ r.current.wind_deg = current["wind_deg"].as();
+ r.current.rain_1h = current["rain"]["1h"].as();
+ r.current.snow_1h = current["snow"]["1h"].as();
JsonObject current_weather = current["weather"][0];
- r.current.weather.id = current_weather["id"] .as();
- r.current.weather.main = current_weather["main"] .as();
+ r.current.weather.id = current_weather["id"].as();
+ r.current.weather.main = current_weather["main"].as();
r.current.weather.description = current_weather["description"].as();
- r.current.weather.icon = current_weather["icon"] .as();
+ r.current.weather.icon = current_weather["icon"].as();
// minutely forecast is currently unused
// i = 0;
@@ -106,26 +106,26 @@ DeserializationError deserializeOneCall(WiFiClient &json,
i = 0;
for (JsonObject hourly : doc["hourly"].as())
{
- r.hourly[i].dt = hourly["dt"] .as();
- r.hourly[i].temp = hourly["temp"] .as();
+ r.hourly[i].dt = hourly["dt"].as();
+ r.hourly[i].temp = hourly["temp"].as();
r.hourly[i].feels_like = hourly["feels_like"].as();
- r.hourly[i].pressure = hourly["pressure"] .as();
- r.hourly[i].humidity = hourly["humidity"] .as();
- r.hourly[i].dew_point = hourly["dew_point"] .as();
- r.hourly[i].clouds = hourly["clouds"] .as();
- r.hourly[i].uvi = hourly["uvi"] .as();
+ r.hourly[i].pressure = hourly["pressure"].as();
+ r.hourly[i].humidity = hourly["humidity"].as();
+ r.hourly[i].dew_point = hourly["dew_point"].as();
+ r.hourly[i].clouds = hourly["clouds"].as();
+ r.hourly[i].uvi = hourly["uvi"].as();
r.hourly[i].visibility = hourly["visibility"].as();
r.hourly[i].wind_speed = hourly["wind_speed"].as();
- r.hourly[i].wind_gust = hourly["wind_gust"] .as();
- r.hourly[i].wind_deg = hourly["wind_deg"] .as();
- r.hourly[i].pop = hourly["pop"] .as();
- r.hourly[i].rain_1h = hourly["rain"]["1h"].as();
- r.hourly[i].snow_1h = hourly["snow"]["1h"].as();
+ r.hourly[i].wind_gust = hourly["wind_gust"].as();
+ r.hourly[i].wind_deg = hourly["wind_deg"].as();
+ r.hourly[i].pop = hourly["pop"].as();
+ r.hourly[i].rain_1h = hourly["rain"]["1h"].as();
+ r.hourly[i].snow_1h = hourly["snow"]["1h"].as();
JsonObject hourly_weather = hourly["weather"][0];
- r.hourly[i].weather.id = hourly_weather["id"] .as();
- r.hourly[i].weather.main = hourly_weather["main"] .as();
+ r.hourly[i].weather.id = hourly_weather["id"].as();
+ r.hourly[i].weather.main = hourly_weather["main"].as();
r.hourly[i].weather.description = hourly_weather["description"].as();
- r.hourly[i].weather.icon = hourly_weather["icon"] .as();
+ r.hourly[i].weather.icon = hourly_weather["icon"].as();
if (i == OWM_NUM_HOURLY - 1)
{
@@ -137,41 +137,41 @@ DeserializationError deserializeOneCall(WiFiClient &json,
i = 0;
for (JsonObject daily : doc["daily"].as())
{
- r.daily[i].dt = daily["dt"] .as();
- r.daily[i].sunrise = daily["sunrise"] .as();
- r.daily[i].sunset = daily["sunset"] .as();
- r.daily[i].moonrise = daily["moonrise"] .as();
- r.daily[i].moonset = daily["moonset"] .as();
+ r.daily[i].dt = daily["dt"].as();
+ r.daily[i].sunrise = daily["sunrise"].as();
+ r.daily[i].sunset = daily["sunset"].as();
+ r.daily[i].moonrise = daily["moonrise"].as();
+ r.daily[i].moonset = daily["moonset"].as();
r.daily[i].moon_phase = daily["moon_phase"].as();
JsonObject daily_temp = daily["temp"];
- r.daily[i].temp.morn = daily_temp["morn"] .as();
- r.daily[i].temp.day = daily_temp["day"] .as();
- r.daily[i].temp.eve = daily_temp["eve"] .as();
+ r.daily[i].temp.morn = daily_temp["morn"].as();
+ r.daily[i].temp.day = daily_temp["day"].as();
+ r.daily[i].temp.eve = daily_temp["eve"].as();
r.daily[i].temp.night = daily_temp["night"].as();
- r.daily[i].temp.min = daily_temp["min"] .as();
- r.daily[i].temp.max = daily_temp["max"] .as();
+ r.daily[i].temp.min = daily_temp["min"].as();
+ r.daily[i].temp.max = daily_temp["max"].as();
JsonObject daily_feels_like = daily["feels_like"];
- r.daily[i].feels_like.morn = daily_feels_like["morn"] .as();
- r.daily[i].feels_like.day = daily_feels_like["day"] .as();
- r.daily[i].feels_like.eve = daily_feels_like["eve"] .as();
+ r.daily[i].feels_like.morn = daily_feels_like["morn"].as();
+ r.daily[i].feels_like.day = daily_feels_like["day"].as();
+ r.daily[i].feels_like.eve = daily_feels_like["eve"].as();
r.daily[i].feels_like.night = daily_feels_like["night"].as();
- r.daily[i].pressure = daily["pressure"] .as();
- r.daily[i].humidity = daily["humidity"] .as();
- r.daily[i].dew_point = daily["dew_point"] .as();
- r.daily[i].clouds = daily["clouds"] .as();
- r.daily[i].uvi = daily["uvi"] .as();
+ r.daily[i].pressure = daily["pressure"].as();
+ r.daily[i].humidity = daily["humidity"].as();
+ r.daily[i].dew_point = daily["dew_point"].as();
+ r.daily[i].clouds = daily["clouds"].as();
+ r.daily[i].uvi = daily["uvi"].as();
r.daily[i].visibility = daily["visibility"].as();
r.daily[i].wind_speed = daily["wind_speed"].as();
- r.daily[i].wind_gust = daily["wind_gust"] .as();
- r.daily[i].wind_deg = daily["wind_deg"] .as();
- r.daily[i].pop = daily["pop"] .as();
- r.daily[i].rain = daily["rain"] .as();
- r.daily[i].snow = daily["snow"] .as();
+ r.daily[i].wind_gust = daily["wind_gust"].as();
+ r.daily[i].wind_deg = daily["wind_deg"].as();
+ r.daily[i].pop = daily["pop"].as();
+ r.daily[i].rain = daily["rain"].as();
+ r.daily[i].snow = daily["snow"].as();
JsonObject daily_weather = daily["weather"][0];
- r.daily[i].weather.id = daily_weather["id"] .as();
- r.daily[i].weather.main = daily_weather["main"] .as();
+ r.daily[i].weather.id = daily_weather["id"].as();
+ r.daily[i].weather.main = daily_weather["main"].as();
r.daily[i].weather.description = daily_weather["description"].as();
- r.daily[i].weather.icon = daily_weather["icon"] .as();
+ r.daily[i].weather.icon = daily_weather["icon"].as();
if (i == OWM_NUM_DAILY - 1)
{
@@ -186,11 +186,11 @@ DeserializationError deserializeOneCall(WiFiClient &json,
{
owm_alerts_t new_alert = {};
// new_alert.sender_name = alerts["sender_name"].as();
- new_alert.event = alerts["event"] .as();
- new_alert.start = alerts["start"] .as();
- new_alert.end = alerts["end"] .as();
+ new_alert.event = alerts["event"].as();
+ new_alert.start = alerts["start"].as();
+ new_alert.end = alerts["end"].as();
// new_alert.description = alerts["description"].as();
- new_alert.tags = alerts["tags"][0] .as();
+ new_alert.tags = alerts["tags"][0].as();
r.alerts.push_back(new_alert);
if (i == OWM_NUM_ALERTS - 1)
@@ -213,13 +213,13 @@ DeserializationError deserializeAirQuality(WiFiClient &json,
DeserializationError error = deserializeJson(doc, json);
#if DEBUG_LEVEL >= 1
- Serial.println("[debug] doc.overflowed() : "
- + String(doc.overflowed()));
+ Serial.println("[debug] doc.overflowed() : " + String(doc.overflowed()));
#endif
#if DEBUG_LEVEL >= 2
serializeJsonPretty(doc, Serial);
#endif
- if (error) {
+ if (error)
+ {
return error;
}
@@ -232,14 +232,14 @@ DeserializationError deserializeAirQuality(WiFiClient &json,
r.main_aqi[i] = list["main"]["aqi"].as();
JsonObject list_components = list["components"];
- r.components.co[i] = list_components["co"].as();
- r.components.no[i] = list_components["no"].as();
- r.components.no2[i] = list_components["no2"].as();
- r.components.o3[i] = list_components["o3"].as();
- r.components.so2[i] = list_components["so2"].as();
+ r.components.co[i] = list_components["co"].as();
+ r.components.no[i] = list_components["no"].as();
+ r.components.no2[i] = list_components["no2"].as();
+ r.components.o3[i] = list_components["o3"].as();
+ r.components.so2[i] = list_components["so2"].as();
r.components.pm2_5[i] = list_components["pm2_5"].as();
- r.components.pm10[i] = list_components["pm10"].as();
- r.components.nh3[i] = list_components["nh3"].as();
+ r.components.pm10[i] = list_components["pm10"].as();
+ r.components.nh3[i] = list_components["nh3"].as();
r.dt[i] = list["dt"].as();
@@ -253,3 +253,188 @@ DeserializationError deserializeAirQuality(WiFiClient &json,
return error;
} // end deserializeAirQuality
+DeserializationError deserializeOpenMeteoCall(WiFiClient &json,
+ owm_resp_onecall_t &r)
+{
+ JsonDocument filter;
+ filter["current"] = true;
+ filter["minutely"] = false;
+ filter["hourly"] = true;
+ filter["daily"] = true;
+#if !DISPLAY_ALERTS
+ filter["alerts"] = false;
+#else
+ // description can be very long so they are filtered out to save on memory
+ // along with sender_name
+ for (int i = 0; i < OWM_NUM_ALERTS; ++i)
+ {
+ filter["alerts"][i]["sender_name"] = false;
+ filter["alerts"][i]["event"] = true;
+ filter["alerts"][i]["start"] = true;
+ filter["alerts"][i]["end"] = true;
+ filter["alerts"][i]["description"] = false;
+ filter["alerts"][i]["tags"] = true;
+ }
+#endif
+
+ JsonDocument doc;
+
+ DeserializationError error = deserializeJson(doc, json, DeserializationOption::Filter(filter));
+
+#if DEBUG_LEVEL >= 1
+ Serial.println("[debug] doc.overflowed() : " + String(doc.overflowed()));
+#endif
+#if DEBUG_LEVEL >= 2
+ serializeJsonPretty(doc, Serial);
+#endif
+ if (error)
+ {
+ return error;
+ }
+
+ r.lat = doc["latitude"].as();
+ r.lon = doc["longitude"].as();
+ r.timezone = doc["timezone"].as();
+ r.timezone_offset = doc["utc_offset_seconds"].as();
+
+ JsonObject current = doc["current"];
+ JsonObject daily = doc["daily"];
+ JsonObject hourly = doc["hourly"];
+
+ r.current.dt = current["time"].as();
+ r.current.sunrise = daily["sunrise"][0].as(); //
+ r.current.sunset = daily["sunset"][0].as(); //
+ r.current.temp = current["temperature_2m"].as();
+ r.current.feels_like = current["apparent_temperature"].as();
+ r.current.pressure = current["surface_pressure"].as(); //
+ r.current.humidity = current["relative_humidity_2m"].as();
+ // r.current.dew_point = current["dew_point"] .as(); //
+ r.current.clouds = current["cloud_cover"].as();
+ r.current.uvi = daily["uv_index_max"][0].as(); //
+ r.current.visibility = hourly["visibility"][0].as(); //
+ r.current.wind_speed = current["wind_speed_10m"].as();
+ r.current.wind_gust = current["wind_gusts_10m"].as();
+ r.current.wind_deg = current["wind_direction_10m"].as(); // w
+ r.current.rain_1h = current["rain"].as();
+ r.current.snow_1h = current["snow"].as();
+ // JsonObject current_weather = current["weather"][0];
+ r.current.weather.id = current["weather_code"].as();
+ // r.current.weather.main = current_weather["main"] .as();
+ // r.current.weather.description = current_weather["description"].as();
+ // r.current.weather.icon = current_weather["icon"] .as();
+
+ // minutely forecast is currently unused
+ // i = 0;
+ // for (JsonObject minutely : doc["minutely"].as())
+ // {
+ // r.minutely[i].dt = minutely["dt"] .as();
+ // r.minutely[i].precipitation = minutely["precipitation"].as();
+
+ // if (i == OWM_NUM_MINUTELY - 1)
+ // {
+ // break;
+ // }
+ // ++i;
+ // }
+
+ int hours = doc["hourly"]["time"].size();
+ for (size_t i = 0; i < hours; i++)
+ {
+ r.hourly[i].dt = hourly["time"][i].as(); // dt means
+ r.hourly[i].temp = hourly["temperature_2m"][i].as();
+ r.hourly[i].feels_like = hourly["apparent_temperature"][i].as();
+ r.hourly[i].pressure = hourly["surface_pressure"][i].as();
+ r.hourly[i].humidity = hourly["relative_humidity_2m"][i].as();
+ r.hourly[i].dew_point = hourly["dew_point_2m"][i].as();
+ r.hourly[i].clouds = hourly["cloud_cover"][i].as();
+ // r.hourly[i].uvi = hourly["uvi"][i] .as();
+ r.hourly[i].visibility = hourly["visibility"][i].as();
+ r.hourly[i].wind_speed = hourly["wind_speed_10m"][i].as();
+ r.hourly[i].wind_gust = hourly["wind_gust_10m"][i].as();
+ r.hourly[i].wind_deg = hourly["wind_deg_10m"][i].as();
+ r.hourly[i].pop = hourly["precipitation_probability"][i].as();
+ r.hourly[i].rain_1h = hourly["rain"][i].as();
+ r.hourly[i].snow_1h = hourly["snowfall"][i].as();
+ // JsonObject hourly_weather = hourly["weather"][0];
+ // r.hourly[i].weather.id = hourly_weather["id"] .as();
+ // r.hourly[i].weather.main = hourly_weather["main"] .as();
+ // r.hourly[i].weather.description = hourly_weather["description"].as();
+ // r.hourly[i].weather.icon = hourly_weather["icon"] .as();
+
+ if (i == OWM_NUM_HOURLY - 1)
+ {
+ break;
+ }
+ }
+
+ int days = doc["daily"]["time"].size();
+ for (size_t i = 0; i < days; i++)
+ {
+ r.daily[i].dt = daily["time"][i].as();
+ r.daily[i].sunrise = daily["sunrise"][i].as();
+ r.daily[i].sunset = daily["sunset"][i].as();
+ // r.daily[i].moonrise = daily["moonrise"] .as();
+ // r.daily[i].moonset = daily["moonset"] .as();
+ // r.daily[i].moon_phase = daily["moon_phase"].as();
+ // JsonObject daily_temp = daily["temp"];
+ // r.daily[i].temp.morn = daily_temp["morn"] .as();
+ // r.daily[i].temp.day = daily_temp["day"] .as();
+ // r.daily[i].temp.eve = daily_temp["eve"] .as();
+ // r.daily[i].temp.night = daily_temp["night"].as();
+ r.daily[i].temp.min = daily["temperature_2m_min"][i].as();
+ r.daily[i].temp.max = daily["temperature_2m_max"][i].as();
+ Serial.println("daily temp min: " + String(r.daily[i].temp.min));
+ Serial.println("daily temp max: " + String(r.daily[i].temp.max));
+ // JsonObject daily_feels_like = daily["feels_like"];
+ // r.daily[i].feels_like.morn = daily_feels_like["morn"] .as();
+ // r.daily[i].feels_like.day = daily_feels_like["day"] .as();
+ // r.daily[i].feels_like.eve = daily_feels_like["eve"] .as();
+ // r.daily[i].feels_like.night = daily_feels_like["night"].as();
+ r.daily[i].pressure = daily["pressure"].as();
+ r.daily[i].humidity = daily["humidity"].as();
+ r.daily[i].dew_point = daily["dew_point"].as();
+ r.daily[i].clouds = daily["clouds"].as();
+ r.daily[i].uvi = daily["uvi"].as();
+ r.daily[i].visibility = daily["visibility"].as();
+ r.daily[i].wind_speed = daily["wind_speed"].as();
+ r.daily[i].wind_gust = daily["wind_gust"].as();
+ r.daily[i].wind_deg = daily["wind_deg"].as();
+ r.daily[i].pop = daily["pop"].as();
+ r.daily[i].rain = daily["rain"].as();
+ r.daily[i].snow = daily["snow"].as();
+ // JsonObject daily_weather = daily["weather"][0];
+ r.daily[i].weather.id = daily["weather_code"][i].as();
+ Serial.println("daily weather id: " + String(r.daily[i].weather.id));
+ // r.daily[i].weather.main = daily_weather["main"] .as