This is a very simple yet large Dot-Matrix Clock-Calendar running MD_Parola library. Many friends seen this clock in my garage and in my Instagram stories: they liked a lot so they convinced me to publish the project here even if a Dot Matrix Clock is nothing new for most of us.
I've (very slightly) redesigned the standard font and designed a simple enclosure. I wrote some info here too for making the library used in this project more understandable since probably is not the simplest one for driving led matrixes: it has a lot of features and effects (it manage sprites too!).
So, even if this clock is something you already seen a lot of times, probably you'll read something new and you'll have some more clues.
UPDATE 24/07/2022Overview
New code on Github repository has new features:
- Automatic DST time change (this is valid for Italy, where DST starts from last Sunday of March to last sunday of October, dunno if this valid for other countries)
- Humidity and Temperature can be sent, optionally, to an MQTT Server
Additionally, user @MrLoba81 modified the STL enclosure for fitting some slightly larger displays having a gap between matrixes. I added those STL to downloads. Please check the Top Frame first than print the main body enclosure.
This clock is based on a NodeMCU (ESP8266) so WiFi is used for setting the right time from a NTP server without user intervention. I've used a NodeMCU Lolin having dimension of about 31x58mm: this exact model (it has the CH340 as UART/USB adapter) is only needed if you want to 3D-print the enclosure I designed and provided here, otherwise you can use whatever you have in your drawers having an ESP8266 on it. The NTP solution is very simple and gives the more accurate results (but obviously you need the WiFi, this can be the only drawback maybe). Time is kept using the TimeLib library by Paul Stoffregen: this library gives also an easy access to time variables making the whole program easier to manage and update. A DHT22 sensor is used for showing temperature and relative humidity too. I perfectly know this sensor is not the most accurate one and will have a drift during the years but is one of the most used, cheap and available.
Data are showed on n°8 8x8 led matrix displays: first 4 displays are static (meaning that are not used scrolling effects here) and shows the actual time (hours:minutes with the time separator flashing). A second block of 4 displays shows day of week, date, temperature and relative humidity by scrolling them from right to left.
This clock program is derived from default example of library used for driving displays: MD_Parola (Parola_Zone_TimeMsg). This was the final result:
I must admit that result is very eye-cathing and professional even if the whole thing is very simple and comes out from a default library example!
Prepare the IDEWe'll use Arduino IDE and I assume you've already installed the ESP8266 extension. You need to install following libraries:
- EasyNTPClient (by Harsha Alva)
- TimeLib (by Paul Stoffregen)
- MD_Parola (by Majic Designs)
- MD_MAX72xx (by Majic Designs)
- Adafruit Unified Sensor Driver (by Adafruit)
- Adafruit DHT library (by Adafruit)
First thing to do is connect the two dot-matrix boards together. Every board has a 5 pin male header on the right and 5 free pads on the left. Take one board and desolder the connector on the right (you can leave it too), then put near two boards and connect them together (DOUT to DIN) using a piece of solid wire and soldering iron for having a larger display:
If you want to use my own enclosure, you must remove also the last pin strip on the display most right since is right-angled and will not fit in the enclosure: you'll mount a straight pinstrip soldering it from top of the board or (better) you'll solder 5 wires as I done:
There are a few things to edit. Here put your SSID (aka WiFi Name) and your SSID password:
// your wifi settings
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
This following part is used for NTP settings, since I'm in Italy, I've used an Italian server and my time offset from UTC is 1 hour (1 hour=3600 seconds), so adjust those 2 values for fitting your needs:
// NTP server
const char* ntpserver = "time.inrim.it";
uint16_t timeoffset=3600; // time offset in seconds
This gist contains a list of world's public NTP servers.
If you need to use a Static IP address for your board, uncomment the following row:
// uncomment if you want to use static IPs
//#define USE_STATIC
and then change those IP addresses:
IPAddress ip(192,168,1,35); // ip address you want to assign to your board
IPAddress gateway(192,168,1,1); // router address
IPAddress subnet(255,255,255,0); // subnet mask
IPAddress dns1(1,1,1,1); // DNS is required for EasyNTP client using a static IP
IPAddress dns2(1,0,0,1);
In this case DNSs are required since EasyNTP will not work properly with static address and no DNS specified (issue #58). You can leave those same DNS I put in the code: are Cloudflare ones.
This following array contains first 3 letters of months name in my language, so you can edit this too for writing them in your own language:
static const char str[][4] PROGMEM = {"Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"};
Same here for day of week names:
static const char str[][10] PROGMEM = {"Domenica", "Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato"};
Some words about the codeMD Parola is a great library for Matrix displays. I like it a lot. In this example display is divided in two indipendent zones. This magic is done here:
P.begin(2); // matrix init as 2 different zones
where P object is instanced here:
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
As you can see this object instance, MD_Parola, requires 3 parameters:
- HARDWARE_TYPE : type of dot matrix board used. For my example I used standard dot matrix board you can find on Amazon or other shops, so my value is MD_MAX72XX::FC16_HW. Other kind of displays can use one of following values: GENERIC_HW, PAROLA_HW, ICSTATION_HW. You can read more about this setting here.
- CS_PIN : microcontroller pin where you attached the Dot-Matrix board CS (Circuit Select) pin, I attached it to D8.
- MAX_DEVICES : is the number of MAX7219s connected (not the MAXimum devices but MAXim/MAX...7219 devices XD). Every board is made up of four 8x8 dot-matrix displays and every single display has his own MAX7219 (usually displays are detachable and you can see the driver IC under, probably you'll not have a genuine MAXim IC but a compatible so you'll read an xx7219 marking). So in this case MAX_DEVICES will be 8.
The two zones will be associated to their own arrays from where library will take data (messages) to show on display using various transition effects (or no effects).
MD_Parola effects (and No effects too) will follow those 3 steps:
- There is an "IN" effect for introducing the message on the display.
- Then the message will stop at center of display, or at left or right (alignment) for a certain amount of milliseconds (pause).
- The message will then use an "OUT" effect for disappearing from display.
IN and OUT effects have their own (same) speed value.
For the most right zone (the one showing calendar, humidity and temperature in this case) I used those settings:
// zone 0 (right): will use the "szMesg" array for showing scrolling messages
P.displayZoneText(0, szMesg, PA_CENTER, SPEED_TIME, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
- 0 : we're setting zone 0. Zone 0 is the nearest to the input (DIN) connector.
- szMesg : this is the pointer to the array we will update for showing message in that zone. So we must update the array called szMesg for updating the display.
- PA_CENTER : the message will stop at center of display when IN effect terminate.
- SPEED_TIME : this variable is defined up in the code and represent the speed of IN and OUT effects.
- 0 : this is the pause value in mS, 0 means that writing will not stop: when IN effect will end, the OUT effect will take place quick, without pause.
- PA_SCROLL_LEFT : "IN" effect, scroll (from the right) to the left.
- PA_SCROLL_LEFT : "OUT" effect, scroll (from the right) to the left.
Please pay attention: message is expected in form of an array, I know most of Arduiners love to use the String object. NO. You can't pass a String object to those functions: you'll got a lot of errors.
For the left zone, the one showing the time, I used those settings:
// zone 1 (left) : will use the "szTime" array for showing always the clock, no effects, no scrolling, static writings
P.displayZoneText(1, szTime, PA_CENTER, SPEED_TIME, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);
- 1 : zone 1 (the next zone after the 0, so the most left in this case).
- szTime : this is the pointer to the array we will update for showing message in that zone.
- PA_CENTER : the message will stop at center of display when "IN" effect terminate.
- SPEED_TIME : this variable is defined up in the code and represent the speed of IN and OUT effects. Anyway is not really used here since there are no moving effects.
- PAUSE_TIME : this variable is defined up in the cose and represent the time in mS the message will remain still.
- PA_PRINT : only print the message, so no effect are used, just print.
- PA_NO_EFFECT : there will be no OUT effect, message will disappear if needed.
Using those settings will result in message printed still in that zone without effects.
3D-Printing the enclosureFor printing the enclosure is needed a 3Dprinter having at least a 235x235mm buildplate. The enclosure is a rectangle having dimensions 271x45.5mm so we will print it in diagonal (STLs are already oriented in this way, turned at 45°), additionally we will use the Brim which adds by default a total of about 19mm to both dimensions (so calculate a 290x64.5).
UPDATE
User MrLoba81 modified the frame for slightly larger dot matrix displays: some sellers will sell you dot matrix display having some gap between a matrix and others, so a larger display will result and the default enclosure is no good. So check the Frame first than print the main body.
Brim width can be changed anyway by changing the number of its lines in slicer settings
Those enclosure dimensions (without brim or skirt) will require a plate having at least dimensions of ~224x224mm (some trigonometry helps) but those dimensions are not standardized, nearest one is 220x220mm but you understand is not suitable for this job.
I Don't know if a 225x225 buildplate printer exists or not. In this case will be good but you must not add skirt or brim.
I've two major advices (they are not really advices but a "you MUST do in this way"):
- Check your start-up G-Code: if you use to print a straight line on a border first than print for purging purposes, you must remove it!
- Use the Brim for a better adhesion: the part is very large and extends to the buildplate borders/angles where is known temperature can be a little unstable. The risk of piece detaching at borders is very high, so the Brim will keep the piece attached (I hope). On a 235x235 buildplate the brim arrives just some millimeters far from the borders, so keep an eye during the first layer printing for avoiding damage if nozzles goes out of the bounds!
At end, you must (remove the brim and then) put 8 M3 inserts (4.5x6mm) in the enclosure top holes.
I removed pinheaders from the NodeMCU for a more compact mount and soldered cables directly on the pads. If you don't want to remove pinheaders, you can consider to mount the NodeMCU upside down in the next steps.
First of all pass 4 M3 screws in the holes made for the NodeMCU (see picture below) and then attach 4 F/M spacers on the other side. The 6 bigger holes in the box corners and at center are intended for M4 screws and can be used for mounting purposes: use what you like (I put some longer M3 spacers there even if I made the hole for M4 screws).
As said I've screwed 4 short Male/Female spacers on that screws fot attaching the NodeMCU. Holes on the enclosure doesn't match perfectly with NodeMCU ones
I tried a couple of times to relocate those holes. There are no accurate technical drawings of this object and it's no easy have a good measure of holes position since they differs a lot from object to object. So after a couple of test-prints I got bored and leaved them in this way!
The NodeMCU will fit a little forced but this turned a good thing since I don't needed to put nuts on top for locking the board:
Gently insert displays letting cables passing in that slotted hole:
I put a PVC red transparent sheet above the display: this will keep display in place and will give a better viewing of it.
Display is not attached to the enclosure in any way: it fits perfectly in the enclosure and this can be enough since this object is meant to stay still somewhere. The PVC sheet on top will block display definitely.
I bought these A4 PVC filters (they're used for photography purposes) and then I used the 3D-printed frame as template for cutting the PVC:
Put the cutted PVC sheet on display, then the frame and screw all using 8 M3 screws in the inserts: screws must pass through the PVC sheet too:
Solder all the cables following the attached schematic. I've put the DHT22 on the back enclosure using double-sided tape: I would preferred use a screw but the hole on the DHT22 is too near to the body so it's impossibile use an M3 Screw. If you've M2.5 or M2 screws, you can try with them (probably M2 is good) passing it in one of enclosure holes. Don't put the DHT22 too near to the NodeMCU.
Finish!
Comments