Skip to content

Instantly share code, notes, and snippets.

@billerby
Last active January 25, 2020 13:19
Show Gist options
  • Save billerby/f690ddc74e14e6ca049073eb56bb4d2e to your computer and use it in GitHub Desktop.
Save billerby/f690ddc74e14e6ca049073eb56bb4d2e to your computer and use it in GitHub Desktop.
Aternate between showing a tetris animated clock: (https://github.com/witnessmenow/WiFi-Tetris-Clock) and DHT21 sensor values for humidity and temperature
/*******************************************************************
Tetris clock that fetches its time Using the EzTimeLibrary
For use with the ESP32 or TinyPICO
* *
Written by Brian Lough
YouTube: https://www.youtube.com/brianlough
Tindie: https://www.tindie.com/stores/brianlough/
Twitter: https://twitter.com/witnessmenow
*******************************************************************/
// ----------------------------
// Standard Libraries - Already Installed if you have ESP32 set up
// ----------------------------
#include <WiFi.h>
// ----------------------------
// Additional Libraries - each one of these will need to be installed.
// ----------------------------
// Enabling this is meant to have a performance
// improvement but its worse for me.
// https://github.com/2dom/PxMatrix/pull/103
//#define double_buffer
#include <PxMatrix.h>
// The library for controlling the LED Matrix
// At time of writing this my changes for the TinyPICO
// Have been merged into the main PxMatrix library,
// but have not been released, so you will need to install
// from Github
//
// If you are using a regular ESP32 you may be able to use
// the library manager version
// https://github.com/2dom/PxMatrix
// Adafruit GFX library is a dependancy for the PxMatrix Library
// Can be installed from the library manager
// https://github.com/adafruit/Adafruit-GFX-Library
#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
// DHT sensor library temperature and humidity
#include "DHT.h"
#define DHTPIN 2 // modify to the pin we connected
#define DHTTYPE DHT21 // AM2301
DHT dht(DHTPIN, DHTTYPE);
#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[] = "Alter_3G"; // your network SSID (name)
char password[] = "hemligt"; // your network key
// Set a timezone using the following list
// https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
#define MYTIMEZONE "Europe/Stockholm"
// Sets whether the clock should be 12 hour format or not.
bool twelveHourFormat = false;
// 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.
bool forceRefresh = true;
// -----------------------------
// ----- Wiring -------
#define P_LAT 22
#define P_A 19
#define P_B 23
#define P_C 18
#define P_D 5
#define P_E 15
#define P_OE 26 //TinyPICO
//#define P_OE 21 //Huzzah32
//#define P_OE 2 // Generic ESP32
// ---------------------
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
hw_timer_t * timer = NULL;
hw_timer_t * animationTimer = NULL;
// PxMATRIX display(32,16,P_LAT, P_OE,P_A,P_B,P_C);
// PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D);
PxMATRIX display(64, 32, P_LAT, P_OE, P_A, P_B, P_C, P_D, P_E);
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 needed for driving the display
void IRAM_ATTR display_updater() {
portENTER_CRITICAL_ISR(&timerMux);
display.display(10);
portEXIT_CRITICAL_ISR(&timerMux);
}
// This method is for controlling the tetris library draw calls
void animationHandler()
{
#ifndef double_buffer
portENTER_CRITICAL_ISR(&timerMux);
#endif
// Not clearing the display and redrawing it when you
// dont need to improves how the refresh rate appears
if (!finishedAnimating) {
#ifdef double_buffer
display.fillScreen(tetris.tetrisBLACK);
#else
display.clearDisplay();
#endif
//display.fillScreen(tetris.tetrisBLACK);
if (displayIntro) {
finishedAnimating = tetris.drawText(1, 21);
} 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);
// Only draw the top letter once the bottom letter is finished.
if (tetris2Done) {
tetris3Done = tetris3.drawText(56, 15);
}
finishedAnimating = tetris1Done && tetris2Done && tetris3Done;
} else {
finishedAnimating = tetris.drawNumbers(2, 26, showColon);
}
}
#ifdef double_buffer
display.showBuffer();
#endif
}
#ifndef double_buffer
portEXIT_CRITICAL_ISR(&timerMux);
#endif
}
void drawIntro(int x = 0, int y = 0)
{
tetris.drawChar("P", x, y, tetris.tetrisCYAN);
tetris.drawChar("o", x + 5, y, tetris.tetrisMAGENTA);
tetris.drawChar("w", x + 11, y, tetris.tetrisYELLOW);
tetris.drawChar("e", x + 17, y, tetris.tetrisGREEN);
tetris.drawChar("r", x + 22, y, tetris.tetrisBLUE);
tetris.drawChar("e", x + 27, y, tetris.tetrisRED);
tetris.drawChar("d", x + 32, y, tetris.tetrisWHITE);
tetris.drawChar(" ", x + 37, y, tetris.tetrisMAGENTA);
tetris.drawChar("b", x + 42, y, tetris.tetrisYELLOW);
tetris.drawChar("y", x + 47, y, tetris.tetrisGREEN);
}
void drawConnecting(int x = 0, int y = 0)
{
tetris.drawChar("C", x, y, tetris.tetrisCYAN);
tetris.drawChar("o", x + 5, y, tetris.tetrisMAGENTA);
tetris.drawChar("n", x + 11, y, tetris.tetrisYELLOW);
tetris.drawChar("n", x + 17, y, tetris.tetrisGREEN);
tetris.drawChar("e", x + 22, y, tetris.tetrisBLUE);
tetris.drawChar("c", x + 27, y, tetris.tetrisRED);
tetris.drawChar("t", x + 32, y, tetris.tetrisWHITE);
tetris.drawChar("i", x + 37, y, tetris.tetrisMAGENTA);
tetris.drawChar("n", x + 42, y, tetris.tetrisYELLOW);
tetris.drawChar("g", x + 47, y, tetris.tetrisGREEN);
}
void setup() {
Serial.begin(115200);
// 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!
// Intialise display library
display.begin(16, SPI_BUS_CLK, 27, SPI_BUS_MISO, SPI_BUS_SS); // TinyPICO
//display.begin(16); // Generic ESP32 including Huzzah
display.flushDisplay();
// (Erik) Initialize DHT library
dht.begin();
// Setup timer for driving display
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &display_updater, true);
timerAlarmWrite(timer, 2000, true);
timerAlarmEnable(timer);
yield();
#ifdef double_buffer
display.fillScreen(tetris.tetrisBLACK);
#else
display.clearDisplay();
#endif
// "connecting"
drawConnecting(5, 10);
#ifdef double_buffer
display.showBuffer();
#endif
// Setup EZ Time
setDebug(INFO);
waitForSync();
Serial.println();
Serial.println("UTC: " + UTC.dateTime());
myTZ.setLocation(F(MYTIMEZONE));
Serial.print(F("Time in your set timezone: "));
Serial.println(myTZ.dateTime());
#ifdef double_buffer
display.fillScreen(tetris.tetrisBLACK);
#else
display.clearDisplay();
#endif
// "Powered By"
drawIntro(6, 12);
#ifdef double_buffer
display.showBuffer();
#endif
delay(2000);
// Start the Animation Timer
tetris.setText("TINY PICO");
animationTimer = timerBegin(1, 80, true);
timerAttachInterrupt(animationTimer, &animationHandler, true);
timerAlarmWrite(animationTimer, 100000, true);
timerAlarmEnable(animationTimer);
// Wait for the animation to finish
while (!finishedAnimating)
{
delay(10); //waiting for intro to finish
}
delay(2000);
finishedAnimating = false;
displayIntro = false;
tetris.scale = 2;
}
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");
}
// Only update Time if its different
if (lastDisplayedTime != timeString) {
Serial.println(timeString);
lastDisplayedTime = timeString;
tetris.setTime(timeString, forceRefresh);
// Must set this to false so animation knows
// to start again
finishedAnimating = false;
}
}
void handleColonAfterAnimation() {
// It will draw the colon every time, but when the colour is black it
// should look like its clearing it.
uint16_t colour = showColon ? tetris.tetrisWHITE : tetris.tetrisBLACK;
// The x position that you draw the tetris animation object
int x = twelveHourFormat ? -6 : 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);
tetris.drawColon(x, y, colour);
}
void loop() {
unsigned long now = millis();
int i = 0;
if (now > oneSecondLoopDue) {
// Every other second we will alternate between temperature an time
if (i % 2 == 0){
// Fetch and display humidity and temperature
float h = dht.readHumidity();
float t = dht.readTemperature();
// check if returns are valid, if they are NaN (not a number) then something went wrong!
if (isnan(t) || isnan(h)){
Serial.println("Failed to read from DHT");
}
else{
Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperature: ");
Serial.print(t);
Serial.println(" *C");
}
}else{
// 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;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment