├── .gitattributes ├── README.md ├── Credentials.h └── HowIsMyDay └── HowIsMyDay.ino /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HowIsMyDay 2 | 3 | Video with explanation: https://youtu.be/a2MiyFGWnU0 4 | -------------------------------------------------------------------------------- /Credentials.h: -------------------------------------------------------------------------------- 1 | 2 | #define CREDENTIALS 1 3 | 4 | // WLAN 5 | #define mySSID "" 6 | #define myPASSWORD "" 7 | 8 | //OpenWeatherMap 9 | #define OPENWEATHERKEY "....." -------------------------------------------------------------------------------- /HowIsMyDay/HowIsMyDay.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 Andreas Spiess 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 6 | 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: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 12 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 13 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /* credentiald.h file contains these lines: 24 | #define mySSID "...." 25 | #define myPASSWORD "....." 26 | #define OPENWEATHERKEY "....." 27 | */ 28 | 29 | // TrigBoard definitions 30 | #define NEOPIXELPIN 5 31 | #define PIXELS 8 32 | #define DONEPIN 15 33 | #define EXT_WAKE 16 34 | 35 | #define MAXINTENSITY 255 36 | 37 | // Parameter 1 = number of pixels in strip 38 | // Parameter 2 = Arduino pin number (most are valid) 39 | // Parameter 3 = pixel type flags, add together as needed: 40 | // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) 41 | // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) 42 | // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) 43 | // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) 44 | // NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) 45 | Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS, NEOPIXELPIN, NEO_GRB + NEO_KHZ800); 46 | 47 | const char* ssid = mySSID; 48 | const char* password = myPASSWORD; 49 | 50 | const String endpoint = "http://api.openweathermap.org/data/2.5/forecast?q=Lausen,CH&units=metric&APPID="; 51 | const String key = OPENWEATHERKEY; 52 | 53 | int timeUTC[40]; 54 | float temp[40]; 55 | float rain[40]; 56 | float cloud[40]; 57 | float snow[40]; 58 | 59 | int morningNumber = 99; 60 | int eveningNumber = 99; 61 | 62 | struct { 63 | uint32_t crc32; 64 | byte data[508]; 65 | } rtcData; 66 | 67 | struct pixelColorStruc { 68 | int red; 69 | int green; 70 | int blue; 71 | } ; 72 | pixelColorStruc pixelColors[PIXELS]; 73 | 74 | 75 | int morningHour = 6; 76 | int eveningHour = 15; 77 | 78 | 79 | String getWeatherData() { 80 | String payload = ""; 81 | HTTPClient http; 82 | 83 | http.begin(endpoint + key); //Specify the URL 84 | int httpCode = http.GET(); //Make the request 85 | 86 | if (httpCode == 200) { //Check for the returning code 87 | 88 | payload = http.getString(); 89 | } 90 | 91 | else { 92 | payload = "E"; 93 | 94 | } 95 | http.end(); //Free the resources 96 | // Serial.println(payload); 97 | // only first 8 elements of array. Delete rest 98 | int i = 0; 99 | int last = payload.indexOf(",{""dt", 0); 100 | while (i < 8) { 101 | last = payload.indexOf(",{", last + 1); 102 | i = i + 1; 103 | } 104 | 105 | return payload.substring(0, last) + "]}"; 106 | } 107 | 108 | void parsePaket(int number, JsonObject& liste) { 109 | 110 | temp[number] = liste["main"]["temp"]; // 20.31 111 | Serial.print(" Temp "); 112 | Serial.print(temp[number]); 113 | 114 | rain[number] = liste["rain"]["3h"]; // 0 115 | Serial.print(" Rain "); 116 | Serial.print(rain[number]); 117 | 118 | snow[number] = liste["snow"]["3h"]; // 0 119 | Serial.print(" Snow "); 120 | Serial.print(snow[number]); 121 | 122 | const char* list_dt_txt = liste["dt_txt"]; // "2018-10-17 15:00:00" 123 | timeUTC[number] = (list_dt_txt[11] - '0') * 10 + list_dt_txt[12] - '0'; 124 | Serial.print(" Time "); 125 | Serial.println(timeUTC[number]); 126 | } 127 | 128 | void decodeWeather(String JSONline) { 129 | 130 | const size_t bufferSize = 4 * JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(4) + 8 * JSON_OBJECT_SIZE(1) + 4 * JSON_OBJECT_SIZE(2) + 5 * JSON_OBJECT_SIZE(4) + 4 * JSON_OBJECT_SIZE(7) + 4 * JSON_OBJECT_SIZE(8) + 1270; 131 | DynamicJsonBuffer jsonBuffer(bufferSize); 132 | const char* json = JSONline.c_str(); 133 | JsonObject& root = jsonBuffer.parseObject(json); 134 | JsonArray& list = root["list"]; 135 | for (int i = 0; i < 8; i++) { 136 | parsePaket(i, list[i]); 137 | } 138 | } 139 | 140 | void applyRules(int dayTime, int index) { 141 | 142 | 143 | // Temp 144 | Serial.print("Temp "); 145 | Serial.println(temp[index]); 146 | if (temp[index] > 21.0) { 147 | pixelColors[dayTime * 4].red = MAXINTENSITY; 148 | } else { 149 | if (temp[index] > 10.0) { 150 | pixelColors[dayTime * 4].red = MAXINTENSITY / 2; 151 | pixelColors[dayTime * 4].blue = MAXINTENSITY / 3; 152 | } else { 153 | pixelColors[dayTime * 4].blue = MAXINTENSITY; 154 | } 155 | } 156 | 157 | // Rain 158 | Serial.print(" Rain "); 159 | Serial.println(rain[index]); 160 | if (rain[index] > 7.0) { 161 | pixelColors[dayTime * 4 + 1].red = MAXINTENSITY; 162 | } else { 163 | if (rain[index] > 2.0) { 164 | pixelColors[dayTime * 4 + 1].red = MAXINTENSITY / 2; 165 | pixelColors[dayTime * 4 + 1].blue = MAXINTENSITY / 3; 166 | } else { 167 | pixelColors[dayTime * 4 + 1].blue = MAXINTENSITY; 168 | } 169 | } 170 | if (rain[index] < 0.1) pixelColors[dayTime * 4 + 1].blue = 0; 171 | 172 | 173 | // Snow 174 | Serial.print(" Snow "); 175 | Serial.println(snow[index]); 176 | if (snow[index] > 7.0) { 177 | pixelColors[dayTime * 4 + 2].red = MAXINTENSITY; 178 | } else { 179 | if (snow[index] > 2.0) { 180 | pixelColors[dayTime * 4 + 2].red = MAXINTENSITY / 2; 181 | pixelColors[dayTime * 4 + 2].blue = MAXINTENSITY / 2; 182 | } else { 183 | pixelColors[dayTime * 4 + 2].blue = MAXINTENSITY; 184 | } 185 | } 186 | if (snow[index] < 0.1) pixelColors[dayTime * 4 + 2].blue = 0; 187 | } 188 | 189 | int mapSpecial(float in, float fromLow, float fromHigh, int toLow, int toHigh) { 190 | int out = (int)map(in, fromLow, fromHigh, toLow, toHigh); 191 | if (out > toHigh) out = toHigh; 192 | if (out < toLow) out = toLow; 193 | return out; 194 | } 195 | 196 | 197 | //-------------- SETUP --------------------------------- 198 | 199 | void setup() { 200 | String weather; 201 | int extWake = 0; 202 | 203 | Serial.begin(115200); 204 | Serial.println(); 205 | Serial.println(); 206 | 207 | #ifdef DONEPIN 208 | pinMode(DONEPIN, OUTPUT); 209 | #endif 210 | 211 | 212 | #ifdef EXT_WAKE 213 | pinMode(EXT_WAKE, INPUT); 214 | Serial.print("Ext_Wake "); 215 | extWake = digitalRead(EXT_WAKE); 216 | Serial.println(extWake); 217 | #endif 218 | 219 | if (extWake == 0) { 220 | strip.begin(); 221 | strip.show(); // Initialize all pixels to 'off' 222 | 223 | float battVoltage = analogRead(A0) / 232.6; 224 | battVoltage = 3.4; 225 | Serial.print("BattVoltage "); 226 | Serial.println(battVoltage); 227 | 228 | if (battVoltage < 3.6) { 229 | Serial.println("BattVoltage low"); 230 | for (int i = 0; i < 8 ; i++) { 231 | strip.setPixelColor(i, MAXINTENSITY, 0, 0); 232 | strip.show(); 233 | delay(50); 234 | strip.setPixelColor(i, 0, 0, 0); 235 | strip.show(); 236 | delay(100); 237 | } 238 | } 239 | 240 | 241 | for (int i = 0; i < PIXELS; i++) { 242 | pixelColors[i].green = 0; 243 | pixelColors[i].red = 0; 244 | pixelColors[i].blue = 0; 245 | } 246 | 247 | WiFi.begin(ssid, password); 248 | bool indicator = false; 249 | 250 | while (WiFi.status() != WL_CONNECTED) { 251 | strip.setPixelColor(7, 0, indicator * MAXINTENSITY, 0); 252 | strip.show(); 253 | indicator = !indicator; 254 | delay(1000); 255 | Serial.println("Connecting to WiFi.."); 256 | } 257 | 258 | Serial.println("Connected to the WiFi network"); 259 | if ((WiFi.status() == WL_CONNECTED)) { //Check the current connection status 260 | do { 261 | weather = getWeatherData(); 262 | Serial.println(weather); 263 | 264 | } while (weather[0] == 'E'); 265 | decodeWeather(weather); 266 | 267 | for (int i = 0; i < 8 ; i++) { 268 | if (timeUTC[i] >= morningHour && timeUTC[i] < morningHour + 3) morningNumber = i; 269 | if (timeUTC[i] >= eveningHour && timeUTC[i] < eveningHour + 3) eveningNumber = i; 270 | } 271 | 272 | Serial.print("morningNumber "); 273 | Serial.println(morningNumber); 274 | Serial.print("eveningNumber "); 275 | Serial.println(eveningNumber); 276 | 277 | applyRules(0, morningNumber); 278 | applyRules(1, eveningNumber); 279 | 280 | for (int i = 0; i < PIXELS; i++) { 281 | strip.setPixelColor(i, pixelColors[i].red, pixelColors[i].green, pixelColors[i].blue); 282 | } 283 | strip.show(); 284 | } 285 | delay(5000); 286 | for (int i = 0; i < PIXELS; i++) { 287 | strip.setPixelColor(i, 0, 0, 0); 288 | } 289 | strip.show(); 290 | } else { 291 | delay(1000); 292 | } 293 | Serial.println("Switching off"); 294 | delay(100); 295 | #ifdef DONEPIN 296 | digitalWrite(DONEPIN, HIGH); 297 | #else 298 | ESP.deepSleep(1000000); 299 | #endif 300 | } 301 | 302 | void loop() { 303 | yield(); 304 | } 305 | --------------------------------------------------------------------------------