OVERVIEW
Tadahh!!!
Well ok, it’s really nothing that special, but it’s my take on the YouTube subscribers counter!
Since Google crippled the YouTube API recently :(
I had to add some other things to make it still relevant and somewhat useful.
So here’s what I came up with…
PARTS USED
NodeMCU V2
MAX7219 Matrix Module
Nextion LCD Display
These are Amazon affiliate links...
They don't cost you anything and it helps me keep the lights on
if you buy something on Amazon. Thank you!
WHAT CAN IT DO?
Like I said before, since the YouTube API doesn’t update the Subscribers count until you reach a certain amount, depending on how many you have already.
So just having a counter that counts the Subscribers would be pretty useless…
g
After thinking about it I decided to add these functions to make my YouTube counter more relevant:
YouTube Subscribers
YouTube Total Views
Clock
Quote of the Day
So now having this on the wall in my workshop makes a little more sense…
THE HARDWARE USED
I decided to go traditional for the number display, I’m using 8x Max7219 LED matrix, these are easy to find and are inexpensive.
But I wanted to add some sort of display to show what those numbers meant.
I decided to use a 2.8 inches Nextion LCD screen, like the Max7219 it’s inexpensive and easy to find.
And of course the NodeMCU Version 2 to get everything working.
THE PLAN
So what I decided to do with all this stuff is this:
The YouTube Information:
Number of Subscribers
Number of Total views
The Clock:
Small animation of Homer falling with clocks on the Nextion.
The Quote of the Day:
Picks a quote from a list to show at randomIf you see this type of information, yours will be different since it’s using a different YouTube Channel…
Again another Homer animation, this time with glasses and talking
MAKING SIMPLE ANIMATIONS ON NEXTION LCD
The 2.8 inch Nextion I’m using for this project only has 4 megabytes of memory available, so I couldn’t make those animation very long without maxing out the memory available.
Also, the ‘basic’ cheap Nextion LCD like I’m using, don’t support video files (only the more expensive ones do that, 80+$) so the animation are made by uploading separate pictures, kinda like an animated GIF.
You might think that since the Nextion I’m using has a resolution of 320×240 pixels, you could upload a lot of pictures, but that’s not the case.
The Nextion Editor converts the images you upload to 16 bits, with no way to change it, so those small 6Kb pictures become 150Kb each!!!!!
So I ended up using 6 frames/pictures for the Clock/Homer animation, and 5 for the YouTube subs and views.
Here’s how to create those animation on the Nextion:
PUTTING IT ALL TOGETHER
To make a case for the MAX7219 LED matrix and the Nextion I used my newly acquired Sindoh 3D Printer.
I wanted to have at least eight Max7219 LED matrix to have enough space for the number area.
I found this great 3D modular case model on Thingiverse:
It’s one of the best one out there for the Max7219 modules sI’m using in this project.
The fact that it’s modular, enables you to make it as big as you want.
For the Nextion 2.8″ LCD screen, again I found this case on Thingiverse:
It’s big enough to house the LCD and the NodeMCU.
The MAX7219 modules are attached together using some jumpers.
I’m using a regular 5V external power supply (1 Amp) plugged into the NodeMCU to power everything.
I’m using the 3.3v output from the NodeMCU to power the LED Matrix.
From my testing, those 8x LED matrix only draw around 50mA when displaying some numbers or text.
To power the Nextion LCD, I’m using the VIN pin on the NodeMCU, which can be used to power the NodeMCU if you want, but it can also output regulated 5V, which the Nextion needs!
The Nextion 2.8 inch LCD screen draws around 50mA.
So that’s 100mA total for the LED matrix and the Nextion screen.
The Regulator on the NodeMCU can provide up to 800mA, so we’re good there!
CONNECTION DIAGRAM
The connections are pretty easy:
We are powering the LED Matrix using the 3.3V and GND from the NodeMCU
For the Nextion LCD, which requires 5V, we are again using the NodeMCU, the VIN pin on the NodeMCU can be used as a power input to power it without using the USB plug, but can also output 5V. So the VIN and GND are used to power the Nextion LCD.
The TX and RX pin of the NodeMCU are connected to the RX and TX pins of the Nextion.
Pins D5, D7 and D8 of the NodeMCU are connected to the right side of the Matrix using CLK, DIN and CS.
THE CODE
This code uses a ‘lot’ of libraries:
2 for the YouTube API
another for the clock (NTP server)
2 libraries for the LED Matrix
one for the Nextion LCD
and 3 more for wifi and stuff
You can find links to all those at the bottom of this page.
The trickiest part of this code, funny enough, was to find a way to insert some commas in the numbers to make them more readable on the LED Matrix.
/* YouTube Counter LED Display
Created by Yvan / https://Brainy-Bits.com
This code is in the public domain...
You can: copy it, use it, modify it, share it or just plain ignore it!
Thx!
*/
#include "Nextion.h" // https://github.com/jyberg/Enhanced-Nextion-Library
#include <MD_Parola.h> // Library to control LED Matrix https://github.com/MajicDesigns/MD_Parola
#include <MD_MAX72xx.h> // Library needed for MD_Parola https://github.com/MajicDesigns/MD_MAX72xx
#include <SPI.h>
#include <YoutubeApi.h> // created by Brian Lough https://github.com/witnessmenow/arduino-youtube-api
#include <ArduinoJson.h> // *Version 5.13.5 needed* - created by bblanchon https://github.com/bblanchon/ArduinoJson
#include <ESP8266WiFi.h> // Library for WiFi communication (installed by default with NodeMCU board)
#include <NTPClient.h> // https://github.com/arduino-libraries/NTPClient
#include <WiFiUdp.h>
NexPage page0 = NexPage(0, 0, "page0");
NexPage page1 = NexPage(1, 0, "page1");
NexPage page2 = NexPage(2, 0, "page2");
NexPage page3 = NexPage(3, 0, "page3");
// List of Quotes
const char q1[] = "A conscience is what hurts when all your other parts feel so good.";
const char q2[] = "Think Im Sarcastic? Watch Me Pretend To Care!";
const char q3[] = "A conclusion is the part where you got tired of thinking.";
const char q4[] = "Two wrongs do not make a right, take your parents as an example.";
const char q5[] = "Accept that some days you are the pigeon, and some days you are the statue.";
const char q6[] = "Always remember that you are absolutely unique... Just like everyone else...";
const char q7[] = "As the Joker said, if you are good at something why do it for free...";
const char q8[] = "Avoid arguments about the toilet seat...use the sink...";
const char q9[] = "I like you. You remind me of when I was young and stupid.";
const char q10[]= "Congratulations, If you press the elevator button three times it goes into hurry mode – really...";
const char q11[]= "Do not take life too seriously, you will not get out alive.";
const char q12[]= "Honesty is the best policy but insanity is the best defense.";
const char q13[]= "I did not climb to the top of the food chain to be a vegetarian...";
const char q14[]= "If a stranger offers you a piece of candy...take two...";
const char q15[]= "I did not say it was your fault, I said I was blaming you.";
const char q16[]= "If I promise to miss you, will you go away?";
const char q17[]= "I am smiling. This should scare you.";
const char q18[]= "It takes patience to listen.. it takes skill to pretend you are listening.";
const char q19[]= "Never tell your problems to anyone...20% do not care and the other 80% are glad you have them...";
const char q20[]= "Oh... I did not tell you? Then It must be none of your business...";
const char q21[]= "Oh... Sorry... Did you mistake me for someone who cares?";
const char q22[]= "Remember, everyone seems normal until you get to know them...";
const char q23[]= "Suicide: Mans way of telling God - You can not fire me, I quit!";
const char q24[]= "The grass may be greener on the other side but at least you do not have to mow it.";
const char q25[]= "We are born naked, wet and hungry. Then things get worse.";
const char *quote_list[] = {
q1, q2, q3, q4, q5, q6, q7, q8, q9, q10,
q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24 };
int chosen_quote;
char current_quote[100]; // temp storage for fortune
// Define NTP Client to get time
const long utcOffsetInSeconds = -14400;
char daysOfTheWeek[7][12] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
/* PAROLA_HW, ///< Use the Parola style hardware modules.
GENERIC_HW, ///< Use 'generic' style hardware modules commonly available.
ICSTATION_HW, ///< Use ICStation style hardware module.
FC16_HW ///< Use FC-16 style hardware module.
*/
#define MAX_DEVICES 8 // Number of modules connected
#define CLK_PIN D5 // CLK pin of matrix connected to pin D5 on NodeMCU
#define DATA_PIN D7 // DATA pin of matrix connected to pin D7 on NodeMCU
#define CS_PIN D8 // CS pin of matrix connected to pin D8 on NodeMCU
MD_Parola MATRIX = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); // Create instance of MD_Parola named MATRIX
#define wifi_name "xxxxx" // your network SSID (name)
#define wifi_password "xxxxx" // your network key
#define google_api_key "xxxxx" // your google API Key
#define youtube_channel_id "xxxxx" // your YouTube Channel ID
WiFiClientSecure client; // create instance of WiFi named client
YoutubeApi get_from_youtube(google_api_key, client); // Create instance of YoutubeAPI named get_from_youtube
long subs = 0; // Variable to save number of Subscribers YouTube
long total_views = 0; // Variable to save number of total views on YouTube
void quotes() {
uint8_t scrollSpeed = 35; // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_LEFT;
uint16_t scrollPause = 0; // in milliseconds
MATRIX.setTextEffect(scrollEffect, scrollEffect);
MATRIX.displayClear();
MATRIX.displayReset();
for (int x=0; x<2; x++) { // Display quote of the day twice
MATRIX.displayText(current_quote, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect);
while (!MATRIX.displayAnimate()) { // If finished displaying message
yield();
}
}
}
void getsubs() {
char buf[21];
char thousand[21];
char million[21];
get_from_youtube.getChannelStatistics(youtube_channel_id);
subs=get_from_youtube.channelStats.subscriberCount;
if (subs>=1000000){
snprintf(thousand,sizeof(thousand),"%ld,%03ld",subs/1000, subs%1000);
thousand[0] = ',';
if (subs>=10000000){
thousand[1] = 0x20;
}
snprintf(million,sizeof(million),"%ld",subs/1000000);
strcpy(buf, million);
strcat(buf, thousand);
}
if ((subs>=1000) && (subs<1000000)) {
snprintf(buf,sizeof(buf),"%ld,%03ld",subs/1000, subs%1000);
}
if (subs<1000) {
snprintf(buf,sizeof(buf),"%ld",subs);
}
MATRIX.print(buf);
delay(10000);
}
void gettotalviews() {
char buf[21];
char thousand[21];
char million[21];
get_from_youtube.getChannelStatistics(youtube_channel_id);
total_views=get_from_youtube.channelStats.viewCount;
if (total_views>=1000000){
snprintf(thousand,sizeof(thousand),"%ld,%03ld",total_views/1000, total_views%1000);
thousand[0] = ',';
if (total_views>=10000000){
thousand[1] = 0x20;
}
snprintf(million,sizeof(million),"%ld",total_views/1000000);
strcpy(buf, million);
strcat(buf, thousand);
}
if ((total_views>=1000) && (total_views<1000000)) {
snprintf(buf,sizeof(buf),"%ld,%03ld",total_views/1000, total_views%1000);
}
if (total_views<1000) {
snprintf(buf,sizeof(buf),"%ld",total_views);
}
MATRIX.print(buf);
delay(10000);
}
void gettime() {
timeClient.update();
char clockdata[17];
char formatted[10];
char formattedDate[11];
timeClient.getFormattedTime().toCharArray(formatted,6);
strcpy(clockdata, daysOfTheWeek[timeClient.getDay()]);
strcat(clockdata, " ");
strcat(clockdata, formatted);
MATRIX.print(clockdata);
delay(10000);
}
void setup() {
MATRIX.begin();
nexInit();
client.setInsecure(); // Needed to get information for the YouTube API on the NodeMcu
WiFi.begin(wifi_name, wifi_password); // connect to the WiFi network
while (WiFi.status() != WL_CONNECTED) { // wait for a connection
delay(500);
}
IPAddress ip = WiFi.localIP();
timeClient.begin();
MATRIX.setIntensity(1);
sendCommand("dims=100"); // Set Nextion screen brightness to maximum
}
void loop() {
chosen_quote=random(0, 23); // Randomly choose a quote of the day
strcpy(current_quote, quote_list[chosen_quote]);
page3.show(); // Change the page on the Nextion screen
quotes();
MATRIX.setTextAlignment(PA_CENTER);
page0.show();
gettime();
page1.show();
getsubs();
page2.show();
gettotalviews();
}
CONCLUSION
I didn’t want to go all crazy with this thing, and spend too much money or time.
All in all, I’m pretty happy with the results.
My favourite function is probably the ‘Quote of the Day’ thing, I get a laugh every time I get inside the workshop.
I know this is like the millionth YouTube subscriber counter out there, but I hope you found this interesting.
Thanks for dropping by, and hope to see you in the next one.
Cheers!
TUTORIAL VIDEO
DOWNLOAD
Copy and Paste the above code/sketch in your Arduino IDE software.
Link to the libraries used in this tutorial:
Arduino YouTube Library by Brian Lough https://github.com/witnessmenow/arduino-youtube-api
ArduinoJson library written by Benoît Blanchon – Install this library using the Arduino IDE Library manager – You need to choose version 5.13.8 since the new versions will not work
Nextion Enhanced Library: https://github.com/jyberg/Enhanced-Nextion-Library
MD Parola Library: https://github.com/MajicDesigns/MD_Parola
MD MAX72xx Library: https://github.com/MajicDesigns/MD_MAX72xx
NTPClient Library: https://github.com/arduino-libraries/NTPClient
Comments