XU4 - Cloudshell LCD with xorg

I am wondering if anybody has managed to get the LCD running cloudshell status information while using Kodi? I remember years ago Kodi (XBMC) could use LCD displays itself rather than using Xorg

Hi Chris,

I did find this on Odroid wiki to enable Xorg on LCD, and various other modes (including dual monitor): http://odroid.com/dokuwiki/doku.php?id=en:xu4_cloudshell_lcd_xorg

Make sure your kernel is updated with:

apt-get update
apt-get upgrade -y
apt-get install -y linux-headers-armhf-odroid-xu3 linux-image-armhf-odroid-xu3

I think you misunderstood me, running Kodi at the same time as using the cloudshell LCD doesn’t work, you can run one or the other, i was must hoping someone here had cracked it

Yep, my apologies. Still waiting for the morning coffee to kick in :slight_smile:

As far as I know, its not possible to use both screens independently at the same time. Your best bet would be to post on the Odroid forums and see if anyone else has found a method.

no worries thanks :slight_smile: This site needs a thanks button :wink:

Hehe, the site could do with a complete revamp 1st :slight_smile: Its a little too much 1999

hehehe it works though :slight_smile:

Finally I found out how achieve to do that by referencing https://www.raspberrypi.org/forums/viewtopic.php?f=44&t=91764&start=50 this post.

First Set AutoStart option to LXDE: Desktop in dietpi-config and edit /etc/X11/xorg.conf like below

Section "Device"
        Identifier      "HDMIOUT"
        Driver          "armsoc"
        Option          "fbdev"         "/dev/fb0"
        Option          "Debug"         "false"
        Option          "DPMS"          "false"
		Option         "ConnectedMonitor" "DFP-1"
EndSection

Section "Device"
        Identifier      "FBTFT"
        Driver          "fbdev"
        Option          "fbdev"         "/dev/fb1"
EndSection

Section "Monitor"
        Identifier      "monitor0"
#        Option          "Primary" "true"
EndSection

Section "Monitor"
        Identifier      "monitor1"
#        Option          "RightOf"       "monitor0"
EndSection

Section "Screen"
        Identifier      "screen0"
        Monitor         "monitor0"
        Device          "HDMIOUT"
        DefaultDepth    24
EndSection

Section "Screen"
        Identifier      "screen1"
        Device          "FBTFT"
        Monitor         "monitor1"
        DefaultDepth    16
EndSection

Section "ServerLayout"
        Identifier      "Default Layout"
        Option          "BlankTime"     "0"
        Option          "StandbyTime"   "0"
        Option          "SuspendTime"   "0"
        Option          "OffTime"       "0"
        Option          "AutoAddDevices" "off"
        Option          "DontVTSwitch" "false"
        Option          "Xinerame"      "off"
        Screen  0       "screen0"	0	0
        Screen  1       "screen1"	1920 	760
EndSection

Section "DRI"
        Mode            0666
EndSection

next, create a file /etc/xdg/autostart.desktop for kodi auto-start

[Desktop Entry]
Type=Application
Name=LXPolKit
Comment=Policykit Authentication Agent
Comment[uk]=Агент авторизації Policykit
Exec=lxpolkit
TryExec=lxpolkit
Icon=gtk-dialog-authentication
NotShowIn=GNOME;KDE;
Hidden=true

and create a file /etc/xdg/desktopmgr-autostart.desktop

[Desktop Entry]
Encoding=UTF-8
Name=Desktop autostart for secondary display
Comment=Start the LXDE environment on secondary display
Exec=/root/bin/desktopmgr.sh
OnlyShowIn=LXDE

for final step, create a script /root/bin/desktopmgr.sh

#!/bin/bash
#
# Start the LXDE desktop environment on the secondary display in a Dual-Head setup, where Xinerama is OFF.
# 

export SECONDARY_DISPLAY=:0.1
export LXDE_CONF_DIR=LXDE_01         # Directory under ~/.config/pcmanfm/ with LXDE configuration for this desktop.
export OPENBOX_CONFIG=$HOME/.config/openbox/lxde_-rc.xml

#xsetroot -display ${SECONDARY_DISPLAY} -solid thistle # For debug. If the secondary screen changes colour, we know that this script is running.

# Start a window manager.
DISPLAY=${SECONDARY_DISPLAY} openbox --config-file ${OPENBOX_CONFIG} &

# Start the desktop environment (wallpaper and desktop icons). It is actually the file manager pcmanfm that manages the desktop, when started with its --desktop option.
#
# Alas, there is a bug in pcmanfm.
# It won't start on DISPLAY :0.1 if there already is another pcmanfm running on the main DISPLAY :0.0
# It seems like it only checks if it already is running on the same X server,
# not taking the possible multiple displays on that server into consideration.
# Workaround by using the DISPLAY environment variable to point to a non-existing DISPLAY :9.0, where it does its check-if-i-am-already-running
# and using the --display argument to point out the real DISPLAY we want it running on.

DISPLAY=:9.0 pcmanfm --display=${SECONDARY_DISPLAY} --desktop  --profile LXDE &

# Start a terminal in the lower left corner of the display.
cd $HOME   # To make the terminal open in our home directory.
xterm htop -display :0.1 -fn *-fixed-*-*-*-8-* -maximized &

edit final line of the script, whatever you want to launch in Cloudshell LCD. Don’t forget display parameter “display:0.1”

and really final step

chmod +x /root/bin/desktopmgr.sh

after reboot you can see kodi on HDMI and htop on LCD (if you copied my script exactly)

I modified dietpi-cloudshell Script to run on xorg dual head environment.

    • Removed Configuration Menu : This part of code causes stop xterm even if it is not being used
  • Removed Parameter
  • Adjust Display Items and layout

You have to set dietpi-cloudshell to run in current screen or terminal in its configuration program.

Create /DietPi/dietpi/dietpi-cloudshell-xorg file

#!/bin/bash
{
	#////////////////////////////////////
	# DietPi Cloudshell
	#
	#////////////////////////////////////
	# Created by Daniel Knight / daniel_haze@hotmail.com / dietpi.com
	#
	#////////////////////////////////////
	#
	# Info:
	# - System Stats for Cloudshell (or monitor/terminal)
	#
	#////////////////////////////////////

	#Force en_GB Locale for whole script. Prevents incorrect parsing with non-english locales.
	LANG=en_GB.UTF-8

	HW_MODEL=$(sed -n 1p /DietPi/dietpi/.hw_model)
	CPU_CORES=$(nproc --all)

	#Version
	DIETPI_CLOUDSHELL_VERSION=5

	#/tmp/.* files used throughout this script.
	FP_TEMP="/tmp/dietpi-cloudshell"

	PROGRAM_NAME="DietPi-Cloudshell"

	#/////////////////////////////////////////////////////////////////////////////////////
	#Global misc functions
	#/////////////////////////////////////////////////////////////////////////////////////

	#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=$(echo -e "$return_value" | sed 's/^-./-0./')
		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="$(( $1 / 1024 )) KB"
			return_value="$(echo "scale=$decimal_count; $1 / 1024" | bc -l ) KB"

		# - MB
		elif (( $1 < 1073741824 )); then
			#return_value="$(( $1 / 1024 / 1024 )) MB"
			return_value="$(echo "scale=$decimal_count; $1 / 1024 / 1024" | bc -l ) MB"

		# - GB
		else
			#return_value="$(( $1 / 1024 / 1024 / 1024 )) GB"
			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="$(( $1 * 8 / 1000 )) Kbit"
				return_value="$(echo "scale=$decimal_count; $1 * 8 / 1000" | bc -l) Kbit"

		# - MBit
		elif (( $1 < 1000000000 )); then
				#return_value="$(( $1 * 8 / 1000 / 1000 )) Mbit"
				return_value="$(echo "scale=$decimal_count; $1  * 8 / 1000 / 1000" | bc -l) Mbit"

		# - GBit
		else
				#return_value="$(( $1 * 8 / 1000 / 1000 / 1000 )) Gbit"
				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"

    }

	#/////////////////////////////////////////////////////////////////////////////////////
	# 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"
	)
	#${#aCOLOUR[@]}

	#user colour
	#${aCOLOUR[$USER_COLOUR_INDEX]}
	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=$(cat /proc/uptime | awk '{print $1}')

		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)
		CPU_GOV=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
		CPU_TEMP=$(( $(cat /sys/class/thermal/thermal_zone0/temp) / 1000 ))

		#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

		CPU_FREQ_1=$(( $(cat /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 (( $HW_MODEL == 11 )); then
			CPU_FREQ_2=$(( $(cat /sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq) / 1000 ))
		fi

		CPU_USAGE=0
		FP_TEMP="/tmp/.cpu_usage"

		# PS (inaccurate)
		ps -axo %cpu | sed '1d' | sed 's/ //' > "$FP_TEMP"
		while read -r line
		do
			CPU_USAGE=$( echo "scale=1;$CPU_USAGE + $line" | bc -l )
		done < $FP_TEMP

		#ps returns usage of each core, so we devide the total by #n cores
		CPU_USAGE=$(echo "scale=0;$CPU_USAGE / $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
	STORAGE_FLASH_TOTAL=0
	STORAGE_FLASH_USED=0
	STORAGE_FLASH_FREE=0
	STORAGE_FLASH_PERCENT=0
	STORAGE_FLASH_PATH=$(sed -n 4p /DietPi/dietpi/.hw_model)

	STORAGE_USB1_TOTAL="N/A"
	STORAGE_USB1_USED="N/A"
	STORAGE_USB1_FREE="N/A"
	STORAGE_USB1_PERCENT=" Not installed."
	STORAGE_USB1_PATH="/mnt/usb_1"

	STORAGE_USB2_TOTAL="N/A"
	STORAGE_USB2_USED="N/A"
	STORAGE_USB2_FREE="N/A"
	STORAGE_USB2_PERCENT=" Not installed."
	STORAGE_USB2_PATH="/mnt/usb_2"
	
	Obtain_STORAGE(){

		FP_TEMP="/tmp/.df"
		df -h > $FP_TEMP

		STORAGE_FLASH_TOTAL="$( cat $FP_TEMP | grep -m1 $STORAGE_FLASH_PATH | awk '{print $2}')B"
		STORAGE_FLASH_USED="$( cat $FP_TEMP | grep -m1 $STORAGE_FLASH_PATH | awk '{print $3}')B"
		STORAGE_FLASH_FREE="$( cat $FP_TEMP | grep -m1 $STORAGE_FLASH_PATH | awk '{print $4}')B"
		STORAGE_FLASH_PERCENT=$( cat $FP_TEMP | grep -m1 $STORAGE_FLASH_PATH | awk '{print $5}' | sed 's/%//g')

		Percent_To_Graph $STORAGE_FLASH_PERCENT
		STORAGE_FLASH_PERCENT=$C_PERCENT_GRAPH

		#check for USB mount
		if (( $(cat $FP_TEMP | grep -ci -m1 "$STORAGE_USB1_PATH" ) == 1 )); then
			STORAGE_USB1_TOTAL="$( cat $FP_TEMP | grep -m1 $STORAGE_USB1_PATH | awk '{print $2}')B"
			STORAGE_USB1_USED="$( cat $FP_TEMP | grep -m1 $STORAGE_USB1_PATH | awk '{print $3}')B"
			STORAGE_USB1_FREE="$( cat $FP_TEMP | grep -m1 $STORAGE_USB1_PATH | awk '{print $4}')B"
			STORAGE_USB1_PERCENT=$( cat $FP_TEMP | grep -m1 $STORAGE_USB1_PATH | awk '{print $5}' | sed 's/%//g')

			Percent_To_Graph $STORAGE_USB1_PERCENT
			STORAGE_USB1_PERCENT=$C_PERCENT_GRAPH
		fi

		if (( $(cat $FP_TEMP | grep -ci -m1 "$STORAGE_USB2_PATH" ) == 1 )); then
			STORAGE_USB2_TOTAL="$( cat $FP_TEMP | grep -m1 $STORAGE_USB2_PATH | awk '{print $2}')B"
			STORAGE_USB2_USED="$( cat $FP_TEMP | grep -m1 $STORAGE_USB2_PATH | awk '{print $3}')B"
			STORAGE_USB2_FREE="$( cat $FP_TEMP | grep -m1 $STORAGE_USB2_PATH | awk '{print $4}')B"
			STORAGE_USB2_PERCENT=$( cat $FP_TEMP | grep -m1 $STORAGE_USB2_PATH | awk '{print $5}' | sed 's/%//g')

			Percent_To_Graph $STORAGE_USB2_PERCENT
			STORAGE_USB2_PERCENT=$C_PERCENT_GRAPH
		fi
	}

	#DietPi
	DIETPI_VERSION_CURRENT=0
	DIETPI_UPDATE_AVAILABLE=0
	DIETPI_WEBSITE="DietPi.com"
	DIETPI_HW_DESCRIPTION="N/A"
	Obtain_DIETPIINFO(){

		#DietPi version
		DIETPI_VERSION_CURRENT="${aCOLOUR[2]}$(cat /DietPi/dietpi/.version)$C_RESET"

		#Current HW
		DIETPI_HW_DESCRIPTION=$(sed -n 2p /DietPi/dietpi/.hw_model)

		#DietPi-Update available?
		DIETPI_UPDATE_AVAILABLE="N/A"
		if [ -f /DietPi/dietpi/.update_available ]; then

			#Set current version to red
			DIETPI_VERSION_CURRENT="${aCOLOUR[1]}$(cat /DietPi/dietpi/.version)$C_RESET"

			local update_version=$(cat /DietPi/dietpi/.update_available)
			if (( $update_version > 0 )); then
				DIETPI_UPDATE_AVAILABLE="${aCOLOUR[2]}$update_version$C_RESET"

			elif (( $update_version == -1 )); then
				DIETPI_UPDATE_AVAILABLE="${aCOLOUR[2]}New Image$C_RESET"
			fi
		fi


	}

	#Network Details
	NETWORK_DETAILS_ADAPTER="eth0"
	NETWORK_DETAILS_IP_INT=0
	NETWORK_DETAILS_MAC_ADDRESS=0
	NETWORK_DETAILS_SIGNAL_STRENGTH=0
	NETWORK_DETAILS_DUPLEXSPEED=0
	NETWORK_DETAILS_HOSTNAME=0
	NETWORK_DETAILS_MODE=0 #1=dhcp, 0=static
	Obtain_NETWORK_DETAILS(){

		FP_TEMP="/tmp/.ifconfig"

		#Hostname
		NETWORK_DETAILS_HOSTNAME=$(hostname)

		#Active network adapater.
		NETWORK_DETAILS_ADAPTER=$(sed -n 3p /DietPi/dietpi/.network)

		#Mode (dhcp/static)
		if (( $(cat /etc/network/interfaces | grep -ci -m1 "iface $NETWORK_DETAILS_ADAPTER inet dhcp") )); then
			NETWORK_DETAILS_MODE="Dhcp"
		else
			NETWORK_DETAILS_MODE="Static"
		fi

		#Ifconfig to /tmp
		ifconfig $NETWORK_DETAILS_ADAPTER > $FP_TEMP

		#IP / MAC addresses
		NETWORK_DETAILS_IP_INT=$(cat "$FP_TEMP" | grep -m1 'inet '| cut -d: -f2 | awk '{ print $1}')
		NETWORK_DETAILS_MAC_ADDRESS=$(cat /sys/class/net/$NETWORK_DETAILS_ADAPTER/address)

		#Speed/Strength
		#Wifi
		if (( $(echo $NETWORK_DETAILS_ADAPTER | grep -ci -m1 'wlan') == 1 )); then
			NETWORK_DETAILS_SIGNAL_STRENGTH="$(iwconfig $NETWORK_DETAILS_ADAPTER | grep -m1 'Signal level=' | awk '{ print $4 }' | sed 's/level=//g' | cut -f1 -d "/")%"
			NETWORK_DETAILS_DUPLEXSPEED="$(iwconfig $NETWORK_DETAILS_ADAPTER | grep -m1 'Bit Rate:' | awk '{ print $2 }' | sed 's/Rate://g')Mbit"
		#Lan
		else
			NETWORK_DETAILS_DUPLEXSPEED="$(cat /sys/class/net/$NETWORK_DETAILS_ADAPTER/speed) Mbit"
			#NETWORK_DETAILS_DUPLEXSPEED=$(mii-tool | awk '{print $3}')
			NETWORK_DETAILS_SIGNAL_STRENGTH="N/A"
		fi

	}

	#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(){

		#Store previous totals
		local total_previous_sent=$NETWORK_USAGE_TOTAL_CURRENT_SENT
		local total_previous_recieved=$NETWORK_USAGE_TOTAL_CURRENT_RECIEVED

		#Update current totals
		local mtu_size=$(netstat -N -i | grep "$NETWORK_DETAILS_ADAPTER" | awk '{print $2}')
		NETWORK_USAGE_TOTAL_CURRENT_RECIEVED=$(( $(netstat -N -i | grep "$NETWORK_DETAILS_ADAPTER" | awk '{print $4}') * $mtu_size ))
		NETWORK_USAGE_TOTAL_CURRENT_SENT=$(( $(netstat -N -i | grep "$NETWORK_DETAILS_ADAPTER" | awk '{print $8}') * $mtu_size ))

		#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)

		# - Ifconfig to /tmp
		#ifconfig $NETWORK_DETAILS_ADAPTER > $FP_TEMP
		#/sys/class/net/ values are being reset by system/kernel when they reach X size. Some sort of "cap".
		#NETWORK_USAGE_TOTAL_CURRENT_SENT=$(( $(cat /sys/class/net/$NETWORK_DETAILS_ADAPTER/statistics/tx_bytes) / 1024 / 1024 ))
		#NETWORK_USAGE_TOTAL_CURRENT_RECIEVED=$(( $(cat /sys/class/net/$NETWORK_DETAILS_ADAPTER/statistics/rx_bytes) / 1024 / 1024 ))

		#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 ))

	}

	#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
		FP_TEMP="/tmp/.mem"
		free -m -o > $FP_TEMP

		#RAM MB
		MEMORY_TOTAL=$(cat $FP_TEMP | grep -m1 'Mem: ' | awk '{print $2}')
		#Grab values and seperate cache from "used and free" results.
		MEMORY_CACHED=$(cat $FP_TEMP | grep -m1 'Mem: ' | awk '{print $7}')
		MEMORY_USED=$(( $(cat $FP_TEMP | grep -m1 'Mem: ' | awk '{print $3}') - $MEMORY_CACHED ))
		MEMORY_FREE=$(( $(cat $FP_TEMP | grep -m1 'Mem: ' | awk '{print $4}') + $MEMORY_CACHED ))
		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=$(cat $FP_TEMP | grep -m1 'Swap: ' | awk '{print $2}')
		# - Swap available and active
		if (( $MEMORY_SWAPTOTAL > 0 )); then
			MEMORY_SWAPUSED=$(cat $FP_TEMP | grep -m1 'Swap: ' | awk '{print $3}')
			MEMORY_SWAPFREE=$(cat $FP_TEMP | grep -m1 'Swap: ' | 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=$(cat "$pihole_log_file" | grep "$today" | awk '/query/ {print $7}' | wc -l)
		#Prevent / 0 on percentage
		if (( $PIHOLE_QUERY_COUNT <= 0 )); then
			PIHOLE_QUERY_COUNT=1
		fi

		PIHOLE_TOTAL_ADS=$(cat "$pihole_log_file" | grep "$today" | 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
	RUN_LOOP=1
	RUN_INTRO=1

	#SCENE INDEXS
	SCENE_CURRENT=2
	SCENE_MAX=7
	SCENE_HARDLIMIT=10 # This must be higher than SCENE_MAX. If we need more than 10, modify save/read file, and whiptail scenes menu

	#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<$SCENE_HARDLIMIT; 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 ""
			echo -e ""
			echo -e ""
			echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}${aAnimation[$i]}"
			echo -e "$C_RESET          v$DIETPI_CLOUDSHELL_VERSION"
			echo -e ""
			echo -e "       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="DietPi - Cloudshell v$DIETPI_CLOUDSHELL_VERSION"
		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
		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 (( $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

	}

	#Storage
	Update_Scene_1(){

		#Update data
		Obtain_STORAGE

		#Clear screen
		clear

		#Banner
		#echo -e "$C_RESET $BANNER_PRINT"

		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Storage:                     "
		echo -e "$C_RESET$STORAGE_FLASH_PERCENT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Flash Used: $C_RESET$STORAGE_FLASH_USED / $STORAGE_FLASH_TOTAL"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Flash Free: $C_RESET$STORAGE_FLASH_FREE"
		
		echo -e "$C_RESET$STORAGE_USB1_PERCENT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} USB1 Used: $C_RESET$STORAGE_USB1_USED / $STORAGE_USB1_TOTAL"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} USB1 Free: $C_RESET$STORAGE_USB1_FREE"
		
		echo -e "$C_RESET$STORAGE_USB2_PERCENT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} USB2 Used: $C_RESET$STORAGE_USB2_USED / $STORAGE_USB2_TOTAL"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} USB2 Free: $C_RESET$STORAGE_USB2_FREE"
	}

	#DietPi
	Update_Scene_2(){

		#Update data
		Obtain_DIETPIINFO

		#Clear screen
		clear

		#Banner
		echo -e "$C_RESET $BANNER_PRINT"
		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE DietPi:                     "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Version   ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $DIETPI_VERSION_CURRENT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Updates   ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $DIETPI_UPDATE_AVAILABLE"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Device    ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $DIETPI_HW_DESCRIPTION"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Website   ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $DIETPI_WEBSITE"

	}

	#NETWORK DETAILS
	Update_Scene_3(){

		#Update data
		Obtain_NETWORK_DETAILS

		#Clear screen
		clear

		#Banner
		echo -e "$C_RESET $BANNER_PRINT"
		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Network Details:            "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} IP      : $C_RESET$NETWORK_DETAILS_IP_INT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Mode    : $C_RESET$NETWORK_DETAILS_MODE"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Adapter : $C_RESET$NETWORK_DETAILS_ADAPTER"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Duplex  : $C_RESET$NETWORK_DETAILS_DUPLEXSPEED"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Signal  : $C_RESET$NETWORK_DETAILS_SIGNAL_STRENGTH"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Hostname: $C_RESET$NETWORK_DETAILS_HOSTNAME"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} MAC: $C_RESET$NETWORK_DETAILS_MAC_ADDRESS"

	}

	#NETWORK USAGE
	Update_Scene_4(){

		#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_5(){

		#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_6(){

		#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(){

		#0-9	Core Settings
		REFRESH_RATE=$(sed -n 1p $FILEPATH_SETTINGS)
		USER_COLOUR_INDEX=$(sed -n 2p $FILEPATH_SETTINGS)
		STORAGE_USB1_PATH=$(sed -n 3p $FILEPATH_SETTINGS)
		TEMPERATURE_OUTPUT_TYPE=$(sed -n 4p $FILEPATH_SETTINGS)
		NETWORK_USAGE_CURRENT_OUTPUT_TYPE=$(sed -n 6p $FILEPATH_SETTINGS)

		#10-19	Enabled Scenes
		local sed_index=11
		for ((i=0; i<$SCENE_MAX; i++))
		do
			aEnabledScenes[$i]=$(sed -n "$sed_index"p $FILEPATH_SETTINGS)
			((sed_index++))
		done

	}

	Write_Settings_File(){

		#0-9	Core Settings
		echo -e "$REFRESH_RATE" > $FILEPATH_SETTINGS
		echo -e "$USER_COLOUR_INDEX" >> $FILEPATH_SETTINGS
		echo -e "$STORAGE_USB1_PATH" >> $FILEPATH_SETTINGS
		echo -e "$TEMPERATURE_OUTPUT_TYPE" >> $FILEPATH_SETTINGS
		echo -e "$NETWORK_USAGE_CURRENT_OUTPUT_TYPE" >> $FILEPATH_SETTINGS
		echo -e "" >> $FILEPATH_SETTINGS
		echo -e "" >> $FILEPATH_SETTINGS
		echo -e "" >> $FILEPATH_SETTINGS
		echo -e "" >> $FILEPATH_SETTINGS

		#10-19	Enabled Scenes
		for ((i=0; i<$SCENE_HARDLIMIT; i++))
		do
			echo -e "${aEnabledScenes[$i]}" >> $FILEPATH_SETTINGS
		done

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Init
	#/////////////////////////////////////////////////////////////////////////////////////
	Init(){

		#--------------------------------------------------------------------------------
		#Load Settings file. Generate if required.
		if [ ! -f "$FILEPATH_SETTINGS" ]; then
			Write_Settings_File
		else
			Read_Settings_File
		fi

		#--------------------------------------------------------------------------------
		#VM disable CPU scene
		if (( $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[6]=0

			#Save settings to disable scene
			Write_Settings_File
		fi

		#--------------------------------------------------------------------------------
		#Ensure we have at least 1 Scene enabled in the settings file.
		local enabled_scene=0
		for ((i=0; i<$SCENE_MAX; i++))
		do
			if (( "${aEnabledScenes[$i]}" == 1 )); 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[2]=1
			SCENE_CURRENT=2

			#Save settings to prevent re-occuring
			Write_Settings_File

		fi

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# MAIN
	#/////////////////////////////////////////////////////////////////////////////////////
	#-----------------------------------------------------------------------------------
	#Init
	Init
	#-----------------------------------------------------------------------------------
	#Run DietPi-Cloudshell

	#prevent sleep - moved to login
	#set font - moved to login
	#Disable Cursor - moved to login

	#Start Intro
	if (( $RUN_INTRO == 1 )); then
		Run_Intro
	fi

	#Set Nice to +10 (not critical)
	renice -n 10 $$ &> /dev/null

	#Start display updates
	while (( $RUN_LOOP == 1 ))
	do

		#Update enabled scenes
		if (( ${aEnabledScenes[$SCENE_CURRENT]} == 1 )); then

			Update_Banner
			Update_Scene_$SCENE_CURRENT

			#Apply refresh rate delay
			sleep $REFRESH_RATE

		fi

		#Scene Switcher
		((SCENE_CURRENT++))

		#Cap
		if (( $SCENE_CURRENT >= $SCENE_MAX )); then
			SCENE_CURRENT=0
		fi

	done

	#-----------------------------------------------------------------------------------
	#Clean up temp files
	rm "$FP_TEMP" &> /dev/null
	#-----------------------------------------------------------------------------------
	#Delete[] Global arrays
	unset aCOLOUR
	unset aEnabledScenes
	#-----------------------------------------------------------------------------------
	exit
	#-----------------------------------------------------------------------------------
}

after creating script, make it excutable

chmod +x /DietPi/dietpi/dietpi-cloudshell-xorg

and modify final line of /root/bin/desktopmgr.sh

xterm /DietPi/dietpi/dietpi-cloudshell-xorg -fullscreen -fn 10x20 -display :0.1 &

Upgrade to v137 prevents this dual head process from functioning properly?!?!

I’ve been running dual head for the past couple months without problems. After the update to v137 the dual head process seems to fail.

Everything starts properly and the LCD shows the first status screen. When the LCD tries to update to the second status screen it appears to loose control and the basic desktop screen, LXDE, takes over. I have reviewed the code provided above and I have not noticed any changes made as a result of the update.

Re-running the /root/bin/desktopmgr.sh scripts brings the LCD back, but it returns to the LXDE screen at the first update again.

I use “Preferences ->Default Applications for LXSession->Autostart” and added /root/bin/desktopmgr.sh
I autostart the LXDE desktop via the Dietpi-config “autostart” option (I don’t start KODI automatically)

Any help would be appreciated.

Everytime DietPi updates, all DietPi scripts are overwritten with the latest versions. So in this case, you’d need to overwrite dietpi-cloudshell with the script posted in this thread.

If that still fails, we have a major change to DietPi-Cloudshell service comming in v140, which fixes some issues with failing to start. This may also require additional changes to make dual head combination functional.
If you created a backup with dietpi-backup, once everything was setup for dual head, you can simply restore to your previous working dual head setup.

If noone has been able to find a “solution” after v140, i’ll see if we can get dual head supported in the sourcecode permanently.

v140 should be released in the next few days.