#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 "PubSubClient.h" /*************************** * Begin Settings **************************/ // Please read http://blog.squix.org/weatherstation-getting-code-adapting-it // for setup instructions // WIFI const char* WIFI_SSID = "MY WIFI"; const char* WIFI_PWD = "WIFI_PASSWORD"; const char* mqtt_server = "MQTT_SERVER_ADDY"; // Setup const int UPDATE_INTERVAL_SECS = 30 * 60; // Update every 10 minutes // Display Settings const int I2C_DISPLAY_ADDRESS = 0x3c; const int SDA_PIN = D3; const int SDC_PIN = D4; // TimeClient settings const float UTC_OFFSET = -5; // Wunderground Settings const boolean IS_METRIC = false; const String WUNDERGRROUND_API_KEY = "MYAPIKEY"; const String WUNDERGRROUND_LANGUAGE = "EN"; const String WUNDERGROUND_COUNTRY = "US"; const String WUNDERGROUND_CITY = "21220"; // Initialize the oled display for address 0x3c // sda-pin=14 and sdc-pin=12 SSD1306Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN); OLEDDisplayUi ui( &display ); /*************************** * End Settings **************************/ TimeClient timeClient(UTC_OFFSET); // Set to false, if you prefere imperial/inches, Fahrenheit WundergroundClient wunderground(false); // flag changed in the ticker function every 10 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 drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex); 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, drawForecast }; int numberOfFrames = 3; OverlayCallback overlays[] = { drawHeaderOverlay }; int numberOfOverlays = 1; void setup_wifi() { Serial.begin(115200); Serial.println(); Serial.println(); // initialize dispaly display.init(); display.clear(); display.display(); //display.flipScreenVertically(); display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_CENTER); display.setContrast(255); WiFi.begin(WIFI_SSID, WIFI_PWD); int counter = 0; while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); display.clear(); display.drawString(64, 10, "Connecting to Network"); Serial.println(WiFi.localIP()); 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++; } ui.setTargetFPS(30); ui.setActiveSymbol(activeSymbole); ui.setInactiveSymbol(inactiveSymbole); // You can change this to // TOP, LEFT, BOTTOM, RIGHT ui.setIndicatorPosition(BOTTOM); // Defines where the first frame is located in the bar. ui.setIndicatorDirection(LEFT_RIGHT); // You can change the transition that is used // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN ui.setFrameAnimation(SLIDE_DOWN); ui.setFrames(frames, numberOfFrames); ui.setOverlays(overlays, numberOfOverlays); // Inital UI takes care of initalising the display too. ui.init(); Serial.println(""); 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) { if (!client.connected()) { reconnect(); } client.loop(); } } void callback(char* topic, byte* payload, unsigned int length) { payload[length] = '\0'; strTopic = String((char*)topic); if(strTopic == "relay/switch1") { switch1 = String((char*)payload); if(switch1 == "on") { Serial.println("on"); digitalWrite(ActvnPin, HIGH); } else { Serial.println("off"); digitalWrite(ActvnPin, LOW); } } } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect("relayStation")) { Serial.println("Connected"); // Once connected, publish an announcement... client.subscribe("relay/#"); } else { Serial.print("Failed, RC="); Serial.print(client.state()); Serial.println(" Retry in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void setup() { Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); pinMode(ActvnPin, OUTPUT); digitalWrite(ActvnPin, LOW); } void drawProgress(OLEDDisplay *display, int percentage, String label) { display->clear(); display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(ArialMT_Plain_10); display->drawString(64, 10, label); display->drawProgressBar(2, 28, 124, 10, percentage); display->display(); } void updateData(OLEDDisplay *display) { drawProgress(display, 10, "Sync Device Time"); timeClient.updateTime(); drawProgress(display, 30, "Sync WX Conditions"); wunderground.updateConditions(WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY); drawProgress(display, 50, "Sync WX Forecasts"); wunderground.updateForecast(WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY); lastUpdate = timeClient.getFormattedTime(); readyForWeatherUpdate = false; drawProgress(display, 100, "Device Sync Complete"); delay(1000); } void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(ArialMT_Plain_10); String date = wunderground.getDate(); int textWidth = display->getStringWidth(date); display->drawString(64 + x, 5 + y, date); display->setFont(ArialMT_Plain_24); String time = timeClient.getFormattedTime(); textWidth = display->getStringWidth(time); display->drawString(64 + x, 15 + y, time); display->setTextAlignment(TEXT_ALIGN_LEFT); } void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { display->setFont(ArialMT_Plain_10); display->setTextAlignment(TEXT_ALIGN_LEFT); display->drawString(60 + x, 5 + y, wunderground.getWeatherText()); display->setFont(ArialMT_Plain_24); String temp = wunderground.getCurrentTemp() + "°F"; display->drawString(60 + x, 15 + y, temp); int tempWidth = display->getStringWidth(temp); display->setFont(Meteocons_Plain_42); String weatherIcon = wunderground.getTodayIcon(); int weatherIconWidth = display->getStringWidth(weatherIcon); display->drawString(32 + x - weatherIconWidth / 2, 05 + y, weatherIcon); } void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { drawForecastDetails(display, x, y, 0); drawForecastDetails(display, x + 44, y, 2); drawForecastDetails(display, x + 88, y, 4); } void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex) { display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(ArialMT_Plain_10); String day = wunderground.getForecastTitle(dayIndex).substring(0, 3); day.toUpperCase(); display->drawString(x + 20, y, day); display->setFont(Meteocons_Plain_21); display->drawString(x + 20, y + 12, wunderground.getForecastIcon(dayIndex)); display->setFont(ArialMT_Plain_10); display->drawString(x + 20, y + 34, wunderground.getForecastLowTemp(dayIndex) + "|" + wunderground.getForecastHighTemp(dayIndex)); display->setTextAlignment(TEXT_ALIGN_LEFT); } void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) { display->setColor(WHITE); display->setFont(ArialMT_Plain_10); String time = timeClient.getFormattedTime().substring(0, 5); display->setTextAlignment(TEXT_ALIGN_LEFT); display->drawString(0, 54, time); display->setTextAlignment(TEXT_ALIGN_RIGHT); String temp = wunderground.getCurrentTemp() + "°F"; display->drawString(128, 54, temp); display->drawHorizontalLine(0, 52, 128); } void setReadyForWeatherUpdate() { Serial.println("Setting readyForUpdate to true"); readyForWeatherUpdate = true; }