├── LICENSE ├── README.md ├── ESP8266 └── EzTimeTetrisClockESP8266 │ └── EzTimeTetrisClockESP8266.ino └── ESP32 or TinyPICO └── EzTimeTetrisClockESP32 └── EzTimeTetrisClockESP32.ino /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Brian Lough 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WiFi-Tetris-Clock 2 | A WiFi clock made of falling tetris blocks. Runs on an ESP32 with an RGB LED Matrix (Currently the EPS8266 version is crashing!) 3 | 4 | ![img](https://thumbs.gfycat.com/RecklessSpecificKoodoo-size_restricted.gif) 5 | 6 | ## Hardware 7 | 8 | - RGB LED Matrix 64 x 32 P3 (The one I'm using) 9 | - [Amazon.co.uk*](https://amzn.to/2zLeqzl) 10 | - Amazon.com - Sold out and equivalent has bad reviews 11 | - [Aliexpress*](http://s.click.aliexpress.com/e/EMvjy3z) - NOTE: I have heard off some people that this seller has changed to a type of board that is not working. [2Dom is on the case](https://github.com/2dom/PxMatrix/issues/119), but maybe buy elsewhere. I can't recomend anywhere else because this is where I bought mine from! 12 | - [TinyPICO](https://www.crowdsupply.com/unexpected-maker/tinypico) 13 | - [ESP32 Mini*](http://s.click.aliexpress.com/e/cozT6Vx6) (The generic ESP32 board I'm working on will be based on this) 14 | - 5v 8A laptop style PSU 15 | - [Aliexpress*](http://s.click.aliexpress.com/e/vzJ2rnE) 16 | - [Amazon.co.uk*](https://amzn.to/2JBauB2) 17 | - [Amazon.com*](https://amzn.to/2Jl93qL) 18 | - [TinyPICO Matrix Shield](https://www.tindie.com/products/brianlough/tinypico-matrix-shield/) 19 | - [D1 Mini Matrix Shield](https://www.tindie.com/products/brianlough/d1-mini-matrix-shield/ 20 | ) (Although not super useful for this project!) 21 | 22 | \* Affilate links 23 | 24 | ## Wiring: 25 | 26 | Wiring is desctribed on the [PxMatrix library](https://github.com/2dom/PxMatrix) pretty well, but to try make it a little easier I have created wiring diagrams for the different types of boards. 27 | 28 | #### Tiny PICO 29 | ![img](https://i.imgur.com/aDPyHFh.png) 30 | 31 | #### Generic ESP32 32 | ![img](https://i.imgur.com/0FB11me.png) 33 | 34 | #### D1 Mini ESP8266 35 | Although not working with this sketch yet 36 | ![img](https://i.imgur.com/bIBcAXR.png) 37 | 38 | #### Power Wiring 39 | 40 | To connect your power supply up to the panel, you can connect the display power wire directly to a DC jack screw terminal breakout or use some larger screw terminals and some perfboard 41 | 42 | ![img](https://i.imgur.com/ulIn681.jpg) 43 | -------------------------------------------------------------------------------- /ESP8266/EzTimeTetrisClockESP8266/EzTimeTetrisClockESP8266.ino: -------------------------------------------------------------------------------- 1 | /******************************************************************* 2 | Tetris clock that fetches its time Using the EzTimeLibrary 3 | 4 | NOTE: THIS IS CURRENTLY CRASHING! 5 | 6 | For use with an ESP8266 7 | * * 8 | Written by Brian Lough 9 | YouTube: https://www.youtube.com/brianlough 10 | Tindie: https://www.tindie.com/stores/brianlough/ 11 | Twitter: https://twitter.com/witnessmenow 12 | *******************************************************************/ 13 | 14 | // ---------------------------- 15 | // Standard Libraries - Already Installed if you have ESP32 set up 16 | // ---------------------------- 17 | 18 | #include 19 | #include 20 | 21 | // ---------------------------- 22 | // Additional Libraries - each one of these will need to be installed. 23 | // ---------------------------- 24 | 25 | 26 | #include 27 | // The library for controlling the LED Matrix 28 | // Can be installed from the library manager 29 | // https://github.com/2dom/PxMatrix 30 | 31 | // Adafruit GFX library is a dependancy for the PxMatrix Library 32 | // Can be installed from the library manager 33 | // https://github.com/adafruit/Adafruit-GFX-Library 34 | 35 | #include 36 | // This library :) 37 | // https://github.com/toblum/TetrisAnimation 38 | 39 | #include 40 | // Library used for getting the time and adjusting for DST 41 | // Search for "ezTime" in the Arduino Library manager 42 | // https://github.com/ropg/ezTime 43 | 44 | // ---- Stuff to configure ---- 45 | 46 | // Initialize Wifi connection to the router 47 | char ssid[] = "SSID"; // your network SSID (name) 48 | char password[] = "password"; // your network key 49 | 50 | // Set a timezone using the following list 51 | // https://en.wikipedia.org/wiki/List_of_tz_database_time_zones 52 | #define MYTIMEZONE "Europe/Dublin" 53 | 54 | // Sets whether the clock should be 12 hour format or not. 55 | bool twelveHourFormat = true; 56 | 57 | // If this is set to false, the number will only change if the value behind it changes 58 | // e.g. the digit representing the least significant minute will be replaced every minute, 59 | // but the most significant number will only be replaced every 10 minutes. 60 | // When true, all digits will be replaced every minute. 61 | bool forceRefresh = true; 62 | // ----------------------------- 63 | 64 | // ----- Wiring ------- 65 | #define P_LAT 16 66 | #define P_A 5 67 | #define P_B 4 68 | #define P_C 15 69 | #define P_OE 2 70 | #define P_D 12 71 | #define P_E 0 72 | // --------------------- 73 | 74 | Ticker display_ticker; 75 | Ticker timer_ticker; 76 | 77 | // PxMATRIX display(32,16,P_LAT, P_OE,P_A,P_B,P_C); 78 | // PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D); 79 | PxMATRIX display(64, 32, P_LAT, P_OE, P_A, P_B, P_C, P_D, P_E); 80 | 81 | TetrisMatrixDraw tetris(display); // Main clock 82 | TetrisMatrixDraw tetris2(display); // The "M" of AM/PM 83 | TetrisMatrixDraw tetris3(display); // The "P" or "A" of AM/PM 84 | 85 | Timezone myTZ; 86 | unsigned long oneSecondLoopDue = 0; 87 | 88 | bool showColon = true; 89 | bool finishedAnimating = false; 90 | bool displayIntro = true; 91 | bool animateFlag = false; 92 | 93 | String lastDisplayedTime = ""; 94 | String lastDisplayedAmPm = ""; 95 | 96 | // This method is needed for driving the display 97 | void display_updater() { 98 | display.display(70); 99 | } 100 | 101 | void setAnimateFlag() { 102 | animateFlag = true; 103 | } 104 | 105 | // This method is for controlling the tetris library draw calls 106 | void animationHandler() 107 | { 108 | // Not clearing the display and redrawing it when you 109 | // dont need to improves how the refresh rate appears 110 | if (!finishedAnimating) { 111 | display.clearDisplay(); 112 | if (displayIntro) { 113 | finishedAnimating = tetris.drawText(1, 21); 114 | } else { 115 | if (twelveHourFormat) { 116 | // Place holders for checking are any of the tetris objects 117 | // currently still animating. 118 | bool tetris1Done = false; 119 | bool tetris2Done = false; 120 | bool tetris3Done = false; 121 | 122 | tetris1Done = tetris.drawNumbers(-6, 26, showColon); 123 | tetris2Done = tetris2.drawText(56, 25); 124 | 125 | // Only draw the top letter once the bottom letter is finished. 126 | if (tetris2Done) { 127 | tetris3Done = tetris3.drawText(56, 15); 128 | } 129 | 130 | finishedAnimating = tetris1Done && tetris2Done && tetris3Done; 131 | 132 | } else { 133 | finishedAnimating = tetris.drawNumbers(2, 26, showColon); 134 | } 135 | } 136 | 137 | } 138 | } 139 | 140 | void drawIntro(int x = 0, int y = 0) 141 | { 142 | tetris.drawChar("W", x, y, tetris.tetrisCYAN); 143 | tetris.drawChar("r", x + 5, y, tetris.tetrisMAGENTA); 144 | tetris.drawChar("i", x + 11, y, tetris.tetrisYELLOW); 145 | tetris.drawChar("t", x + 17, y, tetris.tetrisGREEN); 146 | tetris.drawChar("t", x + 22, y, tetris.tetrisBLUE); 147 | tetris.drawChar("e", x + 27, y, tetris.tetrisRED); 148 | tetris.drawChar("n", x + 32, y, tetris.tetrisWHITE); 149 | tetris.drawChar(" ", x + 37, y, tetris.tetrisMAGENTA); 150 | tetris.drawChar("b", x + 42, y, tetris.tetrisYELLOW); 151 | tetris.drawChar("y", x + 47, y, tetris.tetrisGREEN); 152 | } 153 | 154 | void drawConnecting(int x = 0, int y = 0) 155 | { 156 | tetris.drawChar("C", x, y, tetris.tetrisCYAN); 157 | tetris.drawChar("o", x + 5, y, tetris.tetrisMAGENTA); 158 | tetris.drawChar("n", x + 11, y, tetris.tetrisYELLOW); 159 | tetris.drawChar("n", x + 17, y, tetris.tetrisGREEN); 160 | tetris.drawChar("e", x + 22, y, tetris.tetrisBLUE); 161 | tetris.drawChar("c", x + 27, y, tetris.tetrisRED); 162 | tetris.drawChar("t", x + 32, y, tetris.tetrisWHITE); 163 | tetris.drawChar("i", x + 37, y, tetris.tetrisMAGENTA); 164 | tetris.drawChar("n", x + 42, y, tetris.tetrisYELLOW); 165 | tetris.drawChar("g", x + 47, y, tetris.tetrisGREEN); 166 | } 167 | 168 | void setup() { 169 | Serial.begin(115200); 170 | 171 | // Attempt to connect to Wifi network: 172 | Serial.print("Connecting Wifi: "); 173 | Serial.println(ssid); 174 | 175 | // Set WiFi to station mode and disconnect from an AP if it was Previously 176 | // connected 177 | WiFi.mode(WIFI_STA); 178 | WiFi.begin(ssid, password); 179 | 180 | while (WiFi.status() != WL_CONNECTED) { 181 | Serial.print("."); 182 | delay(500); 183 | } 184 | 185 | Serial.println(""); 186 | Serial.println("WiFi connected"); 187 | Serial.print("IP address: "); 188 | Serial.println(WiFi.localIP()); 189 | 190 | // Do not set up display before WiFi connection 191 | // as it will crash! 192 | 193 | // Intialise display library 194 | display.begin(16); 195 | display.clearDisplay(); 196 | 197 | // Setup ticker for driving display 198 | display_ticker.attach(0.002, display_updater); 199 | yield(); 200 | display.clearDisplay(); 201 | 202 | // "connecting" 203 | drawConnecting(5, 10); 204 | 205 | // Setup EZ Time 206 | setDebug(INFO); 207 | waitForSync(); 208 | 209 | Serial.println(); 210 | Serial.println("UTC: " + UTC.dateTime()); 211 | 212 | myTZ.setLocation(F(MYTIMEZONE)); 213 | Serial.print(F("Time in your set timezone: ")); 214 | Serial.println(myTZ.dateTime()); 215 | 216 | display.clearDisplay(); 217 | //"Powered By" 218 | drawIntro(6, 12); 219 | delay(2000); 220 | 221 | // Start the Animation Timer 222 | tetris.setText("B. LOUGH"); 223 | timer_ticker.attach(0.1, animationHandler); 224 | 225 | // Wait for the animation to finish 226 | while (!finishedAnimating) 227 | { 228 | delay(10); //waiting for intro to finish 229 | } 230 | delay(2000); 231 | //timer_ticker.attach(0.1, setAnimateFlag); 232 | finishedAnimating = false; 233 | displayIntro = false; 234 | tetris.scale = 2; 235 | } 236 | 237 | void setMatrixTime() { 238 | String timeString = ""; 239 | String AmPmString = ""; 240 | if (twelveHourFormat) { 241 | // Get the time in format "1:15" or 11:15 (12 hour, no leading 0) 242 | // Check the EZTime Github page for info on 243 | // time formatting 244 | timeString = myTZ.dateTime("g:i"); 245 | 246 | //If the length is only 4, pad it with 247 | // a space at the beginning 248 | if (timeString.length() == 4) { 249 | timeString = " " + timeString; 250 | } 251 | 252 | //Get if its "AM" or "PM" 253 | AmPmString = myTZ.dateTime("A"); 254 | if (lastDisplayedAmPm != AmPmString) { 255 | Serial.println(AmPmString); 256 | lastDisplayedAmPm = AmPmString; 257 | // Second character is always "M" 258 | // so need to parse it out 259 | tetris2.setText("M", forceRefresh); 260 | 261 | // Parse out first letter of String 262 | tetris3.setText(AmPmString.substring(0, 1), forceRefresh); 263 | } 264 | } else { 265 | // Get time in format "01:15" or "22:15"(24 hour with leading 0) 266 | timeString = myTZ.dateTime("H:i"); 267 | } 268 | 269 | // Only update Time if its different 270 | if (lastDisplayedTime != timeString) { 271 | Serial.println(timeString); 272 | lastDisplayedTime = timeString; 273 | tetris.setTime(timeString, forceRefresh); 274 | 275 | // Must set this to false so animation knows 276 | // to start again 277 | finishedAnimating = false; 278 | } 279 | } 280 | 281 | 282 | void loop() { 283 | unsigned long now = millis(); 284 | // if(false && animateFlag){ 285 | // animateFlag = false; 286 | // animationHandler(); 287 | // } 288 | 289 | // animationHandler(); 290 | if (now > oneSecondLoopDue) { 291 | // We can call this often, but it will only 292 | // update when it needs to 293 | setMatrixTime(); 294 | showColon = !showColon; 295 | oneSecondLoopDue = now + 10000; 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /ESP32 or TinyPICO/EzTimeTetrisClockESP32/EzTimeTetrisClockESP32.ino: -------------------------------------------------------------------------------- 1 | /******************************************************************* 2 | Tetris clock that fetches its time Using the EzTimeLibrary 3 | 4 | For use with the ESP32 or TinyPICO 5 | * * 6 | Written by Brian Lough 7 | YouTube: https://www.youtube.com/brianlough 8 | Tindie: https://www.tindie.com/stores/brianlough/ 9 | Twitter: https://twitter.com/witnessmenow 10 | *******************************************************************/ 11 | 12 | // ---------------------------- 13 | // Standard Libraries - Already Installed if you have ESP32 set up 14 | // ---------------------------- 15 | 16 | #include 17 | 18 | // ---------------------------- 19 | // Additional Libraries - each one of these will need to be installed. 20 | // ---------------------------- 21 | 22 | // Enabling this is meant to have a performance 23 | // improvement but its worse for me. 24 | // https://github.com/2dom/PxMatrix/pull/103 25 | //#define double_buffer 26 | 27 | #include 28 | // The library for controlling the LED Matrix 29 | // At time of writing this my changes for the TinyPICO 30 | // Have been merged into the main PxMatrix library, 31 | // but have not been released, so you will need to install 32 | // from Github 33 | // 34 | // If you are using a regular ESP32 you may be able to use 35 | // the library manager version 36 | // https://github.com/2dom/PxMatrix 37 | 38 | // Adafruit GFX library is a dependancy for the PxMatrix Library 39 | // Can be installed from the library manager 40 | // https://github.com/adafruit/Adafruit-GFX-Library 41 | 42 | #include 43 | // This library draws out characters using a tetris block 44 | // amimation 45 | // Can be installed from the library manager 46 | // https://github.com/toblum/TetrisAnimation 47 | 48 | #include 49 | // Library used for getting the time and adjusting for DST 50 | // Search for "ezTime" in the Arduino Library manager 51 | // https://github.com/ropg/ezTime 52 | 53 | // ---- Stuff to configure ---- 54 | 55 | // Initialize Wifi connection to the router 56 | char ssid[] = "SSID"; // your network SSID (name) 57 | char password[] = "password"; // your network key 58 | 59 | // Set a timezone using the following list 60 | // https://en.wikipedia.org/wiki/List_of_tz_database_time_zones 61 | #define MYTIMEZONE "Europe/Dublin" 62 | 63 | // Sets whether the clock should be 12 hour format or not. 64 | bool twelveHourFormat = true; 65 | 66 | // If this is set to false, the number will only change if the value behind it changes 67 | // e.g. the digit representing the least significant minute will be replaced every minute, 68 | // but the most significant number will only be replaced every 10 minutes. 69 | // When true, all digits will be replaced every minute. 70 | bool forceRefresh = true; 71 | // ----------------------------- 72 | 73 | // ----- Wiring ------- 74 | #define P_LAT 22 75 | #define P_A 19 76 | #define P_B 23 77 | #define P_C 18 78 | #define P_D 5 79 | #define P_E 15 80 | #define P_OE 26 //TinyPICO 81 | //#define P_OE 21 //Huzzah32 82 | //#define P_OE 2 // Generic ESP32 83 | // --------------------- 84 | 85 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 86 | hw_timer_t * timer = NULL; 87 | hw_timer_t * animationTimer = NULL; 88 | 89 | // PxMATRIX display(32,16,P_LAT, P_OE,P_A,P_B,P_C); 90 | // PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D); 91 | PxMATRIX display(64, 32, P_LAT, P_OE, P_A, P_B, P_C, P_D, P_E); 92 | 93 | TetrisMatrixDraw tetris(display); // Main clock 94 | TetrisMatrixDraw tetris2(display); // The "M" of AM/PM 95 | TetrisMatrixDraw tetris3(display); // The "P" or "A" of AM/PM 96 | 97 | Timezone myTZ; 98 | unsigned long oneSecondLoopDue = 0; 99 | 100 | bool showColon = true; 101 | volatile bool finishedAnimating = false; 102 | bool displayIntro = true; 103 | 104 | String lastDisplayedTime = ""; 105 | String lastDisplayedAmPm = ""; 106 | 107 | // This method is needed for driving the display 108 | void IRAM_ATTR display_updater() { 109 | portENTER_CRITICAL_ISR(&timerMux); 110 | display.display(10); 111 | portEXIT_CRITICAL_ISR(&timerMux); 112 | } 113 | 114 | // This method is for controlling the tetris library draw calls 115 | void animationHandler() 116 | { 117 | #ifndef double_buffer 118 | portENTER_CRITICAL_ISR(&timerMux); 119 | #endif 120 | 121 | // Not clearing the display and redrawing it when you 122 | // dont need to improves how the refresh rate appears 123 | if (!finishedAnimating) { 124 | #ifdef double_buffer 125 | display.fillScreen(tetris.tetrisBLACK); 126 | #else 127 | display.clearDisplay(); 128 | #endif 129 | //display.fillScreen(tetris.tetrisBLACK); 130 | if (displayIntro) { 131 | finishedAnimating = tetris.drawText(1, 21); 132 | } else { 133 | if (twelveHourFormat) { 134 | // Place holders for checking are any of the tetris objects 135 | // currently still animating. 136 | bool tetris1Done = false; 137 | bool tetris2Done = false; 138 | bool tetris3Done = false; 139 | 140 | tetris1Done = tetris.drawNumbers(-6, 26, showColon); 141 | tetris2Done = tetris2.drawText(56, 25); 142 | 143 | // Only draw the top letter once the bottom letter is finished. 144 | if (tetris2Done) { 145 | tetris3Done = tetris3.drawText(56, 15); 146 | } 147 | 148 | finishedAnimating = tetris1Done && tetris2Done && tetris3Done; 149 | 150 | } else { 151 | finishedAnimating = tetris.drawNumbers(2, 26, showColon); 152 | } 153 | } 154 | #ifdef double_buffer 155 | display.showBuffer(); 156 | #endif 157 | } 158 | #ifndef double_buffer 159 | portEXIT_CRITICAL_ISR(&timerMux); 160 | #endif 161 | } 162 | 163 | void drawIntro(int x = 0, int y = 0) 164 | { 165 | tetris.drawChar("P", x, y, tetris.tetrisCYAN); 166 | tetris.drawChar("o", x + 5, y, tetris.tetrisMAGENTA); 167 | tetris.drawChar("w", x + 11, y, tetris.tetrisYELLOW); 168 | tetris.drawChar("e", x + 17, y, tetris.tetrisGREEN); 169 | tetris.drawChar("r", x + 22, y, tetris.tetrisBLUE); 170 | tetris.drawChar("e", x + 27, y, tetris.tetrisRED); 171 | tetris.drawChar("d", x + 32, y, tetris.tetrisWHITE); 172 | tetris.drawChar(" ", x + 37, y, tetris.tetrisMAGENTA); 173 | tetris.drawChar("b", x + 42, y, tetris.tetrisYELLOW); 174 | tetris.drawChar("y", x + 47, y, tetris.tetrisGREEN); 175 | } 176 | 177 | void drawConnecting(int x = 0, int y = 0) 178 | { 179 | tetris.drawChar("C", x, y, tetris.tetrisCYAN); 180 | tetris.drawChar("o", x + 5, y, tetris.tetrisMAGENTA); 181 | tetris.drawChar("n", x + 11, y, tetris.tetrisYELLOW); 182 | tetris.drawChar("n", x + 17, y, tetris.tetrisGREEN); 183 | tetris.drawChar("e", x + 22, y, tetris.tetrisBLUE); 184 | tetris.drawChar("c", x + 27, y, tetris.tetrisRED); 185 | tetris.drawChar("t", x + 32, y, tetris.tetrisWHITE); 186 | tetris.drawChar("i", x + 37, y, tetris.tetrisMAGENTA); 187 | tetris.drawChar("n", x + 42, y, tetris.tetrisYELLOW); 188 | tetris.drawChar("g", x + 47, y, tetris.tetrisGREEN); 189 | } 190 | 191 | void setup() { 192 | Serial.begin(115200); 193 | 194 | // Attempt to connect to Wifi network: 195 | Serial.print("Connecting Wifi: "); 196 | Serial.println(ssid); 197 | 198 | // Set WiFi to station mode and disconnect from an AP if it was Previously 199 | // connected 200 | WiFi.mode(WIFI_STA); 201 | WiFi.begin(ssid, password); 202 | 203 | while (WiFi.status() != WL_CONNECTED) { 204 | Serial.print("."); 205 | delay(500); 206 | } 207 | 208 | Serial.println(""); 209 | Serial.println("WiFi connected"); 210 | Serial.print("IP address: "); 211 | Serial.println(WiFi.localIP()); 212 | 213 | // Do not set up display before WiFi connection 214 | // as it will crash! 215 | 216 | // Intialise display library 217 | display.begin(16, SPI_BUS_CLK, 27, SPI_BUS_MISO, SPI_BUS_SS); // TinyPICO 218 | //display.begin(16); // Generic ESP32 including Huzzah 219 | display.flushDisplay(); 220 | 221 | // Setup timer for driving display 222 | timer = timerBegin(0, 80, true); 223 | timerAttachInterrupt(timer, &display_updater, true); 224 | timerAlarmWrite(timer, 2000, true); 225 | timerAlarmEnable(timer); 226 | yield(); 227 | #ifdef double_buffer 228 | display.fillScreen(tetris.tetrisBLACK); 229 | #else 230 | display.clearDisplay(); 231 | #endif 232 | 233 | // "connecting" 234 | drawConnecting(5, 10); 235 | #ifdef double_buffer 236 | display.showBuffer(); 237 | #endif 238 | 239 | // Setup EZ Time 240 | setDebug(INFO); 241 | waitForSync(); 242 | 243 | Serial.println(); 244 | Serial.println("UTC: " + UTC.dateTime()); 245 | 246 | myTZ.setLocation(F(MYTIMEZONE)); 247 | Serial.print(F("Time in your set timezone: ")); 248 | Serial.println(myTZ.dateTime()); 249 | 250 | #ifdef double_buffer 251 | display.fillScreen(tetris.tetrisBLACK); 252 | #else 253 | display.clearDisplay(); 254 | #endif 255 | // "Powered By" 256 | drawIntro(6, 12); 257 | #ifdef double_buffer 258 | display.showBuffer(); 259 | #endif 260 | delay(2000); 261 | 262 | // Start the Animation Timer 263 | tetris.setText("TINY PICO"); 264 | animationTimer = timerBegin(1, 80, true); 265 | timerAttachInterrupt(animationTimer, &animationHandler, true); 266 | timerAlarmWrite(animationTimer, 100000, true); 267 | timerAlarmEnable(animationTimer); 268 | 269 | // Wait for the animation to finish 270 | while (!finishedAnimating) 271 | { 272 | delay(10); //waiting for intro to finish 273 | } 274 | delay(2000); 275 | finishedAnimating = false; 276 | displayIntro = false; 277 | tetris.scale = 2; 278 | } 279 | 280 | void setMatrixTime() { 281 | String timeString = ""; 282 | String AmPmString = ""; 283 | if (twelveHourFormat) { 284 | // Get the time in format "1:15" or 11:15 (12 hour, no leading 0) 285 | // Check the EZTime Github page for info on 286 | // time formatting 287 | timeString = myTZ.dateTime("g:i"); 288 | 289 | //If the length is only 4, pad it with 290 | // a space at the beginning 291 | if (timeString.length() == 4) { 292 | timeString = " " + timeString; 293 | } 294 | 295 | //Get if its "AM" or "PM" 296 | AmPmString = myTZ.dateTime("A"); 297 | if (lastDisplayedAmPm != AmPmString) { 298 | Serial.println(AmPmString); 299 | lastDisplayedAmPm = AmPmString; 300 | // Second character is always "M" 301 | // so need to parse it out 302 | tetris2.setText("M", forceRefresh); 303 | 304 | // Parse out first letter of String 305 | tetris3.setText(AmPmString.substring(0, 1), forceRefresh); 306 | } 307 | } else { 308 | // Get time in format "01:15" or "22:15"(24 hour with leading 0) 309 | timeString = myTZ.dateTime("H:i"); 310 | } 311 | 312 | // Only update Time if its different 313 | if (lastDisplayedTime != timeString) { 314 | Serial.println(timeString); 315 | lastDisplayedTime = timeString; 316 | tetris.setTime(timeString, forceRefresh); 317 | 318 | // Must set this to false so animation knows 319 | // to start again 320 | finishedAnimating = false; 321 | } 322 | } 323 | 324 | void handleColonAfterAnimation() { 325 | 326 | // It will draw the colon every time, but when the colour is black it 327 | // should look like its clearing it. 328 | uint16_t colour = showColon ? tetris.tetrisWHITE : tetris.tetrisBLACK; 329 | // The x position that you draw the tetris animation object 330 | int x = twelveHourFormat ? -6 : 2; 331 | // The y position adjusted for where the blocks will fall from 332 | // (this could be better!) 333 | int y = 26 - (TETRIS_Y_DROP_DEFAULT * tetris.scale); 334 | tetris.drawColon(x, y, colour); 335 | } 336 | 337 | 338 | void loop() { 339 | unsigned long now = millis(); 340 | if (now > oneSecondLoopDue) { 341 | // We can call this often, but it will only 342 | // update when it needs to 343 | setMatrixTime(); 344 | showColon = !showColon; 345 | 346 | // To reduce flicker on the screen we stop clearing the screen 347 | // when the animation is finished, but we still need the colon to 348 | // to blink 349 | if (finishedAnimating) { 350 | handleColonAfterAnimation(); 351 | } 352 | oneSecondLoopDue = now + 1000; 353 | } 354 | } 355 | --------------------------------------------------------------------------------