HeathenHacks
Published © GPL3+

YouTube Subs, Views & Videos Counter

This is a step-by-step guide that I have created for beginners and ArduiNOOBS like me.

BeginnerFull instructions provided1,413
YouTube Subs, Views & Videos Counter

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
LCD Initial Test. (Not Required.)
×1
Wemos D1 Mini
Espressif Wemos D1 Mini
×1
Standard LCD - 16x2 White on Blue
Adafruit Standard LCD - 16x2 White on Blue
×1

Software apps and online services

Google Cloud Resource Manager
This is where we can obtain our API key.
Google Youtube
This is what we will monitor. (Youtube Channel Statistics)

Hand tools and fabrication machines

Screwdriver
Data Cable

Story

Read more

Custom parts and enclosures

LCD Acrylic Display Case

Schematics

D1 Mini Diagram

Code

LCD D1 Mini

Arduino
Add the LiquidCrystal_PCF8574.h and LiquidCrystal_PCF8574.cpp inside the project folder.
#include "Arduino.h"
#include "LiquidCrystal_PCF8574.h"
#include <YoutubeApi.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h> // This Sketch doesn't technically need this, but the library does so it must be installed.

#define LCD_ADDRESS 0x27
#define LCD_ROWS 2
#define LCD_COLUMNS 16
#define SCROLL_DELAY 150
#define BACKLIGHT 255
LiquidCrystal_PCF8574 LCDi2C;

//------- Replace the following! ------
char ssid[] = "Your WiFi Name";       // your network SSID (name)
char password[] = "Your WiFi Password";  // your network key
#define API_KEY "Your Youtube API Key From Google"  // your google apps API Token
#define CHANNEL_ID "Your/Someone's Channel ID / Channel URL" // makes up the url of channel


WiFiClientSecure client;
YoutubeApi api(API_KEY, client);

unsigned long api_mtbs = 180000; //mean time between api requests
unsigned long api_lasttime;   //last time api request has been done

long subs = 0;

void setup() {

  Serial.begin(115200);

  LCDi2C.begin(LCD_COLUMNS, LCD_ROWS, LCD_ADDRESS, BACKLIGHT);

  // Set WiFi to station mode and disconnect from an AP if it was Previously
  // connected
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  // Attempt to connect to Wifi network:
  LCDi2C.print("Connecting To...");
  delay(1000);
  LCDi2C.clear();
  LCDi2C.print("Your Desired Name");
  delay(1000);
  LCDi2C.selectLine(2);
  LCDi2C.print("WiFi Network...");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    LCDi2C.print(".");
    delay(100);
  }
  LCDi2C.clear();
  LCDi2C.print(" WiFi Connected ");
  delay(2000);
  LCDi2C.clear();
  LCDi2C.print("IP Address:");
  LCDi2C.selectLine(2);
  IPAddress ip = WiFi.localIP();
  LCDi2C.print(ip);
  delay(2000);
  LCDi2C.clear();
  LCDi2C.print("Waiting For");
  delay(500);
  LCDi2C.selectLine(2);
  LCDi2C.print("Channel Stats...");
}

void loop() {

  if (millis() - api_lasttime > api_mtbs)  {
    if (api.getChannelStatistics(CHANNEL_ID))
    {
      LCDi2C.clear();
      LCDi2C.print("Subs:");
      LCDi2C.print(api.channelStats.subscriberCount);
      LCDi2C.print(" Vids:");
      LCDi2C.print(api.channelStats.videoCount);
      LCDi2C.selectLine(2);
      LCDi2C.print("Views: ");
      LCDi2C.print(api.channelStats.viewCount);
    }
    api_lasttime = millis();
  }
}

LiquidCrystal_PCF8574.cpp

C/C++
///
/// \file LiquidCrystal_PCF8574.cpp
/// \brief LiquidCrystal (LCD) library with PCF8574 I2C adapter.
///
/// \author Matthias Hertel, http://www.mathertel.de
/// \copyright Copyright (c) 2014 by Matthias Hertel.\n
/// This work is licensed under a BSD style license.\n
/// See http://www.mathertel.de/License.aspx
/// 
/// \details
/// This is a library for driving LiquidCrystal displays (LCD) by using the I2C bus and an PCF8574 I2C adapter.
/// This library is derived from the original Arduino LiquidCrystal library and uses the original Wire library for communication.
///
/// More documentation and source code is available at http://www.mathertel.de/Arduino
///
/// ChangeLog see: LiquidCrystal_PCF8574.h

#include "LiquidCrystal_PCF8574.h"

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
#include <Wire.h>

/// Definitions on how the PCF8574 is connected to the LCD

/// These are Bit-Masks for the special signals and background light
#define PCF_RS  0x01
#define PCF_RW  0x02
#define PCF_EN  0x04
#define PCF_BACKLIGHT 0x08

// Definitions on how the PCF8574 is connected to the LCD
// These are Bit-Masks for the special signals and Background
#define RSMODE_CMD  0
#define RSMODE_DATA 1


// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set: 
//    DL = 1; 8-bit interface data 
//    N = 0; 1-line display 
//    F = 0; 5x8 dot character font 
// 3. Display on/off control: 
//    D = 0; Display off 
//    C = 0; Cursor off 
//    B = 0; Blinking off 
// 4. Entry mode set: 
//    I/D = 1; Increment by 1 
//    S = 0; No shift 
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).

// modification:
// don't use ports from Arduino, but use ports from Wire

// a nibble is a half Byte

// NEW: http://playground.arduino.cc//Code/LCDAPI
// NEW: setBacklight

LiquidCrystal_PCF8574::LiquidCrystal_PCF8574()
{
  //_backlight = 255;
} // LiquidCrystal_PCF8574

LiquidCrystal_PCF8574::LiquidCrystal_PCF8574(uint8_t addr)
{
  _Addr = addr;
  _backlight = 0;
} // LiquidCrystal_PCF8574

void LiquidCrystal_PCF8574::begin(uint8_t cols, uint8_t lines, uint8_t addr, uint8_t backlight)
{
  _backlight = backlight;
  _Addr = addr;
  begin(cols, lines);
}

void LiquidCrystal_PCF8574::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
  // cols ignored !
  _numlines = lines;

  _displayfunction = 0;

  if (lines > 1) {
    _displayfunction |= LCD_2LINE;
  }

  // for some 1 line displays you can select a 10 pixel high font
  if ((dotsize != 0) && (lines == 1)) {
    _displayfunction |= LCD_5x10DOTS;
  }

  // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
  // according to datasheet, we need at least 40ms after power rises above 2.7V
  // before sending commands. Arduino can turn on way befor 4.5V so we'll wait 50
  Wire.begin();

  // initializing th display
  _write2Wire(0x00, LOW, false);
  delayMicroseconds(50000); 

  // put the LCD into 4 bit mode according to the hitachi HD44780 datasheet figure 26, pg 47
  _sendNibble(0x03, RSMODE_CMD);
  delayMicroseconds(4500); 
  _sendNibble(0x03, RSMODE_CMD);
  delayMicroseconds(4500); 
  _sendNibble(0x03, RSMODE_CMD);
  delayMicroseconds(150);
  // finally, set to 4-bit interface
  _sendNibble(0x02, RSMODE_CMD);

  // finally, set # lines, font size, etc.
  _command(LCD_FUNCTIONSET | _displayfunction);  

  // turn the display on with no cursor or blinking default
  _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;  
  display();

  // clear it off
  clear();

  // Initialize to default text direction (for romance languages)
  _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
  // set the entry mode
  _command(LCD_ENTRYMODESET | _displaymode);

  setBacklight(_backlight);
  checkI2CConnection();
}

/********** high level commands, for the user! */
void LiquidCrystal_PCF8574::clear()
{
  _command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystal_PCF8574::home()
{
  _command(LCD_RETURNHOME);  // set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}


/// Set the cursor to a new position. 
void LiquidCrystal_PCF8574::setCursor(uint8_t col, uint8_t row)
{
  int row_offsets[] = { 0x00, 0x40, 0x14, 0x54   };
  if ( row >= _numlines ) {
    row = _numlines-1;    // we count rows starting w/0
  }

  _command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

/** select begining of line
 *  line - 1 for first row, 2 for second row
 *  
 */
void LiquidCrystal_PCF8574::selectLine(uint8_t line)
{
  setCursor(0, line - 1);
}

// Turn the display on/off (quickly)
void LiquidCrystal_PCF8574::noDisplay() {
  _displaycontrol &= ~LCD_DISPLAYON;
  _command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_PCF8574::display() {
  _displaycontrol |= LCD_DISPLAYON;
  _command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turns the underline cursor on/off
void LiquidCrystal_PCF8574::noCursor() {
  _displaycontrol &= ~LCD_CURSORON;
  _command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_PCF8574::cursor() {
  _displaycontrol |= LCD_CURSORON;
  _command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turn on and off the blinking cursor
void LiquidCrystal_PCF8574::noBlink() {
  _displaycontrol &= ~LCD_BLINKON;
  _command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_PCF8574::blink() {
  _displaycontrol |= LCD_BLINKON;
  _command(LCD_DISPLAYCONTROL | _displaycontrol);
}

/** These commands scroll the display without changing the RAM
 *  charsToScroll - how many chars to scroll left
 *  scrollSpeed - define scrolling speed, im milliseconds.
 */

void LiquidCrystal_PCF8574::scrollDisplayLeft(int charsToScroll, int scrollSpeed) {
  for (int i=0 ; i < charsToScroll ; i++)
    {
     _command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
    delay(scrollSpeed);
    }
}

/** These commands scroll the display without changing the RAM
 *  charsToScroll - how many chars to scroll right
 *  scrollSpeed - define scrolling speed, im milliseconds.
 */

void LiquidCrystal_PCF8574::scrollDisplayRight(int charsToScroll, int scrollSpeed) {
  for (int i=0 ; i < charsToScroll ; i++)
    {
    _command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
    delay(scrollSpeed);
    }
}

// This is for text that flows Left to Right
void LiquidCrystal_PCF8574::leftToRight(void) {
  _displaymode |= LCD_ENTRYLEFT;
  _command(LCD_ENTRYMODESET | _displaymode);
}

// This is for text that flows Right to Left
void LiquidCrystal_PCF8574::rightToLeft(void) {
  _displaymode &= ~LCD_ENTRYLEFT;
  _command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'right justify' text from the cursor
void LiquidCrystal_PCF8574::autoscroll(void) {
  _displaymode |= LCD_ENTRYSHIFTINCREMENT;
  _command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'left justify' text from the cursor
void LiquidCrystal_PCF8574::noAutoscroll(void) {
  _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
  _command(LCD_ENTRYMODESET | _displaymode);
}


/// Setting the brightness of the background display light.
/// The backlight can be switched on and off.
/// The current brightness is stored in the private _backlight variable to have it available for further data transfers.
void LiquidCrystal_PCF8574::setBacklight(uint8_t brightness) {
  _backlight = brightness;
  // send no data but set the background-pin right;
  _write2Wire(0x00, RSMODE_DATA, false);
} // setBacklight


// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystal_PCF8574::createChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7; // we only have 8 locations 0-7
  _command(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    write(charmap[i]);
  }
}

/* The write function is needed for derivation from the Print class. */
inline size_t LiquidCrystal_PCF8574::write(uint8_t value) {
  _send(value, RSMODE_DATA);
  return 1; // assume sucess
}

/* ----- low level functions ----- */

inline void LiquidCrystal_PCF8574::_command(uint8_t value) {
  _send(value, RSMODE_CMD);
} // _command()


// write either command or data
void LiquidCrystal_PCF8574::_send(uint8_t value, uint8_t mode) {
  // separate the 4 value-nibbles
  uint8_t valueLo = value    & 0x0F;
  uint8_t valueHi = value>>4 & 0x0F;

  _sendNibble(valueHi, mode);
  _sendNibble(valueLo, mode);
} // _send()


// write a nibble / halfByte with handshake
void LiquidCrystal_PCF8574::_sendNibble(uint8_t halfByte, uint8_t mode) {
  _write2Wire(halfByte, mode, true);
  delayMicroseconds(1);    // enable pulse must be >450ns
  _write2Wire(halfByte, mode, false);
  delayMicroseconds(37);   // commands need > 37us to settle
} // _sendNibble


// private function to change the PCF8674 pins to the given value
void LiquidCrystal_PCF8574::_write2Wire(uint8_t halfByte, uint8_t mode, uint8_t enable) {
  // map the given values to the hardware of the I2C schema
  uint8_t i2cData = halfByte << 4;
  if (mode > 0) i2cData |= PCF_RS;
  // PCF_RW is never used.
  if (enable > 0) i2cData |= PCF_EN;
  if (_backlight > 0) i2cData |= PCF_BACKLIGHT;

  Wire.beginTransmission(_Addr);
  Wire.write(i2cData);
  Wire.endTransmission();   
} // write2Wire

bool LiquidCrystal_PCF8574::checkI2CConnection()
{
  int error;
  // See http://playground.arduino.cc/Main/I2cScanner
  Wire.begin();
  Wire.beginTransmission(_Addr);
  error = Wire.endTransmission();
  
  if (error) 
  {
    Serial.println("LCD not found.");
  }
  return error;
  
}

// The End.

LiquidCrystal_PCF8574.h

C Header File
///
/// \file LiquidCrystal_PCF8574.h
/// \brief LiquidCrystal library with PCF8574 I2C adapter.
///
/// \author Matthias Hertel, http://www.mathertel.de
/// \copyright Copyright (c) 2014 by Matthias Hertel.\n
/// This work is licensed under a BSD style license.\n
/// See http://www.mathertel.de/License.aspx
/// 
/// Copyright (c) 2005-2012 by Matthias Hertel, http://www.mathertel.de/
/// All rights reserved.
///
/// * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
/// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
/// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the 
///   documentation and/or other materials provided with the distribution. Neither the name of the copyright owners nor the names of its 
///   contributors may be used to endorse or promote products derived from this software without specific prior written permission.
///
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
/// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
/// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
/// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
/// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
/// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


/// \details
/// This is a library for driving LiquidCrystal displays (LCD) by using the I2C bus and an PCF8574 I2C adapter.
/// This library is derived from the original Arduino LiquidCrystal library and uses the original Wire library for communication.
///
/// ChangeLog:
/// --------
/// * 19.10.2013 created.
/// * 24.05.2015 Arduino Library Manager compatible.
/// * 20.12.2016 circuito.io:
///                 * Added scrolling multiple chars to scrolling functions
///                 * Added selectLine function, same as setCursor(0, line - 1)
///                 * Added checkI2CConnection - prints to the serial monitor if connection faild. it is called inside begin.



#ifndef LiquidCrystal_PCF8574_h
#define LiquidCrystal_PCF8574_h

#include <inttypes.h>
#include "Print.h"

// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80

// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00

// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00

// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00

// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00

class LiquidCrystal_PCF8574 : public Print {
public:

  LiquidCrystal_PCF8574();
  LiquidCrystal_PCF8574(uint8_t addr);

  void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
  void begin(uint8_t cols, uint8_t lines, uint8_t addr, uint8_t backlight);
  bool checkI2CConnection();

  void clear();
  void home();
  
  void noDisplay();
  void display();
  void noBlink();
  void blink();
  void noCursor();
  void cursor();
  void scrollDisplayLeft(int charsToScroll, int scrollSpeed);
  void scrollDisplayRight(int charsToScroll, int scrollSpeed);
  void leftToRight();
  void rightToLeft();
  void autoscroll();
  void noAutoscroll();

  void setBacklight(uint8_t brightness);
  
  void createChar(uint8_t, uint8_t[]);
  void setCursor(uint8_t col, uint8_t row);
  void selectLine(uint8_t line);

  virtual size_t write(uint8_t);
  using Print::write;

private:
  // low level functions
  void _command(uint8_t);
  void _send(uint8_t value, uint8_t mode);
  void _sendNibble(uint8_t halfByte, uint8_t mode);
  void _write2Wire(uint8_t halfByte, uint8_t mode, uint8_t enable);

// NEW:
  uint8_t _Addr;        ///< Wire Address of the LCD
  uint8_t _backlight;   ///< the backlight intensity 

  uint8_t _displayfunction; ///< lines and dots mode
  uint8_t _displaycontrol;  ///< cursor, display, blink flags
  uint8_t _displaymode;     ///< left2right, autoscroll

  uint8_t _numlines;        ///< The number of rows the display supports.
};

#endif

Credits

HeathenHacks

HeathenHacks

24 projects • 57 followers
I don't know what I'm doing here.

Comments