sonytv/sonytv.sh

485 lines
12 KiB
Bash
Raw Permalink Normal View History

2021-09-16 11:24:09 +10:00
#!/bin/bash
2022-07-08 12:49:42 +10:00
. ${HOME}/.bashtools/bashtools.sh
if [[ -z $HAVE_BASHTOOLS ]]; then
echo "ERROR: bashtools not installed download from https://git.nethack.net/rob/bashtools" >/dev/stderr
exit 1
fi
2021-09-16 11:24:09 +10:00
IRCC_OFF="AAAAAQAAAAEAAAAvAw=="
IRCC_VOLUP="AAAAAQAAAAEAAAASAw=="
errorstr=""
timeout="2"
timeout="-m $timeout"
CONFIGFILE="${HOME}/.sonytvrc"
pskfile="$HOME/.sonytvpsk"
[[ -e $pskfile ]] && psk=$(cat $pskfile) || psk="1111"
wolok=0
verbose=0
VALID_COMMANDS=" on off methods ircc raw ver status setup channel slowoff "
function real_docurl() {
local method httpmethod fullurl data rv arg reqtype
reqtype="$1"
httpmethod="$2"
method="$3"
arg="$4"
if [[ $reqtype == "method" ]]; then
fullurl="$URL/sony/system"
data="{\"id\": 20, \"method\": \"${method}\", \"version\": \"1.0\", \"params\": [\"${arg}\"]}"
if [[ $verbose -eq 1 ]]; then
echo RUNNING curl -u "":${psk} $curlopts -X $httpmethod -H 'Content-Type: application/json' -H "X-Auth-PSK: ${psk}" "$fullurl" -d "$data" >/dev/stderr
fi
curl -u "":${psk} $timeout -s -X $httpmethod -H 'Content-Type: application/json' -H "X-Auth-PSK: ${psk}" -d "$data" $fullurl
rv=$?
else
fullurl="$URL/sony/IRCC"
curl -u "":${psk} $timeout -s -X $httpmethod -H 'Content-Type: application/json' -H "X-Auth-PSK: ${psk}" $fullurl -d @- <<EOF
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:X_SendIRCC xmlns:u="urn:schemas-sony-com:service:IRCC:1">
<IRCCCode>$arg</IRCCCode>
</u:X_SendIRCC>
</s:Body>
</s:Envelope>
EOF
rv=$?
fi
return $rv
}
function runcurl() {
local method rv httpmethod arg reqtype
reqtype=$1
httpmethod=$2
method=$3
arg=$4
errorstr=""
resultstr=$(real_docurl $reqtype $httpmethod "$method" "$arg")
rv=$?
[[ $verbose -eq 1 ]] && echo "Curl retval: $rv"
[[ $verbose -eq 1 ]] && echo "Result: $resultstr"
[[ $verbose -eq 1 ]] && echo "Error: $errorstr"
if [[ $resultstr == *rror* ]]; then
2022-07-08 12:49:42 +10:00
errorstr="$HOST returned '$(echo "$resultstr" | grep errorDescription | sed -e 's/<errorDescription>//;s,</error.*,,;s/^\s*//' )'"
2021-09-16 11:24:09 +10:00
rv=1
elif [[ $rv -ne 0 ]]; then
errorstr="curl failed (timeout?) $resultstr"
else
errorstr=""
fi
return $rv
}
function usage() {
local x this
echo "usage: $0 [OPTIONS] command [count]"
echo
echo " -w secs Wait x seconds between ircc sends."
echo
echo " Valid commands are:"
echo " $VALID_COMMANDS"
echo
echo " Valid shortcuts are:"
echo
format=" %-12s -> %s"
for x in ${!alts[@]}; do
printf "$format" "${alts[$x]}" "${altd[$x]}"
if [[ ! -z ${altarg[$x]} ]]; then
for this in ${altarg[$x]}; do
echo -n " ${this}"
done
fi
echo
done
}
function register_device() {
local me myid initpsk opts
me=$(uname -n)
myid="12345"
initpsk=$1
if [[ -z $initpsk ]]; then
2022-07-08 12:49:42 +10:00
notify "Requesting registration from TV..."
2021-09-16 11:24:09 +10:00
curl -s "$URL/sony/accessControl" -o /dev/null -d @- <<EOF
{"id":13,"method":"actRegister","version":"1.0","params":[{"clientid":"$myid","nickname":"$me"},[{"clientid":"$myid","value":"yes","nickname":"$me","function":"WOL"}]]}
EOF
else
#-u "":${initpsk}
#-H "X-Auth-PSK: ${initpsk}"
2022-07-08 12:49:42 +10:00
notify "Registering with TV..."
2021-09-16 11:24:09 +10:00
res=$(curl -s -u "":${initpsk} "$URL/sony/accessControl" -d @- <<EOF
{"id":13,"method":"actRegister","version":"1.0","params":[{"clientid":"$myid","nickname":"$me"},[{"clientid":"$myid","value":"yes","nickname":"$me","function":"WOL"}]]}
EOF
)
if [[ "$res" == *rror* ]]; then
2022-07-08 12:49:42 +10:00
fail
2021-09-16 11:24:09 +10:00
error "registration failed"
else
2022-07-08 12:49:42 +10:00
ok
2021-09-16 11:24:09 +10:00
info "Registration successful! PSK set to ${BOLD}$psk"
echo "$psk" >"$pskfile"
info "PSK written to $pskfile"
fi
fi
}
function addalt() {
alts[$nalts]=$1
altd[$nalts]=$2
shift 2
altarg[$nalts]="$*"
nalts=$((nalts + 1))
}
function numtoircc() {
case $1 in
1) echo "AAAAAQAAAAEAAAAAAw==";;
2) echo "AAAAAQAAAAEAAAABAw==";;
3) echo "AAAAAQAAAAEAAAACAw==";;
4) echo "AAAAAQAAAAEAAAADAw==";;
5) echo "AAAAAQAAAAEAAAAEAw==";;
6) echo "AAAAAQAAAAEAAAAFAw==";;
7) echo "AAAAAQAAAAEAAAAGAw==";;
8) echo "AAAAAQAAAAEAAAAHAw==";;
9) echo "AAAAAQAAAAEAAAAIAw==";;
0) echo "AAAAAQAAAAEAAAAJAw==";;
11) echo "AAAAAQAAAAEAAAAKAw==";;
12) echo "AAAAAQAAAAEAAAALAw==";;
*) ;;
esac
}
function channametonum() {
case $1 in
"abc") echo "22";;
"jazz") echo "201";;
"win") echo "80";;
*) echo "$1";;
esac
}
IRCC_DELAY=0.4
addalt "volup" "ircc" "VolumeUp"
addalt "vu" "ircc" "VolumeUp"
addalt "voldown" "ircc" "VolumeDown"
addalt "vu" "ircc" "VolumeUp"
addalt "vd" "ircc" "VolumeDown"
addalt "ir" "ircc"
addalt "chan" "channel"
addalt "c" "channel"
addalt "soff" "slowoff"
ARGS="hp:vw:"
while getopts "$ARGS" i; do
case "$i" in
h)
usage;
exit 1;
;;
p)
psk="$OPTARG";
;;
v)
verbose=1
;;
w)
IRCC_DELAY="$OPTARG";
;;
*)
error "invalid argument: $i";
usage;
;;
esac
done
shift $((OPTIND - 1))
if [[ $# -lt 1 ]]; then
usage
exit 1
fi
cmd=$1
shift
nargs=0
# resolve shortcuts
for x in ${!alts[@]}; do
if [[ ${alts[$x]} == $cmd ]]; then
cmd=${altd[$x]}
if [[ ! -z ${altarg[$x]} ]]; then
nargs=0
for this in ${altarg[$x]}; do
arg[$nargs]=${this}
nargs=$((nargs + 1))
done
fi
fi
done
while [[ $# -ge 1 ]]; do
arg[$nargs]="$1"
nargs=$((nargs + 1))
shift
done
if [[ $VALID_COMMANDS != *\ $cmd\ * ]]; then
error "'$cmd' is not a valid command."
exit 1
fi
# read config file
if [[ $cmd != "setup" ]]; then
if [[ -e $CONFIGFILE ]]; then
source $CONFIGFILE
else
error "Can't find config file ($CONFIGFILE) - use '$0 setup' to create it."
exit 1
fi
fi
if which -s wakeonlan; then
if [[ ! -z $MAC ]]; then
wolok=1
fi
fi
#for x in ${!arg[@]}; do
# echo "arg $x = '${arg[$x]}'"
#done
#exit
sendcount=1
if [[ $cmd == "upnp" ]]; then
fullurl="$URL:52323/dmr.xml"
curlarg=""
2022-07-08 12:49:42 +10:00
notify "Obtaining UPnP info from $HOST"
2021-09-16 11:24:09 +10:00
res=$(curl $timeout -s "$fullurl")
rv=$?
if [[ $rv -eq 0 ]]; then
if which -s xq; then
res=$(echo "$res" | xq '.root.device."av:X_IRCCCodeList"')
fi
2022-07-08 12:49:42 +10:00
ok
info "Results:"
2021-09-16 11:24:09 +10:00
echo "$res"
else
2022-07-08 12:49:42 +10:00
fail
2021-09-16 11:24:09 +10:00
error "curl to $fullurl failed"
fi
exit $rv
elif [[ $wolok -eq 1 && $cmd == "on" ]]; then
2022-07-08 12:49:42 +10:00
notify "Sending wake-on-lan packet to $HOST"
2021-09-16 11:24:09 +10:00
if [[ $wolok -eq 1 ]]; then
n=0
while [[ $n -lt 3 ]]; do
wakeonlan ${MAC} >/dev/null
n=$((n + 1))
done
2022-07-08 12:49:42 +10:00
ok
2021-09-16 11:24:09 +10:00
else
2022-07-08 12:49:42 +10:00
fail
2021-09-16 11:24:09 +10:00
error "'wakeonlan' binary is not available - please install it"
exit 1
fi
elif [[ $cmd == "channel" ]]; then
if [[ -z ${arg[0]} ]]; then
error "'channel' command requires an argument"
exit 1
fi
cname=${arg[0]}
cnum=$(channametonum $cname)
if [[ $cname == $cnum ]]; then
2022-07-08 12:49:42 +10:00
notify "Changing channel to $BOLD$cname"
2021-09-16 11:24:09 +10:00
else
2022-07-08 12:49:42 +10:00
notify "Changing channel to $BOLD$cname$PLAIN$GREEN ($cnum)"
2021-09-16 11:24:09 +10:00
fi
for (( i=0; i<${#cnum}; i++ )); do
num=${cnum:$i:1}
code=$(numtoircc $num)
[[ ! -z $code ]] && runcurl ircc POST "" $code
sleep $IRCC_DELAY
done
2022-07-08 12:49:42 +10:00
ok
2021-09-16 11:24:09 +10:00
elif [[ $cmd == "slowoff" ]]; then
if [[ -z ${arg[0]} ]]; then
2022-03-05 09:59:09 +11:00
waittime=2.0
2021-09-16 11:24:09 +10:00
else
waittime=${arg[0]}
fi
if [[ -z ${arg[1]} ]]; then
count=60
else
count=${arg[1]}
fi
# slowly drop volume
code="AAAAAQAAAAEAAAATAw=="
2022-07-08 12:49:42 +10:00
notify "Slowly dropping volume on $HOST..."
2021-09-16 11:24:09 +10:00
n=0
while [[ $n -lt $count ]]; do
runcurl ircc POST "" $code
sleep $waittime
n=$((n + 1))
done
curlarg="$IRCC_OFF"
reqtype="ircc"
what="PowerOff"
httpmethod="POST"
jqs=""
2022-07-08 12:49:42 +10:00
notify "Sending $what to $HOST${ntimes}..."
2021-09-16 11:24:09 +10:00
runcurl $reqtype $httpmethod "$method" $curlarg
2022-07-08 12:49:42 +10:00
ok
2021-09-16 11:24:09 +10:00
else
reqtype="method"
jqs="try (.results[]) // try (.result[]) // ."
if [[ $cmd == "off" ]]; then
curlarg="$IRCC_OFF"
reqtype="ircc"
what="IRCC command PowerOff - $curlarg"
httpmethod="POST"
jqs=""
elif [[ $cmd == "ircc" ]]; then
if [[ -z ${arg[1]} ]]; then
sendcount=1
else
sendcount=${arg[1]}
fi
if [[ -z ${arg[0]} ]]; then
method="getRemoteControllerInfo"
what="List IRCC Commands"
httpmethod="POST"
jqs=".result[1][] | \"\(.name): \(.value)\""
elif [[ ${arg[0]} =~ AAA.* ]]; then
curlarg="${arg[0]}"
reqtype="ircc"
what="Raw IRCC command '${arg[0]}'"
httpmethod="POST"
jqs=""
else
runcurl "method" POST getRemoteControllerInfo
code=$(echo "$resultstr" | jq -r ".result[1][] | select(.name == \"${arg[0]}\") | .value")
if [[ $code =~ AAA.* ]]; then
curlarg="$code"
reqtype="ircc"
#what="IRCC command ${arg[0]} ($code)"
what="IRCC command ${arg[0]}"
httpmethod="POST"
jqs=""
else
error "No IRCC code found for '${arg[0]}'"
exit 1
fi
fi
elif [[ $cmd == "status" ]]; then
method="getPowerStatus"
what="Query Power"
httpmethod="POST"
elif [[ $cmd == "methods" ]]; then
method="getMethodTypes"
what="List Commands"
httpmethod="POST"
jqs=".results[] | .[0]"
elif [[ $cmd == "ver" ]]; then
method="getInterfaceInformation"
what="Query Version"
httpmethod="POST"
elif [[ $cmd == "setup" ]]; then
read -p "Enter IP/hostname of TV> " HOST
ping -t 1 -c 2 $HOST >/dev/null
sleep 1
arpres=$(arp -n ${HOST})
if [[ $? -ne 0 ]]; then
error "Can't determine MAC address for $HOST."
exit 1
fi
MAC=$(echo "$arpres" | awk '{ print $4 }')
URL="http://$HOST"
echo "TV hostname: $HOST"
echo "TV MAC address: $MAC"
echo "TV URL: $URL"
echo
read -p "Is the above correct (y/n)? " yn
if [[ $yn != "y" ]]; then
echo "Aborting."
exit 1
fi
cat > $CONFIGFILE <<EOF
HOST="$HOST"
MAC="$MAC"
URL="$URL"
EOF
info "Config file created in $CONFIGFILE"
register_device
info "Enter the PIN shown on your TV:"
read -p "> " psk
register_device $psk
exit 0
elif [[ $cmd == "raw" ]]; then
if [[ -z ${arg[0]} ]]; then
error "'raw' command requires an argument"
exit 1
fi
method="${arg[0]}"
what="${arg[0]}"
httpmethod="POST"
fi
n=0
if [[ $sendcount -gt 1 ]]; then
ntimes=" $sendcount times"
else
ntimes=""
fi
err=0
2022-07-08 12:49:42 +10:00
csecho -n "$GREEN" "Sending $what to $HOST${ntimes}... "
2021-09-16 11:24:09 +10:00
allresults=""
while [[ $n -lt $sendcount ]]; do
runcurl $reqtype $httpmethod "$method" $curlarg
rv=$?
if [[ $rv -eq 0 ]]; then
if [[ $sendcount -gt 1 ]]; then
2022-07-08 12:49:42 +10:00
csecho -n "$YELLOW" "*^b$((n + 1))^p* "
2021-09-16 11:24:09 +10:00
else
2022-07-08 12:49:42 +10:00
echo
2021-09-16 11:24:09 +10:00
info "Success"
fi
if [[ ! -z $resultstr ]]; then
if [[ ! -z $jqs ]]; then
allresults=""
append=$(echo "$resultstr" | jq -r "${jqs}" | sed 's/^/ /')
allresults=$(printf "%s\n%s\n" "$allresults" "$append")
fi
fi
else
2022-07-08 12:49:42 +10:00
fail
2021-09-16 11:24:09 +10:00
error "$rv: $errorstr"
err=1
break
fi
if [[ $n -ge 1 ]]; then
sleep $IRCC_DELAY
fi
n=$((n + 1))
done
if [[ $sendcount -gt 1 ]]; then
echo
info "Success"
fi
if [[ ! -z $allresults ]]; then
echo "$allresults"
fi
fi
exit 0