#define MMdebug
/* ported by M.M. */
/* Source: https://github.com/toblum/esp_p10_tetris_clock/blob/master/src/tetris_clock.ino */
/*
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#elif defined(ESP32)
#include <WiFi.h>
#include <WebServer.h>
#endif
*/
/* Source: https://github.com/witnessmenow/WiFi-Tetris-Clock/blob/master/ESP32%20or%20TinyPICO/EzTimeTetrisClockESP32/EzTimeTetrisClockESP32.ino */
/*******************************************************************
Tetris clock that fetches its time Using the EzTimeLibrary
For use with the ESP32 or TinyPICO
MM: Display: 128*64 SSD_1306
* *
Written by Brian Lough
YouTube: https://www.youtube.com/brianlough
Tindie: https://www.tindie.com/stores/brianlough/
Twitter: https://twitter.com/witnessmenow
*******************************************************************/
#if defined(ESP8266)
// Pin definitions (ESP-01 / ESP8266):
const uint8_t SDA_PIN = 0; // I2C SDA connected to GPIO0
const uint8_t SCL_PIN = 2; // I2C SCL connected to GPIO2
const uint8_t BUTTON_PIN = 3; // Button on GPIO3 (RX pin)
#elif defined(ESP32)
// MM:
// Pin definitions (ESP32):
const uint8_t SDA_PIN = 21; // I2C SDA connected to GPIO0
const uint8_t SCL_PIN = 22; // I2C SCL connected to GPIO2
const uint8_t BUTTON_PIN = 16; // Button on GPIO3 (RX pin)
#endif
// ----------------------------
// Standard Libraries - Already Installed if you have ESP32 set up
// ----------------------------
#include <WiFi.h>
#include <Ticker.h>
// MM:
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <TetrisMatrixDraw.h>
// This library draws out characters using a tetris block amimation
// Can be installed from the library manager
// https://github.com/toblum/TetrisAnimation
#include <ezTime.h>
// Library used for getting the time and adjusting for DST
// Search for "ezTime" in the Arduino Library manager
// https://github.com/ropg/ezTime
// ---- Stuff to configure ----
// Initialize Wifi connection to the router
//char ssid[] = "SSID"; // your network SSID (name)
//char password[] = "password"; // your network key
//MM:
char ssid[] = "Wokwi-GUEST"; // your network SSID (name)
char password[] = ""; // your network key
// Set a timezone using the following list
// https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
#define MYTIMEZONE "Europe/Berlin"
// Sets whether the clock should be 12 hour format or not.
bool twelveHourFormat = false;
//MM: bool twelveHourFormat = true;
// If this is set to false, the number will only change if the value behind it changes
// e.g. the digit representing the least significant minute will be replaced every minute,
// but the most significant number will only be replaced every 10 minutes.
// When true, all digits will be replaced every minute.
//MM: bool forceRefresh = false;
bool forceRefresh = true;
// -----------------------------
Ticker animationTicker;
// animationTicker.attach(0.05, animationHandler);
// Display:
Adafruit_SSD1306 display(128, 64, &Wire, -1);
bool displayInitialized = false;
TetrisMatrixDraw tetris(display); // Main clock
TetrisMatrixDraw tetris2(display); // The "M" of AM/PM
TetrisMatrixDraw tetris3(display); // The "P" or "A" of AM/PM
Timezone myTZ;
unsigned long oneSecondLoopDue = 0;
bool showColon = true;
volatile bool finishedAnimating = false;
bool displayIntro = true;
String lastDisplayedTime = "";
String lastDisplayedAmPm = "";
// This method is for controlling the tetris library draw calls
void animationHandler()
{
// Serial.println("enter animationHandler()");
// Not clearing the display and redrawing it when you
// dont need to improves how the refresh rate appears
if (!finishedAnimating) {
display.clearDisplay();
if (displayIntro) {
// Serial.println("drawText() call");
// MM: showed that lengthy text longer than 9? chars leads to strange behaviour
// finishedAnimating = tetris.drawText(1, 21);
finishedAnimating = tetris.drawText(1, 42);
// Serial.println("drawText() return");
} else {
if (twelveHourFormat) {
// Place holders for checking are any of the tetris objects
// currently still animating.
bool tetris1Done = false;
bool tetris2Done = false;
bool tetris3Done = false;
// tetris1Done = tetris.drawNumbers(-6, 26, showColon);
// tetris2Done = tetris2.drawText(56, 25);
tetris1Done = tetris.drawNumbers(-10, 54, showColon);
tetris2Done = tetris2.drawText(112, 54);
// Only draw the top letter once the bottom letter is finished.
if (tetris2Done) {
// tetris3Done = tetris3.drawText(56, 15);
tetris3Done = tetris3.drawText(112, 30);
}
finishedAnimating = tetris1Done && tetris2Done && tetris3Done;
} else {
// draw 24h format time
// finishedAnimating = tetris.drawNumbers(2, 26, showColon);
// scale 3: finishedAnimating = tetris.drawNumbers(16, 50, showColon);
finishedAnimating = tetris.drawNumbers(2, 54, showColon);
}
}
}
display.display(); // MM: actually draw?
// Serial.println("leave animationHandler()");
}
void handleColonAfterAnimation() {
// It will draw the colon every time, but when the colour is black it
// should look like its clearing it.
// MM: uint16_t colour = showColon ? tetris.tetrisWHITE : tetris.tetrisBLACK;
uint16_t colour = showColon ? SSD1306_WHITE : SSD1306_BLACK;
// The x position that you draw the tetris animation object
// int x = twelveHourFormat ? -6 : 2;
int x = twelveHourFormat ? -10 : 2;
// The y position adjusted for where the blocks will fall from
// (this could be better!)
// int y = 26 - (TETRIS_Y_DROP_DEFAULT * tetris.scale);
int y = 54 - (TETRIS_Y_DROP_DEFAULT * tetris.scale);
tetris.drawColon(x, y, colour);
display.display(); // MM: draw..
}
void drawIntro(int x = 0, int y = 0)
{
Serial.println("drawIntr2o begin");
display.clearDisplay();
tetris.drawChar("P", x, y, SSD1306_WHITE);
tetris.drawChar("o", x + 5, y, SSD1306_WHITE);
tetris.drawChar("w", x + 11, y, SSD1306_WHITE);
tetris.drawChar("e", x + 17, y, SSD1306_WHITE);
tetris.drawChar("r", x + 22, y, SSD1306_WHITE);
tetris.drawChar("e", x + 27, y, SSD1306_WHITE);
tetris.drawChar("d", x + 32, y, SSD1306_WHITE);
tetris.drawChar(" ", x + 37, y, SSD1306_WHITE);
tetris.drawChar("b", x + 42, y, SSD1306_WHITE);
tetris.drawChar("y", x + 47, y, SSD1306_WHITE);
display.display(); // MM: actually draw?
delay (2000);
Serial.println("drawIntro end");
}
void drawConnecting(int x = 0, int y = 0)
{
Serial.println("drawConnecting begin");
display.clearDisplay();
tetris.drawChar("C", x, y, SSD1306_WHITE);
tetris.drawChar("o", x + 5, y, SSD1306_WHITE);
tetris.drawChar("n", x + 11, y, SSD1306_WHITE);
tetris.drawChar("n", x + 17, y, SSD1306_WHITE);
tetris.drawChar("e", x + 22, y, SSD1306_WHITE);
tetris.drawChar("c", x + 27, y, SSD1306_WHITE);
tetris.drawChar("t", x + 32, y, SSD1306_WHITE);
tetris.drawChar("i", x + 37, y, SSD1306_WHITE);
tetris.drawChar("n", x + 42, y, SSD1306_WHITE);
tetris.drawChar("g", x + 47, y, SSD1306_WHITE);
display.display(); // MM: actually draw?
delay (2000);
Serial.println("drawConnecting end");
}
void setup() {
Serial.begin(115200);
//////////////////////////
// MM:
Serial.println();
Serial.println(F("Booting..."));
pinMode(BUTTON_PIN, INPUT_PULLUP);
/////////////////////////////////////
// Attempt to connect to Wifi network:
Serial.print("Connecting Wifi: ");
Serial.println(ssid);
// Set WiFi to station mode and disconnect from an AP if it was Previously
// connected
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Do not set up display before WiFi connection
// as it will crash!
// MM: Initialize display
Wire.begin(SDA_PIN, SCL_PIN);
if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
displayInitialized = true;
display.setRotation(2);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.print("Booting...");
display.display(); // MM: actually draw?
} else {
Serial.println(F("SSD1306 allocation failed"));
// Leave displayInitialized as false
}
// MM: very important fix!! the hardcoded colors of the TetrisAnimation library do NOT work with Monochrome OLED SSD1306
for (int i = 0; i < 9; i++) {
tetris.tetrisColors[i] = SSD1306_WHITE;
tetris2.tetrisColors[i] = SSD1306_WHITE;
tetris3.tetrisColors[i] = SSD1306_WHITE;
}
// display.clearDisplay();
tetris.scale = 2;
tetris2.scale = 2; tetris3.scale = 2;
// "connecting"
drawConnecting(5, 10);
/////////////////////////////////
// Setup EZ Time
setInterval(60);
setDebug(INFO); // MM: interferes with Ticker?
waitForSync();
Serial.println();
Serial.println("UTC: " + UTC.dateTime());
myTZ.setLocation(F(MYTIMEZONE));
Serial.print(F("Time in your set timezone: "));
Serial.println(myTZ.dateTime());
// "Powered By"
drawIntro(6, 12);
//delay(2000); // MM: original delay
finishedAnimating = false;
Serial.println("TetrisMatrixDraw::setText()");
tetris.setText("TETRISCLK"); // MM: hangs on TETRISCLOCK.. so length of text seems to matter in library call..
//tetris.setText("!#$%&'()");
Serial.println("TETRISCLK");
// Start the Animation Timer
//animationTicker.attach(0.05, animationHandler);
animationTicker.attach_ms(50, animationHandler);
delay(6000);
// Wait for the animation to finish
while (!finishedAnimating)
{
delay(10); // waiting for intro to finish
}
delay(2000);
finishedAnimating = false;
displayIntro = false;
tetris.scale = 4;
}
void setMatrixTime() {
String timeString = "";
String AmPmString = "";
if (twelveHourFormat) {
// Get the time in format "1:15" or 11:15 (12 hour, no leading 0)
// Check the EZTime Github page for info on time formatting
timeString = myTZ.dateTime("g:i");
//If the length is only 4, pad it with a space at the beginning
if (timeString.length() == 4) {
timeString = " " + timeString;
}
//Get if its "AM" or "PM"
AmPmString = myTZ.dateTime("A");
if (lastDisplayedAmPm != AmPmString) {
Serial.println(AmPmString);
lastDisplayedAmPm = AmPmString;
// Second character is always "M"
// so need to parse it out
tetris2.setText("M", forceRefresh);
// Parse out first letter of String
tetris3.setText(AmPmString.substring(0, 1), forceRefresh);
}
} else {
// Get time in format "01:15" or "22:15"(24 hour with leading 0)
timeString = myTZ.dateTime("H:i");
//MM: test: timeString = myTZ.dateTime("23:i");
}
// Only update Time if its different
if (lastDisplayedTime != timeString) {
Serial.print("setMatrixTime(): timeString: ");
Serial.println(timeString);
lastDisplayedTime = timeString;
tetris.setTime(timeString, forceRefresh);
// Must set this to false so animation knows
// to start again
finishedAnimating = false;
}
}
void loop() {
unsigned long now = millis();
// Serial.println("looping loop();");
if (now > oneSecondLoopDue) {
// We can call this often, but it will only
// update when it needs to
setMatrixTime();
showColon = !showColon;
// To reduce flicker on the screen we stop clearing the screen
// when the animation is finished, but we still need the colon to
// to blink
if (finishedAnimating) {
handleColonAfterAnimation();
}
oneSecondLoopDue = now + 1000;
}
}Push during startup
for setup mode
(skipped in emulator)