-
-
Save MCJack123/5c10789fd19d9a04c0371a63c715275e to your computer and use it in GitHub Desktop.
# Requires smbus: sudo apt install python-smbus | |
import I2C_LCD_driver | |
import time | |
import json | |
import httplib | |
import io | |
import os | |
from sys import exit | |
# Add the refresh key here (https://bit.ly/2DM1oRZ) | |
refresh_key = "" | |
# Specifies the number of minutes the clock will appear after (0 to turn off) | |
clock_appear_frequency = 3 | |
lcd = I2C_LCD_driver.lcd(0x27) | |
top_offset = 0 | |
bottom_offset = 0 | |
last_track = None | |
authkey = "" | |
expire_time = 0 | |
need_clock = False | |
timeout = 0 | |
if refresh_key == "": | |
lcd.lcd_display_string(" Please add key ", 1) | |
lcd.lcd_display_string(" to script file ", 2) | |
time.sleep(3) | |
lcd.lcd_display_string("https://bit.ly/ ", 1) | |
lcd.lcd_display_string("2DM1oRZ ", 2) | |
while True: | |
time.sleep(100) | |
def getAuthKey(): | |
global authkey | |
global expire_time | |
tokreq = httplib.HTTPConnection("cppconsole.bruienne.com", timeout=1) | |
tokres = None | |
try: | |
tokreq.request("GET", "/spotipi/get_token.php?token=" + refresh_key) | |
tokres = tokreq.getresponse() | |
except (socket.timeout, ssl.SSLError): | |
lcd.lcd_display_string(" Failed to get ", 1) | |
lcd.lcd_display_string(" access key ", 2) | |
print("Timeout") | |
time.sleep(5) | |
authkey = "" | |
return | |
if tokres.status != 200: | |
lcd.lcd_display_string(" Failed to get ", 1) | |
lcd.lcd_display_string(" access key ", 2) | |
print("HTTP " + str(tokres.status)) | |
time.sleep(5) | |
authkey = "" | |
return | |
tokresbody = tokres.read() | |
if tokresbody == "": | |
lcd.lcd_display_string(" Failed to get ", 1) | |
lcd.lcd_display_string(" access key ", 2) | |
print("Empty body") | |
time.sleep(5) | |
authkey = "" | |
return | |
tokbody = json.loads(tokresbody) | |
authkey = tokbody["token_type"] + " " + tokbody["access_token"] | |
expire_time = time.time() + tokbody["expires_in"] | |
def addWithMax(add1, add2, max, min = 0): | |
if add1 + add2 >= max: | |
return ((add1 + add2) - max * int((add1 + add2) / max)) + min | |
else: | |
return add1 + add2 | |
def substrWrap(string, start, length): | |
retval = "" | |
for i in range(0, length): | |
retval += string[addWithMax(start, i, len(string))] | |
return retval | |
def getTrackData(): | |
req = httplib.HTTPSConnection("api.spotify.com") | |
req.request("GET", "/v1/me/player/currently-playing", None, {"Authorization": authkey}) | |
res = req.getresponse() | |
if res.status != 200: | |
print("Got code " + str(res.status)) | |
return None | |
body = json.loads(res.read()) | |
if body["currently_playing_type"] == "ad": | |
return {"album": "", "artist": "", "track": "Advertisement"} | |
if not body["is_playing"] or body["item"] == None: | |
return None | |
artists = "" | |
for a in body["item"]["artists"]: | |
if artists != "": | |
artists += ", " | |
artists += a["name"] | |
return { | |
"album": body["item"]["album"]["name"], | |
"artist": artists, | |
"track": body["item"]["name"] | |
} | |
print("Getting key...") | |
getAuthKey() | |
lcd.lcd_clear() | |
while True: | |
if expire_time <= time.time() or authkey == "": | |
end_timee = time.time() + 5 | |
while end_timee > time.time(): | |
lcd.lcd_display_string(" %s " %time.strftime("%H:%M:%S"), 1) | |
lcd.lcd_display_string(" %s " %time.strftime("%m/%d/%Y"), 2) | |
time.sleep(.05) | |
top_offset = -4 | |
bottom_offset = -4 | |
getAuthKey() | |
elif int(time.time() % (clock_appear_frequency * 60)) == 0 and clock_appear_frequency > 0: | |
need_clock = True | |
if need_clock and (top_offset == 0 or bottom_offset == 0): | |
end_time = time.time() + 5 | |
lcd.lcd_clear() | |
while end_time > time.time(): | |
lcd.lcd_display_string(" %s " %time.strftime("%H:%M:%S"), 1) | |
lcd.lcd_display_string(" %s " %time.strftime("%m/%d/%Y"), 2) | |
time.sleep(.05) | |
top_offset = -4 | |
bottom_offset = -4 | |
lcd.lcd_clear() | |
need_clock = False | |
track = getTrackData() | |
if track == {}: | |
track = last_track | |
print(track) | |
if track == None: | |
lcd.lcd_display_string(" %s " %time.strftime("%H:%M:%S"), 1) | |
lcd.lcd_display_string(" %s " %time.strftime("%m/%d/%Y"), 2) | |
top_offset = -4 | |
bottom_offset = -4 | |
need_clock = False | |
last_track = None | |
time.sleep(0.25) | |
continue | |
if last_track != track: | |
top_offset = -4 | |
bottom_offset = -4 | |
top_line = track["track"] | |
bottom_line = track["artist"] + " -- " + track["album"] | |
if len(top_line) > 16 and len(bottom_line) > 16: | |
if len(top_line) > len(bottom_line): | |
bottom_line = bottom_line.ljust(len(top_line)) | |
elif len(bottom_line) > len(top_line): | |
top_line = top_line.ljust(len(bottom_line)) | |
top_line_orig = top_line | |
bottom_line_orig = bottom_line | |
top_pos = top_offset | |
if top_pos < 0: | |
top_pos = 0 | |
bottom_pos = bottom_offset | |
if bottom_pos < 0: | |
bottom_pos = 0 | |
if len(top_line) < 16: | |
top_line = top_line.center(16) | |
elif len(top_line) > 16: | |
top_line = substrWrap(top_line + " ", top_pos, 16) | |
if len(bottom_line) < 16: | |
bottom_line = bottom_line.center(16) | |
elif len(bottom_line) > 16: | |
bottom_line = substrWrap(bottom_line + " ", bottom_pos, 16) | |
lcd.lcd_display_string(top_line, 1) | |
lcd.lcd_display_string(bottom_line, 2) | |
top_offset = addWithMax(top_offset, 1, len(top_line_orig) + 4, -4) | |
bottom_offset = addWithMax(bottom_offset, 1, len(bottom_line_orig) + 4, -4) | |
time.sleep(.25) | |
last_track = track |
# -*- coding: utf-8 -*- | |
# Original code found at: | |
# https://gist.github.com/DenisFromHR/cc863375a6e19dce359d | |
""" | |
Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic | |
Made available under GNU GENERAL PUBLIC LICENSE | |
# Modified Python I2C library for Raspberry Pi | |
# as found on http://www.recantha.co.uk/blog/?p=4849 | |
# Joined existing 'i2c_lib.py' and 'lcddriver.py' into a single library | |
# added bits and pieces from various sources | |
# By DenisFromHR (Denis Pleic) | |
# 2015-02-10, ver 0.1 | |
""" | |
# i2c bus (0 -- original Pi, 1 -- Rev 2 Pi) | |
I2CBUS = 1 | |
import smbus | |
from time import sleep | |
class i2c_device: | |
def __init__(self, addr, port=I2CBUS): | |
self.addr = addr | |
self.bus = smbus.SMBus(port) | |
# Write a single command | |
def write_cmd(self, cmd): | |
self.bus.write_byte(self.addr, cmd) | |
sleep(0.0001) | |
# Write a command and argument | |
def write_cmd_arg(self, cmd, data): | |
self.bus.write_byte_data(self.addr, cmd, data) | |
sleep(0.0001) | |
# Write a block of data | |
def write_block_data(self, cmd, data): | |
self.bus.write_block_data(self.addr, cmd, data) | |
sleep(0.0001) | |
# Read a single byte | |
def read(self): | |
return self.bus.read_byte(self.addr) | |
# Read | |
def read_data(self, cmd): | |
return self.bus.read_byte_data(self.addr, cmd) | |
# Read a block of data | |
def read_block_data(self, cmd): | |
return self.bus.read_block_data(self.addr, cmd) | |
# commands | |
LCD_CLEARDISPLAY = 0x01 | |
LCD_RETURNHOME = 0x02 | |
LCD_ENTRYMODESET = 0x04 | |
LCD_DISPLAYCONTROL = 0x08 | |
LCD_CURSORSHIFT = 0x10 | |
LCD_FUNCTIONSET = 0x20 | |
LCD_SETCGRAMADDR = 0x40 | |
LCD_SETDDRAMADDR = 0x80 | |
# flags for display entry mode | |
LCD_ENTRYRIGHT = 0x00 | |
LCD_ENTRYLEFT = 0x02 | |
LCD_ENTRYSHIFTINCREMENT = 0x01 | |
LCD_ENTRYSHIFTDECREMENT = 0x00 | |
# flags for display on/off control | |
LCD_DISPLAYON = 0x04 | |
LCD_DISPLAYOFF = 0x00 | |
LCD_CURSORON = 0x02 | |
LCD_CURSOROFF = 0x00 | |
LCD_BLINKON = 0x01 | |
LCD_BLINKOFF = 0x00 | |
# flags for display/cursor shift | |
LCD_DISPLAYMOVE = 0x08 | |
LCD_CURSORMOVE = 0x00 | |
LCD_MOVERIGHT = 0x04 | |
LCD_MOVELEFT = 0x00 | |
# flags for function set | |
LCD_8BITMODE = 0x10 | |
LCD_4BITMODE = 0x00 | |
LCD_2LINE = 0x08 | |
LCD_1LINE = 0x00 | |
LCD_5x10DOTS = 0x04 | |
LCD_5x8DOTS = 0x00 | |
# flags for backlight control | |
LCD_BACKLIGHT = 0x08 | |
LCD_NOBACKLIGHT = 0x00 | |
En = 0b00000100 # Enable bit | |
Rw = 0b00000010 # Read/Write bit | |
Rs = 0b00000001 # Register select bit | |
class lcd: | |
#initializes objects and lcd | |
def __init__(self, addr): | |
self.lcd_device = i2c_device(addr) | |
self.lcd_write(0x03) | |
self.lcd_write(0x03) | |
self.lcd_write(0x03) | |
self.lcd_write(0x02) | |
self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE) | |
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON) | |
self.lcd_write(LCD_CLEARDISPLAY) | |
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT) | |
sleep(0.2) | |
# clocks EN to latch command | |
def lcd_strobe(self, data): | |
self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT) | |
sleep(.0005) | |
self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT)) | |
sleep(.0001) | |
def lcd_write_four_bits(self, data): | |
self.lcd_device.write_cmd(data | LCD_BACKLIGHT) | |
self.lcd_strobe(data) | |
# write a command to lcd | |
def lcd_write(self, cmd, mode=0): | |
self.lcd_write_four_bits(mode | (cmd & 0xF0)) | |
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0)) | |
# write a character to lcd (or character rom) 0x09: backlight | RS=DR< | |
# works! | |
def lcd_write_char(self, charvalue, mode=1): | |
self.lcd_write_four_bits(mode | (charvalue & 0xF0)) | |
self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0)) | |
# put string function with optional char positioning | |
def lcd_display_string(self, string, line=1, pos=0): | |
if line == 1: | |
pos_new = pos | |
elif line == 2: | |
pos_new = 0x40 + pos | |
elif line == 3: | |
pos_new = 0x14 + pos | |
elif line == 4: | |
pos_new = 0x54 + pos | |
self.lcd_write(0x80 + pos_new) | |
for char in string: | |
self.lcd_write(ord(char), Rs) | |
# clear lcd and set to home | |
def lcd_clear(self): | |
self.lcd_write(LCD_CLEARDISPLAY) | |
self.lcd_write(LCD_RETURNHOME) | |
# define backlight on/off (lcd.backlight(1); off= lcd.backlight(0) | |
def backlight(self, state): # for state, 1 = on, 0 = off | |
if state == 1: | |
self.lcd_device.write_cmd(LCD_BACKLIGHT) | |
elif state == 0: | |
self.lcd_device.write_cmd(LCD_NOBACKLIGHT) | |
# add custom characters (0 - 7) | |
def lcd_load_custom_chars(self, fontdata): | |
self.lcd_write(0x40); | |
for char in fontdata: | |
for line in char: | |
self.lcd_write_char(line) | |
hi. it is awesome your code. i adapted to an LCD 20x4 (getting info about temp CPU and ip, adr. etc) but i get an error when i run the script about ,, clock_appear_frequency " line 117 . Python say that it not was definite . If i comment line 117 the script is running whiteout errors.
Oops, I must have accidentally erased that line. I've updated the script to fix it. Basically, you need to add this to the top of the script below the refresh_key
(line 12):
# Specifies the number of minutes the clock will appear after (0 to turn off)
clock_appear_frequency = 3
That should fix your problem, and will properly show the clock while playing music.
i implement de line, it runs nicely. i am verity impressed by your programming skills.
In past i used jSon lib, on Arduino IDE for a meteo station, but was a liitle harder on a microcontroller like (esp 32). On raspberry Pi is more easy.
thanks for you fast reply.
my respects!
hi. it is awesome your code. i adapted to an LCD 20x4 (getting info about temp CPU and ip, adr. etc) but i get an error when i run the script about ,, clock_appear_frequency " line 117 . Python say that it not was definite . If i comment line 117 the script is running whiteout errors.
I am a beginner in python language.