/**The MIT License (MIT)
Copyright (c) 2016 by Daniel Eichhorn
/CUT/
See more at
Squix - TechBlog
*/
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <JsonListener.h>
#include "SSD1306Wire.h"
#include "OLEDDisplayUi.h"
#include "Wire.h"
#include "WundergroundClient.h"
#include "WeatherStationFonts.h"
#include "WeatherStationImages.h"
#include "TimeClient.h"
#include "ThingspeakClient.h"
// WIFI
const char* WIFI_SSID = "Server";
const char* WIFI_PWD = "serverserver";
// Setup
const int UPDATE_INTERVAL_SECS = 20 * 60; // Update every 20 minutes
// Display Settings
const int I2C_DISPLAY_ADDRESS = 0x3c;
const int SDA_PIN = 0;
const int SDC_PIN = 2;
// TimeClient settings
const float UTC_OFFSET = 3;
// Wunderground Settings
const boolean IS_METRIC = true;
const String WUNDERGRROUND_API_KEY = "***YOUR_WU_API_KEY***";
const String WUNDERGRROUND_LANGUAGE = "EN";
const String WUNDERGROUND_COUNTRY = "UA";
const String WUNDERGROUND_CITY = "Dnipropetrovs'k";
//Thingspeak Settings
const String THINGSPEAK_CHANNEL_ID = "150258";
const String THINGSPEAK_API_READ_KEY = "***YOUR_THINGSPEAK_API_KEY***";
// Initialize the oled display for address 0x3c
// sda-pin=0 and sdc-pin=2
SSD1306Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);
OLEDDisplayUi ui( &display );
TimeClient timeClient(UTC_OFFSET);
// Set to false, if you prefere imperial/inches, Fahrenheit
WundergroundClient wunderground(IS_METRIC);
ThingspeakClient thingspeak;
// flag changed in the ticker function every 20 minutes
bool readyForWeatherUpdate = false;
String lastUpdate = "--";
Ticker ticker;
//declaring prototypes
void drawProgress(OLEDDisplay *display, int percentage, String label);
void updateData(OLEDDisplay *display);
void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecastDay1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecastDay2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecastNight1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecastNight2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecastDetailDay(OLEDDisplay *display, int x, int y, int dayIndex);
void drawForecastDetailNight(OLEDDisplay *display, int x, int y, int dayIndex);
void drawThingspeak(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawAdditional(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
void setReadyForWeatherUpdate();
// Add frames
// this array keeps function pointers to all frames
// frames are the single views that slide from right to left
FrameCallback frames[] = { drawDateTime, drawCurrentWeather, drawForecastDay1, drawForecastDay2,
drawForecastNight1, drawForecastNight2, drawThingspeak, drawAdditional };
int numberOfFrames = 8;
OverlayCallback overlays[] = { drawHeaderOverlay };
int numberOfOverlays = 1;
void setup() {
// Serial.begin(115200);
ui.setTargetFPS(30);
ui.setTimePerFrame(10000);
ui.setFrameAnimation(SLIDE_LEFT);
ui.setFrames(frames, numberOfFrames);
ui.setOverlays(overlays, numberOfOverlays);
ui.disableAllIndicators();
// Inital UI takes care of initalising the display too.
ui.init();
display.flipScreenVertically();
display.setContrast(0);
updateData(&display);
ticker.attach(UPDATE_INTERVAL_SECS, setReadyForWeatherUpdate);
}
void loop() {
if (readyForWeatherUpdate && ui.getUiState()->frameState == FIXED) {
updateData(&display);
}
int remainingTimeBudget = ui.update();
if (remainingTimeBudget > 0) {
// You can do some work here
// Don't do stuff if you are below your
// time budget.
delay(remainingTimeBudget);
}
}
/CUT/
void connectWI_FI(){
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_CENTER);
WiFi.forceSleepWake(); delay(1);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PWD);
int counter = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
display.clear();
display.drawString(64, 10, "Connecting to WiFi");
display.drawXbm(46, 30, 8, 8, counter % 3 == 0 ? activeSymbole : inactiveSymbole);
display.drawXbm(60, 30, 8, 8, counter % 3 == 1 ? activeSymbole : inactiveSymbole);
display.drawXbm(74, 30, 8, 8, counter % 3 == 2 ? activeSymbole : inactiveSymbole);
display.display();
counter++;
}
}
void updateData(OLEDDisplay *display) {
connectWI_FI();
drawProgress(display, 10, "Updating time...");
timeClient.updateTime();
drawProgress(display, 30, "Updating conditions...");
wunderground.updateConditions(WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
drawProgress(display, 50, "Updating forecasts...");
wunderground.updateForecast(WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
drawProgress(display, 80, "Updating thingspeak...");
thingspeak.getLastChannelItem(THINGSPEAK_CHANNEL_ID, THINGSPEAK_API_READ_KEY);
lastUpdate = timeClient.getFormattedTime();
readyForWeatherUpdate = false;
drawProgress(display, 100, "Done...");
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
WiFi.setSleepMode(WIFI_LIGHT_SLEEP);
WiFi.forceSleepBegin();
delay(500);
}
/CUT/
void drawThingspeak(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
float floatPressure;
char floatbufPressure[5];
thingspeak.getFieldValue(1).toCharArray(floatbufPressure,sizeof(floatbufPressure));
floatPressure = atof(floatbufPressure);
float Pressure = floatPressure * 0.750064;
String stringPressure = String( round(Pressure), DEC);
display->setFont(ArialMT_Plain_16);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, 0 +y, thingspeak.getFieldValue(4));
display->drawString(64 + x, 17 + y, thingspeak.getFieldValue(0) + "°C, feels:" + thingspeak.getFieldValue(3) + "°C");
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(2 + x, 33 + y, thingspeak.getFieldValue(2) + "% ");
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(126 + x, 33 + y, stringPressure + "mmHg");
}
void drawAdditional(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
float floatPressure2;
char floatbufPressure2[5];
wunderground.getPressure().toCharArray(floatbufPressure2,sizeof(floatbufPressure2));
floatPressure2 = atof(floatbufPressure2);
float Pressure2 = floatPressure2 * 0.750064;
String stringPressure2 = String( round(Pressure2), DEC);
display->setFont(ArialMT_Plain_10);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(0 + x, 1 +y, "Wind speed.............");
display->drawString(0 + x, 9 +y, "Wind direction.............");
display->drawString(0 + x, 17 +y, "Humidity......................");
display->drawString(0 + x, 25 +y, "Pressure.............");
display->drawString(0 + x, 33 +y, "Dew point.....................");
display->drawString(0 + x, 41 +y, "UV radiation.....................");
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(128 + x, 1 +y, wunderground.getWindSpeed() + "km/h");
display->drawString(128 + x, 9 +y, wunderground.getWindDir());
display->drawString(128 + x, 17 +y, wunderground.getHumidity());
display->drawString(128 + x, 25 +y, stringPressure2 + "mmHg");
display->drawString(128 + x, 33 +y, wunderground.getDewPoint() + "°C");
display->drawString(128 + x, 41 +y, wunderground.getUV());
}
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
display->setColor(WHITE);
display->setFont(ArialMT_Plain_10);
String time = timeClient.getFormattedTime().substring(0, 8);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(0, 53, time);
display->setTextAlignment(TEXT_ALIGN_RIGHT);
String temp = "Feels like:" + wunderground.getFeelsLike() + "°C";
display->drawString(128, 53, temp);
display->drawHorizontalLine(0, 53, 128);
}
void setReadyForWeatherUpdate() {
// Serial.println("Setting readyForUpdate to true");
readyForWeatherUpdate = true;
}