Hello to everyone,
I’m new to this forum and also new to DietPi (it’s absolutely fantastic) but would like to post a little “How-To” about how to modify “dietpi-cloudshell” for MPD (Music Player Daemon Internet Radio).
First of all I modified Scene 4 to show the following MPD information on my LCD display:
(sorry I’m too lazy to create a new scene
)
MPD current Volume %
MPD current Channel / total available Channels
MPD current Station - Artist - Song
example on [scene: 4]:
Sat 29/09/18 - 17:37
MPD Internet Radio:
Volume : 76%
Channel: 59/59
Current Station - Song:
ANTENNE VORARLBERG - Lounge: Milan Euringer and Tube & Berger - Lovebreak
Note: “MPD current Station - Artist - Song” might take more than one line to show, this is why I left the last three lines empty
I also modified another scene (5) to have just a single page for essential system information (wifi SSID added):
example on [scene 5]
Sat 29/09/18 - 17:40
System information:
IP : 192.168.1.76
Signal : -67%
SSID : default
Cpu : 35.6929%
Temp : 48’c
SD space: 23%
Memory Usage: 46/433MB
All the remaining scenes could be deactivated.
First of all, you should backup the original cloudshell file, just in case you may want to go back to the original version:
sudo cp /DietPi/dietpi/dietpi-cloudshell /DietPi/dietpi/dietpi-cloudshell.back
This is my “/DietPi/dietpi/dietpi-cloudshell” file modified:
#!/bin/bash
{
#////////////////////////////////////
# DietPi Cloudshell MPD mod - Scenes 4 & 5 (disable all the others)
#
#////////////////////////////////////
# Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com
# Modifies by pilovis - Italy
#////////////////////////////////////
#
# Info:
# - System Stats for Cloudshell (or monitor/terminal)
#
# Usage:
# dietpi-cloudshell = Config Menu
# dietpi-cloudshell 1 = Run
# dietpi-cloudshell 2 = Run + Skip intro
#////////////////////////////////////
#Import DietPi-Globals ---------------------------------------------------------------
. /DietPi/dietpi/func/dietpi-globals
G_CHECK_ROOT_USER
export G_PROGRAM_NAME='DietPi-Cloudshell'
G_INIT
#Import DietPi-Globals ---------------------------------------------------------------
#Grab Input (valid interger)
INPUT=0
disable_error=1 G_CHECK_VALIDINT $1 && INPUT=$1
#Version
DIETPI_CLOUDSHELL_VERSION=MPD_1.0
#/tmp/.* files used throughout this script.
FP_TEMP="/tmp/$G_PROGRAM_NAME/.tmp"
BLANK_SCREEN_ACTIVE=0
BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED=0
BLANK_SCREEN_TIME_HOUR_START=0
BLANK_SCREEN_TIME_HOUR_END=0
#This will only work if dietpi-cloudshell was started by autostart (login script), as the setterm power options can only be applied when the command originates from the same terminal (no redirects).
RUN_BLANK_SCREEN_AT_SPECIFIC_TIME(){
local current_hour=$(date +%-H)
#Turn screen off
if (( ! $BLANK_SCREEN_ACTIVE )); then
if (( $BLANK_SCREEN_TIME_HOUR_START == $current_hour )); then
clear
echo -e '\n\nScreen will be powered down in under 1 minute\n'
setterm --blank 1 --powersave on &> /dev/tty1 #blank after 1 minute as force requires a poke to bring it back up.
BLANK_SCREEN_ACTIVE=1
fi
#Turn screen on
elif (( $BLANK_SCREEN_TIME_HOUR_END == $current_hour )); then
Disable_Screen_Blanking
fi
}
Disable_Screen_Blanking(){
setterm --blank poke &> /dev/tty1
setterm --reset &> /dev/tty1
setterm --blank 0 --powersave off &> /dev/tty1
BLANK_SCREEN_ACTIVE=0
}
#BC does not allow for printing leading zeros.
BC_ADD_LEADING_ZERO(){
#$1 = string input
local return_value=$1
#BC - Add leading zero to start of .* string.
# +0
if [[ ${return_value:0:1} == '.' ]]; then
return_value="0$return_value"
# -0
elif [[ ${return_value:0:2} == '-.' ]]; then
return_value=$(sed 's/^-./-0./' <<< "$return_value")
fi
echo "$return_value"
}
#Converts a byte int to string, in human readable byte format.
BYTE_PRINT_CONVERSION(){
local return_value=0
local decimal_count=1
#$1=byte value
# - KB
if (( $1 < 1048576 )); then
return_value="$(echo "scale=$decimal_count; $1 / 1024" | bc -l ) KB"
# - MB
elif (( $1 < 1073741824 )); then
return_value="$(echo "scale=$decimal_count; $1 / 1024 / 1024" | bc -l ) MB"
# - GB
else
return_value="$(echo "scale=$decimal_count; $1 / 1024 / 1024 / 1024" | bc -l ) GB"
fi
#BC - Add leading zero to start of .* string.
return_value=$(BC_ADD_LEADING_ZERO "$return_value")
echo "$return_value"
}
#Converts a byte int to string, in human readable bit format.
# - for network data transmission rate (LAN, WLAN, ...)
# - 1MB = 8Mbit | 1Mbit = 0.125MB
BIT_PRINT_CONVERSION(){
local return_value=0
local decimal_count=1
#$1=byte value
# - Kbit
if (( $1 < 1000000 )); then
return_value="$(echo "scale=$decimal_count; $1 * 8 / 1000" | bc -l) Kbit"
# - MBit
elif (( $1 < 1000000000 )); then
return_value="$(echo "scale=$decimal_count; $1 * 8 / 1000 / 1000" | bc -l) Mbit"
# - GBit
else
return_value="$(echo "scale=$decimal_count; $1 * 8 / 1000 / 1000 / 1000" | bc -l) Gbit"
fi
#BC - Add leading zero to start of .* string.
return_value=$(BC_ADD_LEADING_ZERO "$return_value")
echo "$return_value"
}
Init_Term_Options(){
# - Set large font 1st (480x320+)
setfont /usr/share/consolefonts/Uni3-TerminusBold32x16
# - set small font if insufficent number of lines (320x240)
if (( $(tput lines) < 10 )); then
setfont /usr/share/consolefonts/Uni3-TerminusBold24x12.psf
fi
#Disable screen blanking on tty1 initially
Disable_Screen_Blanking
}
#/////////////////////////////////////////////////////////////////////////////////////
# Colours
#/////////////////////////////////////////////////////////////////////////////////////
C_RESET='\e[0m'
C_REVERSE='\e[7m'
#C_BOLD makes normal text "brighter"
C_BOLD='\e[1m'
#Colour array
#0 WHITE
#1 RED
#2 GREEN
#3 YELLOW
#4 BLUE
#5 PURPLE
#6 CYAN
#7 TEST
aCOLOUR=(
'\e[39m'
'\e[31m'
'\e[32m'
'\e[33m'
'\e[34m'
'\e[35m'
'\e[36m'
'\e[93m'
)
#user colour
USER_COLOUR_INDEX=3
C_PERCENT_GRAPH=0
Percent_To_Graph(){
#$1 = int/float 0-100
#$C_PERCENT_GRAPH = return text
#Convert to int
local input_value=$(echo $1 | cut -d. -f1)
#Cap input value
if (( $input_value > 100 )); then
input_value=100
elif (( $input_value < 0 )); then
input_value=0
fi
#Work out a percentage based graph
#18 step split (18 / 100)
if (( $input_value >= 95 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[1]}------WARNING-----$C_RESET]"
elif (( $input_value >= 90 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[1]}-----------------$C_RESET-]"
elif (( $input_value >= 88 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[1]}----------------$C_RESET--]"
elif (( $input_value >= 82 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[1]}---------------$C_RESET---]"
elif (( $input_value >= 76 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[3]}--------------$C_RESET----]"
elif (( $input_value >= 70 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[3]}-------------$C_RESET-----]"
elif (( $input_value >= 64 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[3]}------------$C_RESET------]"
elif (( $input_value >= 56 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[3]}-----------$C_RESET-------]"
elif (( $input_value >= 50 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[3]}----------$C_RESET--------]"
elif (( $input_value >= 44 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[3]}---------$C_RESET---------]"
elif (( $input_value >= 38 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[2]}--------$C_RESET----------]"
elif (( $input_value >= 32 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[2]}-------$C_RESET-----------]"
elif (( $input_value >= 26 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[2]}------$C_RESET------------]"
elif (( $input_value >= 20 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[2]}-----$C_RESET-------------]"
elif (( $input_value >= 15 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[2]}----$C_RESET--------------]"
elif (( $input_value >= 10 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[2]}---$C_RESET---------------]"
elif (( $input_value >= 5 )); then
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[2]}--$C_RESET----------------]"
else
C_PERCENT_GRAPH=" $input_value% [$C_REVERSE${aCOLOUR[2]}-$C_RESET-----------------]"
fi
}
#/////////////////////////////////////////////////////////////////////////////////////
# Obtain Stat Data
#/////////////////////////////////////////////////////////////////////////////////////
TEMPERATURE_CONVERSION_VALUE=0
Obtain_Temperature_Conversion(){
if (( $TEMPERATURE_OUTPUT_TYPE == 0 )); then
TEMPERATURE_CONVERSION_VALUE=$(awk "BEGIN {printf \"%.0f\",$TEMPERATURE_CONVERSION_VALUE * 1.8 + 32"})
TEMPERATURE_CONVERSION_VALUE+="'f"
else
TEMPERATURE_CONVERSION_VALUE+="'c"
fi
}
DATE_TIME=0
Obtain_DATE_TIME(){
DATE_TIME=$(date +"%a %x - %R")
}
UPTIME=0
Obtain_UPTIME(){
local fSeconds=$(awk '{print $1}' <<< $(</proc/uptime))
local seconds=${fSeconds%.*}
local minutes=0
local hours=0
local days=0
while (( $seconds >= 60 )); do
((minutes++))
seconds=$(( $seconds - 60 ))
done
while (( $minutes >= 60 )); do
((hours++))
minutes=$(( $minutes - 60 ))
done
while (( $hours >= 24 )); do
((days++))
hours=$(( $hours - 24 ))
done
UPTIME="Uptime: $days Day, $hours Hour"
}
#CPU
CPU_GOV=0
CPU_TEMP=0
C_CPUTEMP=0
CPU_FREQ_1=0
CPU_FREQ_2=0
CPU_USAGE=0
CPU_TOTALPROCESSES=0
Obtain_CPU(){
CPU_TOTALPROCESSES=$(( $(ps --ppid 2 -p 2 --deselect | wc -l) - 2 )) # - ps process and descriptions.
CPU_GOV=$(</sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
CPU_TEMP=$(G_OBTAIN_CPU_TEMP)
if disable_error=1 G_CHECK_VALIDINT $CPU_TEMP; then
#Obtain colour for temps
if (( $CPU_TEMP >= 65 )); then
C_CPUTEMP=${aCOLOUR[1]}
elif (( $CPU_TEMP >= 50 )); then
C_CPUTEMP=${aCOLOUR[3]}
elif (( $CPU_TEMP >= 35 )); then
C_CPUTEMP=${aCOLOUR[2]}
else
C_CPUTEMP=${aCOLOUR[4]}
fi
#Set 'c or 'f output
TEMPERATURE_CONVERSION_VALUE=$CPU_TEMP
Obtain_Temperature_Conversion
CPU_TEMP=$TEMPERATURE_CONVERSION_VALUE
fi
CPU_FREQ_1=$(( $(</sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 ))
CPU_FREQ_2='N/A'
#Unique additional freq readout for Odroid XU4 (octo, 2nd quad set)
if (( $G_HW_MODEL == 11 )); then
CPU_FREQ_2=$(( $(</sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq) / 1000 ))
fi
CPU_USAGE=0
# PS (inaccurate)
while read -r line
do
CPU_USAGE=$( echo "scale=1;$CPU_USAGE + $line" | bc -l )
done <<< "$(ps -axo %cpu | sed '1d' | sed 's/ //')"
#ps returns usage of each core, so we devide the total by #n cores
CPU_USAGE=$(echo "scale=0;$CPU_USAGE / $G_HW_CPU_CORES" | bc -l )
# TOP (accurate)
# Fails to output in low screen res (https://github.com/Fourdee/DietPi/issues/203#issuecomment-189711968)
# CPU_USAGE=$(BC_ADD_LEADING_ZERO "$(echo "scale=1; 100 - $(top -b -n 1 | grep '%Cpu(s):' | awk '{print $8}')" | bc -l)")
#convert to interger and graph it
Percent_To_Graph $CPU_USAGE
CPU_USAGE=$C_PERCENT_GRAPH
}
#Storage
# - array
MAX_STORAGE=6
STORAGE_TOTAL=()
STORAGE_USED=()
STORAGE_FREE=()
STORAGE_PERCENT=()
STORAGE_PATH=()
STORAGE_NAME=()
Init_STORAGE(){
for ((i=0; i<$MAX_STORAGE; i++))
do
STORAGE_TOTAL[$i]='N/A'
STORAGE_USED[$i]='N/A'
STORAGE_FREE[$i]='N/A'
STORAGE_PERCENT[$i]=' Not installed'
STORAGE_NAME[$i]=0
# 0 reserved for flash storage
if (( $i == 0 )); then
STORAGE_PATH[$i]='/'
STORAGE_NAME[$i]='Flash/RootFS Storage: '
else
STORAGE_PATH[$i]="/mnt/usb_$i"
STORAGE_NAME[$i]="Storage $i: "
fi
done
}
Destroy_STORAGE(){
unset STORAGE_TOTAL
unset STORAGE_USED
unset STORAGE_FREE
unset STORAGE_PERCENT
unset STORAGE_PATH
unset STORAGE_NAME
}
# $1 $2 = Range of indexs to update (eg: 0-1)
Obtain_STORAGE(){
local index_start=$1
local index_end=$2
#df will endless hang when NFS server is down: https://github.com/Fourdee/DietPi/issues/395
# - So lets run it as another thread so we can kill it if it hangs.
local df_failed=0
rm $FP_TEMP
df -Ph > $FP_TEMP &
# - Wait X seconds before terminating the df thread
local max_seconds=4
local current_seconds=0
while [[ ! -f $FP_TEMP ]]
do
#kill
if (( $current_seconds >= $max_seconds )); then
G_DIETPI-NOTIFY 1 'DF failed, unable to obtain drive data'
sleep 2
killall -w df
df_failed=1
echo -e "$(date) | df failed to respond" >> /var/log/dietpi-cloudshell.log
break
else
sleep 1
((current_seconds++))
fi
done
if (( $df_failed )); then
for ((i=$index_start; i<=$index_end; i++))
do
STORAGE_PERCENT[$i]="${STORAGE_PATH[$i]}"
STORAGE_FREE[$i]='DF failed'
done
else
for ((i=$index_start; i<=$index_end; i++))
do
if grep -q "${STORAGE_PATH[$i]}\$" $FP_TEMP; then
STORAGE_TOTAL[$i]=$(grep -m1 "${STORAGE_PATH[$i]}\$" $FP_TEMP | awk '{print $2}'); STORAGE_TOTAL[$i]+='B'
STORAGE_USED[$i]=$(grep -m1 "${STORAGE_PATH[$i]}\$" $FP_TEMP | awk '{print $3}'); STORAGE_USED[$i]+='B'
STORAGE_FREE[$i]=$(grep -m1 "${STORAGE_PATH[$i]}\$" $FP_TEMP | awk '{print $4}'); STORAGE_FREE[$i]+='B'
STORAGE_PERCENT[$i]=$(grep -m1 "${STORAGE_PATH[$i]}\$" $FP_TEMP | awk '{print $5}' | sed 's/%//g')
Percent_To_Graph ${STORAGE_PERCENT[$i]}
STORAGE_PERCENT[$i]=$C_PERCENT_GRAPH
else
STORAGE_PERCENT[$i]="${STORAGE_PATH[$i]}"
STORAGE_FREE[$i]='Mount not active'
fi
done
fi
}
#MPD - Scene 4 modified for MPD-Cloudshell
MPD_CURRENT_SONG=0
MPD_STATION=0
MPD_VOLUME=0
Obtain_MPDINFO(){
#MPD current song
MPD_CURRENT_SONG=$(mpc current)
#MPD current audio volume
MPD_VOLUME=$(mpc status | sed -n '/volume/p' | cut -c8-11 | sed 's/^[ \t]*//')
#MPD current station
MPD_STATION=$(mpc | /bin/grep "#" | /usr/bin/awk '{print $2}' | sed s/#//)
}
#System Information - Scene 5 modified for MPD-Cloudshell
NETWORK_DETAILS_ADAPTER='eth0'
NETWORK_DETAILS_IP_INT=0
NETWORK_DETAILS_SSID=0
NETWORK_DETAILS_SIGNAL_STRENGTH=0
RAM=0
CPU_USAGE=0
FREE_SD_SPACE=0
Obtain_NETWORK_DETAILS(){
#Cpu usage
CPU_USAGE=$(grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage "%"}')
#Active network adapater.
NETWORK_DETAILS_ADAPTER=$(sed -n 3p /DietPi/dietpi/.network)
#Free SD space %
FREE_SD_SPACE=$(df -lh | awk '{if ($6 == "/") { print $5 }}' | head -1)
#IP & wifi SSID
NETWORK_DETAILS_IP_INT=$(sed -n 4p /DietPi/dietpi/.network)
NETWORK_DETAILS_SSID=$(iwgetid -r)
# Wifi Signal
NETWORK_DETAILS_SIGNAL_STRENGTH="$(iwconfig $NETWORK_DETAILS_ADAPTER | grep -m1 'Signal level=' | awk '{ print $4 }' | sed 's/level=//g' | cut -f1 -d "/")%"
#RAM usage
RAM="$(free -m | awk 'NR==2{printf "Memory Usage: %s/%sMB \n", $3,$2,$3 }')"
}
#Network Usage (all values are in bytes)
NETWORK_USAGE_TOTAL_CURRENT_SENT=0
NETWORK_USAGE_TOTAL_CURRENT_RECIEVED=0
NETWORK_USAGE_NOW_CURRENT_SENT=0
NETWORK_USAGE_NOW_CURRENT_RECIEVED=0
NETWORK_USAGE_NOW_INIT=0
NETWORK_USAGE_SECONDS_SINCE_LAST_UPDATE=0
NETWORK_USAGE_DAY_CURRENT_SENT=0
NETWORK_USAGE_DAY_CURRENT_RECIEVED=0
NETWORK_USAGE_DAY_PREVIOUS_SENT=0
NETWORK_USAGE_DAY_PREVIOUS_RECIEVED=0
NETWORK_USAGE_DAY_OF_MONTH=-1
Obtain_NETWORK_USAGE(){
local network_usage_current_recieved=$(</sys/class/net/$NETWORK_DETAILS_ADAPTER/statistics/rx_bytes)
local network_usage_current_sent=$(</sys/class/net/$NETWORK_DETAILS_ADAPTER/statistics/tx_bytes)
#Check for valid integer scrapes, before running calculations: https://dietpi.com/forum/t/dietpi-cloudshell-syntax-error-help/368/5 | https://github.com/Fourdee/DietPi/issues/355
if disable_error=1 G_CHECK_VALIDINT $network_usage_current_recieved && disable_error=1 G_CHECK_VALIDINT $network_usage_current_sent; then
#Store previous totals
local total_previous_sent=$NETWORK_USAGE_TOTAL_CURRENT_SENT
local total_previous_recieved=$NETWORK_USAGE_TOTAL_CURRENT_RECIEVED
#Update current totals
NETWORK_USAGE_TOTAL_CURRENT_RECIEVED=$network_usage_current_recieved
NETWORK_USAGE_TOTAL_CURRENT_SENT=$network_usage_current_sent
#Current usage
# - Work out seconds since last update
local seconds_since_last_update=$(( $(date +%s) - $NETWORK_USAGE_SECONDS_SINCE_LAST_UPDATE ))
# - Init - Override current usage to 0, on first run of scene.
if (( $NETWORK_USAGE_NOW_INIT == 0 )); then
NETWORK_USAGE_NOW_CURRENT_SENT=0
NETWORK_USAGE_NOW_CURRENT_RECIEVED=0
NETWORK_USAGE_NOW_INIT=1
# - Obtain current usage
else
NETWORK_USAGE_NOW_CURRENT_SENT=$(( ( $NETWORK_USAGE_TOTAL_CURRENT_SENT - $total_previous_sent ) / $seconds_since_last_update ))
NETWORK_USAGE_NOW_CURRENT_RECIEVED=$(( ( $NETWORK_USAGE_TOTAL_CURRENT_RECIEVED - $total_previous_recieved ) / $seconds_since_last_update ))
fi
# - Update timestamp
NETWORK_USAGE_SECONDS_SINCE_LAST_UPDATE=$(date +%s)
#Usage today
# - Has the day changed? Also runs on init.
# String if statement, to prevent "leading zero integer error" from $(date): https://github.com/Fourdee/DietPi/issues/272
local dayofmonth=$(date +"%d")
if [[ $NETWORK_USAGE_DAY_OF_MONTH != $dayofmonth ]]; then
#Update previous day values to current
NETWORK_USAGE_DAY_PREVIOUS_SENT=$NETWORK_USAGE_TOTAL_CURRENT_SENT
NETWORK_USAGE_DAY_PREVIOUS_RECIEVED=$NETWORK_USAGE_TOTAL_CURRENT_RECIEVED
NETWORK_USAGE_DAY_OF_MONTH=$dayofmonth
fi
# - Work out todays usage
NETWORK_USAGE_DAY_CURRENT_SENT=$(( $NETWORK_USAGE_TOTAL_CURRENT_SENT - $NETWORK_USAGE_DAY_PREVIOUS_SENT ))
NETWORK_USAGE_DAY_CURRENT_RECIEVED=$(( $NETWORK_USAGE_TOTAL_CURRENT_RECIEVED - $NETWORK_USAGE_DAY_PREVIOUS_RECIEVED ))
fi
}
#Memory
MEMORY_TOTAL=0
MEMORY_FREE=0
MEMORY_USED=0
MEMORY_CACHED=0
MEMORY_PERCENT=0
MEMORY_SWAPTOTAL=0
MEMORY_SWAPUSED=0
MEMORY_SWAPFREE=0
MEMORY_SWAPERCENT=0
Obtain_MEMORY(){
#Write to temp
free -m > $FP_TEMP
#RAM MB
MEMORY_TOTAL=$(grep -m1 'Mem: ' $FP_TEMP | awk '{print $2}')
#MEMORY_CACHED=$(grep -m1 'Mem: ' $FP_TEMP | awk '{print $6}')
MEMORY_USED=$(( $(grep -m1 'Mem: ' $FP_TEMP | awk '{print $3}') ))
MEMORY_FREE=$(( $(grep -m1 'Mem: ' $FP_TEMP | awk '{print $7}') ))
MEMORY_PERCENT=$(echo | awk "{print $MEMORY_USED / $MEMORY_TOTAL * 100}")
#convert to interger and graph it
Percent_To_Graph $MEMORY_PERCENT
MEMORY_PERCENT=$C_PERCENT_GRAPH
#SWAP MB
MEMORY_SWAPTOTAL=$(grep -m1 'Swap: ' $FP_TEMP | awk '{print $2}')
# - Swap available and active
if (( $MEMORY_SWAPTOTAL > 0 )); then
MEMORY_SWAPUSED=$(grep -m1 'Swap: ' $FP_TEMP | awk '{print $3}')
MEMORY_SWAPFREE=$(grep -m1 'Swap: ' $FP_TEMP | awk '{print $4}')
MEMORY_SWAPERCENT=$( echo | awk "{print $MEMORY_SWAPUSED / $MEMORY_SWAPTOTAL * 100}")
#convert to interger and graph it
Percent_To_Graph $MEMORY_SWAPERCENT
MEMORY_SWAPERCENT=$C_PERCENT_GRAPH
else
MEMORY_SWAPERCENT=' Disabled'
fi
}
#PI-HOLE STATS!
PIHOLE_QUERY_COUNT=0
PIHOLE_TOTAL_ADS=0
PIHOLE_PERCENT_ADS=0
PIHOLE_TOTAL_DOMAINS=0
PIHOLE_LAST_DOMAIN_BLOCKED=0
Obtain_PIHOLE(){
local pihole_log_file='/var/log/pihole.log'
#Lets pull the total number of blocked domains only once during 1st run, its quite cpu intensive.
if (( $PIHOLE_TOTAL_DOMAINS == 0 )); then
if [[ -f /etc/pihole/gravity.list ]]; then
PIHOLE_TOTAL_DOMAINS=$(wc -l /etc/pihole/gravity.list | awk '{print $1}')
else
PIHOLE_TOTAL_DOMAINS='Not Installed'
fi
fi
local today=$(date +'%b %e')
PIHOLE_QUERY_COUNT=$(grep "$today" $pihole_log_file | awk '/query/ {print $7}' | wc -l)
#Prevent / 0 on percentage
if (( $PIHOLE_QUERY_COUNT <= 0 )); then
PIHOLE_QUERY_COUNT=1
fi
PIHOLE_TOTAL_ADS=$(grep "$today" $pihole_log_file | awk '/\/etc\/pihole\/gravity.list/ {print $7}' | wc -l)
PIHOLE_PERCENT_ADS=$(echo | awk "{print $PIHOLE_TOTAL_ADS / $PIHOLE_QUERY_COUNT * 100}")
#convert to interger and graph it
Percent_To_Graph $PIHOLE_PERCENT_ADS
PIHOLE_PERCENT_ADS=$C_PERCENT_GRAPH
#Get last blocked domain
if (( $PIHOLE_TOTAL_ADS == 0 )); then
PIHOLE_LAST_DOMAIN_BLOCKED='None'
else
PIHOLE_LAST_DOMAIN_BLOCKED=$(tac /var/log/pihole.log | grep -m1 'gravity.list' | awk '{print $6}' | cut -c 1-24 )
fi
}
#/////////////////////////////////////////////////////////////////////////////////////
# Scene Settings
#/////////////////////////////////////////////////////////////////////////////////////
RUN_INTRO=0
if (( $INPUT == 1 )); then
RUN_INTRO=1
fi
#SCENE INDEXS
SCENE_CURRENT=2
MAX_SCENES=9
#Refresh rate (every X seconds)
REFRESH_RATE=5
#0='f | 1='c
TEMPERATURE_OUTPUT_TYPE=1
#0=bit (Mbit) | 1=byte (MB)
NETWORK_USAGE_CURRENT_OUTPUT_TYPE=0
#Enabled Scenes
aEnabledScenes=()
for ((i=0; i<$MAX_SCENES; i++))
do
aEnabledScenes[$i]=1
done
#/////////////////////////////////////////////////////////////////////////////////////
# Scene Print / Update
#/////////////////////////////////////////////////////////////////////////////////////
Run_Intro(){
#'--------------------------'
clear
local aAnimation=(
' '
'i - c'
'P i - c l'
't P i - c l o'
'e t P i- c l o u'
'i e t Pi- c l o u d s'
'D i etPi- c l o u d s h'
' D ietPi-c l o u d s h e'
' DietPi-cl o u d s h e '
' DietPi-clou d s h e l '
' DietPi-clouds h e l l '
' DietPi-cloudshe l l '
' DietPi-cloudshell '
)
local aBar=(
' '
' '
' '
' '
' '
' '
' '
' '
' '
' '
' '
' '
' '
)
for ((i=0; i<${#aAnimation[@]}; i++))
do
clear
echo -e "$C_RESET"
echo -e '\n\n'
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}${aAnimation[$i]}"
echo -e "$C_RESET v$DIETPI_CLOUDSHELL_VERSION"
echo -e '\n Loading...'
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE${aBar[$i]}"
sleep 0.2
done
#delete[] array
unset aAnimation
unset aBar
sleep 0.1
}
#Top banner
BANNER_PRINT=0
BANNER_MODE=0
Update_Banner(){
#Banner Modes
if (( $BANNER_MODE == 0 )); then
#BANNER_PRINT="Lovisolo P.M. - 2018"
Obtain_DATE_TIME
BANNER_PRINT=$DATE_TIME
elif (( $BANNER_MODE == 1 )); then
Obtain_DATE_TIME
BANNER_PRINT=$DATE_TIME
elif (( $BANNER_MODE == 2 )); then
Obtain_UPTIME
BANNER_PRINT=$UPTIME
fi
#Set next index
((BANNER_MODE++))
#Cap
if (( $BANNER_MODE >= 3 )); then
#BANNER_MODE=0
Obtain_DATE_TIME
BANNER_PRINT=$DATE_TIME
fi
}
#CPU
Update_Scene_0(){
#Update data
Obtain_CPU
#Clear screen
clear
#Banner
echo -e "$C_RESET $BANNER_PRINT"
#
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE CPU Usage: "
echo -e "$C_RESET$CPU_USAGE"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE CPU Stats: "
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Temp ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET $C_CPUTEMP$CPU_TEMP"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Processes ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET $CPU_TOTALPROCESSES"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Governor ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET $CPU_GOV"
#XU3/4 unique octo quad sets
if (( $G_HW_MODEL == 11 )); then
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Freq 0-3 ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET $CPU_FREQ_1 mhz"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Freq 4-7 ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET $CPU_FREQ_2 mhz"
#Generic CPU hardware
else
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Freq ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET $CPU_FREQ_1 mhz"
fi
}
#$1 $2 = Storage index's to update and display (must be a range of 1 , eg: 0-1 1-2 3-4)
Update_Scene_1(){
local index_1=$1
local index_2=$2
#Update data
Obtain_STORAGE $index_1 $index_2
#Clear screen
clear
#Banner
echo -e "$C_RESET $BANNER_PRINT"
#
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE ${STORAGE_NAME[$index_1]}"
echo -e "$C_RESET${STORAGE_PERCENT[$index_1]}"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Used: $C_RESET${STORAGE_USED[$index_1]} / ${STORAGE_TOTAL[$index_1]}"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Free: $C_RESET${STORAGE_FREE[$index_1]}"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE ${STORAGE_NAME[$index_2]}"
echo -e "$C_RESET${STORAGE_PERCENT[$index_2]}"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Used: $C_RESET${STORAGE_USED[$index_2]} / ${STORAGE_TOTAL[$index_2]}"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Free: $C_RESET${STORAGE_FREE[$index_2]}"
}
#MPD - modified for MPD-Cloushell
Update_Scene_4(){
#Update data
Obtain_MPDINFO
Obtain_CPU
#Clear screen
clear
#banner (date-hour)
echo -e "$C_RESET$C_BOLD $BANNER_PRINT"
#MPD info
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE MPD Internet Radio: "
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}Volume ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET $MPD_VOLUME"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}Channel${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET $MPD_STATION"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Current Station - Song: "
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}${aCOLOUR[$USER_COLOUR_INDEX]}$C_RESET$MPD_CURRENT_SONG"
}
#System Information - modified for MPD-Cloushell
Update_Scene_5(){
#Update data
Obtain_NETWORK_DETAILS
#Clear screen
clear
#Banner
echo -e "$C_RESET$C_BOLD $BANNER_PRINT"
#
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE System information: "
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} IP : $C_RESET$NETWORK_DETAILS_IP_INT"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Signal : $C_RESET$NETWORK_DETAILS_SIGNAL_STRENGTH"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} SSID : $C_RESET$NETWORK_DETAILS_SSID"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Cpu : $C_RESET$CPU_USAGE"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Temp : $C_RESET$C_CPUTEMP$CPU_TEMP"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} SD space: $C_RESET$FREE_SD_SPACE"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_RESET $RAM"
}
#NETWORK USAGE
Update_Scene_6(){
#Update data
Obtain_NETWORK_USAGE
# - Convert usage values into human readable format. Run before clearing screen due to additional processing (delay)
local total_sent_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_TOTAL_CURRENT_SENT )
local total_recieved_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_TOTAL_CURRENT_RECIEVED )
local today_sent_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_DAY_CURRENT_SENT )
local today_recieved_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_DAY_CURRENT_RECIEVED )
local now_sent_output=0
local now_recieved_output0
if (( $NETWORK_USAGE_CURRENT_OUTPUT_TYPE == 0 )); then
now_sent_output=$( BIT_PRINT_CONVERSION $NETWORK_USAGE_NOW_CURRENT_SENT )
now_recieved_output=$( BIT_PRINT_CONVERSION $NETWORK_USAGE_NOW_CURRENT_RECIEVED )
else
now_sent_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_NOW_CURRENT_SENT )
now_recieved_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_NOW_CURRENT_RECIEVED )
fi
#Clear screen
clear
#Banner
# - Banner does not fit this scene (>= 9 lines)
#echo -e "$C_RESET $BANNER_PRINT"
#
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Network Usage (TOTAL): "
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Sent : $C_RESET$total_sent_output"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Recieved : $C_RESET$total_recieved_output"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Network Usage (TODAY): "
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Sent : $C_RESET$today_sent_output"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Recieved : $C_RESET$today_recieved_output"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Network Usage (CURRENT): "
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Sent : $C_RESET$now_sent_output/s"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Recieved : $C_RESET$now_recieved_output/s"
}
#Memory
Update_Scene_7(){
#Update data
Obtain_MEMORY
#Clear screen
clear
#Banner
echo -e "$C_RESET $BANNER_PRINT"
#
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Memory Usage (RAM): "
echo -e "$C_RESET$MEMORY_PERCENT"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Used: $C_RESET$MEMORY_USED MB / $MEMORY_TOTAL MB"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Free: $C_RESET$MEMORY_FREE MB"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Memory Usage (SWAP): "
echo -e "$C_RESET$MEMORY_SWAPERCENT"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Used: $C_RESET$MEMORY_SWAPUSED MB / $MEMORY_SWAPTOTAL MB"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Free: $C_RESET$MEMORY_SWAPFREE MB"
}
#Pi-hole
Update_Scene_8(){
#Update data
Obtain_PIHOLE
#Clear screen
clear
#Banner
echo -e "$C_RESET $BANNER_PRINT"
#
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Pi-hole stats (TODAY): "
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Ads Blocked: $C_RESET$PIHOLE_TOTAL_ADS"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} DNS Queries: $C_RESET$PIHOLE_QUERY_COUNT"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Blocked Domains: $C_RESET$PIHOLE_TOTAL_DOMAINS"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE % of traffic = Ads: "
echo -e "$C_RESET$PIHOLE_PERCENT_ADS"
echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Last domain blocked: "
echo -e "$C_RESET $PIHOLE_LAST_DOMAIN_BLOCKED"
}
#/////////////////////////////////////////////////////////////////////////////////////
# Settings File
#/////////////////////////////////////////////////////////////////////////////////////
#Define Location
FILEPATH_SETTINGS='/DietPi/dietpi/.dietpi-cloudshell'
Read_Settings_File(){
if [[ -f $FILEPATH_SETTINGS ]]; then
. $FILEPATH_SETTINGS
fi
}
Write_Settings_File(){
cat << _EOF_ > $FILEPATH_SETTINGS
REFRESH_RATE=$REFRESH_RATE
USER_COLOUR_INDEX=$USER_COLOUR_INDEX
TEMPERATURE_OUTPUT_TYPE=$TEMPERATURE_OUTPUT_TYPE
OUTPUT_DISPLAY_INDEX=$OUTPUT_DISPLAY_INDEX
NETWORK_USAGE_CURRENT_OUTPUT_TYPE=$NETWORK_USAGE_CURRENT_OUTPUT_TYPE
BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED=$BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED
BLANK_SCREEN_TIME_HOUR_START=$BLANK_SCREEN_TIME_HOUR_START
BLANK_SCREEN_TIME_HOUR_END=$BLANK_SCREEN_TIME_HOUR_END
_EOF_
#Add enabled scenes
for ((i=0; i<$MAX_SCENES; i++))
do
echo -e "aEnabledScenes[$i]=${aEnabledScenes[$i]}" >> $FILEPATH_SETTINGS
done
#Add Drive Paths and Names
for ((i=0; i<$MAX_STORAGE; i++))
do
echo -e "STORAGE_PATH[$i]='${STORAGE_PATH[$i]}'" >> $FILEPATH_SETTINGS
echo -e "STORAGE_NAME[$i]='${STORAGE_NAME[$i]}'" >> $FILEPATH_SETTINGS
done
}
#/////////////////////////////////////////////////////////////////////////////////////
# Init
#/////////////////////////////////////////////////////////////////////////////////////
Init(){
#--------------------------------------------------------------------------------
#Storage array
Init_STORAGE
#--------------------------------------------------------------------------------
#Load Settings file.
Read_Settings_File
#--------------------------------------------------------------------------------
#VM disable CPU scene
if (( $G_HW_MODEL == 20 )); then
aEnabledScenes[0]=0
fi
#--------------------------------------------------------------------------------
#Check and disable scenes if software is not installed:
# 6 Pi-hole
if [[ ! -f /etc/pihole/gravity.list ]]; then
aEnabledScenes[8]=0
fi
#--------------------------------------------------------------------------------
#Ensure we have at least 1 Scene enabled in the settings file.
local enabled_scene=0
for ((i=0; i<$MAX_SCENES; i++))
do
if (( ${aEnabledScenes[$i]} )); then
enabled_scene=1
break
fi
done
#No Scenes selected! Override user setting and enable at least 1 scene (dietpi)
if (( $enabled_scene == 0 )); then
aEnabledScenes[4]=1
SCENE_CURRENT=4
fi
#--------------------------------------------------------------------------------
#Update DietPi network shared data: https://github.com/Fourdee/DietPi/issues/359
/DietPi/dietpi/func/obtain_network_details
}
#/////////////////////////////////////////////////////////////////////////////////////
# Start/Stop Control for Menu
#/////////////////////////////////////////////////////////////////////////////////////
#0=tty1 1=current
OUTPUT_DISPLAY_INDEX=0
Menu_Stop(){
#Service if started.
systemctl stop dietpi-cloudshell
#Kill all , excluding Menu.
ps ax | grep '[d]ietpi-cloudshell [1-9]' | awk '{print $1}' > $FP_TEMP
while read -r line
do
kill $line &> /dev/null
done < $FP_TEMP
}
Menu_Start(){
#Are we starting on the current screen? (eg: from tty1)
local output_current_screen=0
if [[ $(tty) == '/dev/tty1' ]]; then
output_current_screen=1
elif (( $OUTPUT_DISPLAY_INDEX == 1 )); then
output_current_screen=1
fi
#Inform user to press CTRL+C to exit
if (( $output_current_screen == 1 )); then
clear
echo -e "$C_RESET"
read -p "Use CTRL+C to exit. Press any key to launch $G_PROGRAM_NAME..."
fi
#Launch in blocking mode
if (( $output_current_screen == 1 )); then
Run_Cloudshell
#Launch as service on main screen
else
systemctl start dietpi-cloudshell
fi
sleep 0.1
}
Run_Cloudshell(){
Init_Term_Options
#Start Intro
if (( $RUN_INTRO )); then
Run_Intro
fi
#Set Nice to +10 (not critical)
renice -n 10 $$ &> /dev/null
#Start display updates
while true
do
if (( $BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED )); then
RUN_BLANK_SCREEN_AT_SPECIFIC_TIME
fi
#Disable updates when screen is blanked
if (( $BLANK_SCREEN_ACTIVE )); then
sleep 60
#Update enabled scenes
else
if (( ${aEnabledScenes[$SCENE_CURRENT]} )); then
Update_Banner
# - Input mode scene update (storage array)
if (( $SCENE_CURRENT == 1 )); then
Update_Scene_1 0 1
# - Input mode scene update (storage array)
elif (( $SCENE_CURRENT == 2 )); then
Update_Scene_1 2 3
# - Input mode scene update (storage array)
elif (( $SCENE_CURRENT == 3 )); then
Update_Scene_1 4 5
# - Normal scene update
else
Update_Scene_$SCENE_CURRENT
fi
#Apply refresh rate delay
sleep $REFRESH_RATE
fi
#Scene Switcher
((SCENE_CURRENT++))
#Cap
if (( $SCENE_CURRENT >= $MAX_SCENES )); then
SCENE_CURRENT=0
fi
fi
done
}
#/////////////////////////////////////////////////////////////////////////////////////
# Menu System
#/////////////////////////////////////////////////////////////////////////////////////
TARGETMENUID=0
LASTSELECTED_ITEM=''
Menu_Exit(){
G_WHIP_SIZE_X_MAX=50
G_WHIP_YESNO "Exit $G_PROGRAM_NAME?"
if (( $? == 0 )); then
#Save changes
Write_Settings_File
#exit
TARGETMENUID=-1
else
#Return to Main Menu
TARGETMENUID=0
fi
}
#TARGETMENUID=0
Menu_Main(){
TARGETMENUID=0
local temp_output_text='Fahrenheit'
if (( $TEMPERATURE_OUTPUT_TYPE == 1 )); then
temp_output_text='Celsius'
fi
local target_output_text='Main Screen (tty1)'
if (( $OUTPUT_DISPLAY_INDEX == 1 )); then
target_output_text='Current screen or terminal'
fi
local bitbyte_output_text='Bit (Kbit, Mbit, Gbit)'
if (( $NETWORK_USAGE_CURRENT_OUTPUT_TYPE == 1 )); then
bitbyte_output_text='Byte (KB, MB, GB)'
fi
local autoscreenoff='Disabled'
if (( $BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED )); then
autoscreenoff='Enabled'
fi
G_WHIP_MENU_ARRAY=(
'Colour' 'Setting: Change the colour scheme.'
'Update Rate' 'Setting: Control the time between screen updates.'
'Scenes' 'Setting: Toggle which scenes are shown.'
'Storage' 'Setting: Set mount locations used for storage stats'
'Temperature' "Setting: Output = $temp_output_text"
'Net Usage Current' "Setting: Output = $bitbyte_output_text"
'Output Display' "Setting: $target_output_text."
'Auto screen off' "Setting: $autoscreenoff | Start $BLANK_SCREEN_TIME_HOUR_START h | End $BLANK_SCREEN_TIME_HOUR_END h"
'Start / Restart' "Apply settings. Launch on $target_output_text."
'Stop' "Stops $G_PROGRAM_NAME."
)
G_WHIP_DEFAULT_ITEM="$LASTSELECTED_ITEM"
G_WHIP_BUTTON_CANCEL_TEXT='Exit'
G_WHIP_MENU
if (( $? == 0 )); then
LASTSELECTED_ITEM="$G_WHIP_RETURNED_VALUE"
case "$G_WHIP_RETURNED_VALUE" in
'Storage')
TARGETMENUID=5
;;
'Auto screen off')
TARGETMENUID=4
;;
'Net Usage Current')
((NETWORK_USAGE_CURRENT_OUTPUT_TYPE++))
if (( $NETWORK_USAGE_CURRENT_OUTPUT_TYPE > 1 )); then
NETWORK_USAGE_CURRENT_OUTPUT_TYPE=0
fi
;;
'Temperature')
((TEMPERATURE_OUTPUT_TYPE++))
if (( $TEMPERATURE_OUTPUT_TYPE > 1 )); then
TEMPERATURE_OUTPUT_TYPE=0
fi
;;
'Output Display')
((OUTPUT_DISPLAY_INDEX++))
if (( $OUTPUT_DISPLAY_INDEX > 1 )); then
OUTPUT_DISPLAY_INDEX=0
fi
;;
'Start / Restart')
Write_Settings_File
Menu_Stop
Menu_Start
;;
'Stop')
Menu_Stop
;;
'Colour')
TARGETMENUID=1
;;
'Update Rate')
TARGETMENUID=2
;;
'Scenes')
TARGETMENUID=3
;;
esac
else
Menu_Exit
fi
}
#TARGETMENUID=1
Menu_Colour(){
#Return to main menu
TARGETMENUID=0
G_WHIP_MENU_ARRAY=(
'0' 'White'
'1' 'Red'
'2' 'Green'
'3' 'Yellow (Default)'
'4' 'Blue'
'5' 'Purple'
'6' 'Cyan'
)
G_WHIP_DEFAULT_ITEM="$USER_COLOUR_INDEX"
G_WHIP_MENU 'Please select a colour scheme.'
if (( $? == 0 )); then
USER_COLOUR_INDEX=$G_WHIP_RETURNED_VALUE
fi
}
#TARGETMENUID=2
Menu_UpdateRate(){
#Return to main menu
TARGETMENUID=0
G_WHIP_MENU_ARRAY=(
'1' 'Second'
'3' 'Seconds'
'5' 'Seconds (Default)'
'10' 'Seconds'
'15' 'Seconds'
'20' 'Seconds'
'30' 'Seconds'
'45' 'Seconds'
'60' 'Seconds'
)
G_WHIP_DEFAULT_ITEM=$REFRESH_RATE
G_WHIP_MENU 'Please select the desired delay, between scene changes and updates.'
if (( $? == 0 )); then
REFRESH_RATE=$G_WHIP_RETURNED_VALUE
fi
}
#TARGETMENUID=3
Menu_SceneSelection(){
#Return to main menu
TARGETMENUID=0
#Get on/off whilptail status
local aWhip_OnOff_Status=()
for ((i=0; i<$MAX_SCENES; i++))
do
#On/Off status
aWhip_OnOff_Status[$i]='on'
if (( ! ${aEnabledScenes[$i]} )); then
aWhip_OnOff_Status[$i]='off'
fi
done
#Define options
local index=0
G_WHIP_CHECKLIST_ARRAY=()
index=0;G_WHIP_CHECKLIST_ARRAY+=($index 'CPU: Temperatures, Usage, frequency and more.' "${aWhip_OnOff_Status[$index]}")
index=1;G_WHIP_CHECKLIST_ARRAY+=($index 'Storage: Usage information for Flash and USB drives' "${aWhip_OnOff_Status[$index]}")
index=2;G_WHIP_CHECKLIST_ARRAY+=($index ' - Additional Storage (USB_2/3)' "${aWhip_OnOff_Status[$index]}")
index=3;G_WHIP_CHECKLIST_ARRAY+=($index ' - Additional Storage (USB_4/5)' "${aWhip_OnOff_Status[$index]}")
index=4;G_WHIP_CHECKLIST_ARRAY+=($index 'DietPi: Information, stats and updates for DietPi.' "${aWhip_OnOff_Status[$index]}")
index=5;G_WHIP_CHECKLIST_ARRAY+=($index 'Network Details: Ip address, Speeds, Signal and more.' "${aWhip_OnOff_Status[$index]}")
index=6;G_WHIP_CHECKLIST_ARRAY+=($index 'Network Usage: Bandwidth usage (sent / recieved).' "${aWhip_OnOff_Status[$index]}")
index=7;G_WHIP_CHECKLIST_ARRAY+=($index 'Memory: Stats for RAM and Swapfile usage.' "${aWhip_OnOff_Status[$index]}")
index=8;G_WHIP_CHECKLIST_ARRAY+=($index 'Pi-hole: Stats for Pi-hole. Total Ads blocked etc.' "${aWhip_OnOff_Status[$index]}")
G_WHIP_CHECKLIST 'Please use the spacebar to toggle which scenes are active.'
if (( $? == 0 )); then
# - Reset all scenes to 0
for ((i=0; i<$MAX_SCENES; i++))
do
aEnabledScenes[$i]=0
done
fi
#Delete[] array
unset aWhip_OnOff_Status
# - Enable required scenes
for i in ${G_WHIP_RETURNED_VALUE[@]}
do
aEnabledScenes[$i]=1
done
}
#TARGETMENUID=4
Menu_BlankScreenAtTime(){
#Return to main menu
TARGETMENUID=0
local blank_screen_at_specific_time_enabled_text='Disabled'
if (( $BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED )); then
blank_screen_at_specific_time_enabled_text='Enabled'
fi
G_WHIP_MENU_ARRAY=(
'Toggle' "$blank_screen_at_specific_time_enabled_text"
'Start time' "Set which hour to power off screen ($BLANK_SCREEN_TIME_HOUR_START)."
'End time' "Set which hour to power on screen ($BLANK_SCREEN_TIME_HOUR_END)."
)
G_WHIP_BUTTON_CANCEL_TEXT='Back'
G_WHIP_MENU 'Automatically power down the screen and disable DietPi-Cloudshell processing during a specific time.\n\nNB: This feature will only work if DietPi-Cloudshell was launched with the DietPi-Autostart option, or, launched from the main screen (tty1).'
if (( $? == 0 )); then
if [[ $G_WHIP_RETURNED_VALUE == 'Toggle' ]];then
((BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED++))
if (( $BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED > 1 )); then
BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED=0
fi
elif [[ $G_WHIP_RETURNED_VALUE == 'Start time' ]];then
G_WHIP_MENU_ARRAY=()
for ((i=0; i<24; i++))
do
G_WHIP_MENU_ARRAY+=($i "Hour")
done
G_WHIP_DEFAULT_ITEM=$BLANK_SCREEN_TIME_HOUR_START
G_WHIP_MENU 'Please select which hour (24h) you would like the screen to power off.'
if (( $? == 0 )); then
BLANK_SCREEN_TIME_HOUR_START=$G_WHIP_RETURNED_VALUE
fi
elif [[ $G_WHIP_RETURNED_VALUE == 'End time' ]];then
G_WHIP_MENU_ARRAY=()
for ((i=0; i<24; i++))
do
G_WHIP_MENU_ARRAY+=($i 'Hour')
done
G_WHIP_DEFAULT_ITEM=$BLANK_SCREEN_TIME_HOUR_END
G_WHIP_MENU 'Please select which hour (24h) you would like the screen to power on.'
if (( $? == 0 )); then
BLANK_SCREEN_TIME_HOUR_END=$G_WHIP_RETURNED_VALUE
fi
fi
TARGETMENUID=4
fi
}
#TARGETMENUID=5
Menu_Storage(){
#Return to main menu
TARGETMENUID=0
G_WHIP_MENU_ARRAY=()
for ((i=1; i<$MAX_STORAGE; i++))
do
G_WHIP_MENU_ARRAY+=( $i ": Drive $i | ${STORAGE_PATH[$i]}" )
done
G_WHIP_BUTTON_CANCEL_TEXT='Back'
G_WHIP_MENU 'Storage Device Mount Location:\n\nDietPi-Cloudshell pulls the storage stats from the drive mount location. If you have custom drives/mounts, please set them here to be displayed during storage scene updates.\n\n - Drive 1 = Displayed during main storage scene\n - Drive 2/3 = Displayed during additional storage scene\n - Drive 4/5 = Displayed during additional storage scene'
if (( $? == 0 )); then
local index=$G_WHIP_RETURNED_VALUE
/DietPi/dietpi/dietpi-drive_manager 1
local return_string="$(</tmp/dietpi-drive_manager_selmnt)"
if [[ $return_string ]]; then
STORAGE_PATH[$index]="$return_string"
fi
TARGETMENUID=5
fi
}
#/////////////////////////////////////////////////////////////////////////////////////
# MAIN
#/////////////////////////////////////////////////////////////////////////////////////
#-----------------------------------------------------------------------------------
#Init
Init
#-----------------------------------------------------------------------------------
#Run menu
if (( $INPUT == 0 )); then
#Start Menu
while (( $TARGETMENUID >= 0 )); do
clear
if (( $TARGETMENUID == 0 )); then
Menu_Main
elif (( $TARGETMENUID == 1 )); then
Menu_Colour
elif (( $TARGETMENUID == 2 )); then
Menu_UpdateRate
elif (( $TARGETMENUID == 3 )); then
Menu_SceneSelection
elif (( $TARGETMENUID == 4 )); then
Menu_BlankScreenAtTime
elif (( $TARGETMENUID == 5 )); then
Menu_Storage
fi
done
#-----------------------------------------------------------------------------------
#Run DietPi-Cloudshell
elif (( $INPUT >= 1 )); then
Run_Cloudshell
fi
#-----------------------------------------------------------------------------------
#Clean up temp files
rm $FP_TEMP &> /dev/null
#-----------------------------------------------------------------------------------
#Delete[] Global arrays
unset aCOLOUR
unset aEnabledScenes
Destroy_STORAGE
#-----------------------------------------------------------------------------------
exit
#-----------------------------------------------------------------------------------
}
@DietPI coders:
feel free to modify the original code to include my MPD scene 

If you want to use the three buttons on 3.2 LCD display with Raspberry, you can use this python script to control the “start/stop”, “next” and “prev” functions (or whatever else) of MPD:
sudo nano /root/buttons.py
#!/usr/bin/env python2
# by pilovis - Italy
import RPi.GPIO as GPIO # Import Raspberry Pi GPIO library
import time
import os
GPIO.setwarnings(False) # Ignore warning for now
GPIO.setmode(GPIO.BOARD) # Use physical pin numbering
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set pin 12 to be an input pin and set initial value to be pulled up (on)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(12, GPIO.BOTH, bouncetime=20) # The buttons have a little bounce, 20ms seems to be a good threshold
GPIO.add_event_detect(16, GPIO.BOTH, bouncetime=20)
GPIO.add_event_detect(18, GPIO.BOTH, bouncetime=20)
while True: # Run forever
if GPIO.input(12) == GPIO.LOW:
os.system("mpc next")
if GPIO.input(16) == GPIO.LOW:
os.system("mpc prev")
if GPIO.input(18) == GPIO.LOW:
os.system("mpc toggle")
time.sleep(1.0) # Polling is a bad thing, let the CPU rest
put the following command in “/etc/rc.local” file, just before the “exit 0” line, to lauch the python script at startup:
/usr/bin/python /root/buttons.py &

If you prefere using Triggerhappy (USB keyboard or USB numeric keypad) to control MPD, this is a sample of the configuration file.
Something I did in the past with MPD and Triggerhappy:
https://www.youtube.com/watch?v=cg18hvhIn4E
Info about Triggerhappy:
https://github.com/wertarbyte/triggerhappy
Triggerhappy installation:
sudo apt-get install triggerhappy
edit Triggerhappy config file:
sudo nano /etc/triggerhappy/triggers.d/example.conf
# Triggerhappy basic configuration file for MPD
# By pilovis - Italy
#
# to edit this file:
#> sudo nano /etc/triggerhappy/triggers.d/example.conf
#
# to determine the buttons name use the following command:
#> sudo thd --dump /dev/input/event*
#example:
#EV_KEY BTN_5 1 #(the name is BTN_5)
#EV_KEY BTN_1 1 #(the name is BTN_1)
#EV_KEY BTN_0 1 #(the name is BTN_0)
#
# to restart triggerhappy
#> sudo /etc/init.d/triggerhappy restart
#
####################################################################
# This is an example configuration for the triggerhappy daemon (thd)
# please note that every file to be processed must end in ".conf"
#
# To view a list of supported event codes, use "thd --listevents" or
# "thd --dump /dev/input/event*"
#
# Format:
# <eventcode> <value> <command>
#
# values for key events are 1 (pressed), 0 (released) or 2 (held)
#
####################################################################
#
## - MPD controls:
#
## decrease volume:
BTN_1 1 /usr/bin/mpc volume -2
#
## increase volume:
BTN_0 1 /usr/bin/mpc volume +2
#
## play - stop MPD
BTN_5 1 /usr/bin/mpc toggle
#
# eof
This is a more comprehensive example with two different keypads support:
# Triggerhappy configuration file for MPD - USB numeric Keypad
# By pilovis - Italy
#
# To view a list of supported event codes, use "thd --listevents" or
# "thd --dump /dev/input/event*"
# Format:
# <eventcode> <value> <command>
# values for key events are 1 (pressed), 0 (released) or 2 (held)
#
## control mpd
#
# start playing
KEY_KPENTER 1 /usr/bin/mpc play
KEY_PLAYPAUSE 1 /usr/bin/mpc play
# next station
KEY_KPSLASH 1 /usr/bin/mpc next
KEY_PAGEUP 1 /usr/bin/mpc next
# prev station
KEY_KPASTERISK 1 /usr/bin/mpc prev
KEY_PAGEDOWN 1 /usr/bin/mpc prev
# stop playing
KEY_KPDOT 1 /usr/bin/mpc stop
KEY_STOPCD 1 /usr/bin/mpc stop
#
## control audio volume
# increase volume +1%:
KEY_KPPLUS 1 /usr/bin/mpc volume +1
KEY_VOLUMEUP 1 /usr/bin/mpc volume +1
# set the volume at the minimum audible level (MUTE mode)
KEY_BACKSPACE 1 /usr/bin/mpc volume 80
KEY_MIN_INTERESTING 1 /usr/bin/mpc volume 80
# decrease volume -1%:
KEY_KPMINUS 1 /usr/bin/mpc volume -1
KEY_VOLUMEDOWN 1 /usr/bin/mpc volume -1
#
# eof
Just an add-on 
a script to load 59 Internet Radio Stations to MPD with just one click:
create the script:
sudo nano /root/add-station.sh
insert the code:
/usr/bin/mpc add http://144.76.106.52:7000/chillout.mp3
/usr/bin/mpc add http://205.164.62.15:9010/
/usr/bin/mpc add http://streaming.radionomy.com/PassionLoveRadio
/usr/bin/mpc add http://176.31.240.87:8025
/usr/bin/mpc add http://stream.srg-ssr.ch/m/rsj/mp3_128
/usr/bin/mpc add http://stream.srg-ssr.ch/m/rsc_it/mp3_128
/usr/bin/mpc add http://stream.srg-ssr.ch/m/rsp/mp3_128
/usr/bin/mpc add http://streaming.radionomy.com/CristalRelax
/usr/bin/mpc add http://streaming.radionomy.com/Radio-Quelit
/usr/bin/mpc add http://streaming.radionomy.com/R-E-T-R-OF-M
/usr/bin/mpc add http://streaming.radionomy.com/radio-accordeon
/usr/bin/mpc add http://streaming.radionomy.com/100-HIT-ra
/usr/bin/mpc add http://streaming.radionomy.com/colombiaromantica
/usr/bin/mpc add http://streaming.radionomy.com/GOLDEN-SIXTIES-SEVENTIES-EIGHTIES-RADIO
/usr/bin/mpc add http://streaming.radionomy.com/radio-oldies-and-rock--n--roll
/usr/bin/mpc add http://hr-mp3-m-h3.akacast.akamaistream.net/7/785/142133/v1/gnl.akacast.akamaistream.net/hr-mp3-m-h3
/usr/bin/mpc add http://streaming.hotmix-radio.net/hotmixradio-lounge-128.mp3
/usr/bin/mpc add http://streaming.radionomy.com/Ambiance-Reggae
/usr/bin/mpc add http://streaming.radionomy.com/always-80s
/usr/bin/mpc add http://streaming.radionomy.com/Hit-s-My-Music-Pop-Rock
/usr/bin/mpc add http://streaming.radionomy.com/Cafe-Romantico-Radio
/usr/bin/mpc add http://streaming.radionomy.com/1000-HITS-Sweet-Radio
/usr/bin/mpc add http://46.37.20.205:8000/rdsmp3
/usr/bin/mpc add http://89.16.185.174:8003/stream
/usr/bin/mpc add http://89.16.185.174:8000/stream
/usr/bin/mpc add http://89.16.185.174:8004/stream
/usr/bin/mpc add http://streaming.radionomy.com/Fm-Tropical-Shad-972
/usr/bin/mpc add http://streaming.radionomy.com/NashvilleEdge
/usr/bin/mpc add http://streaming.radionomy.com/Abacusfm-Nature
/usr/bin/mpc add http://streaming.radionomy.com/chd--radio-country
/usr/bin/mpc add http://streaming.radionomy.com/1-Radio-Dance
/usr/bin/mpc add http://streaming.radionomy.com/Acoustic-FM
/usr/bin/mpc add http://streaming.radionomy.com/ABC-Love
/usr/bin/mpc add http://streaming.radionomy.com/Radio-Nostalgia
/usr/bin/mpc add http://andromeda.shoutca.st:8634/stream
/usr/bin/mpc add http://streaming.radionomy.com/Tsjechische-Blaasmuziek
/usr/bin/mpc add http://streaming.radionomy.com/DanceRO
/usr/bin/mpc add http://streaming.radionomy.com/BobFamilyandfriends
/usr/bin/mpc add http://streaming.radionomy.com/The-Buffalo
/usr/bin/mpc add http://streaming.radionomy.com/VWClassicRock
/usr/bin/mpc add http://icecast2.rte.ie/ieradio1
/usr/bin/mpc add http://listen.radionomy.com/the-smooth-lounge
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1xtra_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio2_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio3_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio4fm_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio4lw_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio4extra_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio5live_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_6music_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_asianet_mf_p
/usr/bin/mpc add http://bbcmedia.ic.llnwd.net/stream/bbcmedia_nangaidheal_mf_p
/usr/bin/mpc add http://webradio.antennevorarlberg.at:80/lovesongs
/usr/bin/mpc add http://webradio.antennevorarlberg.at:80/hits
/usr/bin/mpc add http://webradio.antennevorarlberg.at:80/live
/usr/bin/mpc add http://webradio.antennevorarlberg.at:80/disco
/usr/bin/mpc add http://webradio.antennevorarlberg.at:80/partymix
/usr/bin/mpc add http://webradio.antennevorarlberg.at:80/lounge
give the right permissions to the script:
sudo chmod 755 /root/add-station.sh
launch the script:
sudo /bin/sh /root/add-station.sh
That’s all 
If you like MPD you’ll find here a lot of tips and code I developped for another Linux system (OpenWRT):
https://forum.archive.openwrt.org/viewtopic.php?id=49013&p=1
My D.I.Y. Stereo Hi-Fi MPD Vacuum Tube Internet Radio (the digital part is inside):


Another one (vintage look, old tubes still perfectly fuctional, but recent build: 2013)

Hi,
Many thanks for posting this excellent guide for audiophiles 
Very nice setup as well, even if I am a little jealous 
Raspberry Pi 1 B+ & 3.2 LCD


If I have enough time I will also post an How-to about a D.I.Y. Raspberry MPD i2c 20x4 LCD scrolling display.
My prototype:

Sleep and Wakeup MPD radio
A crontab to automatically reduce audio volume at night (gradually) till stopping audio at late night
edit crontab:
sudo crontab -e
insert the following lines at the end:
0 22 * * * /usr/bin/mpc volume 93 #reduce volume 93% at 22:00
30 22 * * * /usr/bin/mpc volume 90 #reduce volume 90% at 22:30
0 23 * * * /usr/bin/mpc volume 88 #reduce volume 88% at 23:00
30 23 * * * /usr/bin/mpc volume 86 #reduce volume 86% at 23:30
0 0 * * * /usr/bin/mpc volume 84 #reduce volume 84% at 00:00
30 0 * * * /usr/bin/mpc stop #stop audio at 00:30
note: change time and volume level as you wish
to apply crontab changes without reloading:
sudo service cron reload
You might want to Wake Up at the morning, eg. at 7:00 AM from Monday to Friday, with the MPD Internet Radio playing your favourite station and stop music after half an hour (dead line to get out of the bed
),
simply add the following lines:
59 6 * * 1-5 /usr/bin/mpc volume 93 # wakeup volume - adjust for your needs
0 7 * * 1-5 /usr/bin/mpc play # MPD starts playing at 7:00 - Mon-Fri
30 7 * * 1-5 /usr/bin/mpc stop # MPD stops at 7:30 - Mon-Fri
If you want to have an audible beep every exact hour from 08:00 AM to 09:00 PM even if the radio is playing music:
00 08-21 * * * speaker-test -c1 -t sine -f 800 -P 2 -p 0.4 -S 10 -l 1;
I’m also trying to get the touchscreen working even if my raspberry hasn’t got any desktop, just in console mode.
I would like to control the MPD_Cloudshell to switch scene, from “MPD” (default) to “System Information” and so on, every time the screen is touched.
Up to now I can grab the touch event in this way:
sudo apt-get install evtest
sudo evtest /dev/input/event1 | grep -o '(BTN_TOUCH), value 1'
Every time I touch the screen I get this:
(BTN_TOUCH), value 1
I am preparing a 8Gbytes, Raspberry Pi1/2/3, “ready to go” dietpi “MDP Internet Radio” image, with the following features, preinstalled and fully configured:
- MPD and MyMPD (client web interface)
- Alsa Equalizer (10 bands graphic equalizer)
- MPD-Cloudshell (see above)
- Raspi 3.2 Graphic LCD + 3 buttons, support
- i2c 20x4 text LCD, support
- Triggerhappy for USB numeric keypad support
- Infrared integrated remote control (Lirc)
- Mjpg-Streamer with both, USB webcam and Raspicam support, for live cam streaming
- Motion with both, USB webcam and Raspicam support, for triggering an action on a cam motion detected
- Battery RTC (real time clock) module support
- Sleep and Wakeup MPD internet radio
- Text2Speech (svox US,GB,DE,ES,FR,IT languages) Talking Clock (to speak the time) & Talking Reminder
- Automatic GPIO control for relay board to switch on/off the External Audio Amplifier on MPD start/stop (or anything else)
… and much more.
Everything is optimized for Raspberry Pi1B with 512 Mbytes RAM @ 1Ghz (overclock),
Stay tuned! 