Need working example of websocket or restAPI call in python

Hi volumio coders,

i need your help.
I try to get my 1.3" Display running. Requirement ST7789 driver.
So i searched the web and found a python script which works with some example features.

I got it modified to get control of:

  • background
  • static text and position
  • drawing rectangles (for volume or progress bar)

Now i would like to add some dynamic informations from volumio, like:

  • album
  • artist
  • Songtitle
  • path to cover image

I also read the volumio docs for development and how socket.io and REST-Api should work.
My coding skills are limited, i wrote a few “Magic Mirror Modules” in javascript.

Has anybody a working example, how i can use

  • socket.io
    or
  • RestAPI
    in a python script do get the informations mentioned above?

I already installed the depencies for:

  • python-rpi.gpio
  • python-spidev
  • python-pip
  • python-pil
  • python-numpy
  • pip install st7789
  • pip install socketIO-client-2 and/or pip install -U socketIO-client --user

Or has anybody alternatively a working javascript with the st7789 display driver?

I am looking forward hearing from you.

AxLED

Hi volumio coders,

this is what i have so far:

#!/usr/bin/env python

import time
from colorsys import hsv_to_rgb
from PIL import Image, ImageDraw, ImageFont
import os
import os.path
from os import path
from ST7789 import ST7789
from socketIO_client import SocketIO, LoggingNamespace

# get the path of the script
script_path = os.path.dirname(os.path.abspath( __file__ ))
# set script path as current directory - 
os.chdir(script_path)

MODE=0
OVERLAY=2
TIMEBAR=1
BLANK=0

def on_connect():
    print('connect')
    #socketIO.emit('getState', '', on_push_state)
    #socketIO.wait()
    return 'connected'

def on_push_state(*args):
      #print('state', args)
      global status
      global title
      global artist
      global album
      global albumart
      status = args[0]['status'].encode('ascii', 'ignore')
      title = args[0]['title'].encode('ascii', 'ignore')
      #artist = args[0]['artist'].encode('ascii', 'ignore') #Problem wenn es leer ist
      #album = args[0]['album'] #Problem wenn es leer ist
      albumart = args[0]['albumart'].encode('ascii', 'ignore')
      print status + ',' + title + ',' + albumart
      #socketIO.wait()
      #draw.text((100, 100), 'Hallo')
      draw.text((100, 100), status, font=font_l)
      disp.display(img)
      #disp.reset()
      return 'hallo'

socketIO = SocketIO('localhost', 3000)
socketIO.on('connect', on_connect)
#socketIO.wait_for_callbacks(seconds=1)
#on_connect()
#socketIO.once('connect', on_connect)
status = 'unknown'

#socketIO.on('pushState', on_push_state)
# get initial state
#socketIO.emit('getState', '', on_push_state)
#socketIO.wait()

disp = ST7789(
    rotation=90,  # Needed to display the right way up on Pirate Audio
    port=0,       # SPI port
    cs=1,         # SPI port Chip-select channel
    dc=9,         # BCM pin used for data/command
    backlight=13,
    spi_speed_hz=80 * 1000 * 1000
)

# Initialize display.
disp.begin()

WIDTH = 240
HEIGHT = 240
font_s = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf',20)
font_m = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf',24)
font_l = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf',30)

img = Image.new('RGB', (240, 240), color=(0, 0, 0, 25))

#play_icons = Image.open(script_path + '/images/controls-play.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
#play_icons_dark = Image.open(script_path + '/images/controls-play-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")

#pause_icons = Image.open(script_path + '/images/controls-pause.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
#pause_icons_dark = Image.open(script_path + '/images/controls-pause-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")

#vol_icons = Image.open(script_path + '/images/controls-vol.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
#vol_icons_dark = Image.open(script_path + '/images/controls-vol-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")

#bt_back = Image.open(script_path + '/images/bta.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
#ap_back = Image.open(script_path + '/images/airplay.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
#jp_back = Image.open(script_path + '/images/jack.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
#sp_back = Image.open(script_path + '/images/spotify.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
#sq_back = Image.open(script_path + '/images/squeeze.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")

draw = ImageDraw.Draw(img, 'RGBA')

#with SocketIO('localhost', 3000) as socketIO:
    #socketIO.emit('aaa')
#    socketIO.emit('getState', '', on_push_state)
    #socketIO.wait(seconds=1)
#    socketIO.wait_for_callbacks(seconds=1)
#    print 'with text erreicht'
#    print socketIO.emit('getState', '', on_push_state)

def main():
    while True:
        print 'dev main angesprochen'
        #socketIO.on('connect', on_connect)
        #socketIO.connect('http://localhost:3000')

        disp.set_backlight(True)
        #mit socket verbinden
        socketIO.on('pushState', on_push_state)
        # get initial state
        #socketIO.emit('getState', '', on_push_state)
        result = socketIO.on('pushState', on_push_state)
        print(result)

        result = socketIO.emit('getState', on_push_state)
        print(result)

        result = socketIO.emit('getState', on_push_state)
        print(result)

        
        #disp.display(img)
        #socketIO.wait()
        socketIO.wait_for_callbacks(seconds=1)
        result = socketIO.emit('getState', on_push_state)
        print(result)
        time.sleep(2)

if __name__ == '__main__':
    try:
       main()
       socketIO.wait()
       #socketIO.wait_for_callbacks(seconds=1)
    except KeyboardInterrupt:
        disp.reset()
        disp.set_backlight(False)
        pass

What works (somehow):

  • getting some informations from socket and print them to terminal
  • displaying status, but there is a problem, that text will be overwritten on top of the already displayed text

What dont work:

  • get socket connect without socketIO.wit()
  • loop

Pictures:
First text displayed:
display_1.jpg

second text display (it is stop and play overlayed):
display_2.jpg

Is there anybody who can give me tipps to move forward?

Thanks, AxLED

Hi volumio coders,

i got it working the way i wanted. So now my pimoroni pirate audio 3W stereo amp with 1.3" IPS display is fully supported by volumio.

Thanks to author of https://github.com/rusconi/TFT-MoodeCoverArt, i used some parts of his code.

Here is my code python (.py):

#!/usr/bin/env python

import time
from colorsys import hsv_to_rgb
from PIL import ImageFont, Image, ImageDraw, ImageStat
import os
import os.path
from os import path
import ST7789 as ST7789
from socketIO_client import SocketIO, LoggingNamespace
import requests
from io import BytesIO
from numpy import mean
import logging
# logging.getLogger('socketIO-client').setLevel(logging.DEBUG)
# logging.basicConfig()

# get the path of the script
script_path = os.path.dirname(os.path.abspath( __file__ ))
# set script path as current directory
os.chdir(script_path)


def on_connect():
    print('connect')
    return 'connected'


def on_push_state(*args):
    # print('state', args)
    # img = Image.new('RGB', (240, 240), color=(0, 0, 0, 25))
    img = Image.new('RGBA', (240, 240), color=(0, 0, 0, 25))
    status = args[0]['status'].encode('ascii', 'ignore')

    # Load albumcover or radio cover
    albumart = args[0]['albumart'].encode('ascii', 'ignore')
    # print 'Albumart0:',albumart
    # print 'Laenge Albumart0:',len(albumart)

    if len(albumart) == 0:  # to catch a empty field on start
        albumart = 'http://localhost:3000/albumart'
        # print 'Albumart1:',albumart
    if 'http:' not in albumart:
        albumart = 'http://localhost:3000'+args[0]['albumart']
        # print 'http hinzugefugt:',albumart

    # print 'Albumart2:',albumart
    response = requests.get(albumart)
    img = Image.open(BytesIO(response.content))
    img = img.resize((WIDTH, HEIGHT))

    # Light / Dark Symbols an bars, depending on background
    im_stat = ImageStat.Stat(img)
    im_mean = im_stat.mean
    mn = mean(im_mean)

    txt_col = (255, 255, 255)
    bar_col = (255, 255, 255, 255)
    dark = False
    if mn > 175:
        txt_col = (55, 55, 55)
        dark = True
        bar_col = (100, 100, 100, 225)
    if mn < 80:
        txt_col = (200, 200, 200)

    # print 'Modus dark:',dark

    # paste button symbol overlay in light/dark mode
    if status == 'play':
        if dark is False:
            img.paste(pause_icons, (0, 0), pause_icons)
        else:
            img.paste(pause_icons_dark, (0, 0), pause_icons_dark)
    else:
        if dark is False:
            img.paste(play_icons, (0, 0), play_icons)
        else:
            img.paste(play_icons_dark, (0, 0), play_icons_dark)

    # img
    # img = Image.new('RGB', (240, 240), color=(0, 0, 0, 25))
    # draw
    draw = ImageDraw.Draw(img, 'RGBA')

    top = 7
    if 'artist' in args[0]:
        x1 = 20
        w1, y1 = draw.textsize(args[0]['artist'], font_m)
        x1 = x1-20
        if x1 < (WIDTH - w1 - 20):
            x1 = 0
        if w1 <= WIDTH:
            x1 = (WIDTH - w1)//2
        draw.text((x1, top), args[0]['artist'], font=font_m, fill=txt_col)
        # print 'Artist:',args[0]['artist']

    top = 35

    if 'album' in args[0]:
        # print 'Album:',args[0]['album']
        # if args[0]['album'] != None:
        if args[0]['album'] is not None:
            x2 = 20
            w2, y2 = draw.textsize(args[0]['album'], font_s)
            x2 = x2-20
            if x2 < (WIDTH - w2 - 20):
                x2 = 0
            if w2 <= WIDTH:
                x2 = (WIDTH - w2)//2
            draw.text((x2, top), args[0]['album'], font=font_s, fill=txt_col)

    if 'title' in args[0]:
        x3 = 20
        w3, y3 = draw.textsize(args[0]['title'], font_l)
        x3 = x3-20
        if x3 < (WIDTH - w3 - 20):
            x3 = 0
        if w3 <= WIDTH:
            x3 = (WIDTH - w3)//2
            # thin border
            # shadowcolor = "black"
            # draw.text((x3-1, 105), args[0]['title'], font=font_l, fill=shadowcolor)
            # draw.text((x3+1, 105), args[0]['title'], font=font_l, fill=shadowcolor)
            # draw.text((x3, 105-1), args[0]['title'], font=font_l, fill=shadowcolor)
            # draw.text((x3, 105+1), args[0]['title'], font=font_l, fill=shadowcolor)y
        draw.text((x3, 105), args[0]['title'], font=font_l, fill=txt_col)  # fill by mean

    # volume bar
    # volume = args[0]['volume']
    # vol_x = int((float(volume)/100)*(WIDTH - 33))
    # volume = args[0]['volume']
    vol_x = int((float(args[0]['volume'])/100)*(WIDTH - 33))
    # draw.text((200, 200), str(volume), font=font_m) #volume
    draw.rectangle((5, 184, WIDTH-34, 184+8), (255, 255, 255, 145))
    draw.rectangle((5, 184, vol_x, 184+8), bar_col)

    # time bar
    if 'duration' in args[0]:
        duration = args[0]['duration']  # seconds
        # print 'duration found:',duration
        if duration != 0:
            # print 'duration ungleich 0'
            if 'seek' in args[0]:
                seek = args[0]['seek']  # time elapsed seconds
                # print 'seek found:',seek
                if seek != 0:
                    el_time = int(float(args[0]['seek'])/1000)
                    du_time = int(float(args[0]['duration']))
                    dur_x = int((float(el_time)/float(du_time))*(WIDTH-10))
                    draw.rectangle((5, 222, WIDTH-5, 222 + 12), (255, 255, 255, 145))
                    draw.rectangle((5, 222, dur_x, 222 + 12), bar_col)

    # print status + ',' + title + ',' + albumart + ', Vol:' + str(volume)
    # Draw the image on the display hardware
    disp.display(img)

socketIO = SocketIO('localhost', 3000)
socketIO.on('connect', on_connect)

# Create ST7789 LCD display class.
disp = ST7789.ST7789(
    rotation=90,  # Needed to display the right way up on Pirate Audio
    port=0,       # SPI port
    cs=1,         # SPI port Chip-select channel
    dc=9,         # BCM pin used for data/command
    backlight=13,
    spi_speed_hz=80 * 1000 * 1000
)

# Initialize display.
disp.begin()

WIDTH = 240
HEIGHT = 240
font_s = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf', 20)
font_m = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf', 24)
font_l = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf', 30)

# img = Image.new('RGB', (240, 240), color=(0, 0, 0, 25))

play_icons = Image.open('images/controls-play.png').resize((240, 240))
play_icons_dark = Image.open('images/controls-play-dark.png').resize((240, 240))
pause_icons = Image.open('images/controls-pause.png').resize((240, 240))
pause_icons_dark = Image.open('images/controls-pause-dark.png').resize((240, 240))

# vol_icons = Image.open(script_path + '/images/controls-vol.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# vol_icons_dark = Image.open(script_path + '/images/controls-vol-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")

# bt_back = Image.open(script_path + '/images/bta.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# ap_back = Image.open(script_path + '/images/airplay.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# jp_back = Image.open(script_path + '/images/jack.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# sp_back = Image.open(script_path + '/images/spotify.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# sq_back = Image.open(script_path + '/images/squeeze.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")

# draw = ImageDraw.Draw(img, 'RGBA')


def main():
    while True:
        print ('dev main angesprochen')
        disp.set_backlight(True)
        # mit socket verbinden
        socketIO.on('pushState', on_push_state)
        # get initial state
        socketIO.emit('getState', '', on_push_state)
        socketIO.wait()
        # socketIO.wait_for_callbacks(seconds=1)
        time.sleep(1)

if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            img = Image.new('RGB', (240, 240), color=(0, 0, 0))
            draw = ImageDraw.Draw(img)
            draw.rectangle((0, 0, 240, 240), (0, 0, 0))
            disp.display(img)
            disp.set_backlight(False)
            pass

I let this python script start with raspberry in rc.local, so after booting volumio, the display shows some informations.

Maybe this thread is helping some other volumio users for the use of:

  • pimoroni pirate audio 3W stereo amp with 1.3" IPS display
  • websocket calls in python
  • etc.

Greetings

AxLED

4 Likes

Well done for solving AxLED. Sounds like your experiments may well make the basis for a ‘Guide’

Hi AxLED, thanks for sharing your work, I tried your instructions with no luck and very little know-how in Python. Only got the buttons working and the display showed snow, like the old TVs, if you can relate. Now is not even booting up.

Can you do a Step by step guide for noobs?

Currently working on a portable Zero W with Volumio and using the display is the missing part. I can share my work with your contribution and if you like it maybe print for you a couple of 3D cases to try it out.

Thanks again, Cheers

J.

Hi @Jorge_Daetz,

(1) first of all you have to install some depencies:
Open a terminal and enter:

sudo apt-get update
sudo apt-get install python-rpi.gpio python-spidev python-pip python-pil python-numpy

sudo pip install st7789

(2) second you have to put some lines in /boot/config.txt, open a terminal and enter:
sudo nano /boot/config.txt

and add following lines

####### needed for Amp Hat ####
dtparam=spi=on
gpio=25=op,dh
####### Fix for Button X Y ####
gpio=16=pu
gpio=20=pu

and reboot.

(3) Now create a python file with my modified code:

#!/usr/bin/env python

import time
from colorsys import hsv_to_rgb
from PIL import ImageFont, Image, ImageDraw, ImageStat
import os
import os.path
from os import path
import ST7789 as ST7789
from socketIO_client import SocketIO, LoggingNamespace
import requests
from io import BytesIO
from numpy import mean
import sys
import logging
# logging.getLogger('socketIO-client').setLevel(logging.DEBUG)
# logging.basicConfig()
import signal
import RPi.GPIO as GPIO

# get the path of the script
# script_path = os.path.dirname(os.path.abspath( __file__ ))
script_path = os.path.dirname(os.path.abspath(__file__))
# set script path as current directory
os.chdir(script_path)


def on_connect():
    print('connect')


def on_disconnect():
    print('disconnect')
    img = Image.new('RGBA', (240, 240), color=(0, 0, 0, 25))
    img = Image.open('/volumio/app/plugins/miscellanea/albumart/default.jpg')
    img = img.resize((WIDTH, HEIGHT))
    draw = ImageDraw.Draw(img, 'RGBA')
    draw.text((10, 200), 'shuting down ...', font=font_m, fill=(255, 255, 255))
    disp.display(img)


def on_push_state(*args):
    img = Image.new('RGBA', (240, 240), color=(0, 0, 0, 25))
    global status
    global service
    status = args[0]['status'].encode('ascii', 'ignore')
    service = args[0]['service'].encode('ascii', 'ignore')
    # Load albumcover or radio cover
    albumart = args[0]['albumart'].encode('ascii', 'ignore')

    if len(albumart) == 0:  # to catch a empty field on start
        albumart = 'http://localhost:3000/albumart'
    if 'http:' not in albumart:
        albumart = 'http://localhost:3000'+args[0]['albumart']

    response = requests.get(albumart)
    img = Image.open(BytesIO(response.content))
    img = img.resize((WIDTH, HEIGHT))

    # Light / Dark Symbols an bars, depending on background
    im_stat = ImageStat.Stat(img)
    im_mean = im_stat.mean
    mn = mean(im_mean)

    txt_col = (255, 255, 255)
    # bar_col = (255, 255, 255, 255)
    bar_bgcol = (200, 200, 200)
    bar_col = (255, 255, 255)
    dark = False
    if mn > 175:
        txt_col = (55, 55, 55)
        dark = True
        # bar_col = (100, 100, 100, 225)
        bar_bgcol = (255, 255, 255)
        bar_col = (100, 100, 100)
    if mn < 80:
        txt_col = (200, 200, 200)

    # paste button symbol overlay in light/dark mode
    if status == 'play':
        if dark is False:
            img.paste(pause_icons, (0, 0), pause_icons)
        else:
            img.paste(pause_icons_dark, (0, 0), pause_icons_dark)
    else:
        if dark is False:
            img.paste(play_icons, (0, 0), play_icons)
        else:
            img.paste(play_icons_dark, (0, 0), play_icons_dark)

    draw = ImageDraw.Draw(img, 'RGBA')

    top = 7
    if 'artist' in args[0]:
        x1 = 20
        w1, y1 = draw.textsize(args[0]['artist'], font_m)
        x1 = x1-20
        if x1 < (WIDTH - w1 - 20):
            x1 = 0
        if w1 <= WIDTH:
            x1 = (WIDTH - w1)//2
        draw.text((x1, top), args[0]['artist'], font=font_m, fill=txt_col)
    top = 35

    if 'album' in args[0]:
        if args[0]['album'] is not None:
            x2 = 20
            w2, y2 = draw.textsize(args[0]['album'], font_s)
            x2 = x2-20
            if x2 < (WIDTH - w2 - 20):
                x2 = 0
            if w2 <= WIDTH:
                x2 = (WIDTH - w2)//2
            draw.text((x2, top), args[0]['album'], font=font_s, fill=txt_col)

    if 'title' in args[0]:
        x3 = 20
        w3, y3 = draw.textsize(args[0]['title'], font_l)
        x3 = x3-20
        if x3 < (WIDTH - w3 - 20):
            x3 = 0
        if w3 <= WIDTH:
            x3 = (WIDTH - w3)//2
            # thin border
            # shadowcolor = "black"
            # draw.text((x3-1, 105), args[0]['title'], font=font_l,
            # fill=shadowcolor)
            # draw.text((x3+1, 105), args[0]['title'], font=font_l,
            # fill=shadowcolor)
            # draw.text((x3, 105-1), args[0]['title'], font=font_l,
            # fill=shadowcolor)
            # draw.text((x3, 105+1), args[0]['title'], font=font_l,
            # fill=shadowcolor)
        draw.text((x3, 105), args[0]['title'], font=font_l, fill=txt_col)  # fill by mean

    # volume bar
    vol_x = int((float(args[0]['volume'])/100)*(WIDTH - 33))
    # draw.rectangle((5, 184, WIDTH-34, 184+8), (255, 255, 255, 145))
    draw.rectangle((5, 184, WIDTH-34, 184+8), bar_bgcol)  # background
    draw.rectangle((5, 184, vol_x, 184+8), bar_col)

    # time bar
    if 'duration' in args[0]:
        duration = args[0]['duration']  # seconds
        if duration != 0:
            if 'seek' in args[0]:
                seek = args[0]['seek']  # time elapsed seconds
                if seek != 0:
                    el_time = int(float(args[0]['seek'])/1000)
                    du_time = int(float(args[0]['duration']))
                    dur_x = int((float(el_time)/float(du_time))*(WIDTH-10))
                    # draw.rectangle((5, 222, WIDTH-5, 222 + 12), (255, 255, 255, 145))
                    draw.rectangle((5, 222, WIDTH-5, 222 + 12), bar_bgcol)  # background
                    draw.rectangle((5, 222, dur_x, 222 + 12), bar_col)

    # Draw the image on the display hardware
    disp.display(img)

socketIO = SocketIO('localhost', 3000)
socketIO.on('connect', on_connect)

# Create ST7789 LCD display class.
disp = ST7789.ST7789(
    rotation=90,  # Needed to display the right way up on Pirate Audio
    port=0,       # SPI port
    cs=1,         # SPI port Chip-select channel
    dc=9,         # BCM pin used for data/command
    backlight=13,
    spi_speed_hz=80 * 1000 * 1000
)

# Initialize display.
disp.begin()

WIDTH = 240
HEIGHT = 240
font_s = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf', 20)
font_m = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf', 24)
font_l = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf', 30)

play_icons = Image.open('images/controls-play.png').resize((240, 240))
play_icons_dark = Image.open('images/controls-play-dark.png').resize((240, 240))
pause_icons = Image.open('images/controls-pause.png').resize((240, 240))
pause_icons_dark = Image.open('images/controls-pause-dark.png').resize((240, 240))

# vol_icons = Image.open(script_path + '/images/controls-vol.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# vol_icons_dark = Image.open(script_path + '/images/controls-vol-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")

# bt_back = Image.open(script_path + '/images/bta.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# ap_back = Image.open(script_path + '/images/airplay.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# jp_back = Image.open(script_path + '/images/jack.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# sp_back = Image.open(script_path + '/images/spotify.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")
# sq_back = Image.open(script_path + '/images/squeeze.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA")

# 100
# BUTTONS = [5, 6, 16, 20]
BUTTONS = [16]
LABELS = ['A', 'B', 'X', 'Y']
# Set up RPi.GPIO with the "BCM" numbering scheme
GPIO.setmode(GPIO.BCM)
# Buttons connect to ground when pressed, so we should set them up
# with a "PULL UP", which weakly pulls the input signal to 3.3V.
GPIO.setup(BUTTONS, GPIO.IN, pull_up_down=GPIO.PUD_UP)


def handle_button(pin):
    label = LABELS[BUTTONS.index(pin)]
    print("Button press detected on pin: {} label: {}".format(pin, label))
    if pin == 5:
        # print('Play/pause')
        print(status, service)
        if (status == 'play') and (service == 'webradio'):
            socketIO.emit('stop')
        elif (status == 'play'):
            socketIO.emit('pause')
        else:
            socketIO.emit('play')
    if pin == 6:
        print('volDown')
        socketIO.emit('volume', '-')
    if pin == 16:
        print('initalisiere Shutdown')
        on_disconnect()
        os.system("sudo shutdown -h now")
        sys.exit()
    if pin == 20:
        print('volUp')
        socketIO.emit('volume', '+')
# 100


def main():
    while True:
        print ('def main angesprochen')
        # 100
        for pin in BUTTONS:
            GPIO.add_event_detect(pin, GPIO.FALLING, handle_button, bouncetime=100)
        # 100
        disp.set_backlight(True)
        # mit socket verbinden
        socketIO.on('pushState', on_push_state)
        # get initial state
        socketIO.emit('getState', '', on_push_state)
        socketIO.wait()
        # socketIO.wait_for_callbacks(seconds=1)
        # time.sleep(1)
        time.sleep(0.01)

if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            img = Image.new('RGB', (240, 240), color=(0, 0, 0))
            draw = ImageDraw.Draw(img)
            draw.rectangle((0, 0, 240, 240), (0, 0, 0))
            disp.display(img)
            disp.set_backlight(False)
            pass

The amp and the buttons should work with starting volumio (and GPIO Button Plugin).
(4) The display can be startet as follows, open a terminal and enter:
python /pathtoyourfile/file.py
Now the display should work or you should get at least an error message in your terminal.

If everything works, you can put the python file in autostart to execute it while booting.

Regards

AxLED

Fettgedruckter Text

2 Likes

Thanks a lot for the quick response. Will try it out this evening and let you know

Cheers

J.

Hi AxLED

Thanks again, now is clear what I have to do.

While trying your instructions I got this error

volumio@volumio:~/dac$ python daclcd.py
Traceback (most recent call last):
File “daclcd.py”, line 10, in
from socketIO_client import SocketIO, LoggingNamespace
ImportError: No module named socketIO_client
volumio@volumio:~/dac$ cd…
volumio@volumio:~$ cd…
volumio@volumio:/home$ cd /boot
volumio@volumio:/boot$ python /home/volumio/dac/daclcd.py
Traceback (most recent call last):
File “/home/volumio/dac/daclcd.py”, line 10, in
from socketIO_client import SocketIO, LoggingNamespace
ImportError: No module named socketIO_client

**I tried then to install SocketIO, not sure if this was the way to go

volumio@volumio:/boot$ pip install -U socketIO-client --user
Downloading/unpacking socketIO-client
Downloading socketIO-client-0.7.2.tar.gz
Running setup.py (path:/tmp/pip-build-uFuro9/socketIO-client/setup.py) egg_info for package socketIO-client

warning: no files found matching '*.html'
warning: no files found matching '*.js'
warning: no previously-included files matching '*.pyc' found anywhere in distribution

Downloading/unpacking requests>=2.7.0 (from socketIO-client)
Downloading requests-2.24.0-py2.py3-none-any.whl (61kB): 61kB downloaded
Downloading/unpacking six from https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl#sha256=8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced (from socketIO-client)
Downloading six-1.15.0-py2.py3-none-any.whl
Downloading/unpacking websocket-client (from socketIO-client)
Downloading websocket_client-0.57.0-py2.py3-none-any.whl (200kB): 200kB downloaded
Downloading/unpacking certifi>=2017.4.17 (from requests>=2.7.0->socketIO-client)
Downloading certifi-2020.6.20-py2.py3-none-any.whl (156kB): 156kB downloaded
Downloading/unpacking idna>=2.5,<3 (from requests>=2.7.0->socketIO-client)
Downloading idna-2.9-py2.py3-none-any.whl (58kB): 58kB downloaded
Downloading/unpacking urllib3>=1.21.1,!=1.25.0,!=1.25.1,<1.26 (from requests>=2.7.0->socketIO-client)
Downloading urllib3-1.25.9-py2.py3-none-any.whl (126kB): 126kB downloaded
Downloading/unpacking chardet>=3.0.2,<4 (from requests>=2.7.0->socketIO-client)
Downloading chardet-3.0.4-py2.py3-none-any.whl (133kB): 133kB downloaded
Installing collected packages: socketIO-client, requests, six, websocket-client, certifi, idna, urllib3, chardet
Running setup.py install for socketIO-client

warning: no files found matching '*.html'
warning: no files found matching '*.js'
warning: no previously-included files matching '*.pyc' found anywhere in distribution

Successfully installed socketIO-client requests six websocket-client certifi idna urllib3 chardet
Cleaning up…

After that running the script gave me this result

volumio@volumio:~/dac$ python daclcd.py
Traceback (most recent call last):
File “daclcd.py”, line 177, in
font_s = ImageFont.truetype(script_path + ‘/fonts/Roboto-Medium.ttf’, 20)
File “/usr/lib/python2.7/dist-packages/PIL/ImageFont.py”, line 240, in truetype
return FreeTypeFont(font, size, index, encoding)
File “/usr/lib/python2.7/dist-packages/PIL/ImageFont.py”, line 137, in init
self.font = core.getfont(font, size, index, encoding)
IOError: cannot open resource

At this point the display turned on but with “snow” on the screen, not really rendering anything.

Is there a missing dependency with SocketIO? something else?

As I said, these are for me first steps on working with scripts, the problem might be obvious for someone with know how.

Thanks again
J.

@Jorge_Daetz,

So the first steps are made.

To your second problem:
I forget that i have a “font” and a “image” folder in that folder, where the daclcd.py is located.

yourfolder
|-daclcd.py
|-fonts
_|-Roboto-Medium.ttf
|-images
_|-airplay.png
_|-bta.png
_|-controls-pause.png
_|-controls-pause-dark.png
_|-controls-play.png
_|-controls-play-dark.png
_|-controls-vol.png
_|-controls-vol-dark.png
_|-default-cover-v6.jpg
_|-jack.png
_|-spotifiy.png
_|-squeeze.png

See attached zip. So if you copy the files in the right place you should come further.
fonts_and_images.zip (259,6 KB)

To your first problem (maybe already solved by yourself, so only try if adding the missing folders dont work):
I can remember that install of socket.io was difficult and i am not sure which one is needed, so i installed the following. Open a terminal and enter:

sudo easy_install pip

pip install socketIO-client-2
pip install -U socketIO-client –user (bzw. mit sudo)
pip install "python-socketio[client]"

it can be, that you have to execute some of the code above with sudo in front, depends on the terminalmessage if executed without sudo.

Regards

AxLED

1 Like

Also may need to change the line that checks for ‘http:’ to just ‘http’ as some images are https

@kenhayward
Thanks for the hint, i found out by myself in the meantime but unfortunatelly i am not able to edit my “old” post.

AxLED

As a relative newbie to raspberry pi I really appreciated the step by step instructions and I managed to get this working… My python script executes successfully. Although I have to ctrl>C to stop it, that’s OK right?

But I can’t get it to start on booting. I tried following instructions on using systemd

sample.service file contains

[Unit]
Description=PAScreen
After=multi-user.target

[Service]
Type=simple
ExecStart=/user/bin/python /volumio/pascreen/pascreen.py

[Install]
WantedBy=multi-user.target

Running status I get failed the following on running a status check

@dasmyler
if running pascreen.py manually works then most of the work is done.
I put the .py script in autostart the following way:
Step 1:
Set permissions so that your.py is executable
sudo chmod +x /pathwhatever/your.py

Step 2:
put path in rc.local
sudo nano /etc/rc.local

put the path and your .py scrip before “exit 0” (dont forget the “&” ampersand at the and)

/pathwhatever/your.py &
exit 0

This way it works on my Pi Zero W

AxLED

Thank you! That works, wasn’t using the ampersand when I tried it.

Hi,

i improved the code and put it on github.
Details see Volumio pirate audio post

Regards

AxLED