Advertisement
macca-nz

ESP32_WX_FORECASTER_threading

Aug 1st, 2020 (edited)
613
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 37.46 KB | None | 0 0
  1. /*
  2.  * June 28 2022
  3.  * Changed from a single loop to ESP32 threading putting original sketch functions on "Core 0" and my user functions on
  4.  * "Core 1". Also noted that the original display driver library I had been using is not the library that
  5.  * Thingpulse updates so now we are using the current version (4.3.0) from https://github.com/ThingPulse/esp8266-oled-ssd1306
  6.  *
  7.  * November 8th 2021
  8.  * It looks as if the bug is indeed to do with millis() rollover at 49 days when the screen is in
  9.  * "displayOff()" mode. What I don't know yet is if the sketch itself crashes or if it's just the display.
  10.  * Have now added a re-initialize button for the screen and will let it crash to see if
  11.  * resetting the display resolves the problem. Millis is now being used again but not the timer library
  12.  * I'm using the onboard LED to indicate "ON solid = standard WAKE", "1sec Blink = Wake by display reset" and
  13.  * "250mS fast Blink = Starts at one second to millis() roll over"
  14.  * NOTE: When the screen is on and the timer is running both buttons are disabled till the timer expires.
  15.  *
  16.  * September 18 2021
  17.  * Bug: After nearly 3 months the display will no longer turn on
  18.  * Suspect it's being caused by the millis() roll-over
  19.  * Have changed the button pin to be "INPUT_PULLUP" So no need for the 10K pull down now
  20.  * Have removed adruino-timer library and the millis() button debounce as in #3 above
  21.  * to see if this solves the problem. More to come
  22.  *
  23.  * October 16 2020
  24.  * This is not my code but I have modified it from the original as posted in
  25.  * https://www.instructables.com/ESP32ESP8266-Weather-ForecasterPredictor/
  26.  * You will find my hardware list and pin map on this post as nz-macca
  27.  *
  28.  * My changes in this sketch are:-
  29.  * #1 Upgraded to a 2.4" OLED and changed from I2C to SPI interface. You can still use the 0.9" driver
  30.  * #2 Added extra screen for Room Temperature display
  31.  * #3 Added code and library for timer to create a screen timeout (5min)
  32.  * #4 Modifyied the NTP config so it knows your region and will auto adjust for daylight savings changes
  33.  * #5 The "OLEDDisplayUi.cpp" file I have has various API's configured in it's object class. I changed slide duration there
  34.  * # Timer library  https://github.com/contrem/arduino-timer
  35.  * # OLED UI Library used  https://github.com/helmut64/OLED_SSD1306
  36.  * # NTP instructions used  https://www.bitsnblobs.com/network-time-using-esp8266
  37.  *  
  38.  * Note about the BMP280 library
  39.  * If you use a Chinese clone BMP280 sensor then you will most likely need to make a simple change to the
  40.  * "Adafruit_BMP280.h" file as I did. You'll know if it's needed as the redings are wrong.
  41.  * The error is on lines 32. The clone has a 0x76 address as default so just swap default an alt
  42.  
  43.  *
  44.  * ORIGINAL HEADER BEGINS
  45.  * Last udpate: Added enumerated weather types, improved efficiency
  46.  * Last update: 07-Aug-17, with improved forecast rules
  47.  *
  48.  * ESP8266 and BMP180 or BME280 and OLED SH1106 or SSD1306 display Weather Forecaster
  49.  * Using air pressure changes to predict weather based on an advanced set of forecasting rules.
  50.  * The 'MIT License (MIT) Copyright (c) 2016 by David Bird'. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  51.  * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,  
  52.  * 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
  53.  * following conditions:    
  54.  * The above copyright ('as annotated') notice and this permission notice shall be included in all copies or substantial portions of the Software and where the  
  55.  * software use is visible to an end-user.  
  56.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
  57.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER    
  58.  * 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.
  59.  * See more at http://dsbird.org.uk
  60.  */
  61.  
  62. #include <SPI.h>                //Needed as I'm using and SPI OLED not I2C OLED
  63. //#include "SSD1306.h"          //https://github.com/helmut64/OLED_SSD1306 // For I2C Display (V4 Old library)
  64. #include "SSD1306Spi.h"         //https://github.com/ThingPulse/esp8266-oled-ssd1306 // For SPI Display
  65. #include "OLEDDisplayUi.h"      //https://github.com/ThingPulse/esp8266-oled-ssd1306
  66. #include <WiFi.h>
  67. #include <WiFiUdp.h>
  68. #include <time.h>
  69. #include <Wire.h>               // Original sketch only needed Wire lib for sensor and OLED
  70. #include <Adafruit_BMP280.h>    // When using a Chinese clone make sure you fix default address. See notes above
  71.  
  72. #define OLED_DC 4               // SPI OLED_DC PIN
  73. #define OLED_CS 5               // SPI OLED_CS PIN
  74. #define OLED_RES 16             // SPI OLED_RESET PIN
  75. #define LED 2                   // ESP32 onboard LED
  76.  
  77. #define icon_width  40
  78. #define icon_height 40
  79.  
  80. // Screen switchs and variables
  81. #define   WAKE_PIN 12               // Momentary push-button to wake display and start the 3 minute timeout
  82. #define   SCREEN_RESET_PIN 14       // Momentary push-button wakes and resets the display and starts 3 min timeout
  83. #define   OFF_COUNT 3600            // This creates a screen 3 minute timeout (3600 x 50mS = 180,000mS /1000/60 = 3 minutes
  84. #define   DUTY_CYCLE 50             // For de-bouncing the buttons and to create the screen timeout (see line above)
  85. uint8_t   wakeState, lastWakeState = HIGH, screenResetState, lastScreenReset = HIGH,
  86.           blinkCount = 0, ledState = HIGH, blinkRate;
  87. uint16_t  timeout = 0;
  88. bool      wakePress = false, screenResetPress = false, screenON = true, blink = false,
  89.           updateLED = true;
  90. uint32_t  previousTime = 0;
  91. const uint64_t oneSecToMillisRoll = 0xFFFFFC17;       // FFFFFC17 = 4,294,966,295 which is 1000mS before millis rollover
  92.                                                       // FFFFFFFF = 4,294,967,295 which is when millis rolls over (49 days)
  93. // Define each of the *icons for display
  94. const uint8_t rain_icon[] PROGMEM = {
  95.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  96.   0x81, 0xFF, 0xFF, 0xFF, 0x3F, 0x04, 0xFE, 0xFF, 0xFF, 0xDF, 0xF0, 0xFC,
  97.   0xFF, 0xFF, 0xE7, 0xFF, 0xFB, 0xFF, 0xFF, 0xFB, 0xFF, 0xF3, 0xFF, 0xFF,
  98.   0xFD, 0xFF, 0xE7, 0xFF, 0xFF, 0xFD, 0xFF, 0x0F, 0xFE, 0x0F, 0xF8, 0xFF,
  99.   0x8F, 0xFC, 0xE7, 0xFB, 0xFF, 0xC7, 0xF9, 0xF7, 0xE3, 0xFF, 0xC3, 0xF3,
  100.   0xF3, 0xDF, 0xFF, 0xE8, 0xE7, 0xF9, 0xFF, 0xFF, 0xFE, 0xEF, 0xFD, 0xFF,
  101.   0xFF, 0xFF, 0xE7, 0xF9, 0xFF, 0xFF, 0xFF, 0xF7, 0xFB, 0xFF, 0xFF, 0xFF,
  102.   0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xF9, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF,
  103.   0xFF, 0xFF, 0x3F, 0xFE, 0x3F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x7D, 0xBF,
  104.   0xEF, 0xFF, 0xFF, 0xBE, 0xDF, 0xF7, 0xFF, 0x7F, 0xDF, 0xEF, 0xFB, 0xFF,
  105.   0xBF, 0xEF, 0xF7, 0xFD, 0xFF, 0xDF, 0xF7, 0xFB, 0xFE, 0xFF, 0xEF, 0xFB,
  106.   0x7D, 0xFF, 0xFF, 0xF7, 0xFD, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  107.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  108.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  109.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  110.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  111.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  112.  
  113. const uint8_t sunny_icon[] PROGMEM = {
  114.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF,
  115.   0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF,
  116.   0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFD, 0xDF, 0xFF, 0xE3, 0xFF, 0xF8, 0x8F,
  117.   0xFF, 0xE3, 0x7F, 0xF0, 0x07, 0xFF, 0xE3, 0x3F, 0xF8, 0x0F, 0xFE, 0xFF,
  118.   0x1F, 0xFC, 0x1F, 0x7C, 0x00, 0x0E, 0xFE, 0x3F, 0x18, 0x00, 0x1C, 0xFF,
  119.   0x7F, 0xCC, 0xFF, 0xB1, 0xFF, 0xFF, 0xE6, 0xFF, 0xE7, 0xFF, 0xFF, 0xF3,
  120.   0xFF, 0xCF, 0xFF, 0xFF, 0xF1, 0xFF, 0x9F, 0xFF, 0xFF, 0xF9, 0xFF, 0x9F,
  121.   0xFF, 0xFF, 0xF9, 0xFF, 0x9F, 0xFF, 0xFF, 0xF9, 0xFF, 0x9F, 0xFF, 0x01,
  122.   0xF9, 0xFF, 0x9F, 0x80, 0x01, 0xF9, 0xFF, 0x9F, 0x80, 0x01, 0xF9, 0xFF,
  123.   0x9F, 0x80, 0xFF, 0xF9, 0xFF, 0x9F, 0xFF, 0xFF, 0xF1, 0xFF, 0x8F, 0xFF,
  124.   0xFF, 0xF1, 0xFF, 0x8F, 0xFF, 0xFF, 0xE3, 0xFF, 0xE7, 0xFF, 0xFF, 0xC7,
  125.   0xFF, 0xF3, 0xFF, 0xFF, 0x8D, 0xFF, 0xD8, 0xFF, 0xFF, 0x38, 0x00, 0x8C,
  126.   0xFF, 0x7F, 0x70, 0x00, 0x07, 0xFF, 0x3F, 0xF8, 0xFF, 0x0F, 0xFE, 0x1F,
  127.   0xFC, 0xE3, 0x1F, 0xFC, 0x0F, 0xFE, 0xE3, 0x3F, 0xF8, 0x07, 0xFF, 0xE3,
  128.   0x7F, 0xF0, 0x8F, 0xFF, 0xE3, 0xFF, 0xF8, 0xDF, 0xFF, 0xE3, 0xFF, 0xFD,
  129.   0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF,
  130.   0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  131.  
  132. const uint8_t mostlysunny_icon[] PROGMEM = {
  133.   0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFD, 0x7E,
  134.   0xFF, 0xFF, 0xFF, 0xFB, 0xBF, 0xEF, 0xFF, 0xFF, 0x17, 0xE0, 0xF7, 0xFF,
  135.   0xFF, 0xCF, 0x9F, 0xF9, 0xFF, 0xFF, 0xE6, 0x3F, 0xFD, 0xFF, 0xFF, 0xF5,
  136.   0x7F, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0xFF, 0xF9, 0xFF, 0x00,
  137.   0xFF, 0xFF, 0xFD, 0x7F, 0x08, 0xFC, 0xFF, 0xFD, 0xBF, 0xE1, 0xF9, 0xFF,
  138.   0xFD, 0xCF, 0xFF, 0xF7, 0xFF, 0xFD, 0xF7, 0xFF, 0xE7, 0xFF, 0xF9, 0xFB,
  139.   0xFF, 0xCF, 0xFF, 0xF3, 0xFB, 0xFF, 0x1F, 0xFC, 0x17, 0xF0, 0xFF, 0x1F,
  140.   0xF9, 0xC7, 0xF7, 0xFF, 0x8F, 0xF3, 0xEF, 0xC7, 0xFF, 0x87, 0xE7, 0xE7,
  141.   0xBF, 0xFF, 0xD1, 0xCF, 0xF3, 0xFF, 0xFF, 0xFD, 0xDF, 0xFB, 0xFF, 0xFF,
  142.   0xFF, 0xCF, 0xF3, 0xFF, 0xFF, 0xFF, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xE7,
  143.   0xF7, 0xFF, 0xFF, 0xFF, 0xF3, 0xEF, 0xFF, 0xFF, 0xFF, 0xF9, 0x9F, 0xFF,
  144.   0xFF, 0x7F, 0xFC, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  145.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  146.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  147.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  148.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  149.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  150.  
  151. const uint8_t cloudy_icon[] PROGMEM = {
  152.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  153.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  154.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  155.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  156.   0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x7F, 0x78, 0xFC, 0xFF,
  157.   0xFF, 0xBF, 0xFF, 0xF9, 0xFF, 0xFF, 0xCF, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7,
  158.   0xFF, 0xE7, 0xFF, 0xFF, 0xFB, 0xFF, 0xCF, 0xFF, 0xFF, 0xFB, 0xFF, 0x1F,
  159.   0xFC, 0x3F, 0xF0, 0xFF, 0xE7, 0xFB, 0xCF, 0xF7, 0xFF, 0xF3, 0xF7, 0xEF,
  160.   0xCF, 0xFF, 0xF9, 0xEF, 0xF7, 0xBF, 0xFF, 0xFD, 0xCF, 0xF3, 0xFF, 0xFF,
  161.   0xFD, 0xDF, 0xFB, 0xFF, 0xFF, 0xFF, 0xDF, 0xFB, 0xFF, 0xFF, 0xFF, 0xEF,
  162.   0xF7, 0xFF, 0xFF, 0xFF, 0xE7, 0xF7, 0xFF, 0xFF, 0xFF, 0xF3, 0xEF, 0xFF,
  163.   0xFF, 0xFF, 0xF9, 0x9F, 0xFF, 0xFF, 0x7F, 0xFC, 0x7F, 0x00, 0x00, 0x00,
  164.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  165.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  166.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  167.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  168.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  169.  
  170. const uint8_t tstorms_icon[] PROGMEM = {
  171.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  172.   0x81, 0xFF, 0xFF, 0xFF, 0x3F, 0x04, 0xFE, 0xFF, 0xFF, 0xDF, 0xF0, 0xFC,
  173.   0xFF, 0xFF, 0xE7, 0xFF, 0xFB, 0xFF, 0xFF, 0xFB, 0xFF, 0xF3, 0xFF, 0xFF,
  174.   0xFD, 0xFF, 0xE7, 0xFF, 0xFF, 0xFD, 0xFF, 0x0F, 0xFE, 0x0F, 0xF8, 0xFF,
  175.   0x8F, 0xFC, 0xE7, 0xFB, 0xFF, 0xC7, 0xF9, 0xF7, 0xE3, 0xFF, 0xC3, 0xF3,
  176.   0xF3, 0xDF, 0xFF, 0xE8, 0xE7, 0xF9, 0xFF, 0xFF, 0xFE, 0xEF, 0xFD, 0xFF,
  177.   0xFF, 0xFF, 0xE7, 0xF9, 0xFF, 0xFF, 0xFF, 0xF7, 0xFB, 0xFF, 0xFF, 0xFF,
  178.   0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xF9, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF,
  179.   0xFF, 0xFF, 0x3F, 0xFE, 0x3F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x7F, 0x7F,
  180.   0xFF, 0xFF, 0xFF, 0xBF, 0xBF, 0xFF, 0xFF, 0xFF, 0xDF, 0x8F, 0xFF, 0xFF,
  181.   0xFF, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xF7, 0xFB, 0xFF, 0xFF, 0xFF, 0x4F,
  182.   0xF7, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xFF, 0xFF, 0xDF, 0xF1, 0xFF,
  183.   0xFF, 0xFF, 0xDF, 0xFE, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
  184.   0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF,
  185.   0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  186.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  187.   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, };
  188.  
  189. String      time_str, weather_text, weather_extra_text;
  190. int         last_reading_hour, reading_hour, hr_cnt;
  191. const char* ssid     = "MillFlat_El_Rancho";
  192. const char* password = "140824500925";
  193. enum image_names { // enumerated table used to point to images
  194.                   rain_img, sunny_img, mostlysunny_img, cloudy_img, tstorms_img,
  195.                  } image;
  196.  
  197. //NTP TZ_INFO for Auto Zone and Daylight savings Offsets
  198. // This from Github    NZST-12NZDT,M9.5.0,M4.1.0/3  -- NZST-12NZDT-13,M10.1.0/02:00:00,M3.3.0/03:00:00
  199. // from <https://remotemonitoringsystems.ca/time-zone-abbreviations.php>
  200. //If the above doesn't work try https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  201. const char* NTP_SERVER = "pool.ntp.org";  
  202. const char* TZ_INFO    = "NZST-12NZDT,M9.5.0,M4.1.0/3";
  203.  
  204. // Define and enumerated type and assign values to expected weather types.
  205. // These values help to determine the average weather preceeding a 'no-change' forecast e.g. rain, rain then mostlysun = -1 (-1 + -1 + 1) resulting on balance = more rain
  206. enum weather_type {unknown     =  4,
  207.                    sunny       =  2,
  208.                    mostlysunny =  1,
  209.                    cloudy      =  0,
  210.                    rain        = -1,
  211.                    tstorms     = -2
  212.                    };
  213.  
  214. enum weather_description {GoodClearWeather, BecomingClearer,
  215.                           NoChange, ClearSpells, ClearingWithin12hrs, ClearingAndColder,
  216.                           GettingWarmer, WarmerIn2daysRainLikely,
  217.                           ExpectRain, WarmerRainWithin36hrs, RainIn18hrs, RainHighWindsClearAndCool,
  218.                           GalesHeavyRainSnowInWinter
  219.                           };
  220.  
  221. weather_type current_wx; // Enable the current wx to be recorded
  222.  
  223. // An array structure to record pressure, temperaturre, humidity and weather state
  224. typedef struct {
  225.   float pressure;            // air pressure at the designated hour
  226.   float temperature;         // temperature at the designated hour
  227.   float humidity;            // humidity at the designated hour
  228.   weather_type wx_state_1hr; // weather state at 1-hour
  229.   weather_type wx_state_3hr; // weather state at 3-hour point
  230. } wx_record_type;
  231.  
  232. wx_record_type reading[24]; // An array covering 24-hours to enable P, T, % and Wx state to be recorded for every hour
  233.  
  234. int wx_average_1hr, wx_average_3hr; // Indicators of average weather
  235.  
  236. bool look_3hr = true;
  237. bool look_1hr = false;
  238.  
  239. //SSD1306 display(0x3c); // OLED display object definition (address, SDA, SCL)
  240. SSD1306Spi display(OLED_RES, OLED_DC, OLED_CS);   //Because I'm using SPI OLED
  241. OLEDDisplayUi ui     ( &display );
  242.  
  243. Adafruit_BMP280 bmp;   //BMP Sensor object
  244.  
  245. WiFiClient client; // wifi client object
  246.  
  247. // Used to adjust sensor reading to correct pressure for your location
  248. #define pressure_offset 3.8  //5.7 has 1.7 variation to AKL Airport
  249.  
  250. /////////////////////////////////////////////////////////////////////////
  251. // What's displayed along the top line - NTP Date and Time Overlay
  252. void msOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
  253.   display->setTextAlignment(TEXT_ALIGN_LEFT);
  254.   display->drawString(0,0, time_str.substring(0,8));  //HH:MM:SS Sat 05-07-17
  255.   display->setTextAlignment(TEXT_ALIGN_RIGHT);
  256.   display->drawString(128,0, time_str.substring(9));
  257.   display->setTextAlignment(TEXT_ALIGN_LEFT);
  258. }
  259.  
  260. // This frame draws a weather icon based on 3-hours of data for the prediction
  261. void drawFrame1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  262.   float trend  = reading[23].pressure - reading[20].pressure;                          // Trend over the last 3-hours
  263.   ForecastToImgTxt(get_forecast_text(reading[23].pressure, trend, look_3hr));          // From forecast and trend determine what image to display
  264.   if (image == rain_img) display->drawXbm(x+0,y+15, icon_width, icon_height, rain_icon);               // Display corresponding image
  265.   if (image == sunny_img) display->drawXbm(x+0,y+15, icon_width, icon_height, sunny_icon);             // Display corresponding image
  266.   if (image == mostlysunny_img) display->drawXbm(x+0,y+15, icon_width, icon_height, mostlysunny_icon); // Display corresponding image
  267.   if (image == cloudy_img) display->drawXbm(x+0,y+15, icon_width, icon_height, cloudy_icon);           // Display corresponding image
  268.   if (image == tstorms_img) display->drawXbm(x+0,y+15, icon_width, icon_height, tstorms_icon);         // Display corresponding image
  269.   display->drawStringMaxWidth(x+45,y+12,90,String(reading[23].pressure,1)+" hPA");     // Show current air pressure
  270.   display->drawStringMaxWidth(x+45,y+25,90,String(trend,1)+" "+get_trend_text(trend)); // and pressure trend
  271. }
  272.  
  273. // This frame shows a weather description based on 3-hours of data for the prediction
  274. void drawFrame2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  275.   float  trend = reading[23].pressure - reading[20].pressure;                             // Get current trend over last 3-hours
  276.   weather_description wx_text = get_forecast_text(reading[23].pressure, trend, look_3hr); // Convert to forecast text based on 3-hours
  277.   ForecastToImgTxt(wx_text);                                                              // Display corresponding text
  278.   display->setFont(ArialMT_Plain_16);
  279.   display->drawStringMaxWidth(x+0,y+10,127,weather_text);
  280.   display->setFont(ArialMT_Plain_10);
  281. }
  282.  
  283. // This frame draws a graph of pressure (delta) change for the last 24-hours, see Annex* for more details
  284. void drawFrame3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  285.   int gwidth   = 75; // Graph width in pixels
  286.   int gscale   = 30; // Graph height in pixels
  287.   int num_bars = 8;  // Number of bars to display
  288.   #define yscale 8   // Graph +/- y-axis scale  e.g. 8 displays +/-8 and scales data accordingly
  289.   float bar_width = gwidth / (num_bars+1); // Determine bar width based on graph width
  290.   x = 30; // Sets position of graph on screen
  291.   y = 15; // Sets position of graph on screen
  292.   display->drawVerticalLine(x, y, gscale+1);
  293.   display->drawString(x-18,y-6,">+"+String(yscale));
  294.   display->drawString(x-8,y+gscale/2-6,"0");
  295.   display->drawString(x-15,y+gscale-6,"<-"+String(yscale));
  296.   display->drawString(x-30,y+gscale/2-6,String(hr_cnt%24));
  297.   display->drawString(x+2+(bar_width+3)*0, y+gscale,"-24");  // 24hr marker at bar 0
  298.   display->drawString(x+2+(bar_width+3)*2, y+gscale,"-12");  // 12hr marker at bar 2
  299.   display->drawString(x+2+(bar_width+3)*5, y+gscale,"-2");   // 2hr  marker at bar 5
  300.   display->drawString(x+2+(bar_width+3)*7, y+gscale,"0");    // 0hr  marker at bar 7
  301.   int display_points [8] = {0,5,11,17,20,21,22,23}; // Only display time for hours 0,5,11,17,20,21,22,23
  302.   float value;
  303.   for (int bar_num = 0; bar_num < num_bars; bar_num++){      // Now display a bar at each hour position -24, -18, -12, -6, -3, -2, -1 and 0 hour
  304.     value = map(reading[display_points[bar_num]].pressure, reading[23].pressure-yscale, reading[23].pressure+yscale, gscale, 0);
  305.     if (value > gscale) value = gscale;                      // Screen scale is 0 to e.g. 40pixels, this stops drawing beyond graph bounds
  306.     if (value < 0     ) value = 0;                           // 0 is top of graph, this stops drawing beyond graph bounds
  307.     display->drawHorizontalLine(x+bar_num*(bar_width+3)+2, y+value, bar_width);
  308.     for (int yplus=gscale; yplus > value; yplus = yplus - 1) {
  309.       display->drawHorizontalLine(x+bar_num*(bar_width+3)+2, y + yplus, bar_width);
  310.     }
  311.   }
  312. }
  313.  
  314. // This frame draws a weather icon based on 1-hour of data for the prediction
  315. void drawFrame4(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  316.   reading[23].pressure = (reading[23].pressure + read_pressure())/2;                 // Update rolling average, gets reset on the hour transition
  317.   float  trend = reading[23].pressure - reading[22].pressure;                        // Get short-term trend for the last 1-hour
  318.   weather_description wx_text = get_forecast_text(read_pressure(), trend, look_1hr); // Convert to forecast text based on 1-hours
  319.   ForecastToImgTxt(wx_text);
  320.   if (image == rain_img) display->drawXbm(x+0,y+15, icon_width, icon_height, rain_icon);               // Display corresponding image
  321.   if (image == sunny_img) display->drawXbm(x+0,y+15, icon_width, icon_height, sunny_icon);             // Display corresponding image
  322.   if (image == mostlysunny_img) display->drawXbm(x+0,y+15, icon_width, icon_height, mostlysunny_icon); // Display corresponding image
  323.   if (image == cloudy_img) display->drawXbm(x+0,y+15, icon_width, icon_height, cloudy_icon);           // Display corresponding image
  324.   if (image == tstorms_img) display->drawXbm(x+0,y+15, icon_width, icon_height, tstorms_icon);         // Display corresponding image
  325.   display->drawStringMaxWidth(x+45,y+12,90,"1-Hr forecast");
  326.   display->drawStringMaxWidth(x+45,y+22,90,String(read_pressure(),1)+" hPA");
  327.   display->drawStringMaxWidth(x+47,y+32,90,String(trend,1)+" "+get_trend_text(trend));
  328. }
  329.  
  330. // This frame shows a weather description based on 1-hour of data for the prediction
  331. void drawFrame5(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  332.   reading[23].pressure = (reading[23].pressure + read_pressure())/2;                 // Update rolling average
  333.   float  trend = reading[23].pressure - reading[22].pressure;                        // Get short-term trend
  334.   weather_description wx_text = get_forecast_text(read_pressure(), trend, look_1hr); // Convert to forecast text based on 1-hours
  335.   ForecastToImgTxt(wx_text);
  336.   display->drawString(x+0,y+10,"Short-term forecast:");
  337.   display->setFont(ArialMT_Plain_16);
  338.   display->drawStringMaxWidth(x+0,y+18,127,weather_text);
  339.   display->setFont(ArialMT_Plain_10);
  340. }
  341. // Added this fram to display Room Temp
  342. void drawFrame6(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  343.   display->drawString(x+20,y+10,"Room Temperature:");
  344.   display->setFont(ArialMT_Plain_16);
  345.   display->drawStringMaxWidth(x+30,y+22,97,String(read_temperature())+(" *C"));
  346.   display->setFont(ArialMT_Plain_10);
  347.   //display->drawString(x+20,y+40,("Reset Count: ")+String(countDisplay()));
  348. }
  349.  
  350. float read_pressure(){
  351.   int reading = (bmp.readPressure()/100.0F+pressure_offset)*10; // Rounded result to 1-decimal place
  352.   return (float)reading/10;
  353. }
  354.  
  355. float read_temperature(){                                       // Added for a Local Temp reading
  356.   int reading = bmp.readTemperature()*100;
  357.   return (float)reading /100;
  358. }
  359.  
  360. // Convert pressure trend to text
  361. String get_trend_text(float trend){
  362.   String trend_str = "Steady"; // Default weather state
  363.   if (trend > 3.5)                          { trend_str = "Rising fast";  }
  364.   else if (trend >   1.5  && trend <= 3.5)  { trend_str = "Rising";       }
  365.   else if (trend >   0.25 && trend <= 1.5)  { trend_str = "Rising slow";  }
  366.   else if (trend >  -0.25 && trend <  0.25) { trend_str = "Steady";       }
  367.   else if (trend >= -1.5  && trend < -0.25) { trend_str = "Falling slow"; }
  368.   else if (trend >= -3.5  && trend < -1.5)  { trend_str = "Falling";      }
  369.   else if (trend <= -3.5)                   { trend_str = "Falling fast"; }
  370.   return trend_str;
  371. }
  372.  
  373. // Convert forecast text to a corresponding image for display together with a record of the current weather
  374. void ForecastToImgTxt(weather_description wx_text){
  375.   if      (wx_text == GoodClearWeather)           {image = sunny_img;       current_wx = sunny;        weather_text = "Good clear weather";}
  376.   else if (wx_text == BecomingClearer)            {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = "Becoming clearer";}
  377.   else if (wx_text == NoChange)                   {image = cloudy_img;      current_wx = cloudy;       weather_text = "No change, clearing";}
  378.   else if (wx_text == ClearSpells)                {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = "Clear spells";}
  379.   else if (wx_text == ClearingWithin12hrs)        {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = "Clearing within 12-hrs";}
  380.   else if (wx_text == ClearingAndColder)          {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = "Clearing and colder";}
  381.   else if (wx_text == GettingWarmer)              {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = "Getting warmer";}
  382.   else if (wx_text == WarmerIn2daysRainLikely)    {image = rain_img;        current_wx = rain;         weather_text = "Warmer in 2-days, rain likely";}
  383.   else if (wx_text == ExpectRain)                 {image = rain_img;        current_wx = rain;         weather_text = "Expect rain";}
  384.   else if (wx_text == WarmerRainWithin36hrs)      {image = rain_img;        current_wx = rain;         weather_text = "Warmer, rain within 36-hrs";}
  385.   else if (wx_text == RainIn18hrs)                {image = rain_img;        current_wx = rain;         weather_text = "Rain in 18-hrs";}
  386.   else if (wx_text == RainHighWindsClearAndCool)  {image = rain_img;        current_wx = rain;         weather_text = "Rain, high winds, clear and cool";}
  387.   else if (wx_text == GalesHeavyRainSnowInWinter) {image = tstorms_img;     current_wx = tstorms;      weather_text = "Gales, heavy rain, in winter snow";}
  388. }
  389.  
  390. // Convert pressure and trend to a weather description either for 1 or 3 hours with the boolean true/false switch
  391. weather_description get_forecast_text(float pressure_now, float trend, bool range) {
  392.   String trend_str = get_trend_text(trend);
  393.   weather_description wx_text = NoChange; //As a default forecast
  394.   image = cloudy_img; // Generally when there is 'no change' then cloudy is the conditions
  395.   if (pressure_now >= 1022.68 )                                                          {wx_text = GoodClearWeather;}
  396.   if (pressure_now >= 1022.7  && trend_str  == "Falling fast")                           {wx_text = WarmerRainWithin36hrs;}
  397.   if (pressure_now >= 1013.2  && pressure_now <= 1022.68 &&
  398.      (trend_str == "Steady" || trend_str == "Rising slow"))                              {wx_text = NoChange; (range?wx_history_3hr():wx_history_1hr()); }
  399.   if (pressure_now >= 1013.2 && pressure_now <= 1022.68 &&
  400.      (trend_str == "Rising" || trend_str == "Rising fast"))                              {wx_text = GettingWarmer;}
  401.   if (pressure_now >= 1013.2 && pressure_now <= 1022.68 && trend_str == "Rising slow")   {wx_text = BecomingClearer;}
  402.   if (pressure_now >= 1013.2 && pressure_now <= 1022.68 &&
  403.      (trend_str == "Falling fast"))                                                      {wx_text = ExpectRain;}
  404.   if (pressure_now >= 1013.2 && pressure_now <= 1022.68 && trend_str  == "Steady")       {wx_text = ClearSpells; (range?wx_history_3hr():wx_history_1hr());};
  405.   if (pressure_now <= 1013.2 && (trend_str == "Falling slow" || trend_str == "Falling")) {wx_text = RainIn18hrs;}
  406.   if (pressure_now <= 1013.2  &&  trend_str == "Falling fast")                           {wx_text = RainHighWindsClearAndCool;}
  407.   if (pressure_now <= 1013.2  &&
  408.      (trend_str == "Rising" || trend_str=="Rising slow"||trend_str=="Rising fast"))      {wx_text = ClearingWithin12hrs;}
  409.   if (pressure_now <= 1009.14 && trend_str  == "Falling fast")                           {wx_text = GalesHeavyRainSnowInWinter;}
  410.   if (pressure_now <= 1009.14 && trend_str  == "Rising fast")                            {wx_text = ClearingAndColder;}
  411.   return wx_text;
  412. }
  413.  
  414. // Convert 1-hr weather history to text
  415. void wx_history_1hr() {
  416.   if      (wx_average_1hr >  0) weather_extra_text = ", expect sun";
  417.   else if (wx_average_1hr == 0) weather_extra_text = ", mainly cloudy";
  418.   else if (wx_average_1hr <  0) weather_extra_text = ", expect rain";
  419.   else weather_extra_text = "";
  420. }
  421.  
  422. // Convert 3-hr weather history to text
  423. void wx_history_3hr() {
  424.   if      (wx_average_3hr >  0) weather_extra_text = ", expect sun";
  425.   else if (wx_average_3hr == 0) weather_extra_text = ", mainly cloudy";
  426.   else if (wx_average_3hr <  0) weather_extra_text = ", expect rain";
  427.   else weather_extra_text = "";
  428. }
  429.  
  430. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  431.  
  432. // This array keeps function pointers to all frames  // Added a 6th frame for Room Temp
  433. // frames are the single views that slide in
  434. FrameCallback frames[] = { drawFrame1, drawFrame2, drawFrame3, drawFrame4, drawFrame5, drawFrame6 };
  435.  
  436. // how many frames are there?
  437. uint8_t frameCount = 6;
  438.  
  439. // Overlays are statically drawn on top of a frame eg. a clock
  440. OverlayCallback overlays[] = { msOverlay };
  441. uint8_t overlaysCount = 1;
  442.  
  443. void loop2(void *pvParameters){    // Core 1 loop - User tasks
  444.   while (1){
  445.       uint32_t currentMillis = millis();
  446.       if(!screenON){
  447.           wakeState = digitalRead(WAKE_PIN);
  448.           screenResetState = digitalRead(SCREEN_RESET_PIN);
  449.               if(wakeState != lastWakeState){
  450.                   previousTime = currentMillis;
  451.                   wakePress = true;
  452.                   timeout = 0;
  453.               }
  454.               if(screenResetState != lastScreenReset){
  455.                   previousTime = currentMillis;
  456.                   screenResetPress = true;
  457.               }
  458.       }
  459.       if(currentMillis >= oneSecToMillisRoll){    // One second to millis() rollover
  460.           blinkRate = 5;                          // Set to 2 x blinks per second (5 x 50 = 250mS)
  461.           blinkCount = 0;
  462.           blink = true;                           // Enable a blinking LED so we know that millis has rolled over
  463.       }
  464.       if(currentMillis - previousTime >= DUTY_CYCLE){
  465.           previousTime = currentMillis;
  466.          
  467.           if(wakePress){
  468.               if(wakeState == LOW){                  
  469.                   timeout = 0;
  470.                   display.displayOn();
  471.                   screenON = true;
  472.                   ledState = HIGH;
  473.                   updateLED = true;
  474.                   wakePress = false;
  475.               }
  476.           }
  477.           if(screenResetPress){
  478.               if(screenResetState == LOW){
  479.                   display.resetDisplay();
  480.                   display.displayOn();
  481.                   timeout = 0;
  482.                   screenON = true;
  483.                   blinkRate = 20;
  484.                   blink = true;
  485.                   blinkCount = 0;
  486.                   screenResetPress = false;
  487.               }
  488.           }
  489.           if(screenON){
  490.               timeout++;
  491.               if(timeout >= OFF_COUNT){
  492.                   display.displayOff();
  493.                   blink = false;
  494.                   ledState = LOW;
  495.                   updateLED = true;
  496.                   screenON = false;
  497.               }
  498.           }
  499.           if(blink){
  500.               blinkCount++;
  501.               if(blinkCount >= blinkRate){
  502.                   blinkCount = 0;
  503.                   ledState = !ledState;
  504.                   updateLED = true;
  505.               }
  506.           }
  507.           if(updateLED){
  508.               digitalWrite(LED, ledState);
  509.               updateLED = false;
  510.           }
  511.       }
  512.       lastWakeState = wakeState;
  513.       lastScreenReset = screenResetState;      
  514.       //Serial.println(time_str);
  515.       //Serial.println(read_pressure());
  516.   }
  517. }
  518.  
  519. void loop1(void *pvParameters){    // Core 0 - Original loop
  520.   while (1) {
  521.     uint32_t remainingTimeBudget = ui.update();
  522.     update_time_and_data();
  523.     delay(remainingTimeBudget);
  524.     }
  525. }
  526.  
  527. void setup() {
  528.   float p,t;
  529.   Serial.begin(115200);
  530.   pinMode(WAKE_PIN, INPUT_PULLUP);
  531.   pinMode(SCREEN_RESET_PIN, INPUT_PULLUP);
  532.   pinMode(LED, OUTPUT);
  533.  
  534.   if (!StartWiFi(ssid,password)) Serial.println("Failed to start WiFi Service after 20 attempts");;
  535.  
  536.   /* configTime(12*3600, 0, "pool.ntp.org"); // +1hour (1*60*60=3600=+1hour) ahead for DST in the UK */
  537.   configTime(0, 0, NTP_SERVER); // if TZ configured
  538.     setenv("TZ", TZ_INFO, 1);   // for TZ and Daylight Auto change
  539.   time_t now = time(nullptr);
  540.   delay(2000); // Wait for time to start
  541.  
  542.   if (!bmp.begin()) { Serial.println("Could not find a sensor, check wiring!");}
  543.     else
  544.   {
  545.     Serial.println("Found a sensor continuing");
  546.     while (isnan(bmp.readPressure())) { Serial.println(bmp.readPressure()); }
  547.   }
  548.  
  549.   /* Default settings from datasheet. */
  550.   bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
  551.                   Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
  552.                   Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
  553.                   Adafruit_BMP280::FILTER_X16,      /* Filtering. */
  554.                   Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
  555.                  
  556.                  
  557.   while (!update_time());  //Get the latest time
  558.   for (int i = 0; i <= 23; i++){ // At the start all array values are the same as a baseline
  559.     reading[i].pressure     = read_pressure();       // A rounded to 1-decimal place version of pressure
  560.     reading[i].temperature  = bmp.readTemperature(); // Enabled
  561.  //   reading[i].humidity     = bme.readHumidity();    // Although not used, but avialable
  562.     reading[i].wx_state_1hr = unknown;               // To begin with  
  563.     reading[i].wx_state_3hr = unknown;               // To begin with
  564.   }                                                  // Note that only 0,5,11,17,20,21,22,23 are used as display positions
  565.   last_reading_hour = reading_hour;
  566.   wx_average_1hr = 0; // Until we get a better idea
  567.   wx_average_3hr = 0; // Until we get a better idea
  568.  
  569.  
  570.   // An ESP is capable of rendering 60fps in 80Mhz mode but leaves little time for anything else,
  571.   // run at 160Mhz mode or just set it to about 30 fps
  572.   ui.setTargetFPS(20);                     // @20fps it seems fine so should leave plenty of resource
  573.   ui.setIndicatorPosition(BOTTOM);         // You can change this to TOP, LEFT, BOTTOM, RIGHT
  574.   ui.setIndicatorDirection(LEFT_RIGHT);    // Defines where the first frame is located in the bar
  575.   ui.setFrameAnimation(SLIDE_LEFT);        // You can change the transition that is used SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN
  576.   ui.setFrames(frames, frameCount);        // Add frames
  577.   ui.setOverlays(overlays, overlaysCount); // Add overlays
  578.   ui.init();                               // Initialising the UI will init the display too.
  579.   display.flipScreenVertically();
  580.   display.setFont(ArialMT_Plain_10);
  581.   display.setTextAlignment(TEXT_ALIGN_LEFT);
  582.   xTaskCreatePinnedToCore(loop2, "loop2", 4096, NULL, 1, NULL, 1);
  583.   xTaskCreatePinnedToCore(loop1, "loop1", 4096, NULL, 1, NULL, 0);
  584. }
  585. void loop() {}
  586.  
  587. void update_time_and_data(){
  588.   while (!update_time());
  589.   if (reading_hour != last_reading_hour) { // If the hour has advanced, then shift readings left and record new values at array element [23]
  590.     for (int i = 0; i < 23;i++){
  591.       reading[i].pressure     = reading[i+1].pressure;
  592.       reading[i].temperature  = reading[i+1].temperature;
  593.       reading[i].wx_state_1hr = reading[i+1].wx_state_1hr;
  594.       reading[i].wx_state_3hr = reading[i+1].wx_state_3hr;
  595.     }
  596.     reading[23].pressure     = read_pressure(); // Update time=now with current value of pressure
  597.     reading[23].wx_state_1hr = current_wx;
  598.     reading[23].wx_state_3hr = current_wx;
  599.     last_reading_hour        = reading_hour;
  600.     hr_cnt++;
  601.     wx_average_1hr = reading[22].wx_state_1hr + current_wx;           // Used to predict 1-hour forecast extra text
  602.     wx_average_3hr = 0;
  603.     for (int i=23;i >= 21; i--){                                      // Used to predict 3-hour forecast extra text
  604.       wx_average_3hr = wx_average_3hr + (int)reading[i].wx_state_3hr; // On average the last 3-hours of weather is used for the 'no change' forecast - e.g. more of the same?
  605.     }
  606.   }  
  607. }
  608.  
  609. bool update_time(){
  610.   time_t now = time(nullptr);
  611.   struct tm *now_tm;
  612.   int hour,min,second,day,month,year;
  613.   now = time(NULL);
  614.   now_tm = localtime(&now);
  615.   hour = now_tm->tm_hour;
  616.   min  = now_tm->tm_min;
  617.   int weekday = now_tm->tm_wday;
  618.   String week_days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  619.   String wday = week_days[weekday];
  620.   second = now_tm->tm_sec;
  621.   day    = now_tm->tm_mday;
  622.   month  = now_tm->tm_mon + 1;
  623.   year   = now_tm->tm_year - 100;// YY only no CC element add 1900 for CC element too
  624.   // Needs to be in the format HH:MM:SS Sat 05-07-17
  625.   time_str = (hour<10?"0":"")+String(hour)+":"+(min<10?"0":"")+String(min)+":"+(second<10?"0":"")+String(second)+" "+wday+(day<10?" 0":" ")+String(day)+"-"+(month<10?"0":"")+String(month)+"-"+String(year);
  626.  // Serial.println(time_str);
  627.   reading_hour = hour;
  628.   return true;
  629. }
  630.  
  631. int StartWiFi(const char* ssid, const char* password){
  632.   int connAttempts = 0;
  633.   Serial.println("\r\nConnecting to: "+String(ssid));
  634.   WiFi.begin(ssid, password);
  635.   while (WiFi.status() != WL_CONNECTED ) {
  636.     delay(500);
  637.     Serial.print(".");
  638.     if(connAttempts > 20) return false;
  639.     connAttempts++;
  640.   }
  641.   Serial.print("WiFi connected\r\nIP address: ");
  642.   Serial.println(WiFi.localIP());
  643.   return true;
  644. }
  645.  
  646. /*void BMP280_Reset(){
  647.   Wire.beginTransmission(BMP280_ADDRESS);
  648.   Wire.write((uint8_t)BMP280_REGISTER_SOFTRESET);
  649.   Wire.write((uint8_t)0xB6);
  650.   Wire.endTransmission();
  651.   delay(5000);
  652.   return;
  653. } */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement