—「0X://Explanation」
i saw someone with a youtube subscriber counter display and decided i wanted one as well, but i don't have many subs, so instead i will do something i have alot of:
pageviews! we are coming up on 50k so its a perfect time to build the counter <3 we passed 50k before i could finish, thanks <3 but also cmon >:c
(at the final moment working on the project it was: 51823)
suprisingly i dont have any led matrix displays and node mcu v3's on hand (though i do have the ESP XXXX units, i just dont know how to use them), so i had to order parts. in addition to that i've begun 3d printing the case:
the middle piece of the case has detached thrice while printing, which never happens. this has caused (un)believable frustration as this has never happened. theories: (1) the glue sticks are too dry cuz i s*ck at closing them. (2) i thought it was supports but i already ruled that out so it better be #1. i'll work on the electronics and programming in the meantime.
here is the code i wrote in python to grab the view count (with censored info):
import pyautogui, sys, time
"""Analytics Reporting"""
from apiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
SCOPES = ['https://www.███████.com/auth/analytics.readonly']
KEY_FILE_LOCATION = '██████████████████.json'
VIEW_ID = '██████████'
def initialize_analyticsreporting():
"""Initializes an Analytics Reporting API V4 service object.
Returns:
An authorized Analytics Reporting API V4 service object.
"""
credentials = ServiceAccountCredentials.from_json_keyfile_name(
KEY_FILE_LOCATION, SCOPES)
# Build the service object.
analytics = build('analyticsreporting', 'v4', credentials=credentials)
return analytics
def get_report(analytics):
"""Queries the Analytics Reporting API V4.
Args:
analytics: An authorized Analytics Reporting API V4 service object.
Returns:
The Analytics Reporting API V4 response.
"""
return analytics.reports().batchGet(
body={
'reportRequests': [
{
'viewId': VIEW_ID,
'dateRanges': [{'startDate': '5000daysAgo', 'endDate': 'today'}],
#'metrics': [{'expression': 'ga:sessions'}],
'metrics': [{'expression': 'ga:pageviews'}],
'dimensions': [{'name': 'ga:country'}]
}]
}
).execute()
def print_response(response):
"""Parses and prints the Analytics Reporting API V4 response.
Args:
response: An Analytics Reporting API V4 response.
"""
count = 0
for report in response.get('reports', []):
columnHeader = report.get('columnHeader', {})
dimensionHeaders = columnHeader.get('dimensions', [])
metricHeaders = columnHeader.get('metricHeader', {}).get('metricHeaderEntries', [])
for row in report.get('data', {}).get('rows', []):
dimensions = row.get('dimensions', [])
dateRangeValues = row.get('metrics', [])
#for header, dimension in zip(dimensionHeaders, dimensions):
#print(header + ': ', dimension)
for i, values in enumerate(dateRangeValues):
#print('Date range:', str(i))
for metricHeader, value in zip(metricHeaders, values.get('values')):
#print(metricHeader.get('name') + ':f', value)
count = count + int(value)
print(str(count) + " views")
def main():
analytics = initialize_analyticsreporting()
response = get_report(analytics)
print_response(response)
if __name__ == '__main__':
main()
this code just prints it to the console,, now to get it running on the node mcu v3,,, and over wifi,,,, and displayed on the led matrix,,,,,
everything is here!, but alas it cannot be that simple. programming the software doesn't seem that hard right? well we'll see... i won't bore you with the details, but i wasted time searching for what i need and setlled on micropython for the nodemcuv3, my naive self pressed forward assuming i could get this setup in an afternoon.
ok so i went on over to the micropython docs and began following the tutorial. sure a bit foreign, but nothing too out of my comfot zone right? (see next)
well that can't be good. (awhile later): well turns out the repl just displays jargin if the baud rate is wrong (and sometimes even when its right), but nothing a few resets couldn't fix. lets just configure webrepl now! (see next)
ah, joyous.
reflashed the board with a more modern .bin file, still nothing. to reddit we go! my question was answered by the lovely u/ImpressiveVersion9, and to my suprise, their solution worked (even tho i couldve sworn i had already tried it). nonetheless if finally connected:
as delightful as this may seem, the next occurence soured the mood quite a bit. my python script can't run on the nodemcu v3. not entirely sure why, but i'll come up with something else. and i did! (kinda). i wrote a flask python server that outputs the view count as html (because i was able to write an html grabber in micropython). i could then host this on some random pc/microcomputer in my room somewhere, but theres one caveat. i cant get the localhost to be available over lan (despite my incessant (and correct) use if my device ip). so that is where i'm currently stuck, ill keep trying other methods till i get this server hosted.
p.s. i also discovered the max7219 library by mcauser which allowed me to program the displays (enough to show 1,2,3,4,5,6,7,8, but not much else yet. wish me luck (bonus: they are extremely bright):
i think i forgot to mention what i printed for the case: but the files i used are this and this. other than that i did all* the rest of the programming, which was quite a hassle.
basically i had to make a local webserver that runs the python script cuz it didnt run properly on the esp8266, so i did that. then using urequests i was able to fetch the html on the local web server and pull the data i need from it it!
so here's the final version of the main.py file running on the esp8266, with probably some unnecessary bits, since its just an amalgamation of code:
# on MicroPython for ESP8266 & MAX7219 LED display
# by Alan Wang, Taiwan
import network, urequests, utime, ntptime
from machine import Pin, SPI, Timer, reset
# the new grab function thingy
import urequests
# the time loop
import time
# MAX7219 driver: https://github.com/mcauser/micropython-max7219
# Note: this driver is designed for 4-in-1 MAX7219 modules.
# VCC: 3.3V or 5V
# GND: GND
# DIN: MOSI (D7)
# CS: D8
# CLK: SCK (D5)
from max7219 import Matrix8x8
# ----------------------------------------
# WiFi AP ssid and password
SSID = "█████ ██████"
PW = "██████████"
# config parameters
TIMEZONE_HOUR_OFFSET = 8 # timezone hour offset
MAX7219_NUM = 4 # Number of MAX7219 LED modules
MAX7219_BRIGHTNESS = 11 # MAX7219 brightness (0-15)
MAX7219_INVERT = False # Invert MAX7219 display
MAX7219_SCROLL_DELAY = 30 # MAX7219 display scrolling speed (ms)
CLOCK_TIMER_DELAY = 900000 # clock update delay (ms)
API_TIMER_DELAY = 300000 # API query delay (ms)
DISPLAY_TIMER_DELAY = (len(fmt) + MAX7219_NUM) * 8 * MAX7219_SCROLL_DELAY + 2000
print("--- the thingy --")
data = dict()
data_available = False
timer_api = Timer(-1)
timer_clock = Timer(-1)
timer_display = Timer(-1)
led = Pin(2, Pin.OUT, value=1)
# setup MAX7219
spi = SPI(1, baudrate=10000000, polarity=0, phase=0)
display = Matrix8x8(spi, Pin(15), 8)
# connect to WiFi
print("Connecting to WiFi...")
wifi = network.WLAN(network.STA_IF)
wifi.active(True)
wifi.connect(SSID, PW)
while not wifi.isconnected():
pass
print("Connected.")
# decorator for checking WiFi status
def wifi_check_decorator(func):
def wrapper(*args, **kwargs):
if not wifi.isconnected():
# stop timers
timer_api.deinit()
timer_clock.deinit()
timer_display.deinit()
# reboot
reset()
else:
# run decorated functions
led.value(0)
func(*args, **kwargs)
led.value(1)
return wrapper
global dsp
dsp = ""
starttime = time.time()
while True:
try:
# the new request grab
response = urequests.get("http://192.168.0.40:4996/")
alltext = response.text
alltext = alltext.replace('█████████', '')
alltext = alltext.replace('████████████', '')
alltext = alltext.replace('███████████', '')
alltext = alltext.replace('█████████', '')
alltext = alltext.replace(' ███████', '')
alltext = alltext.replace('████████', '')
alltext = alltext.replace('████████████', '')
alltext = alltext.replace('██████████', '')
bruh = int(alltext)
if bruh > 99999:
global dsp
dsp = '00'+str(bruh)
elif bruh > 999999:
global dsp
dsp = '0'+str(bruh)
else:
global dsp
dsp = '000'+str(bruh)
display.fill(0)
display.text(" ",0,0,1)
display.text(dsp,0,0,1)
display.brightness(4)
display.show()
time.sleep(60.0 - ((time.time() - starttime) % 60.0))
except:
time.sleep(60.0 - ((time.time() - starttime) % 60.0))
now just solder it up and make sure it works:
positive! i decided to keep it on my windowsil:
and its all done! it updates every minute, and honestly it seems like it wasnt much of a hassle, but thats just the result of my brain removing the trauma of me troubleshooting this thing. definitely recommend this to learn about new things, i learned alot!
┈ ren ♡