ESP32 – Gesammelte Daten und ein Stück Wetterstation

http://esp-idf.readthedocs.io/en/latest/api-reference/index.html

https://www.espressif.com/en/products/hardware/esp32/resources

https://www.bluetooth.com/specifications/gatt/services

https://www.instructables.com/id/ESP32ESP8266-Weather-ForecasterPredictor/

https://www.instructables.com/id/IOT-Made-Simple-Playing-With-the-ESP32-on-Arduino-/

 

Small WeatherStation for ESP32 with BMP180 and SSD1306

 

/* Last udpate: Added enumerated weather types, improved efficiency

* Last update: 25-March-2018, with improved forecast rules *  

* ESP32 and BMP180 or BME280 and OLED SH1106 or SSD1306 display Weather Forecaster  

* Using air pressure changes to predict weather based on an advanced set of forecasting rules.  

* 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  

* documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,   

* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the  

* following conditions:     

* The above copyright (‘as annotated’) notice and this permission notice shall be included in all copies or substantial portions of the Software and where the    

* software use is visible to an end-user.   

* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    

* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER     

* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

* See more at http://dsbird.org.uk*/

#include “SSD1306.h” // Version 4 or higher

#include “OLEDDisplayUi.h” // Version 4 or higher#include <WiFi.h>

#include “time.h”

#include <Wire.h>//

#include <Adafruit_BME280.h>

#include <Adafruit_BMP085.h> // If using BMP180 or BMP085 and update line: 173/174 accordingly e.g. BME and BME or BMP and BMP 

#define icon_width  40#

define icon_height 40 // Define each of the *icons for displayconst uint8_t rain_icon[] PROGMEM = {  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0x81, 0xFF, 0xFF, 0xFF, 0x3F, 0x04, 0xFE, 0xFF, 0xFF, 0xDF, 0xF0, 0xFC,   0xFF, 0xFF, 0xE7, 0xFF, 0xFB, 0xFF, 0xFF, 0xFB, 0xFF, 0xF3, 0xFF, 0xFF,   0xFD, 0xFF, 0xE7, 0xFF, 0xFF, 0xFD, 0xFF, 0x0F, 0xFE, 0x0F, 0xF8, 0xFF,   0x8F, 0xFC, 0xE7, 0xFB, 0xFF, 0xC7, 0xF9, 0xF7, 0xE3, 0xFF, 0xC3, 0xF3,   0xF3, 0xDF, 0xFF, 0xE8, 0xE7, 0xF9, 0xFF, 0xFF, 0xFE, 0xEF, 0xFD, 0xFF,   0xFF, 0xFF, 0xE7, 0xF9, 0xFF, 0xFF, 0xFF, 0xF7, 0xFB, 0xFF, 0xFF, 0xFF,   0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xF9, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF,   0xFF, 0xFF, 0x3F, 0xFE, 0x3F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x7D, 0xBF,   0xEF, 0xFF, 0xFF, 0xBE, 0xDF, 0xF7, 0xFF, 0x7F, 0xDF, 0xEF, 0xFB, 0xFF,   0xBF, 0xEF, 0xF7, 0xFD, 0xFF, 0xDF, 0xF7, 0xFB, 0xFE, 0xFF, 0xEF, 0xFB,   0x7D, 0xFF, 0xFF, 0xF7, 0xFD, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };const uint8_t sunny_icon[] PROGMEM = {  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF,   0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF,   0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFD, 0xDF, 0xFF, 0xE3, 0xFF, 0xF8, 0x8F,   0xFF, 0xE3, 0x7F, 0xF0, 0x07, 0xFF, 0xE3, 0x3F, 0xF8, 0x0F, 0xFE, 0xFF,   0x1F, 0xFC, 0x1F, 0x7C, 0x00, 0x0E, 0xFE, 0x3F, 0x18, 0x00, 0x1C, 0xFF,   0x7F, 0xCC, 0xFF, 0xB1, 0xFF, 0xFF, 0xE6, 0xFF, 0xE7, 0xFF, 0xFF, 0xF3,   0xFF, 0xCF, 0xFF, 0xFF, 0xF1, 0xFF, 0x9F, 0xFF, 0xFF, 0xF9, 0xFF, 0x9F,   0xFF, 0xFF, 0xF9, 0xFF, 0x9F, 0xFF, 0xFF, 0xF9, 0xFF, 0x9F, 0xFF, 0x01,   0xF9, 0xFF, 0x9F, 0x80, 0x01, 0xF9, 0xFF, 0x9F, 0x80, 0x01, 0xF9, 0xFF,   0x9F, 0x80, 0xFF, 0xF9, 0xFF, 0x9F, 0xFF, 0xFF, 0xF1, 0xFF, 0x8F, 0xFF,   0xFF, 0xF1, 0xFF, 0x8F, 0xFF, 0xFF, 0xE3, 0xFF, 0xE7, 0xFF, 0xFF, 0xC7,   0xFF, 0xF3, 0xFF, 0xFF, 0x8D, 0xFF, 0xD8, 0xFF, 0xFF, 0x38, 0x00, 0x8C,   0xFF, 0x7F, 0x70, 0x00, 0x07, 0xFF, 0x3F, 0xF8, 0xFF, 0x0F, 0xFE, 0x1F,   0xFC, 0xE3, 0x1F, 0xFC, 0x0F, 0xFE, 0xE3, 0x3F, 0xF8, 0x07, 0xFF, 0xE3,   0x7F, 0xF0, 0x8F, 0xFF, 0xE3, 0xFF, 0xF8, 0xDF, 0xFF, 0xE3, 0xFF, 0xFD,   0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF,   0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };const uint8_t mostlysunny_icon[] PROGMEM = {  0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFD, 0x7E,   0xFF, 0xFF, 0xFF, 0xFB, 0xBF, 0xEF, 0xFF, 0xFF, 0x17, 0xE0, 0xF7, 0xFF,   0xFF, 0xCF, 0x9F, 0xF9, 0xFF, 0xFF, 0xE6, 0x3F, 0xFD, 0xFF, 0xFF, 0xF5,   0x7F, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFE, 0xFF, 0xFF, 0xF9, 0xFF, 0x00,   0xFF, 0xFF, 0xFD, 0x7F, 0x08, 0xFC, 0xFF, 0xFD, 0xBF, 0xE1, 0xF9, 0xFF,   0xFD, 0xCF, 0xFF, 0xF7, 0xFF, 0xFD, 0xF7, 0xFF, 0xE7, 0xFF, 0xF9, 0xFB,   0xFF, 0xCF, 0xFF, 0xF3, 0xFB, 0xFF, 0x1F, 0xFC, 0x17, 0xF0, 0xFF, 0x1F,   0xF9, 0xC7, 0xF7, 0xFF, 0x8F, 0xF3, 0xEF, 0xC7, 0xFF, 0x87, 0xE7, 0xE7,   0xBF, 0xFF, 0xD1, 0xCF, 0xF3, 0xFF, 0xFF, 0xFD, 0xDF, 0xFB, 0xFF, 0xFF,   0xFF, 0xCF, 0xF3, 0xFF, 0xFF, 0xFF, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xE7,   0xF7, 0xFF, 0xFF, 0xFF, 0xF3, 0xEF, 0xFF, 0xFF, 0xFF, 0xF9, 0x9F, 0xFF,   0xFF, 0x7F, 0xFC, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };  const uint8_t cloudy_icon[] PROGMEM = {  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x7F, 0x78, 0xFC, 0xFF,   0xFF, 0xBF, 0xFF, 0xF9, 0xFF, 0xFF, 0xCF, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7,   0xFF, 0xE7, 0xFF, 0xFF, 0xFB, 0xFF, 0xCF, 0xFF, 0xFF, 0xFB, 0xFF, 0x1F,   0xFC, 0x3F, 0xF0, 0xFF, 0xE7, 0xFB, 0xCF, 0xF7, 0xFF, 0xF3, 0xF7, 0xEF,   0xCF, 0xFF, 0xF9, 0xEF, 0xF7, 0xBF, 0xFF, 0xFD, 0xCF, 0xF3, 0xFF, 0xFF,   0xFD, 0xDF, 0xFB, 0xFF, 0xFF, 0xFF, 0xDF, 0xFB, 0xFF, 0xFF, 0xFF, 0xEF,   0xF7, 0xFF, 0xFF, 0xFF, 0xE7, 0xF7, 0xFF, 0xFF, 0xFF, 0xF3, 0xEF, 0xFF,   0xFF, 0xFF, 0xF9, 0x9F, 0xFF, 0xFF, 0x7F, 0xFC, 0x7F, 0x00, 0x00, 0x00,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };const uint8_t tstorms_icon[] PROGMEM = {  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0x81, 0xFF, 0xFF, 0xFF, 0x3F, 0x04, 0xFE, 0xFF, 0xFF, 0xDF, 0xF0, 0xFC,   0xFF, 0xFF, 0xE7, 0xFF, 0xFB, 0xFF, 0xFF, 0xFB, 0xFF, 0xF3, 0xFF, 0xFF,   0xFD, 0xFF, 0xE7, 0xFF, 0xFF, 0xFD, 0xFF, 0x0F, 0xFE, 0x0F, 0xF8, 0xFF,   0x8F, 0xFC, 0xE7, 0xFB, 0xFF, 0xC7, 0xF9, 0xF7, 0xE3, 0xFF, 0xC3, 0xF3,   0xF3, 0xDF, 0xFF, 0xE8, 0xE7, 0xF9, 0xFF, 0xFF, 0xFE, 0xEF, 0xFD, 0xFF,   0xFF, 0xFF, 0xE7, 0xF9, 0xFF, 0xFF, 0xFF, 0xF7, 0xFB, 0xFF, 0xFF, 0xFF,   0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xF9, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF,   0xFF, 0xFF, 0x3F, 0xFE, 0x3F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x7F, 0x7F,   0xFF, 0xFF, 0xFF, 0xBF, 0xBF, 0xFF, 0xFF, 0xFF, 0xDF, 0x8F, 0xFF, 0xFF,   0xFF, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xF7, 0xFB, 0xFF, 0xFF, 0xFF, 0x4F,   0xF7, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xFF, 0xFF, 0xDF, 0xF1, 0xFF,   0xFF, 0xFF, 0xDF, 0xFE, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,   0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF,   0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };  String      time_str, weather_text, weather_extra_text;int         last_reading_hour, reading_hour, hr_cnt;const char* ssid     = “UT-VNet”;const char* password = “43246641485350293845”;enum image_names { // enumerated table used to point to images                  rain_img, sunny_img, mostlysunny_img, cloudy_img, tstorms_img,                 } image;// Define and enumerated type and assign values to expected weather types.// 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 rainenum weather_type {unknown     =  4,                   sunny       =  2,                   mostlysunny =  1,                   cloudy      =  0,                   rain        = -1,                   tstorms     = -2                   };enum weather_description {GoodClearWeather, BecomingClearer,                          NoChange, ClearSpells, ClearingWithin12hrs, ClearingAndColder,                          GettingWarmer, WarmerIn2daysRainLikely,                          ExpectRain, WarmerRainWithin36hrs, RainIn18hrs, RainHighWindsClearAndCool,                          GalesHeavyRainSnowInWinter                          };weather_type current_wx; // Enable the current wx to be recordedconst uint8_t* image_table[] PROGMEM = {rain_icon, sunny_icon, mostlysunny_icon, cloudy_icon, tstorms_icon}; // An array of image icons// An array structure to record pressure, temperaturre, humidity and weather statetypedef struct {  float pressure;            // air pressure at the designated hour  float temperature;         // temperature at the designated hour  float humidity;            // humidity at the designated hour  weather_type wx_state_1hr; // weather state at 1-hour  weather_type wx_state_3hr; // weather state at 3-hour point} wx_record_type;wx_record_type reading[24]; // An array covering 24-hours to enable P, T, % and Wx state to be recorded for every hourint wx_average_1hr, wx_average_3hr; // Indicators of average weatherbool look_3hr = true;bool look_1hr = false; SSD1306 display(0x3c, 5,4); // OLED display object definition (address, SDA, SCL)OLEDDisplayUi ui     ( &display );//Adafruit_BME280 bme;Adafruit_BMP085 bme; // If using BMP180 or BMP085WiFiClient client; // wifi client object#define pressure_offset 3.3 // Used to adjust sensor reading to correct pressure for your location/////////////////////////////////////////////////////////////////////////// What’s displayed along the top linevoid msOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {  display->setTextAlignment(TEXT_ALIGN_LEFT);  display->drawString(0,0, time_str.substring(0,8));  //HH:MM:SS Sat 05-07-17  display->setTextAlignment(TEXT_ALIGN_RIGHT);  display->drawString(128,0, time_str.substring(9));  display->setTextAlignment(TEXT_ALIGN_LEFT);}// This frame draws a weather icon based on 3-hours of data for the predictionvoid drawFrame1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {  float trend  = reading[23].pressure – reading[20].pressure;                          // Trend over the last 3-hours  ForecastToImgTxt(get_forecast_text(reading[23].pressure, trend, look_3hr));          // From forecast and trend determine what image to display  display->drawXbm(x+0,y+15, icon_width, icon_height, image_table[image]);             // Display corresponding image  display->drawStringMaxWidth(x+45,y+12,90,String(reading[23].pressure,1)+” hPA”);     // Show current air pressure   display->drawStringMaxWidth(x+45,y+25,90,String(trend,1)+” “+get_trend_text(trend)); // and pressure trend}// This frame shows a weather description based on 3-hours of data for the predictionvoid drawFrame2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {  float  trend = reading[23].pressure – reading[20].pressure;                             // Get current trend over last 3-hours  weather_description wx_text = get_forecast_text(reading[23].pressure, trend, look_3hr); // Convert to forecast text based on 3-hours  ForecastToImgTxt(wx_text);                                                              // Display corresponding text  display->setFont(ArialMT_Plain_16);  display->drawStringMaxWidth(x+0,y+10,127,weather_text);  display->setFont(ArialMT_Plain_10);}// This frame draws a graph of pressure (delta) change for the last 24-hours, see Annex* for more detailsvoid drawFrame3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {  int gwidth   = 75; // Graph width in pixels  int gscale   = 30; // Graph height in pixels  int num_bars = 8;  // Number of bars to display  #define yscale 8   // Graph +/- y-axis scale  e.g. 8 displays +/-8 and scales data accordingly  float bar_width = gwidth / (num_bars+1); // Determine bar width based on graph width  x = 30; // Sets position of graph on screen  y = 15; // Sets position of graph on screen  display->drawVerticalLine(x, y, gscale+1);  display->drawString(x-18,y-6,”>+”+String(yscale));  display->drawString(x-8,y+gscale/2-6,”0″);  display->drawString(x-15,y+gscale-6,”<-“+String(yscale));  display->drawString(x-30,y+gscale/2-6,String(hr_cnt%24));  display->drawString(x+2+(bar_width+3)*0, y+gscale,”-24″);  // 24hr marker at bar 0  display->drawString(x+2+(bar_width+3)*2, y+gscale,”-12″);  // 12hr marker at bar 2  display->drawString(x+2+(bar_width+3)*5, y+gscale,”-2″);   // 2hr  marker at bar 5  display->drawString(x+2+(bar_width+3)*7, y+gscale,”0″);    // 0hr  marker at bar 7  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  float value;  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    value = map(reading[display_points[bar_num]].pressure, reading[23].pressure-yscale, reading[23].pressure+yscale, gscale, 0);    if (value > gscale) value = gscale;                      // Screen scale is 0 to e.g. 40pixels, this stops drawing beyond graph bounds    if (value < 0     ) value = 0;                           // 0 is top of graph, this stops drawing beyond graph bounds    display->drawHorizontalLine(x+bar_num*(bar_width+3)+2, y+value, bar_width);    for (int yplus=gscale; yplus > value; yplus = yplus – 1) {      display->drawHorizontalLine(x+bar_num*(bar_width+3)+2, y + yplus, bar_width);    }  }}// This frame draws a weather icon based on 1-hour of data for the predictionvoid drawFrame4(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {  reading[23].pressure = (reading[23].pressure + read_pressure())/2;                 // Update rolling average, gets reset on the hour transition  float  trend = reading[23].pressure – reading[22].pressure;                        // Get short-term trend for the last 1-hour  weather_description wx_text = get_forecast_text(read_pressure(), trend, look_1hr); // Convert to forecast text based on 1-hours  ForecastToImgTxt(wx_text);  display->drawXbm(x+0,y+15, 40, 40, image_table[image]);           // Display corresponding image  display->drawStringMaxWidth(x+45,y+12,90,”1-Hr forecast”);  display->drawStringMaxWidth(x+45,y+22,90,String(read_pressure(),1)+” hPA”);  display->drawStringMaxWidth(x+47,y+32,90,String(trend,1)+” “+get_trend_text(trend));}// This frame shows a weather description based on 1-hour of data for the predictionvoid drawFrame5(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {  reading[23].pressure = (reading[23].pressure + read_pressure())/2;                 // Update rolling average  float  trend = reading[23].pressure – reading[22].pressure;                        // Get short-term trend  weather_description wx_text = get_forecast_text(read_pressure(), trend, look_1hr); // Convert to forecast text based on 1-hours  ForecastToImgTxt(wx_text);  display->drawString(x+0,y+10,”Short-term forecast:”);  display->setFont(ArialMT_Plain_16);  display->drawStringMaxWidth(x+0,y+18,127,weather_text);  display->setFont(ArialMT_Plain_10);}float read_pressure(){  int reading = (bme.readPressure()/100.0F+pressure_offset)*10; // Rounded result to 1-decimal place  return (float)reading/10;}// Convert pressure trend to textString get_trend_text(float trend){  String trend_str = “Steady”; // Default weather state  if (trend > 3.5)                          { trend_str = “Rising fast”;  }  else if (trend >   1.5  && trend <= 3.5)  { trend_str = “Rising”;       }  else if (trend >   0.25 && trend <= 1.5)  { trend_str = “Rising slow”;  }  else if (trend >  -0.25 && trend <  0.25) { trend_str = “Steady”;       }  else if (trend >= -1.5  && trend < -0.25) { trend_str = “Falling slow”; }  else if (trend >= -3.5  && trend < -1.5)  { trend_str = “Falling”;      }  else if (trend <= -3.5)                   { trend_str = “Falling fast”; }  return trend_str;}// Convert forecast text to a corresponding image for display together with a record of the current weathervoid ForecastToImgTxt(weather_description wx_text){  if      (wx_text == GoodClearWeather)           {image = sunny_img;       current_wx = sunny;        weather_text = “Good clear weather”;}  else if (wx_text == BecomingClearer)            {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = “Becoming clearer”;}  else if (wx_text == NoChange)                   {image = cloudy_img;      current_wx = cloudy;       weather_text = “No change, clearing”;}  else if (wx_text == ClearSpells)                {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = “Clear spells”;}  else if (wx_text == ClearingWithin12hrs)        {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = “Clearing within 12-hrs”;}  else if (wx_text == ClearingAndColder)          {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = “Clearing and colder”;}  else if (wx_text == GettingWarmer)              {image = mostlysunny_img; current_wx = mostlysunny;  weather_text = “Getting warmer”;}  else if (wx_text == WarmerIn2daysRainLikely)    {image = rain_img;        current_wx = rain;         weather_text = “Warmer in 2-days, rain likely”;}  else if (wx_text == ExpectRain)                 {image = rain_img;        current_wx = rain;         weather_text = “Expect rain”;}  else if (wx_text == WarmerRainWithin36hrs)      {image = rain_img;        current_wx = rain;         weather_text = “Warmer, rain within 36-hrs”;}  else if (wx_text == RainIn18hrs)                {image = rain_img;        current_wx = rain;         weather_text = “Rain in 18-hrs”;}  else if (wx_text == RainHighWindsClearAndCool)  {image = rain_img;        current_wx = rain;         weather_text = “Rain, high winds, clear and cool”;}  else if (wx_text == GalesHeavyRainSnowInWinter) {image = tstorms_img;     current_wx = tstorms;      weather_text = “Gales, heavy rain, in winter snow”;}}// Convert pressure and trend to a weather description either for 1 or 3 hours with the boolean true/false switchweather_description get_forecast_text(float pressure_now, float trend, bool range) {  String trend_str = get_trend_text(trend);  weather_description wx_text = NoChange; //As a default forecast   image = cloudy_img; // Generally when there is ‘no change’ then cloudy is the conditions  if (pressure_now >= 1022.68 )                                                          {wx_text = GoodClearWeather;}  if (pressure_now >= 1022.7  && trend_str  == “Falling fast”)                           {wx_text = WarmerRainWithin36hrs;}  if (pressure_now >= 1013.2  && pressure_now <= 1022.68 &&      (trend_str == “Steady” || trend_str == “Rising slow”))                              {wx_text = NoChange; (range?wx_history_3hr():wx_history_1hr()); }  if (pressure_now >= 1013.2 && pressure_now <= 1022.68 &&     (trend_str == “Rising” || trend_str == “Rising fast”))                              {wx_text = GettingWarmer;}  if (pressure_now >= 1013.2 && pressure_now <= 1022.68 && trend_str == “Rising slow”)   {wx_text = BecomingClearer;}  if (pressure_now >= 1013.2 && pressure_now <= 1022.68 &&      (trend_str == “Falling slow” || trend_str == “Falling fast”))                       {wx_text = ExpectRain;}  if (pressure_now >= 1013.2 && pressure_now <= 1022.68 && trend_str  == “Steady”)       {wx_text = ClearSpells; (range?wx_history_3hr():wx_history_1hr());};  if (pressure_now <= 1013.2 && (trend_str == “Falling slow” || trend_str == “Falling”)) {wx_text = RainIn18hrs;}  if (pressure_now <= 1013.2  &&  trend_str == “Falling fast”)                           {wx_text = RainHighWindsClearAndCool;}  if (pressure_now <= 1013.2  &&      (trend_str == “Rising” || trend_str==”Rising slow”||trend_str==”Rising fast”))      {wx_text = ClearingWithin12hrs;}  if (pressure_now <= 1009.14 && trend_str  == “Falling fast”)                           {wx_text = GalesHeavyRainSnowInWinter;}  if (pressure_now <= 1009.14 && trend_str  == “Rising fast”)                            {wx_text = ClearingAndColder;}  return wx_text;}// Convert 1-hr weather history to textvoid wx_history_1hr() {  if      (wx_average_1hr >  0) weather_extra_text = “, expect sun”;  else if (wx_average_1hr == 0) weather_extra_text = “, mainly cloudy”;  else if (wx_average_1hr <  0) weather_extra_text = “, expect rain”;  else weather_extra_text = “”;}// Convert 3-hr weather history to textvoid wx_history_3hr() {  if      (wx_average_3hr >  0) weather_extra_text = “, expect sun”;  else if (wx_average_3hr == 0) weather_extra_text = “, mainly cloudy”;  else if (wx_average_3hr <  0) weather_extra_text = “, expect rain”;  else weather_extra_text = “”;}///////////////////////////////////////////////////////////////////////////////////////////////////////// This array keeps function pointers to all frames// frames are the single views that slide inFrameCallback frames[] = { drawFrame1, drawFrame2, drawFrame3, drawFrame4, drawFrame5};// how many frames are there?int frameCount = 5;// Overlays are statically drawn on top of a frame eg. a clockOverlayCallback overlays[] = { msOverlay };int overlaysCount = 1;void setup() {   float p,t;  Serial.begin(115200);  Wire.begin(5,4);  if (!StartWiFi(ssid,password)) Serial.println(“Failed to start WiFi Service after 20 attempts”);;  configTime(1, 3600, “pool.ntp.org”);  if (!bme.begin()) { Serial.println(“Could not find a sensor, check wiring!”);}    else   {    Serial.println(“Found a sensor continuing”);    while (isnan(bme.readPressure())) { Serial.println(bme.readPressure()); }  }  while (!update_time());  //Get the latest time  for (int i = 0; i <= 23; i++){ // At the start all array values are the same as a baseline     reading[i].pressure     = read_pressure();       // A rounded to 1-decimal place version of pressure    reading[i].temperature  = bme.readTemperature(); // Although not used, but avialable    reading[i].humidity     = bme.readAltitude();    // Although not used, but avialable    reading[i].wx_state_1hr = unknown;               // To begin with      reading[i].wx_state_3hr = unknown;               // To begin with   }                                                  // Note that only 0,5,11,17,20,21,22,23 are used as display positions  last_reading_hour = reading_hour;  wx_average_1hr = 0; // Until we get a better idea  wx_average_3hr = 0; // Until we get a better idea    // An ESP is capable of rendering 60fps in 80Mhz mode but leaves little time for anything else, run at 160Mhz mode or just set it to about 30 fps  ui.setTargetFPS(20);  ui.setIndicatorPosition(BOTTOM);         // You can change this to TOP, LEFT, BOTTOM, RIGHT  ui.setIndicatorDirection(LEFT_RIGHT);    // Defines where the first frame is located in the bar  ui.setFrameAnimation(SLIDE_LEFT);        // You can change the transition that is used SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN  ui.setFrames(frames, frameCount);        // Add frames  ui.setOverlays(overlays, overlaysCount); // Add overlays  ui.init(); // Initialising the UI will init the display too.  display.flipScreenVertically();  display.setFont(ArialMT_Plain_10);  display.setTextAlignment(TEXT_ALIGN_LEFT);}void loop() {  int remainingTimeBudget = ui.update();  update_time_and_data();  if (remainingTimeBudget > 0) { // Do some work here if required    //for (int i = 0; i < 24;i++){    //  Serial.println(String(i)+” “+String(reading[pressure][i]));    //}    delay(remainingTimeBudget);  }}void update_time_and_data(){  while (!update_time());  if (reading_hour != last_reading_hour) { // If the hour has advanced, then shift readings left and record new values at array element [23]    for (int i = 0; i < 23;i++){      reading[i].pressure     = reading[i+1].pressure;      reading[i].temperature  = reading[i+1].temperature;      reading[i].wx_state_1hr = reading[i+1].wx_state_1hr;      reading[i].wx_state_3hr = reading[i+1].wx_state_3hr;    }    reading[23].pressure     = read_pressure(); // Update time=now with current value of pressure    reading[23].wx_state_1hr = current_wx;    reading[23].wx_state_3hr = current_wx;    last_reading_hour        = reading_hour;    hr_cnt++;    wx_average_1hr = reading[22].wx_state_1hr + current_wx;           // Used to predict 1-hour forecast extra text    wx_average_3hr = 0;    for (int i=23;i >= 21; i–){                                      // Used to predict 3-hour forecast extra text       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?    }  }  }bool update_time(){  struct tm timeinfo;  if(!getLocalTime(&timeinfo)){    Serial.println(“Failed to obtain time”);    return false;  }  //See http://www.cplusplus.com/reference/ctime/strftime/  Serial.println(&timeinfo, “%A, %d %B %y %H:%M:%S”); // Displays: Saturday, 24 June 17 14:05:49  char strftime_buf[64];  strftime(strftime_buf, sizeof(strftime_buf), “%R:%S   %a %d-%m-%y”, &timeinfo);  time_str = strftime_buf;  // Now is this format HH:MM:SS Sat 05-07-17  reading_hour = time_str.substring(0,2).toInt();  return true;}int StartWiFi(const char* ssid, const char* password){  int connAttempts = 0;  Serial.println(“rnConnecting to: “+String(ssid));  WiFi.begin(ssid, password); 

while (WiFi.status() != WL_CONNECTED ) {delay(500);Serial.print(“.”);  if(connAttempts > 20) return false;connAttempts++;}Serial.print(“WiFi connectedrnIP address: “); 

Serial.println(WiFi.localIP());  return true;}/*FRAME-3 description // This frame draws a graph of pressure (delata) change for the last 24-hours, see Annex* for more details// Draws a ‘relative value’ chart using reading[23] as the baseline// +8 |// +7 |–  //    : // +1 |–  —  —  —  —  —  —   //  0 +-24+-18+-12+-8-+-3-+-2-+-1-+-0-+// -1 |  // -2 |//    The ‘reading’ array holds values for Pressure, Temperature, Humidity and Wx State for the last 24-hours//    [00][01][02][03][04][05][06][07][08][09][10][11][12][13][14][15][16][17][18][19][20][21][22][23] Values are shifted left <– each hour//     ^-23Hr              ^-18Hr                  ^-12Hr                  ^-6Hr       ^-3 ^-2 ^-1 ^0Hr//     P  ~ readings in each array position//     T  ~ readings in each array position//     %  ~ readings in each array position//     Wx ~ readings in each array position
// Forecast basics:// Look at the pressure change over3 hours// If pressure is descending, then a low pressure area is approaching // If pressure is ascending , then a low is passing or a high pressure is coming// When pressure is changing rapidly (>6hPa/3 hours), it will be windy (or potentially windy) 
// More detailed:// Pressure falling slowly (0.5 – 3 hPa in 3h): low is weak, dying or moving slowly. You might get some rain but typically no high winds.// Pressure falling moderately (3-6 hPa/3h): rapid movement or deepening low. Moderate winds and rain and a warm front.                                           : the low is passing fast, the day after tomorrow will typically be fine. // Pressure falling fast (6-12 hPa/3h) : Storm conditions highly likely.// Pressure rises are connected with gradually drier weather
 */

Schreibe einen Kommentar