Introduction
This page describes how to Control TVâs and power outlets. The process is called âInternet of Thingsâ (IoT). The IoT programs here are designed for Linux and have been tested in Ubuntu. The coding is done in Bash.
At the heart of the system is the tvpowered
program
which starts after you login. A configuration file is required
in your ~/.config/autostart
directory to launch it.
Press the power button on your computer and then:
- tvpowered script wakes up from sleep
- Sony TV turns on
- Bias light behind Sony TV (a.k.a. Primary TV or TV #1) turns on
- Bias light behind TCL TV (a.k.a. Google TV, Secondary TV or TV #2) turns on
- TCL / Google TV turns on
Press the power button on Sony TV remote control and then:
- Sony TV will be shut off (which power button does anyway)
- TCL/Google Android TV will be shut off
- Bias light behind the Sony TV will be shut off
- Bias light behind the TCL / Google TV will be shut off
- Computer will be put to sleep or shutdown
- tvpowered script continues when system wakes up
A variety of independent scripts are provided to make life convenient.
The bash script light-tog
toggles the wall outlet power
behind the main TV (Sony). In this case the power controls a
lamp to provide bias lighting which reduces eye strain.
The bash script light-tog2
toggles the wall outlet power
behind the second TV (TCL). In this case the power controls a
lamp to provide bias lighting which reduces eye strain.
To power off the bias lights behind the TVs, the script
/etc/NetworkManager/dispatcher.d/pre-down.d/smartplug_off
can be run. See below for details on setting up script.
Note the same functionality is provided by tvpowered
when the system is turned off with the TV remote.
There are five additional bash scripts to control a Sony TV screen:
pictureoff.sh
Turns off the Sony TV screen but leaves sound onpictureoff
same as pictureoff.sh but resides in pathpictureon.sh
Turns on the Sony TV screen which consumes 100 wattspicturetog.sh
Toggles Sony TV screen off and onpicturetog
same as picturetog.sh but resides in path
To assist with setting up your âInternet of Thingsâ (IoT) the program ssh-setup is used to document the devices attached to your LAN and/or Wi-Fi router.
Table of Contents
- Introduction
- âtvpoweredâ Sony Bravia TV Controller
- âsmartplug_offâ Smart Plugs Turn Off Lights
- âsoundâ Switch System Sound Output to HDMI
- Primary TV (Sony) and Second TV (TCL) Setup
- âlight-togâ Toggle Light Behind Primary (Sony) TV
- âlight-tog2â Toggle Light Behind Second TV
- âpicturetogâ Toggle Sony TV picture Off and On
- âpictureoffâ Turn Off Sony TV Picture
- TP-Link Wi-Fi Smart Plug âhs100.shâ Script
nvhda
Enable nVidia GeForce GTX 970M Sound- Discover IP addresses With
ssh-setup
âtvpoweredâ Sony Bravia TV Controller
The tvpowered bash script is the heart of the
IoT (Internet of Things) system provided by Pippim.
The script is loaded when you sign on because it
is stored in the ~/.config/autostart
directory.
tvpowered automatically establishes communication with your Sony TV and displays a desktop notification when successful.
âtvpoweredâ Key Features
There are some unique âbells & whistlesâ:
- When volume is changed via TV remote control, the volume level is displayed in desktop notification.
- The desktop notification is instantly updated when consecutive volume changes are made. The usual five or ten second delay is overriden for instant feedback.
- When Sony TV is powered off via TV remote control, the power outlet for the light behind the TV and secondary TV is turned off and your system is put to sleep or shutdown. The TCL / Google TV is also powered off.
- You are reminded if communication between the TV and your computer isnât working.
- When your computer system wakes up from sleep / resumes from suspend, the lights behind the Sony TV and TCL / Google TV are turned on.
- Work in Progress is to turn on Sony TV and Google TV as well.
Change Primary TV Volume
When the main TV (Sony) picture is normally turned off, you have no idea what the sound system current volume level is. The tvpowered script will display a notification on whatever monitor you are currently working on when the volume is changed using the TVâs remote control. The notification message includes a progress bar from 0 (TV muted) to 100 (TV maximum volume).
If you are interested in the Bash code to make a progress bar, the relevant code is below:
VolumeBar () {
Bar="" # Progress Bar / Volume level
Len=25 # Length of Progress Bar / Volume level
Div=4 # Divisor into Volume for # of full blocks
Fill="â" # Fill background up to $Len
Parts=8 # Divisor into Volume for # of part blocks
# UTF-8 left blocks: 1, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8
Arr=("â" "â" "â" "â" "â" "â" "â" "â")
FullBlock=$((${1} / Div)) # Number of full blocks
PartBlock=$((${1} % Parts)) # Size of partial block (array index)
while [[ $FullBlock -gt 0 ]]; do
Bar="$Bar${Arr[0]}" # Add 1 full block into Progress Bar
(( FullBlock-- )) # Decrement full blocks counter
done
# If remainder zero no partial block, else append character from array
if [[ $PartBlock -gt 0 ]]; then
Bar="$Bar${Arr[$PartBlock]}"
fi
while [[ "${#Bar}" -lt "$Len" ]]; do
Bar="$Bar$Fill" # Pad Progress Bar with fill character
done
} # VolumeBar
âtvpoweredâ Bash Script
Below is the Bash script you can copy to your system:
#!/bin/bash
# NAME: tvpowered
# PATH: /usr/bin/ OR ~/bin (/home/USERNAME/bin) OR /mnt/e/bin/
#
# DESC: When TV is powered off automatically suspend the laptop.
# DATE: June 9, 2020. Modified January 13, 2024.
#
# NOTE: Written for Ask Ubuntu question:
# https://askubuntu.com/questions/1247484/
# 4-clicks-to-shut-down-ubuntu-can-we-reduce-this
# UPDT: Jun 10 2020: Make name politically correct for Microsoft guidelines.
# Change name from 'slave2tv' to 'tvpowered'. Abandon approach of polling
# i2c, drm, i915, nvidia, xrandr, etc to see if monitor turned off. Setup
# WiFi on TV instead and use Sony REST API to communicate TV status.
# Jun 11 2020: Add pop-up bubble status messages. Add dependencies.
# Add Init. Add WaitUserSignOn. Add $SCTL constant. Convert
# in-line code to mainline format.
# Oct 03 2020: If ethernet disconnected we don't want to suspend.
# Add Init. Add WaitUserSignOn. Add $SCTL constant. Convert
# in-line code to mainline format.
# Oct 18 2020: If WiFi disconnected we don't want to suspend.
# Dec 23 2020: After resume turn off picture with power savings.
# Dec 31 2020: Fast popping bubble messages when volume changes.
# Jan 09 2021: Improve performance and reduce system resources.
# Jan 31 2021: Switch from /tmp to /run/user/1000 (RAM).
# Mar 13 2023: New IP address 19 after power outage.
# Mar 26 2023: Change volume partial UTF-8 ticks from 4 to 8.
# Mar 28 2023: Change call to `pictureoff`
# Mar 30 2023: Google TV to sleep (TV Remote Power Off).
# May 28 2023: Turn on TVs and lights behind TVs on resume.
# Jun 10 2023: Use nmap to verify TCL/Google TV on-line.
# Jan 13 2024: Notes on TCL/Google TV debug options.
# Sep 29 2024: Create TurnGtvOn() and TurnGtvOff()
# Embed code - No longer requires light-tog and light-tog2 or
# /etc/NetworkManager/dispatcher.d/pre-down.d/smartplug_off
# Replace 'nmap' with much faster: 'timeout 0.1 adb connect'
# Sep 30 2024: If sunlight is 100 % then don't turn on bias lights.
# Oct 04 2024: If GTV already powered off, don't try again.
# Oct 11 2024: Fix log message format
# Oct 12 2024: 'GtvPowerStatus': Speed up & simply turning Google TV on.
# Oct 13 2024: Logging optional for SonyPowerStatus() & GtvPowerStatus()
# Oct 17 2024: Check sunlight percentage last when eyesome up-to-date.
# TODO: Create HomA (Home Automation) using Python (homa.py) that powers
# devices on/off in parallel. Create HomAc (client) for HomAd (daemon).
# adb will hang if Google TV is off so use ping to see if TV is on:
# $ time sudo ping 192.168.0.17 -c1 -W1
# PING 192.168.0.17 (192.168.0.17) 56(84) bytes of data.
# 64 bytes from 192.168.0.17: icmp_seq=1 ttl=64 time=0.696 ms
# --- 192.168.0.17 ping statistics ---
# 1 packets transmitted, 1 received, 0% packet loss, time 0ms
# rtt min/avg/max/mdev = 0.696/0.696/0.696/0.000 ms
# real 0m0.007s
# user 0m0.000s
# sys 0m0.006s
# To prevent adb hanging, use linux timeout command:
# $ timeout 0.1 adb connect 192.168.0.17
# already connected to 192.168.0.17:5555
# Sources:
# https://gist.github.com/kalleth/e10e8f3b8b7cb1bac21463b0073a65fb#cec-sonycec
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/audio/v1_0/setAudioVolume/index.html
# https://developer.sony.com/develop/audio-control-api/get-started/http-example#tutorial-step-2
# https://en.wikipedia.org/wiki/CURL
# https://stackoverflow.com/questions/7172784/how-do-i-post-json-data-with-curl
# https://stackoverflow.com/questions/2829613/how-do-you-tell-if-a-string-contains-another-string-in-posix-sh
SCTL=suspend # systemctl parameter: 'suspend' or 'poweroff'
STV_IP=192.168.0.19 # IP address for Sony TV on LAN
GTV_IP=192.168.0.17 # IP address for Google TV on LAN for Android Debug Bridge
GTV_Online="" # Google TV is not turned on
PWRD=123 # Password for Sony TV IP Connect (Pre-Shared key)
# TCL / Goggle TV MAC address for wake on lan. No effect if TV already on.
GTV_MAC="c0:79:82:41:2f:1f"
# 2024-09-30 - If problems revoke USB, turn off USB debugging, click build 7 times
# RSA key fingerprint: a7:ad:1f:82:66:16:15:eb:bc:54:85:56:ce:ad:d4:2b
# ~/.android/adbkey.pub - holds a lot more complicated key 700+ characters
# Nighttime bias lights
SLI_IP="192.168.0.15" # Sony TV bias light
GLI_IP="192.168.0.20" # TCL/Google TV bias light
SunlightPercent="" # Percentage of sunlight, requires eyesome brightness
# Must have curl package.
command -v curl >/dev/null 2>&1 || { echo >&2 \
"'curl' package required but it is not installed. Aborting."; \
exit 2; }
# Must have notify-send from libnotify-bin package
command -v notify-send >/dev/null 2>&1 || { echo >&2 \
"'libnotify-bin' package required but it is not installed. Aborting."; \
exit 3; }
# Must have adb (Android Debug Bridge) package
# TODO: Test when needed and skip code if not installed
command -v adb >/dev/null 2>&1 || { echo >&2 \
"'adb' package required but it is not installed. Aborting."; \
exit 4; }
# Must have nmap package
#command -v nmap >/dev/null 2>&1 || { echo >&2 \
# "'nmap' package required but it is not installed. Aborting."; \
# exit 5; }
cURLit () {
# $1 = JSON String in pretty format converted to file for cURL --data.
# $2 = Sony subsystem to talk to, eg accessControl, audio, system, etc.
# 3 = variable name to receive reply from TV
local TEMP Result ReturnState
# Declare Result as reference to argument 3 provided (Bash 4.3 or greater)
declare -n Result=$3 # ERROR: declare: `': not a valid identifier
# Create temporary file in RAM for curl command
TEMP=$(mktemp --tmpdir=/run/user/1000 tvpowered.XXXXXXXX)
echo "$1" > "$TEMP"
# -s = silent
Result=$(curl -s -H "Content-Type: application/json; charset=UTF-8" \
-H "X-Auth-PSK: $PWRD" \
--data @"$TEMP" \
http://$STV_IP/sony/"$2")
if [[ -n "$Result" ]]; then
# 2024-10-11 - Results appear every second and aren't useful:
# curl Result: {"result":[{"status":"active"}],"id":50}
# curl Result: {"result":[[{"target":"speaker","volume":22,"mute":false,
# "maxVolume":100,"minVolume":0},{"target":"headphone","volume":15,"mute":false,
# "maxVolume":100,"minVolume":0}]],"id":33}
: # no-op
fi
ReturnState="$?"
# TO-DO: check $? and if non-zero pop up dialog with $TEMP contents
rm "$TEMP"
# Test string
#curl -s -H "Content-Type: application/json; charset=UTF-8" -H "X-Auth-PSK: 123" --data "{ "method": "getPowerStatus", "id": 50, "params": [], "version": "1.0" }" http://192.168.0.16sony/system
} # cURLit
GtvPowerStatus () {
# Check if GTV is turned on. Maybe spammed if checking for power off
local Reply
if [[ "$1" == "loggable" ]] ; then
log "GtvPowerStatus(): Get TCL / Google TV power status on '$GTV_IP'"
fi
# Is it turned on now? Reply is null if timeout which occurs when device off
Reply=$(timeout 1 adb shell dumpsys input_method | grep -i screenon)
if [[ $Reply == *"true"* ]]; then
if [[ "$1" == "loggable" ]] ; then
log "GtvPowerStatus(): TCL / Google TV is ON. Reply is: '$Reply'"
fi
return 0 # Reply = "screenOn = true"
else
if [[ "$1" == "loggable" ]] ; then
log "GtvPowerStatus(): TCL / Google TV is OFF. Reply is: '$Reply'"
fi
return 1 # Reply = "Terminated" (Timeout)
fi
} # GtvPowerStatus
TurnGtvOn() {
# TurnGtvOn sends KEYCODE_WAKEUP as if remote control
if command -v adb >/dev/null 2>&1 ; then
log "TurnGtvOn(): 'timeout 0.1 adb shell input keyevent KEYCODE_WAKEUP'"
timeout 0.1 adb shell input keyevent KEYCODE_WAKEUP
fi
} # TurnGtvOn
TurnGtvOff () {
# TurnGtvOff sends KEYCODE_SLEEP as if remote control
# Must have adb (Android Debug Bridge) package
command -v adb >/dev/null 2>&1 || { echo >&2 \
"'adb' package required but it is not installed. Skipping."; \
return 4; }
local Reply
# Is it turned on now?
#Reply=$(timeout 1 adb shell dumpsys input_method | grep -i screenon)
#if ! [[ $Reply == *"true"* ]]; then
if ! GtvPowerStatus ; then
log "TurnGtvOff(): TCL / Google TV is already OFF. No reply on: '$GTV_IP'"
return 0 # Reply = "Terminated" (Timeout)
fi
# Reply = "screenOn = true"
log "TurnGtvOff(): 'adb shell input keyevent KEYCODE_SLEEP'"
adb shell input keyevent KEYCODE_SLEEP # Turn Google TV off
log "TurnGtvOff(): 'adb disconnect'"
adb disconnect # Will reconnect on resume
} # TurnGtvOff
TurnSonyOn () {
local Reply ReturnState
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/setPowerStatus/index.html
JSONstr='{
"method": "setPowerStatus",
"id": 55,
"params": [{"status": true}],
"version": "1.0"
}'
cURLit "$JSONstr" "system" Reply # No $ for Reply variable! pass pointer
ReturnState="$?" # Usually '6', not checked.
#echo "ReturnState: $ReturnState Reply: $Reply" # Remove # for debugging
# Reply: { "result": [], "id": 55 }
log "TurnSonyOn(): value of ReturnState: '$ReturnState'"
} # TurnSonyOn
TurnSonyOff () {
local Reply ReturnState
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/setPowerStatus/index.html
JSONstr='{
"method": "setPowerStatus",
"id": 55,
"params": [{"status": false}],
"version": "1.0"
}'
cURLit "$JSONstr" "system" Reply # No $ for Reply variable! pass pointer
ReturnState="$?" # Usually '6', not checked.
#echo "ReturnState: $ReturnState Reply: $Reply" # Remove # for debugging
# Reply: { "result": [], "id": 55 }
log "TurnSonyOff(): value of ReturnState: '$ReturnState'"
} # TurnSonyOff
ForceLight() {
# $1 plugname
# $2 "ON" or "OFF"
# NOTE: hs100.sh must be installed for hs100 tp-link power plug.
# https://developer.gnome.org/NetworkManager/stable/NetworkManager.html
# Must have hs100.sh
command -v hs100.sh >/dev/null 2>&1 || { echo >&2 \
"'hs100.sh' required but it is not installed. Skipping."; \
return 6; }
PlugName="$1" # Sony TV bias light or Google TV bias light
Force="$2" # "ON" or "OFF"
TvName="$3" # "Sony TV" or "Google TV"
log "Set $TvName Bias Light $PlugName to $Force."
status=$(hs100.sh -i "$PlugName" check | cut -f2)
if [ -z "$status" ]; then
log "Error hs100.sh 'check' returned null for IP $PlugName."
return 7
fi
if [ "$status" == "$Force" ] ; then
log "$TvName Bias Light $PlugName status is already $status."
return 0 # Nothing to do already correct state
fi
if [ "$status" == "OFF" ] ; then
hs100.sh -i "$PlugName" on
elif [ "$status" == "ON" ] ; then
hs100.sh -i "$PlugName" off
else
log "Error hs100.sh not responding check connection and IP $PlugName."
fi
} # ForceLight
GetSunlightPercent () {
# Return 0 if power on, 1 if power off
local Reply fname
fname="/usr/local/bin/.eyesome-percent"
#Reply=$(cat /usr/local/bin/.eyesome-percent 2>/dev/null | cut -d' ' -f1)
Reply=$(cut -d' ' -f1 < "$fname")
SunlightPercent=""
if [ -z "$Reply" ] ; then
log "GetSunlightPercent(): Error reading '$fname'"
return 1 # Reply = <null> string
elif [[ $Reply == *"No such file"* ]]; then
# Reply = "bash: /usr/local/bin/.eyesome-percen: No such file or directory"
log "GetSunlightPercent(): Error: '$Reply'"
return 1
else
log "GetSunlightPercent(): '$fname' percentage: '$Reply'"
SunlightPercent="$Reply"
return 0 # Reply = "0 %" or "50 %" or "100 %", etc.
fi
} # GetSunlightPercent
TurnLightsOn() {
# Turn bias lights on if sunlight percentage < 100%
GetSunlightPercent
if [[ -z "$SunlightPercent" ]] || (( SunlightPercent < 100 )); then
ForceLight "$SLI_IP" ON "Sony TV"
ForceLight "$GLI_IP" ON "TCL / Google TV"
fi
} # TurnLightsOn
TurnLightsOff() {
ForceLight "$SLI_IP" OFF "Sony TV"
ForceLight "$GLI_IP" OFF "TCL / Google TV"
} # TurnLightsOff
GtvConnect () {
# Return 0 if able to connect, 1 if unable to connect
# Set GTV_Online "" if reply contains "error" or "unable", else connection message
# 2024-10-12 - Recent design was two attempts, but now with GtvPowerStatus only one
# attempt is needed.
local Reply Cnt
GTV_Online="" # Caller checks GTV_Online. If blank then not connected
if command -v adb >/dev/null 2>&1 ; then
log "GtvConnect(): Send: 'timeout 0.1 adb connect' to: '$GTV_IP'"
else
GTV_Online="adb command not found"
log "GtvConnect(): value of GTV_Online: '$GTV_Online'"
return 0 # Must return true to exit forever loop
fi
Reply=$(timeout 0.1 adb connect "$GTV_IP" 2>&1)
log "GtvConnect(): Reply: '$Reply'"
if [[ $Reply == *"connected"* ]] ; then
GTV_Online="$Reply"
log "GtvConnect(): success! | Reply: '$Reply'"
return 0 # Reply = "connected to 192.168.0.17:5555"
fi
if [ -z "$Reply" ] ; then
log "GtvConnect(): failed due to no reply."
elif [[ $Reply == *"unable"* ]] || [[ $Reply == *"error"* ]] ; then
log "GtvConnect(): failed due to no reply with 'unable' or 'error'."
else
log "GtvConnect(): failed due to unknown error."
fi
return 1
# 2024-10-12 - Original two attempt loop below is now deprecated
# TWO attempts required because:
# Sending magic packet to 255.255.255.255:9 with c0:79:82:41:2f:1f
# value of GTV_Online: 'connected to 192.168.0.17:5555'
# Connecting to ADB (Android Debugging Bridge) on: 192.168.0.17
# error: device offline
for ((i = 0 ; i <= 1 ; i++ )) ; do
Reply=$(timeout 0.1 adb connect "$GTV_IP" 2>&1)
GTV_Online=""
if [ -z "$Reply" ] ; then
return 1 # Reply = <null> string
elif [[ $Reply == *"unable"* ]] || [[ $Reply == *"error"* ]] ; then
return 1 # Reply = "unable to connect..." / "error: device offline"
elif (( i == 0 )) ; then
log "GtvConnect(): sleeping at i: '$i' | Reply: '$Reply'"
# Assume success and power on ASAP, worse case is second wakeup
TurnGtvOn # Send KEYCODE_WAKEUP
sleep 0.5 # If not connected due to lag sleep before trying again
continue
elif [[ $Reply == *"connected"* ]] ; then
GTV_Online="$Reply"
log "GtvConnect(): success at i: '$i' | Reply: '$Reply'"
return 0 # Reply = "connected to 192.168.0.17:5555"
else
log "GtvConnect(): failed at i: '$i' | Reply: '$Reply'"
return 1 # Reply = "connected to 192.168.0.17:5555"
fi
done
} # GtvConnect
SonyPowerStatus () {
# Return 0 if power on, 1 if power off
local Reply ReturnState
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/getPowerStatus/index.html
JSONstr='{
"method": "getPowerStatus",
"id": 50,
"params": [],
"version": "1.0"
}'
cURLit "$JSONstr" "system" Reply # No $ for Reply variable! pass pointer
ReturnState="$?" # Usually '6', not checked.
#echo "ReturnState: $ReturnState Reply: $Reply" # Remove # for debugging
# Reply: {"result":[{"status":"active"}],"id":50}
# or: {"result":[{"status":"standby"}],"id":50}
if [[ "$1" == "loggable" ]] ; then
log "SonyPowerStatus(): value of Reply: $Reply" # Spams every second
fi
# Does 'active' substring exist in TV's reply?
[[ "${Reply#*active}" != "$Reply" ]] && return 0
# TV is turned off (standby) or no network (blank)
return 1
} # SonyPowerStatus
GetVolume () {
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/audio/v1_0/getVolumeInformation/index.html
JSONstr='{
"method": "getVolumeInformation",
"id": 33,
"params": [],
"version": "1.0"
}'
# Then pass string to cURL for execution
cURLit "$JSONstr" "audio" Reply
# Sample output:
# Volume:, {"result":[[{"target":"speaker","volume":44,"mute":false,
# "maxVolume":100,"minVolume":0},{"target":"headphone","volume":15,
# "mute":false,"maxVolume":100,"minVolume":0}]],"id":33}
Start="${Reply:41:4}"
Volume=${Start%,*}
return "$Volume"
} # GetVolume
Bar="" # Global Volume Level bar
VolumeBar () {
Bar="" # Progress Bar / Volume level
Len=25 # Length of Progress Bar / Volume level
Div=4 # Divisor into Volume for # of full blocks
Fill="â" # Fill background up to $Len
Parts=8 # Divisor into Volume for # of part blocks
# UTF-8 left blocks: 1, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8
Arr=("â" "â" "â" "â" "â" "â" "â" "â")
FullBlock=$((${1} / Div)) # Number of full blocks
PartBlock=$((${1} % Parts)) # Size of partial block (array index)
while [[ $FullBlock -gt 0 ]]; do
Bar="$Bar${Arr[0]}" # Add 1 full block into Progress Bar
(( FullBlock-- )) # Decrement full blocks counter
done
# If remainder zero no partial block, else append character from array
if [[ $PartBlock -gt 0 ]]; then
Bar="$Bar${Arr[$PartBlock]}"
fi
while [[ "${#Bar}" -lt "$Len" ]]; do
Bar="$Bar$Fill" # Pad Progress Bar with fill character
done
} # VolumeBar
log () {
# Echo output to screen if connected. Always output to logger.
if [ -t 1 ] ; then # Connected to terminal supporting "echo" command?
local ts
ts=$(date +"%T.%3N") # Timestamp HH:MM:SS.hhh
echo "$ts" "$1"
else
# logger already has timestamp. '-t' argument repeats string on every line
logger --id=$$ -t "tvpowered" "$1"
fi
} # log
WaitForSignOn () {
# tvpowered might be loaded during boot. The user name is required
# for sending popup bubble messages and dialogs to screen. We must
# wait until user signs on to get .Xauthority file settings.
log "WaitForSignOn(): ...until non-blank: UserName="
log " who -u | grep -F '(:0)' | head -n 1 | awk '{print \$1}'"
# code lifted from eyesome.sh
SpamWait=1
TotalWait=0
# Wait for user to sign on then get Xserver access for xrandr calls
UserName=""
while [[ $UserName == "" ]]; do
# Find UserName currently logged in.
UserName="$(who -u | grep -F '(:0)' | head -n 1 | awk '{print $1}')"
[[ $UserName != "" ]] && break
sleep $SpamWait
TotalWait=$(( TotalWait + SpamWait ))
done
if [[ $TotalWait -gt 0 ]] ; then
log "Waited $TotalWait seconds for $UserName to login."
xhost local:root
export XAUTHORITY="/home/$UserName/.Xauthority"
fi
} # WaitForSignOn
LastVolume=0
CurrVolume=0
Init () {
# If TV not powered up Spam user for 10 minutes that 'tvpowered' is running
# and will shut down / suspend system
# If GTV was powered off when system went to sleep adb server *might* running
# Takes 3 seconds to restart adb server so do it first in the background
if command -v adb >/dev/null 2>&1 ; then
log "Init(): Calling 'adb kill-server && adb start-server &'"
adb kill-server && adb start-server &
log "" # cosmetic blank line
fi
WaitForSignOn # Might be called by root during boot before user signed on.
Cnt=1
while : ; do
if SonyPowerStatus loggable; then
log "Sony TV is powered on. 'tvpowered' is now waiting for TV to power off."
break
else
log "Powering on Sony TV - attempt number: $Cnt"
TurnSonyOn
# Spam user every 60 seconds
(( $(( Cnt % 60 )) == 0 )) && \
notify-send --urgency=critical "tvpowered" \
-h string:x-canonical-private-synchronous:startup \
--icon=/usr/share/icons/gnome/48x48/devices/display.png \
"TV not communicating.\n Checking TV again..."
fi
sleep 1 # 2024-09-29 - shorten sleep from 3 to 1 second
(( Cnt++ ))
done
log "" # cosmetic blank line
# GTV_Online=$(nmap "$GTV_IP" | grep 'host up')
# 2024-10-12 - nmap removed recently because it takes a long time to run
GetVolume # Get Sony TV current volume level
LastVolume="$?"
VolumeBar $LastVolume
notify-send --urgency=critical "tvpowered" \
--icon=/usr/share/icons/gnome/48x48/devices/display.png \
"Fully activated.\n System will $SCTL when TV powered off. Volume: $LastVolume $Bar"
# GTV power on takes the longest time to run so turn it on last
Cnt=1
Max=60
GTV_Online=""
log "Init(): $Max times: wakeonlan, GtvConnect(), GtvPowerOn(), GtvPowerStatus()"
log "" # cosmetic blank line
if command -v wakeonlan >/dev/null 2>&1 ; then
while [[ "$GTV_Online" != *"connected"* ]]; do
log "Init(): Waking up TCL/Google TV - attempt number: $Cnt"
wakeonlan "$GTV_MAC" # Wakeup google TV
#GTV_Online=$(nmap "$GTV_IP" | grep 'host up')
# nmap run time takes 3 seconds fail and .1 second to succeed
sleep .5
if GtvConnect ; then # 'timeout .1 adb connect'
TurnGtvOn # 'adb shell input keyevent KEYCODE_WAKEUP'
fi
(( Cnt++ ))
if (( Cnt > Max )); then
log "Init(): Failed to wakeup TCL/Google TV after $Max attempts. Aborting"
break
fi
if [[ "$GTV_Online" == *"connected"* ]]; then
# Final 1 second check for power on status
if GtvPowerStatus loggable ; then
break
else
log "Init(): Final power check failed. Attempting again"
log "" # cosmetic blank line
GTV_Online=""
fi
fi
done
log "" # cosmetic blank line
log "Init(): FINAL value of GTV_Online: '$GTV_Online'"
# First time and if adb stops working, set TV's developer options:
# 1. Remove existing authorized adb keys on device
# 2. Enable developer options (click settings/build version - 7 times)
# 3. Enter Developer Options and turn on 'USB Debugging'
# 4. Turn on 'Verify apps over USB'
# 5. Turn on 'Mobile data always active'
# 6. Select 'USB Configuration' = "Charging"
# 7. wakeonlan requires ethernet. It might be necessary to turn off WiFi
# 8. First time TV will prompt to confirm computer access and always allow
fi
# Do last so eyesome has chance to update sunlight percentage
log "" # cosmetic blank line
log "Init(): Calling TurnLightsOn() - TV Bias Lighting"
TurnLightsOn # Turn on Sony and Google TV's bias lights if < 100% sunlight
return 0 # Always returns True
} # Init
###################################
# MAINLINE #
###################################
Main () {
log "" # cosmetic blank line
log "$0: 'tvpowered' Initialization."
log "Ensuring TV is powered on before starting."
Init # Turn on TV's and Bias Lights
log "" # cosmetic blank line
log "$0: Fully activated."
log " Waiting for TV to power off and then will $SCTL."
log " Sony TV LastVolume: '$LastVolume'"
Cnt=0
VolumeCnt=0 # TV Remote changed volume, so shorter sleep
while : ; do
# Wait forever for TV to power off. Don't output to log every second
if ! SonyPowerStatus no_log; then
# START FROM ABOVE:
# This was causing 2% CPU drain with Network Manager and
# debus-daemon. So move from above SonyPowerStatus to below.
# If network down then wait for it to come up.
#etherup=$(cat /sys/class/net/e*/carrier) # Returns 1 even disconnected
#wifi_up=$(cat /sys/class/net/w*/carrier)
#if [[ $etherup <> "1" && $wifi_up <> "1" ]] ; then
state=$(nmcli -f STATE -t g) # Network manager takes .5 CPU
if [[ $state == disconnected ]] ; then
# Spam user every 60 * Cot seconds
notify-send --urgency=critical "tvpowered" \
-h string:x-canonical-private-synchronous:startup \
--icon=/usr/share/icons/gnome/48x48/devices/display.png \
"Internet not up.\nChecking Ethernet and/or WiFi state again..."
sleep $((Cnt * 60))
(( Cnt++ ))
continue
else
Cnt=0 # Reset timer for next loop
fi
# END FROM ABOVE: If network down then wait for it to come up
state=$(nmcli -f STATE -t g) # Network manager takes .5 CPU
if [[ $state == disconnected ]] ; then
log "Unexpected Network disconnect, aborting suspend."
else
log "" # cosmetic blank line
log "TV Powered off. 'systemctl $SCTL' being called."
# /etc/NetworkManager/dispatcher.d/pre-down.d/smartplug_off
log "" # cosmetic blank line
TurnLightsOff # Turn off Sony and Google TVs' bias lights
log "" # cosmetic blank line
TurnGtvOff # Turn off TCL / Google TV if it is powered on
#echo "Turning off Sony TV just in case abnormal suspend."
#TurnSonyOff
# echo /etc/NetworkManager/dispatcher.d/pre-down.d/smartplug_off
log "" # cosmetic blank line
log "Calling 'systemctl $SCTL'"
systemctl "$SCTL" # Turn computer off or sleep
sleep 5 # Without sleep, Init starts during suspend
# systemctl will suspend. When resuming we hit next line
log "" # cosmetic blank line
log "System powered back up. Checking if TV powered on. '$0'."
Init # Turn on TV's and Bias Lights
# May 28, 2023 only turn picture off during work hours
# pictureoff # Picture off energy saving
fi
fi
GetVolume
CurrVolume="$?"
# echo CurrVolume: $CurrVolume LastVolume: $LastVolume
if [[ "$CurrVolume" != "$LastVolume" ]] ; then
# Make volume bar using progress bar methods
VolumeBar $CurrVolume
# Ask Ubuntu: https://askubuntu.com/a/871207/307523
notify-send --urgency=critical "tvpowered" \
-h string:x-canonical-private-synchronous:volume \
--icon=/usr/share/icons/gnome/48x48/devices/audio-speakers.png \
"Volume: $CurrVolume $Bar"
LastVolume=$CurrVolume
VolumeCnt=100 # For 1 second, faster checks for volume change
# TODO: Process VolumeCnt internally in loop instead of larger loop
fi
if [[ $VolumeCnt -gt 0 ]]; then
(( VolumeCnt-- ))
SleepTime=.01
else
SleepTime=.75
fi
sleep $SleepTime
done
exit 0
} # Main
Main "$@"
Configuring Bash Script
There are lines near the top of the tvpowered
script you need to
configure for your system:
SCTL=suspend # systemctl parameter: 'suspend' or 'poweroff'
STV_IP=192.168.0.19 # IP address for Sony TV on LAN
GTV_IP=192.168.0.17 # IP address for Google TV on LAN for Android Debug Bridge
GTV_Online="" # Google TV is not turned on
PWRD=123 # Password for Sony TV IP Connect (Pre-Shared key)
# TCL / Goggle TV MAC address for wake on lan. No effect if TV already on.
GTV_MAC="c0:79:82:41:2f:1f"
# 2024-09-30 - If problems revoke USB, turn off USB debugging, click build 7 times
# RSA key fingerprint: a7:ad:1f:82:66:16:15:eb:bc:54:85:56:ce:ad:d4:2b
# ~/.android/adbkey.pub - holds a lot more complicated key 700+ characters
# Nighttime bias lights
SLI_IP="192.168.0.15" # Sony TV bias light
GLI_IP="192.168.0.20" # TCL/Google TV bias light
Automatically Start Bash Script
In your ~/.config/autostart
directory create the file
tvpowered.desktop
. The file needs to contain:
[Desktop Entry]
Type=Application
Exec=tvpowered
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_CA]=tvpowered
Name=tvpowered
Comment[en_CA]=Powering off Sony TV suspends system
Comment=Powering off Sony TV suspends system
âtvpoweredâ prerequisites
This program only works with Sony Bravia TVs. The Sony REST API is required. For more details visit Sony Bravia IP Control đ
A LAN (ethernet) or Wi-Fi connection is required for both your Sony TV and your computer. A LAN connection is required for your TCL/Google TV.
Linux is required and preferably the Ubuntu distribution. The following programs are required:
adb
- Linux package for powering off TCL / Google TVcurl
- Linux package for communicating with Sony TVlibnotify-bin
- Linux package for desktop notification messageswakeonlan
- Linux application to wakeup TCL / Google TV
âsmartplug_offâ Smart Plugs Turn Off Lights
The smartplug_off
bash script functionality is duplicated in
tvpowered
when the computer system is shutdown or suspended.
The script needs to be created with sudo
powers in the
/etc/NetworkManager/dispatcher.d/pre-down.d/
directory.
âsmartplug_offâ Key Features
Called by Network Manager when the network is going down. The Network is always brought down when computer system is shutting down or being suspended. This makes the Network Manager a convenient way to shut off power to wall outlet smart plugs behind the TV that control the nighttime bias lighting.
âsmartplug_offâ Bash Script
Below is the Bash script that needs to placed in the
/etc/NetworkManager/dispatcher.d/pre-down.d/
directory:
#!/bin/bash
# NAME: smartplug_off
# PATH: /etc/NetworkManager/dispatcher.d/pre-down.d
# DESC: Turn off Smart Plug controlled lights behind TVs.
# DATE: March 7, 2020. Modified: March 28, 2023.
# CALL: Called by Network Manager before going down. Network manager in turn
# is called by systemd during suspend/hibernate/shutdown
# NOTE: hs100.sh must be installed for hs100 TP-Link power plug.
# https://developer.gnome.org/NetworkManager/stable/NetworkManager.html
PlugName="192.168.0.15" # Sony TV bias light
status=$(hs100.sh -i "$PlugName" check | cut -f2)
if [ $status == "OFF" ] ; then
: # Nothing to do already off
elif [ $status == "ON" ] ; then
hs100.sh -i "$PlugName" off
else
echo Error hs100.sh not responding check connection and IP "$PlugName".
fi
PlugName="192.168.0.17" # Google TV bias light
status=$(hs100.sh -i "$PlugName" check | cut -f2)
if [ $status == "OFF" ] ; then
: # Nothing to do already off
elif [ $status == "ON" ] ; then
hs100.sh -i "$PlugName" off
else
echo Error hs100.sh not responding check connection and IP "$PlugName".
fi
Configuring Bash Script
There are two lines you need to configure to your system:
PlugName="192.168.0.15" # Sony TV bias light
...
PlugName="192.168.0.21" # Google TV bias light
The first âPlugNameâ is 1/3rd of the way in the file. The second âPlugNameâ is 2/3rds of the way in the file.
âsmarplug_offâ Prerequisites
/usr/bin/hs100.sh
must be installed to control Smart Plugs.
See TP-Link Wi-Fi Smart Plug HS100 đ
for more information.
âsoundâ Switch System Sound Output to HDMI
The âsoundâ bash script is called whenever the computer system resumes from suspend / wakes from sleep.
The script needs to be created with sudo
powers in the
/lib/systemd/system-sleep/
directory.
âsoundâ Key Features
A bug in Pulse Audio 8 sets the output sound device to Laptop when system goes to sleep. The system sound device doesnât default to HDMI when the system wakes up / resumes from suspend.
To solve this problem the Pulse Audio settings are modified.
âsoundâ Bash Script
Below is the Bash script you can copy to your system:
#!/bin/sh
# NAME: sound
# PATH: /lib/systemd/system-sleep
# CALL: Called from SystemD automatically
# DESC: PulseAudo 8 sets sound to laptop when going to sleep.
# This script sets sound back to TV.
# DATE: Sep 23 2016. Modified: Dec 19 2020.
# NOTE: Test psmouse for askubuntu.com "Touchpad not working after suspending laptop"
# UPDT: Dec 19 2020 - Comment out sleep commands to speedup suspend/resume.
# Aug 5, 2018 - Turn off executition bit. As per AU turn off automatic switching:
# https://askubuntu.com/questions/1061414/how-to-disable-pulseaudio-automatic-device-switch/1061578#1061578
# Turn execution bit back on as there is no sound at all.
case $1/$2 in
pre/*)
echo "$0: Going to $2..."
# Place your pre suspend commands here, or `exit 0` if no pre suspend action required
# modprobe -r psmouse
# sleep 1 # Dec 19 2020 - Sleep slows down suspend.
;;
post/*)
echo "$0: Waking up from $2..."
# Place your post suspend (resume) commands here, or `exit 0` if no post suspend action required
# sleep 2 # Dec 19 2020 - Sleep slows down resume.
# modprobe psmouse
export PULSE_RUNTIME_PATH="/run/user/1000/pulse/"
sudo -u rick -E pacmd set-card-profile 0 output:hdmi-stereo
;;
esac
Configuring Bash Script
There are two lines (near the bottom of the file) that you need to configure to your system:
export PULSE_RUNTIME_PATH="/run/user/1000/pulse/"
sudo -u rick -E pacmd set-card-profile 0 output:hdmi-stereo
The first line shows your User Number which is usually â1000â.
The User Number is assigned when you sign on. If 1000
is
not your user number, then change it appropriately.
On the second line, replace rick
with your Username.
âsoundâ Prerequisites
It is assumed you are running Pulse Audio in Linux.
Primary TV (Sony) and Second TV (TCL) Setup
Here is what the system setup looks like:
- Top Left is a Sony 50â Full HD Android TV. The picture is usually turned off to save power but the sound system is always on.
- Top Right is a TCL 43â 4K Google TV. Because it is 4K, it has size of four Full HD screens.
- Bottom Right is an Alienware 17â Full HD laptop screen. The laptop has two HDMI channels. One channel is powered by a nVidia GeForce GTX 970M. The other channel is powered by an Intel Core i-7 GPU using ThunderBolt 3 USB-C to HDMI converter.
There are two lamps. One behind the Sony TV and one behind the TCL TV. Each lamp is controlled by a Kasa TP-Link Smart Plug. The lamps serve as âbias lightsâ to reduce eyestrain at night.
The Sony TV has a sound system with subwoofer that is used all the time. The Sony TV picture is only used occasionally for viewing movies and YouTube. On the Sony TV you can see that YouTube is currently running.
For your computer to communicate with the Sony TV the REST API needs to be configured. tvpowered uses the following Sony Bravia TV REST API functions:
The TCL Google TV is 4K which allows four screen sizes of full HD.
Consequently this TV is where most of the work is done. You
can comfortably have 10 windows open on a 4K screen. This is
also a good monitor for stashing all your Desktop Icons for
Shortcuts. The program iconic
is used to move desktop icons
to the middle monitor.
To communicate with the Google TV you need to enable Android Developer mode. See How to Set Up and Use ADB on Android TV đ. On March 30, 2023 work has begun to automatically power off the TCL Google (Secondary) TV when the Sony (Primary) TV remote is powered off. Use:
sudo apt install abd
To install Android Bridge Debugadb connect 192.168.0.21
to connect TV at IP address 21.adb shell input keyevent 26
to toggle the TV on/off.
The Alienware 17â laptop screen is where the file manager, web browser and music player playlist windows reside.
âlight-togâ Toggle Light Behind Primary (Sony) TV
The light-tog
bash script is used whenever you
want to toggle the light behind your TV off or on.
Generally during the day the light is turned off
and during night the light is turned on.
âlight-togâ Key Features
A light behind your TV is hard to reach. The âlight-togâ script makes it easy to turn the light off and on.
âlight-togâ Desktop Shortcut
Instead of typing âlight-togâ in the command line, it is convenient to have a Desktop Shortcut you can click.
In your ~/Desktop/
directory, create the file light-tog.desktop
containing:
[Desktop Entry]
Name=Toggle Sony TV Light
GenericName=Toggle Sony TV Light
Comment=Toggle Sony TV Light
Exec=light-tog
Icon=preferences-desktop-screensaver
Terminal=false
Type=Application
Categories=Application;
âlight-togâ Bash Script
Below is the Bash script you can copy to your system:
#!/bin/bash
# NAME: light-tog
# PATH: /usr/bin/ OR ~/bin (/home/USERNAME/bin) OR /mnt/e/bin/
# DESC: Flip light power for TV light
# DATE: January 20, 2020. Modified: March 28, 2023.
# CALL: light-tog
# NOTE: hs100.sh must be installed for hs100 TP-Link power plug.
PlugName="192.168.0.15" # hs100 Wi-Fi smart plug behind Sony TV.
status=$(hs100.sh -i "$PlugName" check | cut -f2)
if [ $status == "OFF" ] ; then
hs100.sh -i "$PlugName" on
elif [ $status == "ON" ] ; then
hs100.sh -i "$PlugName" off
else
echo Error hs100.sh not responding. Check Sony TV smartplug and IP "$PlugName".
fi
Configuring Bash Script
There is one line you need to configure to your system:
PlugName="192.168.0.15" # hs100 Wi-Fi smart plug behind Sony TV.
Change the IP address to what your network assigned it. See the
ssh-setup
script output. For example:
========== nmap -sn 192.168.0/24 ============================================
hitronhub.home (192.168.0.1) (0.0012s latency). MAC: A8:4E:3F:82:98:B2 (Unknown)
SONY.light (192.168.0.15) (0.010s latency). MAC: 50:D4:F7:EB:41:35 (Unknown)
TCL.LAN (192.168.0.17) (-0.100s latency). MAC: C0:79:82:41:2F:1F (Unknown)
SONY.LAN (192.168.0.19) (-0.100s latency). MAC: AC:9B:0A:DF:3F:D9 (Sony)
TCL.light (192.168.0.21) (0.010s latency). MAC: 50:D4:F7:EB:46:7C (Unknown)
Router.Login (192.168.0.254) (-0.087s latency). MAC: 00:05:CA:00:00:09 (Hitron Technology)
alien (192.168.0.12) LOCAL NETWORK CARD
âlight-togâ Prerequisites
/usr/bin/hs100.sh
must be installed to control Smart Plugs.
See TP-Link Wi-Fi Smart Plug HS100 đ
for more information.
âlight-tog2â Toggle Light Behind Second TV
The âlight-tog2â bash script is called whenever you want to toggle the light behind your second TV off or on. Generally during the day the light is turned off and during night the light is turned on.
âlight-tog2â Key Features
The light behind your second TV is hard to reach. The âlight-tog2â script makes it easy to turn the light off and on.
âlight-tog2â Desktop Shortcut
Instead of typing light-tog2
in the command line, it
is convenient to have a Desktop Shortcut you can click.
In your ~/Desktop/
directory, create the file light-tog2.desktop
containing:
[Desktop Entry]
Name=Toggle TCL TV Light
GenericName=Toggle TCL TV Light
Comment=Toggle TCL TV Light
Exec=light-tog2
Icon=preferences-desktop-screensaver
Terminal=false
Type=Application
Categories=Application;
âlight-tog2â Bash Script
Below is the Bash script you can copy to your system:
#!/bin/bash
# NAME: light-tog2
# PATH: /usr/bin/ OR ~/bin (/home/USERNAME/bin) OR /mnt/e/bin/
# DESC: Flip power for Kitchen light behind TCL TV
# DATE: September 4, 2022. Modified: March 28, 2023.
# CALL: light-tog2
# NOTE: hs100.sh must be installed for hs100 TP-Link power plug.
# UPDT: September 29, 2022. After power outage IP changed from 20 to 19.
# March 14, 2023. After power outage IP changed from 19 to 20.
# March 23, 2023. After power outage IP changed from 20 to 17.
# March 25, 2023. Name change from flipkitchen to fliptv2.
# March 27, 2023. Name change from fliptv2 to light-tog2.
PlugName="192.168.0.21" # hs103 Wi-Fi smart plug in kitchen behind TCL TV.
status=$(hs100.sh -i "$PlugName" check | cut -f2)
if [ $status == "OFF" ] ; then
hs100.sh -i "$PlugName" on
elif [ $status == "ON" ] ; then
hs100.sh -i "$PlugName" off
else
echo Error hs100.sh not responding. Check TCL TV smartplug and IP "$PlugName".
fi
Configuring Bash Script
There is one line you need to configure to your system:
PlugName="192.168.0.21" # hs103 Wi-Fi smart plug in kitchen behind TCL TV.
Change the IP address to what your network assigned it. See the
ssh-setup
script output. For example:
========== nmap -sn 192.168.0/24 ============================================
hitronhub.home (192.168.0.1) (0.0012s latency). MAC: A8:4E:3F:82:98:B2 (Unknown)
SONY.light (192.168.0.15) (0.010s latency). MAC: 50:D4:F7:EB:41:35 (Unknown)
TCL.LAN (192.168.0.17) (-0.100s latency). MAC: C0:79:82:41:2F:1F (Unknown)
SONY.LAN (192.168.0.19) (-0.100s latency). MAC: AC:9B:0A:DF:3F:D9 (Sony)
TCL.light (192.168.0.21) (0.010s latency). MAC: 50:D4:F7:EB:46:7C (Unknown)
Router.Login (192.168.0.254) (-0.087s latency). MAC: 00:05:CA:00:00:09 (Hitron Technology)
alien (192.168.0.12) LOCAL NETWORK CARD
âlight-tog2â Prerequisites
/usr/bin/hs100.sh
must be installed to control Smart Plugs.
See TP-Link Wi-Fi Smart Plug HS100 đ
for more information.
âpicturetogâ Toggle Sony TV picture Off and On
The picturetog
bash script toggles the Sony TV picture
(screen) off and on. When the picture is turned off this
is known as âPower Savings Mode Onâ. The reason being
that 100 watts of power is saved. The sound system and
all other TV functions like volume change still work.
âpicturetogâ Key Features
When your system is turned on or you resume from suspend /
wake from sleep the Sony TV (Primary) picture is turned
off automatically. The picturetog
script is used to turn
the Sony TV picture back on so you can watch a movie or
whatever.
âpicturetogâ Desktop Shortcut
Instead of typing picturetog in the command line, it is convenient to have a Desktop Shortcut you can click.
In your ~/Desktop/
directory, create the file
picturetog.desktop
containing:
[Desktop Entry]
Name=Toggle Sony TV Picture
GenericName=Toggle Sony TV Picture
Comment=Toggle Sony TV Picture
Exec=picturetog
Icon=preferences-desktop-display
Terminal=false
Type=Application
Categories=Application;
âpicturetogâ Bash Script
Below is the Bash script you can copy to your system:
#!/bin/bash
# NAME: picturetog
# PATH: /usr/bin/ OR ~/bin (/home/USERNAME/bin)
# DESC: Toggle Sony Bravia TV picture off/on but leave on sound.
# DATE: March 7, 2020. Modified March 28, 2023.
# CALL: Called by command line or Desktop Application Shortcut Icon.
# NOTE: A Sony Bravia TV or Sony Professional Display is required.
# In Sony documentation (links below) turning the picture off
# is called "Turning Power Savings Mode On". About 100 watts is saved.
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/
# https://developer.gnome.org/NetworkManager/stable/NetworkManager.html
# UPDT: March 23, 2023. Change Sony TV IP address from 16 to 19
# March 28, 2023. Update documentation.
IP=192.168.0.19 # LAN IP address for Sony Bravia TV
PWRD=123 # Sony Bravia TV Password for Communicaations
cURLit () {
# $1 = JSON String, $2 = Sony subsystem to talk to, eg accessControl,
# audio, system
# Returns $Retn currently must be defined as global variable.
# Create temporary file in RAM for curl command
TEMP=$(mktemp --tmpdir json.XXXXXXXX)
echo "$1" > "$TEMP"
# -s = silent
Retn=$(curl -s -H "Content-Type: application/json; charset=UTF-8" \
-H "X-Auth-PSK: $PWRD" \
--data @"$TEMP" \
http://$IP/sony/"$2")
# TO-DO: check $? and if non-zero pop up dialog with $TEMP contents
rm "$TEMP"
} # cURLit
GetPowerStatus () {
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/getPowerStatus/index.html
JSONstr='{
"method": "getPowerStatus",
"id": 50,
"params": [],
"version": "1.0"
}'
# TO-DO: Make Retn passed parm instead of global var
Retn=""
# Then pass string to cURL for execution
cURLit "$JSONstr" "system"
# Retn: {"result":[{"status":"active"}],"id":50}
# or: {"result":[{"status":"standby"}],"id":50}
[[ "${Retn#*active}" != "$Retn" ]] && return 0
# TV is turned off
# Might want timer tests to make sure we aren't repeatedly turning off
return 1
} # GetPowerStatus
GetPowerSavingMode () {
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/getPowerSavingMode/index.html
JSONstr='{
"method": "getPowerSavingMode",
"id": 51,
"params": [],
"version": "1.0"
}'
# TO-DO: Make Retn passed parm instead of global var
Retn=""
# Then pass string to cURL for execution
cURLit "$JSONstr" "system"
# "off" - Power saving mode is disabled.
# "low" - Power saving mode is enabled at a low level.
# "high" - Power saving mode is enabled at a high level.
# "pictureOff" - Power saving mode is enabled with the panel output off.
echo $Retn
return 0
} # GetPowerSavingMode
SetPowerSavingMode () {
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/setPowerSavingMode/index.html
JSONstr='{
"method": "setPowerSavingMode",
"id": 52,
"params": [{"mode": "'"${1}"'"}],
"version": "1.0"
}'
# TO-DO: Make Retn passed parm instead of global var
Retn=""
# Then pass string to cURL for execution
cURLit "$JSONstr" "system"
# "off" - Power saving mode is disabled.
# "low" - Power saving mode is enabled at a low level.
# "high" - Power saving mode is enabled at a high level.
# "pictureOff" - Power saving mode is enabled with the panel output off.
echo $Retn
return 0
} # SetPowerSavingMode
###################################
# MAINLINE #
###################################
# Get current Power Saving Setting and toggle it.
if GetPowerStatus ; then
GetPowerSavingMode
# Try to strip out word "off" in current power saving status
if [[ "${Retn#*off}" != "$Retn" ]] ; then
# Current power saving mode is "off"
SetPowerSavingMode "pictureOff"
else
# Current power saving mode is "pictureOff"
SetPowerSavingMode "off"
fi
fi
Configuring Bash Script
There is one line you need to configure to your system:
IP=192.168.0.19 # LAN for Sony
Change the IP address to what your network assigned it. See the
ssh-setup
script output. For example:
========== nmap -sn 192.168.0/24 ============================================
hitronhub.home (192.168.0.1) (0.0012s latency). MAC: A8:4E:3F:82:98:B2 (Unknown)
SONY.light (192.168.0.15) (0.010s latency). MAC: 50:D4:F7:EB:41:35 (Unknown)
TCL.LAN (192.168.0.17) (-0.100s latency). MAC: C0:79:82:41:2F:1F (Unknown)
SONY.LAN (192.168.0.19) (-0.100s latency). MAC: AC:9B:0A:DF:3F:D9 (Sony)
TCL.light (192.168.0.21) (0.010s latency). MAC: 50:D4:F7:EB:46:7C (Unknown)
Router.Login (192.168.0.254) (-0.087s latency). MAC: 00:05:CA:00:00:09 (Hitron Technology)
alien (192.168.0.12) LOCAL NETWORK CARD
âpicturetogâ Prerequisites
A Sony Bravia TV or Professional Display is required. The
Linux package curl
must also be installed.
âpictureoffâ Turn Off Sony TV Picture
The pictureoff
bash script is called when the computer
is turned on, rebooted or resumes from suspend (wakes from sleep).
âpictureoffâ Bash Script
Below is the Bash script you can copy to your system:
#!/bin/bash
# NAME: pictureoff
# PATH: /usr/bin/ OR ~/bin (/home/USERNAME/bin) OR /mnt/e/bin/
# DESC: Toggle Sony Bravia TV picture off/on but leave on sound.
# DATE: March 7, 2020. Modified March 28, 2023.
# CALL: Called by command line or .../bin/tvpowered
# NOTE: A Sony Bravia TV or Sony Professional Display is required.
# In Sony documentation (links below) turning the picture off
# is called "Turning Power Savings Mode On". About 100 watts is saved.
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/
# https://developer.gnome.org/NetworkManager/stable/NetworkManager.html
# UPDT: March 23, 2023. Change Sony TV IP address from 16 to 19
# March 28, 2023. Update documentation.
IP=192.168.0.19 # LAN IP address for Sony Bravia TV
PWRD=123 # Sony Bravia TV Password for Communications
cURLit () {
# $1 = JSON String, $2 = Sony subsystem to talk to, eg accessControl,
# audio, system
# Returns $Retn currently must be defined as global variable.
# Create temporary file in RAM for curl command
TEMP=$(mktemp --tmpdir json.XXXXXXXX)
echo "$1" > "$TEMP"
# -s = silent
Retn=$(curl -s -H "Content-Type: application/json; charset=UTF-8" \
-H "X-Auth-PSK: $PWRD" \
--data @"$TEMP" \
http://$IP/sony/"$2")
# TO-DO: check $? and if non-zero pop up dialog with $TEMP contents
rm "$TEMP"
} # cURLit
GetPowerStatus () {
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/getPowerStatus/index.html
JSONstr='{
"method": "getPowerStatus",
"id": 50,
"params": [],
"version": "1.0"
}'
# TO-DO: Make Retn passed parm instead of global var
Retn=""
# Then pass string to cURL for execution
cURLit "$JSONstr" "system"
# Retn: {"result":[{"status":"active"}],"id":50}
# or: {"result":[{"status":"standby"}],"id":50}
[[ "${Retn#*active}" != "$Retn" ]] && return 0
# TV is turned off
# Might want timer tests to make sure we aren't repeatedly turning off
return 1
} # GetPowerStatus
GetPowerSavingMode () {
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/getPowerSavingMode/index.html
JSONstr='{
"method": "getPowerSavingMode",
"id": 51,
"params": [],
"version": "1.0"
}'
# TO-DO: Make Retn passed parm instead of global var
Retn=""
# Then pass string to cURL for execution
cURLit "$JSONstr" "system"
# "off" - Power saving mode is disabled.
# "low" - Power saving mode is enabled at a low level.
# "high" - Power saving mode is enabled at a high level.
# "pictureOff" - Power saving mode is enabled with the panel output off.
echo $Retn
return 0
} # GetPowerSavingMode
SetPowerSavingMode () {
# Copy and paste JSON strings from Sony website:
# https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/setPowerSavingMode/index.html
JSONstr='{
"method": "setPowerSavingMode",
"id": 52,
"params": [{"mode": "'"${1}"'"}],
"version": "1.0"
}'
# TO-DO: Make Retn passed parm instead of global var
Retn=""
# Then pass string to cURL for execution
cURLit "$JSONstr" "system"
# "off" - Power saving mode is disabled.
# "low" - Power saving mode is enabled at a low level.
# "high" - Power saving mode is enabled at a high level.
# "pictureOff" - Power saving mode is enabled with the panel output off.
echo $Retn
return 0
} # SetPowerSavingMode
###################################
# MAINLINE #
###################################
# Get current Power Saving Setting and turn off picture.
if GetPowerStatus ; then
SetPowerSavingMode "pictureOff"
GetPowerSavingMode
fi
Configuring Bash Script
There is one line you need to configure to your system:
IP=192.168.0.19 # LAN IP address for Sony Bravia TV
Change the IP address to what your network assigned it. See the
ssh-setup
script output. For example:
========== nmap -sn 192.168.0/24 ============================================
hitronhub.home (192.168.0.1) (0.0012s latency). MAC: A8:4E:3F:82:98:B2 (Unknown)
SONY.light (192.168.0.15) (0.010s latency). MAC: 50:D4:F7:EB:41:35 (Unknown)
TCL.LAN (192.168.0.17) (-0.100s latency). MAC: C0:79:82:41:2F:1F (Unknown)
SONY.LAN (192.168.0.19) (-0.100s latency). MAC: AC:9B:0A:DF:3F:D9 (Sony)
TCL.light (192.168.0.21) (0.010s latency). MAC: 50:D4:F7:EB:46:7C (Unknown)
Router.Login (192.168.0.254) (-0.087s latency). MAC: 00:05:CA:00:00:09 (Hitron Technology)
alien (192.168.0.12) LOCAL NETWORK CARD
âpictureoffâ Prerequisites
A Sony Bravia TV or Professional Display is required. The
Linux package curl
must also be installed.
On your Sony TV go to âSettingsâ, âNetworkâ, and then go to:
- Remote device settings section, turn on the âControl Remotelyâ option.
- Home Network, IP control section, set Authentication to âNormal and Pre-Shared Keyâ. Also turn on the âSimple IP controlâ option.
Do not try to reconfigure your Sony TV while tvpowered
script is already running. Your desktop manager may not
see the Sony TV as powered up and will rearrange windows.
TP-Link Wi-Fi Smart Plug âhs100.shâ Script
The CNET Tutorial đ will help you physically install your Smart Plug and connect it to your network.
The bash script
/usr/bin/hs100.sh
must be installed to control Smart Plugs.
See TP-Link Wi-Fi Smart Plug HS100 đ
for more information.
The Bash Script is listed below but you must visit GitHub Page to get instructions.
âhs100.shâ Bash Script
#!/bin/bash
set -o errexit
(( "$DEBUG" )) && set -o xtrace
here=$(cd $(dirname $BASH_SOURCE[0]); echo $PWD)
##
# Switch the TP-LINK HS100 wlan smart plug on and off, query for status
# Tested with firmware 1.0.8
#
# Credits to Thomas Baust for the query/status/emeter commands
#
# Author George Georgovassilis, https://github.com/ggeorgovassilis/linuxscripts
# encoded (the reverse of decode) commands to send to the plug
# encoded {"system":{"set_relay_state":{"state":1}}}
payload_on="AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu36Lfog=="
# encoded {"system":{"set_relay_state":{"state":0}}}
payload_off="AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu3qPeow=="
# encoded { "system":{ "get_sysinfo":null } }
payload_query="AAAAI9Dw0qHYq9+61/XPtJS20bTAn+yV5o/hh+jK8J7rh+vLtpbr"
# the encoded request { "emeter":{ "get_realtime":null } }
payload_emeter="AAAAJNDw0rfav8uu3P7Ev5+92r/LlOaD4o76k/6buYPtmPSYuMXlmA=="
# BSD base64 decode on osx has different options
# BSD od (octal dump) on osx has different options
od_offset=4
# BSD netcat on osx has different options
nc_timeout=2
NCOPTS=""
#NCOPTS+='-v' # verbose
case $OSTYPE in
darwin*)
BASE64DEC="-D"
ODOPTS="-j $od_offset -A n -t u1"
NCOPTS+=" -G $nc_timeout"
;;
linux*)
BASE64DEC="-d"
ODOPTS="--skip-bytes=$od_offset --address-radix=n -t u1 --width=9999"
NCOPTS+=" -w $nc_timeout"
;;
esac
# tools
error(){
echo >&2 "$@"
exit 2
}
quiet(){
$@ >/dev/null 2>&1
}
mac_from_ip()
{
# if you've contacted an IP recently, the arp cache has juicy info
local ip=$1
mac=$(arp -a \
| grep "($ip)" \
| egrep -o '(([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2})' )
[ -z "$mac" ] && { echo 2>&1 "arp didn't find a MAC for $ip!"; return 1; }
echo $mac
}
unique_hostname()
{
# given a prefix and a MAC for a host, construct a unique name for the host
local prefix=$1; [ -n $prefix ] || return 1
local mac=$2; [ -n $mac ] || return 1
# use the first 7 characters of the shasum as unique ID
hash=$(echo $mac | shasum)
hs100host=hs100${hash:0:7}
echo $hs100host
}
host_entry()
{
host=$1
ip=$2
printf "${ip}\t${host}\n" >> /etc/hosts
echo plug $host has ip $ip
}
my_plugs()
{
cat /etc/hosts | grep hs100 | awk '{ print $2 }'
}
check_dependency()
{
dep=$1; shift
message=$@
quiet command -v "$dep" || error "$message"
}
check_dependencies() {
check_dependency nc \
"The nc programme for sending data over the network isn't" \
"in the path, communication with the plug will fail"
check_dependency base64 \
"The base64 programme for decoding base64 encoded strings isn't" \
"info the path, decoding of payloads will fail"
check_dependency od \
"The od programme for converting binary data to numbers isn't" \
"in the path, the status and emeter commands will fail"
check_dependency nmap \
"The nmap programme for mapping networks isn't"\
"in the path, the discover command will fail"
check_dependency shasum \
"The shasum programme for hashing strings isn't"\
"in the path, the sudo discover command will fail"
check_dependency arp \
"The arp programme to access Address Resolution Protocol cache isn't"\
"in the path, the sudo discover command will fail"
}
usage() {
echo "Usage: $0 [-i IP] [-p PORT] COMMAND"
echo "where COMMAND is one of: ${commands[@]}"
exit 1
}
check_arg() {
name="$1"
value="$2"
if [ -z "$value" ]; then
echo "missing argument $name"
usage
fi
}
# Check for a single string in a list of space-separated strings.
# e.g. has "foo" "foo bar baz" is true, but has "f" "foo bar baz" is not.
# from https://chromium.googlesource.com/chromiumos/platform/crosutils/+/master/common.sh
has()
{ [[ " ${*:2} " == *" $1 "* ]]; }
check_command()
{ has "$1" "$commands"; }
send_to_plug() {
ip="$1"
port="$2"
payload="$3"
if ! echo -n "$payload" | base64 ${BASE64DEC} | nc $NCOPTS $ip $port
then
echo couldn''t connect to $ip:$port, nc failed with exit code $?
fi
}
decode(){
code=171
input_num=`od $ODOPTS`
IFS=' ' read -r -a array <<< "$input_num"
args_for_printf=""
for element in "${array[@]}"
do
output=$(( $element ^ $code ))
args_for_printf="$args_for_printf\x$(printf %x $output)"
code=$element
done
printf "$args_for_printf"
}
pretty_json()
{
# read from stdin
if quiet command -v python
then
python -m json.tool
else
cat
echo
fi
}
query_plug(){
payload=$1
check_dependency od \
"The od programme for converting binary data to numbers isn't" \
"in the path, the status and emeter commands will fail"
check_arg "ip" $plugs
check_arg "port" $port
for ip in ${plugs[@]}
do
send_to_plug $ip $port "$payload" | decode | pretty_json
done
}
# plug commands
cmd_discover(){
check_arg "port" $port
check_dependency nmap \
"The nmap programme for mapping networks isn't"\
"in the path, the discover command will fail"
myip="`${here}/myip.sh`"
subnet=$(echo $myip | egrep -o '([0-9]{1,3}\.){3}')
subnet=${subnet}0-255
declare -a hs100ip
hs100ip=( $(nmap -Pn -p ${port} --open ${subnet} \
| grep 'Nmap scan report for' \
| egrep -o '(([0-9]{1,3}\.){3}[0-9]{1,3})' ) \
) \
|| error "Could not find any hs100 plugs"
# if we can't write this to /etc/hosts, echo what we found and quit
if ! [ -w /etc/hosts ]
then
echo HS100 plugs found: ${hs100ip[@]}
return 0
fi
check_dependency shasum \
"The shasum programme for hashing strings isn't"\
"in the path, the sudo discover command will fail"
check_dependency arp \
"The arp programme to access Address Resolution Protocol cache isn't"\
"in the path, the sudo discover command will fail"
# remove existing hs100* hosts entries
sed -i.bak /hs100/d /etc/hosts
if [[ ${#hs100ip[@]} = 1 ]]
then
host_entry hs100 $hs100ip
return 0
fi
# multiple HS100 plugs on the network, hash MAC address for unique hostname
for ip in ${hs100ip[@]}
do
# since we just hit it with nmap, it should be in the arp cache
mac=`mac_from_ip $ip`
hs100host=`unique_hostname hs100 $mac`
host_entry $hs100host $ip
done
return 0
}
cmd_print_plug_relay_state(){
check_arg "ip" $plugs
check_arg "port" $port
for ip in ${plugs[@]}
do
printf "$ip\t"
output=`send_to_plug $ip $port "$payload_query" \
| decode \
| egrep -o 'relay_state":[0,1]' \
| egrep -o '[0,1]'`
if (( output == 0 )); then
echo OFF
elif (( output == 1 )); then
echo ON
else
echo Couldn''t understand plug response $output
fi
done
}
cmd_print_plug_status(){
query_plug "$payload_query"
}
cmd_print_plug_consumption(){
query_plug "$payload_emeter"
}
cmd_switch_on(){
check_arg "ip" $plugs
check_arg "port" $port
for ip in ${plugs[@]}
do
send_to_plug $ip $port $payload_on > /dev/null
done
}
cmd_switch_off(){
check_arg "ip" $plugs
check_arg "port" $port
for ip in ${plugs[@]}
do
send_to_plug $ip $port $payload_off > /dev/null
done
}
commands=" on off check status emeter discover list "
# run the Main progamme, if we are not being sourced
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
# process args with getopt(1). See `man getopt`
args=`getopt qvi:p: $*` || { usage; exit 1; }
set -- $args
declare -a plugs;
for i #in $@
do
case "$i" in
-q) opt_quiet=yes; shift;;
-v) set -o xtrace; shift;;
-i) plugs=$2; shift; shift;;
-p) port=$2; shift; shift;;
--) shift; break;;
#*) error "Getopt broke! Found $i"
esac
done
: ${plugs=`my_plugs`}
: ${port=9999}
cmd=$1
#check_dependencies
check_dependency nc \
"The nc programme for sending data over the network isn't" \
"in the path, communication with the plug will fail"
check_dependency base64 \
"The base64 programme for decoding base64 encoded strings isn't" \
"info the path, decoding of payloads will fail"
check_arg "command" $cmd
check_command $cmd
case "$cmd" in
discover) cmd_discover;;
list) plugs=`my_plugs`; for p in ${plugs[@]}; do echo $p; done;;
on) cmd_switch_on;;
off) cmd_switch_off;;
check) cmd_print_plug_relay_state;;
status) cmd_print_plug_status;;
emeter) cmd_print_plug_consumption;;
*) usage;;
esac
fi # end main program
nvhda
Enable nVidia GeForce GTX 970M Sound
Using DKMS (Dynamic Kernel Management System) the nvhda
C program is automatically compiled with each kernel update.
nvhda
- Install using DKMS đ
There is a nVidia GTX 970M Bug Report đ
that suggests problems may be caused by Laptop Management Package
called TLP
.
nvhda
Key Features
Due to a bug between nVidia and Linux (perhaps caused by TLP) there is no sound when the system is powered up.
To solve this problem the nvhda
C program is used. Whenever
you install a new Linux Kernel version, the program is
automatically recompiled by DKMS.
Discover IP addresses With ssh-setup
#!/bin/bash
# NAME: ssh-setup
# PATH: /mnt/e/bin
# DESC: Display network details needed to setup SSH or debug after setup.
# CALL: Called from terminal with `sudo` permissions.
# DATE: June 18, 2020. Modified: June 23, 2020.
# NOTE: When debugging script place terminal results in appropriate sections.
# UPDT: Jun 23 2020: Change 'sshd.config' to 'ssh_config'. Add route and arp.
# From: https://askubuntu.com/questions/628383/output-only-mac-address-on-ubuntu#comment892989_628387
export LANG=C # Force english names for sed search. For example in
# another language HWaddr is direcciĂłnHW
if [[ $(id -u) != 0 ]]; then # root powers needed to call this script
echo >&2 "'$(basename $0)' must be called with 'sudo'"
exit 1
fi
# Must have the nmap package.
command -v nmap >/dev/null 2>&1 || { echo >&2 \
"'nmap' package required but it is not installed. Aborting."; \
exit 2; }
# Must have the lshw package.
command -v lshw >/dev/null 2>&1 || { echo >&2 \
"'lshw' package required but it is not installed. Aborting."; \
exit 3; }
# OTHER PACKAGES CONSIDERED AND REJECTED:
# $ network-test
# The program 'network-test' is currently not installed. You can install it
# by typing: 'sudo apt install ifupdown-extra'
# Seems kind of lame and has md5 checksum error.
# $ netstat | wc -l
# 824
# Way to many lines to make use of. Might be good to track down specific addy.
# $ iwconfig
# wlp60s0 IEEE 802.11 ESSID:"XXXXXXXXXXXXXX"
# Mode:Managed Frequency:5.22 GHz Access Point: AE:20:2E:CC:94:50
# Bit Rate=6 Mb/s Tx-Power=23 dBm
# Reveals router name (EESID) which is bad for neighbours to know us by....
echo
echo "Gathering system details - Will take 15 - 30 seconds"
Display () {
# $1 = command that was run (sometimes abridged version if lots of seds)
# $2 = output from command
echo " "
String1="========== $1 "
String2="====================================================================="
String3="$String1$String2"
echo "${String3:0:79}"
echo " "
echo "$2"
} # Display
# What systemd network services are running?
NET_Service="" # Default no directory
NET_Service=$(systemctl status net*)
Display 'systemctl status net*' "$NET_Service"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
(ABRIDGED)
* network-online.target - Network is Online
* networking.service - Raise network interfaces
* network.target - Network
* network-pre.target - Network (Pre)
---------------------------------------------------------------------------- */
END
# Is SSH systemd service (aliased as sshd) running?
SSH_Service="" # Default no directory
SSH_Service=$(systemctl status ssh)
Display 'systemctl status ssh' "$SSH_Service"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
â ssh.service
Loaded: not-found (Reason: No such file or directory)
Active: inactive (dead)
---------------------------------------------------------------------------- */
END
# What SSH keys are already setup?
SSH_Keys="" # Default no directory
[[ -d ~/.ssh ]] && SSH_Keys=$(ls -l ~/.ssh | \
grep -v ^total)
# remove total line
Display '[[ -d ~/.ssh ]] && SSH_Keys=$(ls -l ~/.ssh)' "$SSH_Keys"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
id_rsa
id_rsa.pub
known_hosts
---------------------------------------------------------------------------- */
END
# What SSH packages are currently installed?
SSH_Installed="" # Default no SSH packages
SSH_Installed=$(apt list 2>/dev/null | grep ssh | grep installed | \
sed 's/ \[installed.*//')
# remove [installed] & [installed, automatic] strings
Display "apt list 2>/dev/null | grep ssh | grep installed" "$SSH_Installed"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
libssh-4/xenial-updates,xenial-security,now 0.6.3-4.3ubuntu0.5 amd64
libssh-gcrypt-4/xenial-updates,xenial-security,now 0.6.3-4.3ubuntu0.5 amd64
libssh2-1/xenial-updates,xenial-security,now 1.5.0-2ubuntu0.1 amd64
openssh-client/xenial-updates,xenial-security,now 1:7.2p2-4ubuntu2.8 amd64
sshfs/xenial,now 2.5-1ubuntu1 amd64
---------------------------------------------------------------------------- */
END
# What is the SSH configuration?
SSH_Config="" # Default no SSH packages
[[ -f /etc/ssh/ssh_config ]] && SSH_Config=$(cat /etc/ssh/ssh_config)
Display "cat /etc/ssh/ssh_config" "$SSH_Config"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
---------------------------------------------------------------------------- */
END
# What IP address are on this machine?
LOCAL_IP_Addresses="" # Default machine has no network cards
LOCAL_IP_Addresses=$(ifconfig -a | grep -v ^' ' -A1 | \
grep -v '\-\-')
# grep to -v to remove extra lines
Display "ifconfig -a | grep -v ^' ' -A1" "$LOCAL_IP_Addresses"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
enp59s0 Link encap:Ethernet HWaddr 28:f1:0e:2a:1a:ed
inet addr:192.168.0.12 Bcast:192.168.0.255 Mask:255.255.255.0
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
wlp60s0 Link encap:Ethernet HWaddr 9c:b6:d0:10:37:f7
inet addr:192.168.0.10 Bcast:192.168.0.255 Mask:255.255.255.0
---------------------------------------------------------------------------- */
END
# What IP address (potential servers/clients) are visible on network?
NET_IP_Addresses="" # Default LAN is not running
NET_IP_Addresses=$(nmap -sn 192.168.0/24 | \
sed '/^Starting Nmap/d' | \
sed '/^Nmap done/d' | \
sed -z 's/Nmap scan report for //g' | \
sed -z 's/\nHost is up\./ LOCAL NETWORK CARD/g' | \
sed -z 's/\nHost is up / /g' | \
sed -z 's/\nMAC Address: / MAC: /g' )
# sed 's/MAC.*(/(/g') # MAC makes line too long
# Use sed to remove line breaks making results lengthy
Display "nmap -sn 192.168.0/24" "$NET_IP_Addresses"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
hitronhub.home (192.168.0.1) (0.0011s latency). MAC: AC:20:2E:CC:94:52 (Unknown)
dell (192.168.0.13) (0.00026s latency). MAC: 5C:F9:DD:5C:9C:53 (Dell)
dell (192.168.0.14) (0.00026s latency). MAC: 5C:F9:DD:5C:9C:53 (Dell)
hs100 (192.168.0.15) (-0.078s latency). MAC: 50:D4:F7:EB:41:35 (Unknown)
android-47cdabb50f83a5ee (192.168.0.16) (-0.076s latency). MAC: 18:4F:32:8D:AA:97 (Hon Hai Precision Ind.)
192.168.0.254 (0.00045s latency). MAC: 00:05:CA:00:00:09 (Hitron Technology)
alien (192.168.0.10) LOCAL NETWORK CARD
alien (192.168.0.12) LOCAL NETWORK CARD
---------------------------------------------------------------------------- */
END
#What network cards are installed:
NetworkCards="" # Contents of /etc/hosts should contain all IP addresses on LAN
NetworkCards=$(lshw -c network | grep -Ei 'description|product|serial' | \
sed 's/ description: //g' | \
sed -z 's/\n product: /: /g' | \
sed -z 's/\n serial: / - /g')
Display "lshw -c network | grep -Ei 'description|product|serial'" "$NetworkCards"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
Ethernet interface: Killer E2400 Gigabit Ethernet Controller - 28:f1:0e:2a:1a:ed
Wireless interface: QCA6174 802.11ac Wireless Network Adapter - 9c:b6:d0:10:37:f7
---------------------------------------------------------------------------- */
END
# Email /etc/hosts file to yourself and update contents below on machine
STATIC_IP_Addresses="" # Contents of /etc/hosts should contain all IP addresses on LAN
STATIC_IP_Addresses=$(cat /etc/hosts | grep 192.168)
Display "cat /etc/hosts | grep 192.168" "$STATIC_IP_Addresses"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
192.168.0.10 alien AW 17R3 WiFi 9c:b6:d0:10:37:f7
192.168.0.12 alien AW 17R3 Ethernet 28:f1:0e:2a:1a:ed
192.168.0.13 dell Inspiron 17R-SE-7720 Ethernet 5c:f9:dd:5c:9c:53
192.168.0.14 dell Inspiron 17R-SE-7720 WiFi 60:6c:66:86:de:bd
192.168.0.15 hs100 Sony TV Wall Light
192.168.0.16 android-47cdabb50f83a5ee Sony Bravia TV KBL 50W800C
---------------------------------------------------------------------------- */
END
# Firewall
# Selecteend TLP stats that might prove helpful for debuggin.
ufw_stats="" # Contents of /etc/hosts should contain all IP addresses on LAN
ufw_stats=$(ufw status verbose)
Display "FIREWALL: ufw status verbose" "$ufw_stats"
echo "-------------- \
For above setting check that ports 9 & 22 allowed --------------"
echo "Port 9 is usually used for Wake On Lan (WOL)"
echo "Port 22 is usually used for remote terminal login"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
-------------- Any error messages below are coming from tlp-stat --------------
cat: /sys/class/power_supply/hidpp_battery_23/present: No such file or directory
cat: /sys/class/power_supply/hidpp_battery_24/present: No such file or directory
---------------------------------------------------------------------------- */
END
echo -------------- \
Any error messages below are coming from tlp-stat --------------
# Selected TLP stats that might prove helpful for debuggin.
TLP_stats="" # Contents of /etc/hosts should contain all IP addresses on LAN
command -v tlp-stat >/dev/null 2>&1 && \
TLP_stats=$(tlp-stat | grep -E '^autosuspend|ENABLE|WOL')
Display "tlp-stat | grep -E '^autosuspend|ENABLE|WOL'" "$TLP_stats"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
TLP_ENABLE=1
WOL_DISABLE=Y
autosuspend = enabled
---------------------------------------------------------------------------- */
END
: <<'END'
/* ------------------ WOL (Wake On LAN) General Comments --------------------
******************* UBUNTU 16.04 *******************
From: https://askubuntu.com/questions/764158/
how-to-enable-wake-on-lan-wol-in-ubuntu-16-04
Also: http://manpages.ubuntu.com/manpages/xenial/man8/NetworkManager.8.html
In Ubuntu 16.04 set WOL_DISABLE=N in /etc/default/tlp to avoid getting WOL
disabled by TLP power management.
http://linrunner.de/en/tlp/docs/tlp-configuration.html
Add NETDOWN=no in /etc/default/halt to prevent powering off the network
card during shutdown
Enable Wake on LAN in /etc/network/interfaces when static network
configuration is used.
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet static
address 192.168.0.10
netmask 255.255.255.0
gateway 192.168.0.1
dns-nameservers 192.168.0.1
up ethtool -s eth0 wol g
Enable wake on lan in BIOS, enter the BIOS setup and look for something
called "Wake up on PCI event", "Wake up on LAN" or similar. Change it so
that it is enabled. Save your settings and reboot.
https://help.ubuntu.com/community/WakeOnLan
Warning some motherboards / network controllers don't support WOL from the
cold boot (S5 state, where the power to the system is physically turned off
and back on again). In that case, at least one power cycle (power up,
shutdown) has to be performed. To mitigate to the problem, the BIOS can be
configured to power up when AC is restored and schedule a shutdown inside
Ubuntu afterwards. Refer to the motherboard's manual for further details.
******************* UBUNTU 18.04 *******************
NOTE: In Ubuntu 18.04 /etc/network/interfaces maybe DEPRECATED
You might have to create your own script for WOL in:
/etc/NetworkManager/dispatcher.d/99-Xxxxxx
See: https://askubuntu.com/a/1111656/307523
https://wiki.archlinux.org/index.php/
NetworkManager#Network_services_with_NetworkManager_dispatcher
---------------------------------------------------------------------------- */
END
# WOL from: https://wiki.debian.org/WakeOnLan
# apt install ethtool
# ethtool -s eth0 wol g
# Above is NOT PERSISTENT across suspend/resume cycle so issue upon resume
# not just boot. /etc/network/interfaces above has setup.
# Archwiki: https://wiki.archlinux.org/index.php/Wake-on-LAN
# apt install wakeonlan
# wol target_MAC_address
# From: https://www.thegeekstuff.com/2008/11/
# wol-wakeonlan-guide-remotely-turn-on-servers-without-physical-access/
# wakeonlan 5c:f9:dd:5c:9c:53
# Do we have 'NETDOWN=no' line present for machines that shutdown"?
HaltConfig="" # Default no file
[[ -f /etc/default/halt ]] && HaltConfig=$(cat /etc/default/halt)
Display 'cat /etc/default/halt' "$HaltConfig"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
# Default behaviour of shutdown -h / halt. Set to "halt" or "poweroff".
HALT=poweroff
---------------------------------------------------------------------------- */
END
# Do we have static IP addresses setup?
NetworkInterfaces="" # Default no file
[[ -f /etc/network/interfaces ]] && NetworkInterfaces=$(cat /etc/network/interfaces)
Display 'cat /etc/network/interfaces' "$NetworkInterfaces"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
# interfaces(5) file used by ifup(8) and ifdown(8)
# /etc/network/interfaces
# For Ubuntu 16.04 ONLY according to notes in ssh-setup
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.0.10
netmask 255.255.255.0
gateway 192.168.0.1
dns-nameservers 192.168.0.1
up ethtool -s eth0 wol g
---------------------------------------------------------------------------- */
END
# Hide your router address below if publishing!
nmcliConnections="" # Default no file
nmcliConnections=$(nmcli -p connection show)
Display 'nmcli -p connection show' "$nmcliConnections"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
====================================================================================
NetworkManager connection profiles
====================================================================================
NAME UUID TYPE DEVICE
------------------------------------------------------------------------------------
Xxxx-Xxxxxx-Xx cf8fda92-0e59-4d0e-8821-cedb4be10d26 802-11-wireless wlp60s0
Wired connection 1 378122bb-ad44-3ddd-a616-c93e1bf0f828 802-3-ethernet enp59s0
Xxxxxxxxx-5G 73c40a50-0f2e-431c-b12c-e4712b3abdb4 802-11-wireless --
---------------------------------------------------------------------------- */
END
EthernetInterface=$(ifconfig -a | grep ^'e' | cut -d' ' -f1)
Display "ifconfig -a | grep ^'e' | cut -d' ' -f1" \
"Ethernet Interface that could be used for WOL: $EthernetInterface"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
Ethernet Interface that could be used for WOL: enp59s0
---------------------------------------------------------------------------- */
END
# What WOL_Settings exist for Ethernet Interface?
WOL_Setting="'ethtool' not installed."
command -v ethtool >/dev/null 2>&1 && \
WOL_Setting="$(ethtool $EthernetInterface | grep -i 'Wake-on:')"
Display "ethtool $EthernetInterface | grep -i 'Wake-on:'" "$WOL_Setting"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
Supports Wake-on: pumbag
Wake-on: g
---------------------------------------------------------------------------- */
END
# What WOL_Settings exist for Ethernet Interface?
Route="'ethtool' not installed."
Route="$(route)"
Display "route" "$Route"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default hitronhub.home 0.0.0.0 UG 100 0 0 enp59s0
default hitronhub.home 0.0.0.0 UG 600 0 0 wlp60s0
link-local * 255.255.0.0 U 1000 0 0 enp59s0
192.168.0.0 * 255.255.255.0 U 100 0 0 enp59s0
192.168.0.0 * 255.255.255.0 U 600 0 0 wlp60s0
---------------------------------------------------------------------------- */
END
Arp="'apr' not installed."
Arp="$(arp)"
Display "arp" "$Arp"
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
Address HWtype HWaddress Flags Mask Iface
192.168.0.4 (incomplete) enp59s0
192.168.0.254 ether 00:05:ca:00:00:09 C enp59s0
hs100 ether 50:d4:f7:eb:41:35 C enp59s0
dell ether 5c:f9:dd:5c:9c:53 C enp59s0
hitronhub.home ether ac:20:2e:cc:94:52 C enp59s0
android-47cdabb50f83a5e ether 18:4f:32:8d:aa:97 C enp59s0
hitronhub.home ether ac:20:2e:cc:94:52 C wlp60s0
20.20.20.1 ether ac:20:2e:cc:94:52 C enp59s0
dell (incomplete) enp59s0
---------------------------------------------------------------------------- */
END
Display 'END OF REPORT' ""
## TEST STUFF
#Spare:
: <<'END'
/* ------------ RESULTS -------------------------------------------------------
---------------------------------------------------------------------------- */
END