Es war super …
Hier ein Bericht von heise.de zu der Mini MakerFair Minden.
Hier ein Bericht von heise.de zu der Mini MakerFair Minden.
Hallo zusammen,
jeden 3. Freitag im Monat findet in der Stadtbibliothek in Minden das Treffen des MakerSPace statt.
Von 15:00 bis 18:00 Uhr basteln, grübeln und lachen wir gemeinsam.
Ob Jung, ob Alt. Mit AntMe hat jeder Spass sich mir der ProgrammierSprache C# auseinander zu setzen.
Tutorial auf Deutsch:
hier eine gute Anleitung auf deutsch, wie Ihr das MicroPhython auf dem ESP installiert und die ersten Gehversuche macht.
Ein ESP32 mit MicroPython (Video – YouTube)
Hier noch die wichtigsten Links:
https://micropython.org/download#esp32
Hier die schnelle Übersicht zu ganz einfachen Befehlen …
Welcome to MicroPython on the ESP32!
For generic online docs please visit http://docs.micropython.org/
https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/wiki
import machine // besser: from machine import Pin (spart Speicher)
pin12 = machine.Pin(12, machine.Pin.OUT)
pin12.value(1)
pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)
print(pin13.value())
i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))
i2c.scan()
i2c.writeto(addr, b'1234')
i2c.readfrom(addr, 4)
import network
sta_if = network.WLAN(network.STA_IF); sta_if.active(True)
sta_if.scan() # Scan for available access points
sta_if.connect("<AP_name>", "<password>") # Connect to an AP
sta_if.isconnected() # Check for successful connection
CTRL-A -- on a blank line, enter raw REPL mode
CTRL-B -- on a blank line, enter normal REPL mode
CTRL-C -- interrupt a running program
CTRL-D -- on a blank line, do a soft reset of the board
CTRL-E -- on a blank line, enter paste mode
For further help on a specific object, type help(obj)
For a list of available modules, type help(‘modules’)
—————————————————————————
screen /dev/tty.ESPPORT 115200 // Shell starten und mit dem ESP verbinden default:115200 dann 2-3 mal "CTRL + C" drücken ...
>>>Befehl
Beispiel:
>>>print("Hallo")
——————————————————————————————
noch etwas netter ist die RShell
Aufrufen mit:
rshell --buffer-ssize=30 -p /dev/tty.ESPPORT //(bei mir z.B.: /dev/tty.SLAB_USBtoUART)
Befehle in der RSHELL:
boards // zeigt Dir alle angeschlossenen Boards und die Namen
ls "boardname" // z.B.: "ls pyboard" - listet die Dateien auf dem Board. Wenn Ihr noch //nichts gemacht habt dann findet Ihr da nur die boot.py
// Die boot.py wird bei jedem Start des Boards ausgeführt. Auch nach dem aufwachen aus dem DeepSleep Modus.
// Euer Programm steht dann in der Regel in der main.py
edit /pyboard/boot.py // ruft die Datei boot.py im StandartEditor auf. Exit mit :q! für nicht speichern
Etwas netter ist es wenn Ihr einen anderen Editor benutzt. Verlasst die rshell und startet sie neu mit dem Befehl:
rshell --buffer-size=30 -p /dev/tty.ESPPORT -a -e nano
// damit macht Ihr für die aktuelle Sitzung den Editor "nano" zum StandartEditor
——————————————————————————————–
Aufrufen einer KomandoOberfläche (REPL):
REPL // hier könnt Ihr wieder direkt Befehle ausführen
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-/
/* 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
*/