Hi All,
I have been using Volumio for a while in headless mode. I wanted to have the touch screen as well so for Christmas I was brought the official Raspberry Pi 7" touch screen. I made/modified a stand for it to go in and also had a button to be able to control the backlight level of the display. I used a number of posts/sites to get the screen working how I wanted so I made a guide to help me in the future. I thought I would share if anyone else would find it useful. If you don’t want the button for backlight control stop at the “Install Python GPIO” section and reboot device!
Hardware
https://www.thingiverse.com/thing:3318343
The button is connected to pins 37 and 39 and the LED in the button is connected between pins 33 and 39 with a 2k2ohmn resistor (draws a max of about 0.4mA with that resistor - the LED has a forward voltage of 2.5V). I chose such a high value as I only wanted the LED ring to glow and not illuminate, an annoyance of mine with many “proper” products with their blinding LEDs!
Install Volumio as normal
Install and activate touchscreen plugin in Volumio Plugins
Enable SSH:
goto http://VOLUMIOIP/dev in your browser
Click ENABLE button for SSH
Load PuTTY (or other SSH client) and log into Volumio
(default username: volumio - default password: volumio)
Update Packages:
sudo apt-get update
Remove mouse pointer
[spoiler]
sudo nano /lib/systemd/system/volumio-kiosk.service
find line:
ExecStart=/usr/bin/startx /etc/X11/Xsession /opt/volumiokiosk.sh
change to:
ExecStart=/usr/bin/startx /etc/X11/Xsession /opt/volumiokiosk.sh -- -nocursor
[/spoiler]
Stop screen blanking and crashed message
[spoiler]
sudo nano /opt/volumiokiosk.sh
change lines:
xset +dpms
xset s blank
xset 0 0 120
to:
xset -dpms
xset s off
#xset 0 0 120
When you reboot sometimes the browser doesn’t quit properly and you end up with the request box asking to restore session. To stop that happening also change the line:
--user-data-dir='/data/volumiokiosk' --no-sandbox http://localhost:3000
to
--user-data-dir='/data/volumiokiosk' --no-sandbox --app=http://localhost:3000
[/code][/spoiler]
[b][i]Install and activate Matchbox onscreen keyboard[/i][/b]
[spoiler]First install the software:
[code]
sudo apt-get install matchbox-window-manager matchbox-keyboard
[/code]
Edit volumiokiosk.sh to activate keyboard
[code]
sudo nano /opt/volumiokiosk.sh
[/code]
Add the following after the "xset" commands:
[code]matchbox-keyboard -d &
matchbox-window-manager -use_titlebar no &[/code]
Then comment out the line:
[code]
openbox-session &
[/code]
to
[code]
#openbox-session &
[/code]
Exit and save [CTRL]+X and then press Y to save.
Next update the keyboard.xml for something more touch friendly for our needs (thanks to Xoliul for this! - it gives a simple QWERTY layout with numbers but nothing more and should be enough for most needs on this. Of course you can edit it and make your own!)
Backup and edit the keyboard.xml with:
[code]cd /usr/share/matchbox-keyboard/
sudo mv keyboard.xml keyboard.xml_old
sudo nano keyboard.xml[/code]
In nano copy the following:
[code]<?xml version="1.0" encoding="UTF-8"?>
<keyboard>
<layout id="default keyboard">
<row>
<key>
<default display="Q" action="q"/>
</key>
<key>
<default display="W" action="w"/>
</key>
<key>
<default display="E" action="e"/>
</key>
<key>
<default display="R" action="r"/>
</key>
<key>
<default display="T" action="t"/>
</key>
<key>
<default display="Y" action="y"/>
</key>
<key>
<default display="U" action="u"/>
</key>
<key>
<default display="I" action="i"/>
</key>
<key>
<default display="O" action="o"/>
</key>
<key>
<default display="P" action="p"/>
</key>
<key>
<default display="1"/>
</key>
<key>
<default display="2"/>
</key>
<key fill="true">
<default display="⌫" action="backspace"/>
<!-- <default display="Bksp" action="backspace"/> -->
</key>
</row>
<row>
<key>
<default display="A" action="a"/>
</key>
<key>
<default display="S" action="s"/>
</key>
<key>
<default display="D" action="d"/>
</key>
<key>
<default display="F" action="f"/>
</key>
<key>
<default display="G" action="g"/>
</key>
<key>
<default display="H" action="h"/>
</key>
<key>
<default display="J" action="j"/>
</key>
<key>
<default display="K" action="k"/>
</key>
<key>
<default display="L" action="l"/>
</key>
<key>
<default display="3" />
</key>
<key>
<default display="4" />
</key>
<key>
<default display="5" />
</key>
<key fill="true">
<default display="⏎" action="return"/>
</key>
</row>
<row>
<key>
<default display="Z" action="z"/>
</key>
<key>
<default display="X" action="x"/>
</key>
<key>
<default display="C" action="c"/>
</key>
<key>
<default display="V" action="v"/>
</key>
<key>
<default display="B" action="b"/>
</key>
<key>
<default display="N" action="n"/>
</key>
<key>
<default display="M" action="m"/>
</key>
<key>
<default display="6" />
</key>
<key>
<default display="7" />
</key>
<key>
<default display="8" />
</key>
<key>
<default display="9" />
</key>
<key>
<default display="0" />
</key>
<key fill="true">
<default display="␣" action="space" />
</key>
</row>
</layout>
</keyboard>[/code]
Again close and save the file then reboot to see your work![/spoiler]
[b][i]Move track and volume controls up (stops them clipping on the bottom of the screen)[/i][/b]
[b][size=150]CAUTION [/size][/b]- You are editing Volumio's Files which will prevent updating. To update you will need to restore the file using the Factory Reset in the System settings
[spoiler][code]
cd /volumio/http/www/styles
sudo nano app-013f2d5c5e.css
press [CTRL]+W to search and type in "volumeManager{margin-top"
this should show the line:
[code]
@media (max-width:767px){#trackManagerWrapper{left:-30px;right:-30px}}#trackManager,.volumeManager{margin-top:110px}
[/code]
change margin-top:110px to margin-top:55px
You can also search for:
webkit-scrollbar{width:10px;height:10px}:
and change the width to a larger number to make the scroll bar more finger friendly (40px should be fine)[/spoiler]
Install Python GPIO
[spoiler]Download:
wget https://sourceforge.net/projects/raspberry-gpio-python/files/raspbian-wheezy/python-rpi.gpio_0.6.2~wheezy-1_armhf.deb
(check version here: [url]https://sourceforge.net/projects/raspberry-gpio-python/files/raspbian-wheezy/[/url] and replace "python-rpi.gpio_0.6.2~wheezy-1_armhf.deb" with current version)
Install:
sudo dpkg -i python-rpi.gpio_0.6.2~wheezy-1_armhf.deb
[/spoiler]
Install Python backlight library:
[spoiler]Install PIP:
sudo apt install python-pip
Install backlight library:
sudo pip install rpi_backlight
[/spoiler]
Setup button script:
[spoiler]Note: When updating just copy new code over old (or edit lines) and reboot machine
mkdir scripts
cd scripts
nano bl-control.py
Paste following:
[code]#!/bin/python
########################## User Variables ###########################
screenDelay = 30 # number of minutes before turning off the screen #
blState = 2 # default brightness of the backlight (1-3) #
LOWBRIGHT = 32 # lowest brightness level # Set these between #
MIDBRIGHT = 64 # medium brightness level # 11-255 for custom #
HIGBRIGHT = 192 # highest brightness level # brightness levels #
#####################################################################
import RPi.GPIO as GPIO
import time
import rpi_backlight as bl
import subprocess
import os
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(13, GPIO.OUT)
led = GPIO.PWM(13, 2000)
led.start(100)
ledLvl = 100
ledDir = 0
buttonState = 0 #current button state
lastButtonState = 0 #previous button state
timePressed = 0 #when was button pressed
stateChange = “” #holds command when changing bl state
lastStatus = “” #stores playback state when turning off bl
lastBlState = blState #previous backlight state (primed with default
lastPlayState = “play” #what was volumio doing when bl turned off
pausedTime = 0 #when was unit paused
gamma = 2.8 #gamma adjust for LED (makes breathing smooth)
max_in = 100.0 #the maximum level to call for adjustment
max_out = 100.0 #the maximum level for PWM (100 for RPi)
levelOutput = 0.0 #variable to hold the adjusted level output
screenDelay = screenDelay * 60 # change from minutes to seconds for timer
bl.set_power(True) #turn on bl
bl.set_brightness(64, smooth = True, duration = 1) #set bl level
while 1: #repeat continously
buttonState = 1 - GPIO.input(26) #invert state due to pullup
try: #trys to open volumio and if it hasn't loaded waits 5 seconds to try again - this is as the script loads befor volumio and was causing the script to fail to load
status = subprocess.check_output("volumio status | sed -e 's/true/True/g' -e 's/false/False/g' -e 's/null/False/g'", shell=True) #find out current status of volumio
status = eval(status)
if (status["status"] == "pause" and lastPlayState == "play"): # checks if volumio has just paused
pausedTime = time.time() # store the time volumio paused
elif (status["status"] == "stop" and lastPlayState == "play"): # checks if volumio has just stopped
pausedTime = time.time()
elif (status["status"] == "play" and lastPlayState <> "play" and blState == 0): # has volumio started playing and is the backlight off
stateChange = "resume" # restore backlight
if (time.time() - pausedTime > screenDelay and status["status"] <> "play" and blState <> 0): # check if paused for longer than "screenDelay" seconds, volumio is not playing and backlight is on
stateChange = "blOff" # turn off backlight
if (buttonState == 1 and lastButtonState == 0):
timePressed = time.time() #store time button pressed
elif (buttonState == 1 and lastButtonState == 1): #button held
if (time.time() - timePressed > 2): #if held for more than two seconds turn off bl
stateChange = "blOff"
elif (buttonState == 0 and lastButtonState == 1): #button released
if (time.time() - timePressed <= 2): #if button released before two seconds passed change brightness
pausedTime = time.time() # update pause time to reset the timer
if (lastStatus == "play"): # checks to see if unit was previously paused by using the button to turn off backlight and resumes again
stateChange = "resume" # resume screen brightness and playback
else: # otherwise just move to next brightness level
stateChange = "nextBL"
elif (buttonState == 0 and lastButtonState == 0): #button not pressed
if (blState == 0): #backlight if off, 'breath' the LED
levelOutput = ((ledLvl/max_in) ** gamma) * max_out #gamma calculation
if (levelOutput > 100): levelOutput = 100 #clamp output to max PWM level (100 for RPi)
if (ledDir == 0): #ramp intensity down
led.ChangeDutyCycle(levelOutput) #set PWM output from gamma corrected level
ledLvl = ledLvl - 1 #reduce brightness for next pass
if (ledLvl == 1): #when brightness at lowest point (not 0 as LED goes off and looks odd)
ledDir = 1 #switch brightness direction to increase
else: #ramp intensity up
led.ChangeDutyCycle(levelOutput)
ledLvl = ledLvl + 1
if (ledLvl == 100): #switch direction when at max brightness
ledDir = 0
time.sleep(0.05) #if no button being pressed sleep for 50mSec - prevents loading a thread
if (stateChange == "blOff"):
os.system("volumio volume mute") #mute volume
if (status["status"] == "play"): #check if currently playing
os.system("volumio pause") #pause playback
lastStatus = "play" #store that the unit was playing when backlight turned off
lastBlState = blState #store the current backlight level
blState = 0 #set to backlight off
stateChange = ""
bl.set_brightness(11, smooth = True, duration = 1) #reduce brightness to min
bl.set_power(False) #then turn off completly.
elif (stateChange == "nextBL" or stateChange == "resume"):
led.ChangeDutyCycle(100) #turn on led
if (stateChange == "nextBL"): #chang to next bl level
if (blState == 0): #restore bl level if previously off
blState = lastBlState
else:
blState = blState - 1 #next bl level
if (blState < 1): #roll-over
blState = 3
elif (stateChange == "resume"): #restore bl level and start playing (if paused when turning off bl)
os.system("volumio volume unmute") #unmute volume
blState = lastBlState
if (lastStatus == "play"):
os.system("volumio play")
lastStatus = ""
# next section sets current brightness level. Change the first number in bl.set_brightness
# between 11-255 if other brightness levels required.
if (blState == 1):
bl.set_power(True)
bl.set_brightness(LOWBRIGHT, smooth = True, duration = 1)
elif (blState == 2):
bl.set_power(True)
bl.set_brightness(MIDBRIGHT, smooth = True, duration = 1)
elif (blState == 3):
bl.set_power(True)
bl.set_brightness(HIGBRIGHT, smooth = True, duration = 1)
stateChange = ""
lastPlayState = status["status"]
lastButtonState = buttonState #store current button state to determine if button still being pressed or not.
except: #wait five seconds for volumio to load
time.sleep(5)[/code]
At the top of the script there are the user variable. These allow the default settings to be changed for the backlight time delay and the default backlight level as well as the backlight brightness for each level
########################## User Variables ###########################
screenDelay = 30 # number of minutes before turning off the screen #
blState = 2 # default brightness of the backlight (1-3) #
LOWBRIGHT = 32 # lowest brightness level # Set these between #
MIDBRIGHT = 64 # medium brightness level # 11-255 for custom #
HIGBRIGHT = 192 # highest brightness level # brightness levels #
#####################################################################
Press [CTRL]+X and save file.
Set bl-control.py to boot on startup:
sudo nano /etc/rc.local
before the final “exit 0” paste:
python /home/volumio/scripts/bl-control.py &
(the “&” is important to allow the script to run in the background!)[/spoiler]
Reboot device!
sudo reboot
If all goes to plan you should reboot and pressing the button will change the backlight level and holding should turn it off, with the LED “breathing”.
Sites and posts that helped me with this
[spoiler]https://volumio.org/forum/volumio-touchscreen-mouse-cursor-t6629.html
https://volumio.org/forum/screentimeout-rpi-touchscreen-t5059.html#p23854
https://volumio.org/forum/installing-rpi-gpio-volumio-t3544.html#p15591
https://github.com/linusg/rpi-backlight
https://www.hackster.io/glowascii/raspberry-pi-shutdown-restart-button-d5fd07
https://stackoverflow.com/questions/48133509/python-2-7-9-subprocess-convert-check-output-to-dictionary-volumio
https://learn.adafruit.com/led-tricks-gamma-correction/the-longer-fix
https://raspberrypi.stackexchange.com/questions/68734/how-do-i-disable-restore-pages-chromium-didnt-shut-down-correctly-prompt
https://volumio.org/forum/virtual-keyboard-kiosk-mode-t4995.html[/spoiler]
Updates:
2018/12/29: updated python script to pause music (if playing) when turning off backlight and resume when turning back on
2019/01/01: added gamma correction for LED brightness to make it look smoother
2019/01/02: warning about changing positions of volume and track
2019/01/06: Updated to remove Chromium restore pages dialog if it doesn’t get closed correctly on shutdown/reboot
2019/01/11: Added section to install the on screen keyboard “matchbox-keyboard”
2019/01/12: Updated python script to turn off screen when paused for a given amount.
2019/02/02: Removed bug where playback didn’t resume after turning off the backlight manually (thanks to ReM.2311for finding it). Added ability to easy change the backlight levels with the “User Variables” section. All 3 settings can be adjust to what ever is preferred. Mutes audio on pause and un-mutes on playback (again thanks to ReM.2311 for the suggestion!)
Old Script
[spoiler][code][code]#!/bin/python
import RPi.GPIO as GPIO
import time
import rpi_backlight as bl
import subprocess
import os
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(13, GPIO.OUT)
led = GPIO.PWM(13, 2000)
led.start(100)
ledLvl = 100
ledDir = 0
buttonState = 0 #current button state
lastButtonState = 0 #previous button state
timePressed = 0 #when was button pressed
lastBrightness = 0 #brightness when backlight turned off
lastStatus = “” #was the volumio playing when turning off screen
blState = 2 #current bl level
bl.set_power(True) #turn on bl
bl.set_brightness(64, smooth = True, duration = 1) #set bl level
gamma = 2.8 #gamma adjust for LED (makes breathing more consistant)
max_in = 100.0 #the maximum level to call for adjustment
max_out = 100.0 #the maximum level for PWM (100 for RPi)
levelOutput = 0.0 #variable to hold the adjusted level output
while 1: #repeat continously
buttonState = 1 - GPIO.input(26) #invert state due to pullup
if (buttonState == 1 and lastButtonState == 0): #button pressed
timePressed = time.time() #store time button pressed
elif (buttonState == 1 and lastButtonState == 1): #button held
if (time.time() - timePressed > 2): #if held for more than two seconds turn off bl
status = subprocess.check_output("volumio status | sed -e 's/true/True/g' -e 's/false/False/g' -e 's/null/False/g'", shell=True)
status = eval(status)
if (status["status"] == "play"):
os.system("volumio pause")
lastStatus = "play"
lastBrightness = blState #store current bl level
blState = 0 #set bl level to off
bl.set_brightness(11, smooth = True, duration = 1) #reduce bl down
bl.set_power(False) #turn bl off
ledLvl = 100
ledDir = 0
elif (buttonState == 0 and lastButtonState == 1): #button released
if (time.time() - timePressed <= 2): #if button released before two seconds passed change brightness
if (lastBrightness > 0): #determines if bl was off and reset to bl level before turning off
blState = lastBrightness
lastBrightness = 0 #reset
if (lastStatus == "play"):
os.system("volumio play")
lastStatus = ""
else: #other wise go to next bl level
blState = blState - 1
if (blState < 1): #roll-over
blState = 3
#next section sets current level. Change the first number in bl.set_brightness between 11-255 if
#other brightness levels required. Ignore the blState == 0.
if (blState == 0):
bl.set_brightness(11, smooth = True, duration = 1)
bl.set_power(False)
elif (blState == 1):
bl.set_power(True)
bl.set_brightness(32, smooth = True, duration = 1)
elif (blState == 2):
bl.set_power(True)
bl.set_brightness(64, smooth = True, duration = 1)
elif (blState == 3):
bl.set_power(True)
bl.set_brightness(192, smooth = True, duration = 1)
elif (buttonState == 0 and lastButtonState == 0): #button not pressed
if (blState == 0): #backlight if off, 'breath' the LED
levelOutput = ((ledLvl/max_in) ** gamma) * max_out #gamma calculation
if (levelOutput > 100): levelOutput = 100 #clamp output to max PWM level (100 for RPi)
if (ledDir == 0): #ramp intensity down
led.ChangeDutyCycle(levelOutput) #set PWM output from gamma corrected level
ledLvl = ledLvl - 1 #reduce brightness for next pass
if (ledLvl == 1): #when brightness at lowest point (not 0 as LED goes off and looks odd)
ledDir = 1 #switch brightness direction to increase
else: #ramp intensity up
led.ChangeDutyCycle(levelOutput)
ledLvl = ledLvl + 1
if (ledLvl == 100): #switch direction when at max brightness
ledDir = 0
else:
led.ChangeDutyCycle(100)
time.sleep(0.05) #if no button being pressed sleep for 50mSec - prevents loading a thread
lastButtonState = buttonState #store current button state to determine if button still being pressed or not.
[/code][/code][/spoiler]