NanoPi NEO2 SPI LCD接続とか。 [NanoPi Neo]
NanoPi NEO2 メモ
参考にさせて頂いたページはこちら。⇒ NanoPi-NEOとMPDとOLEDで音楽再生サーバ
MPD関連は特に変更なし。
■ 主な変更点
・interface: i2c → SPI
・device: OLED ssd1306 → LCD ST7735S (これを使用)
・luma.lcd library
■ 使用libraryとか、OS imageとか
・luma.lcd 0.5.0 python library
・Official rom image
nanopi-neo2_ubuntu-core-xenial_4.11.2_20170605.zip
・RPi.GPIO 0.5.8 (上記、nanopi-neo2_ubuntu-core-xenial_4.11.2_20170605.zip に含まれる)
・NanoHatOLED source
■ 注意点
・ここの記述にあるように、 NanoPi用RPi.GPIOは"June 5, 2017" 以降のimage(2017/07/03時点 nanopi-neo2_ubuntu-core-xenial_4.11.2_20170605.zip のみ)に含まれているので、これ以外のイメージ(nanopi-neo2_ubuntu-oled_4.11.2_20170531.zip)などに含まれている RPi.GPIO 0.5.11では動作せず。
★ RPi.GPIO 0.58の控えと戻し(重要)
1. ubuntu-core-xenial_4.11.2_20170605 imageインストール & OS初期設定
2. RPi.GPIO 0.58の控え
3. NanoHatOLED インストール
「NanoHat OLED関係を入れる」を参照
4. luma.lcd インストール
5. RPi.GPIO 0.58への戻し
※この時点で RPi.GPIO 0.5.11(NanoPiでは動かない...)にupdateされているハズなので戻す。
1. h_offset=1, v_offset=2
⇒ 要画面表示位置調整
2. transfer_size=64 指定必須
⇒ 未指定時4096がデフォだが64を指定しないとspi dev open後のデータ送信不可
3. rotate=1 or 3 設定時は framebuffer="full_frame" 指定不可
⇒ エラーは出ないが画面表示ぐちゃぐちゃ
■code
/root/NanoPi-NEO_OLED_MPD/oled_mpd.py
★参考コード
参考にさせて頂いたページはこちら。⇒ NanoPi-NEOとMPDとOLEDで音楽再生サーバ
MPD関連は特に変更なし。
■ 主な変更点
・interface: i2c → SPI
・device: OLED ssd1306 → LCD ST7735S (これを使用)
・luma.lcd library
■ 使用libraryとか、OS imageとか
・luma.lcd 0.5.0 python library
・Official rom image
nanopi-neo2_ubuntu-core-xenial_4.11.2_20170605.zip
・RPi.GPIO 0.5.8 (上記、nanopi-neo2_ubuntu-core-xenial_4.11.2_20170605.zip に含まれる)
・NanoHatOLED source
■ 注意点
・ここの記述にあるように、 NanoPi用RPi.GPIOは"June 5, 2017" 以降のimage(2017/07/03時点 nanopi-neo2_ubuntu-core-xenial_4.11.2_20170605.zip のみ)に含まれているので、これ以外のイメージ(nanopi-neo2_ubuntu-oled_4.11.2_20170531.zip)などに含まれている RPi.GPIO 0.5.11では動作せず。
★ RPi.GPIO 0.58の控えと戻し(重要)
1. ubuntu-core-xenial_4.11.2_20170605 imageインストール & OS初期設定
2. RPi.GPIO 0.58の控え
# cd /usr/local/lib/python2.7/dist-packages/ # tar cvf ~/RPi_0.58.tar RPi*
3. NanoHatOLED インストール
「NanoHat OLED関係を入れる」を参照
4. luma.lcd インストール
5. RPi.GPIO 0.58への戻し
※この時点で RPi.GPIO 0.5.11(NanoPiでは動かない...)にupdateされているハズなので戻す。
# cd /usr/local/lib/python2.7/dist-packages/ # rm -rf RPi* # tar xvf ~/RPi_0.58.tar # pip list | grep RPi RPi.GPIO (0.5.8) #■物理接続
-------------------------------------------------------------- LCD NanoPi Neo2 (CN1 Pin No.) -------------------------------------------------------------- VLED ---- 2 5V VCC ---- 17 3.3V DC/A0 ---- 18 UART1_CTS/GPIOG9 (gpio_DC=18) SDA ---- 19 SPI0_MOSI/GPIOC0 GND ---- 20 GND RST ---- 22 UART2_RX/GPIOA1 (gpio_RST=22) SCLK ---- 23 SPI0_CLK/GPIOC2 CS ---- 24 SPI0_CS/GPIOC3 --------------------------------------------------------------■ハマッたところ
serial = spi(bus_speed_hz=32000000, transfer_size=64, port=0, device=0, gpio=GPIO, gpio_DC=18, gpio_RST=22) device = st7735(serial, h_offset=1, v_offset=2, rotate=1)
1. h_offset=1, v_offset=2
⇒ 要画面表示位置調整
2. transfer_size=64 指定必須
⇒ 未指定時4096がデフォだが64を指定しないとspi dev open後のデータ送信不可
3. rotate=1 or 3 設定時は framebuffer="full_frame" 指定不可
⇒ エラーは出ないが画面表示ぐちゃぐちゃ
■code
/root/NanoPi-NEO_OLED_MPD/oled_mpd.py
#!/usr/bin/env python # -*- encoding:utf8 -*- # # apt-get install fonts-takao-pgothic # apt-get install python-mutagen python3-mutagen import os import sys import time import signal import socket import errno import subprocess import RPi.GPIO as GPIO from luma.core.serial import spi from luma.lcd.device import st7735 from PIL import Image from PIL import ImageFont from PIL import ImageDraw mpd_music_dir = "/media/" scroll_unit = 1 title_height = 18 font_title = ImageFont.truetype('TakaoPGothic.ttf', 14, encoding='unic') font_info = ImageFont.truetype('TakaoPGothic.ttf', 11, encoding='unic') font_audio = ImageFont.load_default() font_time = ImageFont.truetype('TakaoPGothic.ttf', 27); font_date = ImageFont.truetype('TakaoPGothic.ttf', 16); mpd_host = 'localhost' mpd_port = 6600 mpd_bufsize = 8192 def receive_signal(signum, stack): try: soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) soc.connect((mpd_host, mpd_port)) soc.recv(mpd_bufsize) if signum == signal.SIGUSR1: print 'K1 pressed' soc.send('previous\n') soc.recv(mpd_bufsize) if signum == signal.SIGUSR2: print 'K2 pressed' soc.send('status\n') buff = soc.recv(mpd_bufsize) state_list = buff.splitlines() for line in range(0,len(state_list)): if state_list[line].startswith(r"state: "): info_state = state_list[line].replace(r"state: ", "") print(info_state) if info_state == 'play' : soc.send('stop\n') soc.recv(mpd_bufsize) else: soc.send('play\n') soc.recv(mpd_bufsize) if signum == signal.SIGALRM: print 'K3 pressed' soc.send('next\n') soc.recv(mpd_bufsize) except socket.error as cerr: if cerr.errno == errno.EINTR: buff = soc.recv(mpd_bufsize) print("Exception! :", sys.exc_info()) pass signal.signal(signal.SIGUSR1, receive_signal) signal.signal(signal.SIGUSR2, receive_signal) signal.signal(signal.SIGALRM, receive_signal) GPIO.setwarnings(False) GPIO.setmode(GPIO.BOARD) serial = spi(bus_speed_hz=32000000, transfer_size=64, port=0, device=0, gpio=GPIO, gpio_DC=18, gpio_RST=22) #device = st7735(serial, framebuffer="full_frame", h_offset=1, v_offset=2) device = st7735(serial, h_offset=1, v_offset=2, rotate=1) oled_width = device.width oled_height = device.height # cover_size = oled_height - title_height - 20 cover_size = device.width - 12 # OLED image image = Image.new('RGB', (oled_width, oled_height)) draw = ImageDraw.Draw(image) draw.rectangle((0,0,oled_width,oled_height), outline=0, fill=0) music_file = "" cover_image = Image.new('RGB', (cover_size, cover_size)) title_image = Image.new('RGB', (oled_width, title_height)) title_offset = 0 # Draw opening image try: device.display(Image.open('opening.png').resize((oled_width,oled_height)).convert('RGB')) time.sleep(0.4) except: device.display(image) soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) soc.connect((mpd_host, mpd_port)) soc.recv(mpd_bufsize) # soc.send('commands\n') # rcv = soc.recv(mpd_bufsize) # print("commands:") # print("----- start ----------") # print( rcv ) # print("----- end ----------\n") while True: try: soc.send('currentsong\n') buff = soc.recv(mpd_bufsize) song_list = buff.splitlines() # print("currentsong:") # print("----- start ----------") # print( buff ) # print("----- end ----------\n") soc.send('status\n') buff = soc.recv(mpd_bufsize) state_list = buff.splitlines() # print("status:") # print("----- start ----------") # print( buff ) # print("----- end ----------\n") info_state = "" info_audio = "" info_elapsed = 0 info_duration = 0 info_title = "" info_artist = "" info_album = "" info_file = "" except socket.error as e: if e.errno == errno.EINTR: buff = soc.recv(mpd_bufsize) print("Exception! :", sys.exc_info()) continue for line in range(0,len(state_list)): if state_list[line].startswith("state: "): info_state = state_list[line].replace("state: ", "") if state_list[line].startswith("audio: "): info_audio = state_list[line].replace("audio: ", "") if state_list[line].startswith("elapsed: "): info_elapsed = float(state_list[line].replace("elapsed: ", "")) if state_list[line].startswith("time: "): info_duration = float(state_list[line].split(":")[2]) for line in range(0,len(song_list)): if song_list[line].startswith("file: "): info_file = song_list[line].replace("file: ", "") if song_list[line].startswith("Artist: "): info_artist = song_list[line].replace("Artist: ", "") if song_list[line].startswith("Album: "): info_album = song_list[line].replace("Album: ", "") if song_list[line].startswith("Title: "): info_title = song_list[line].replace("Title: ", "") # clear the image draw.rectangle((0,0,oled_width,oled_height), outline=0, fill=0) if info_state != "stop": if info_title == "" : name = info_file.split('/') name.reverse() info_title = name[0] try: info_album = name[1] except: info_album = "" try: info_artist = name[2] except: info_artist = "" if info_file != music_file : music_file = info_file; file_path = mpd_music_dir + info_file cover_path = mpd_music_dir + os.path.split(music_file)[0] + "/front.jpg" print('--------------------------------------------') print(file_path) try: from mutagen import File file = File(file_path) # mutagen can automatically detect format and typeof tags if hasattr(file,'tags') : # for FLAC if hasattr(file,'pictures') : print( 'type = pictures' ) print( file.pictures ) artwork = file.pictures[0].data # for mp3 elif 'APIC:' in file : print( 'type = APIC' ) artwork = file.tags['APIC:'].data # for m4a elif 'covr' in file : print( 'type = covr' ) # print dir( file.tags['covr'][0]) artwork = file.tags['covr'][0] else: print('NoPicture!, dump tags') print( file.tags ) with open('front.jpg', 'wb') as img: img.write(artwork) # write artwork to new image cover_path = "front.jpg" else: print( 'type = NO TAGS') except: print("Exception! :", sys.exc_info()) ## print( file.tags ) continue print( cover_path ) cover_draw = ImageDraw.Draw(cover_image) ####### cover_draw.rectangle((0,0,cover_size-1,cover_size-1), outline="white", fill=0) if os.path.isfile( cover_path ) : front_image = Image.open(cover_path).convert('RGB').resize((cover_size-1,cover_size-1),Image.ANTIALIAS) cover_image.paste( front_image.convert('RGB'), (0,0)) else: text_x, text_y = font_audio.getsize("NoImage") cover_draw.text(((cover_size-text_x)/2, (cover_size - text_y)/2 ), "NoImage", font=font_audio, fill="white") # Generate title image title_width, dmy_y = font_title.getsize(unicode(info_title,'utf-8')) title_offset = oled_width / 2; title_image = Image.new('RGB', (title_width, title_height)) title_draw = ImageDraw.Draw(title_image) title_draw.rectangle((0,0, title_width, title_height), outline=0, fill=0) title_draw.text((0,0), unicode(info_title,'utf-8'), font=font_title, fill="white") # Title x = 0 y = cover_size + 2 if oled_width < title_image.width : if title_image.width < -title_offset : title_offset = oled_width / 2 if title_offset < 0 : x = title_offset time.sleep(0.04) title_offset = title_offset - scroll_unit image.paste(title_image, (x,y)) x = 0; # Current playback position y = cover_size r = (oled_width * info_elapsed / info_duration) if 0 < info_duration else oled_width draw.line((x, y, r, y ), fill="red") # Cover Image y += 2; image.paste( cover_image, (5,0)) # artist name, album name, audio format ### x = cover_size + 3; x = 0 y += title_height -5; draw.text((x, y), unicode(info_artist,'utf-8'), font=font_info, fill="lime") draw.text((x, y + (oled_height - 10 - y) / 2), unicode(info_album,'utf-8'), font=font_info, fill="cyan") draw.text((x, oled_height - 10), unicode(info_audio,'utf-8'), font=font_audio, fill="navy") else: music_file = "" draw.text((2, 4),time.strftime("%A"), font=font_date,fill="skyblue") draw.text((2,21),time.strftime("%e %b %Y"), font=font_date,fill="skyblue") draw.text((2,77),time.strftime("%X"), font=font_time,fill="white") device.display(image)
★参考コード