From 20700df88c10cee53ff9451853f7c9a465564d38 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Thu, 16 Sep 2021 11:24:09 +1000 Subject: [PATCH] Adding script --- sonytv.sh | 495 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 495 insertions(+) create mode 100755 sonytv.sh diff --git a/sonytv.sh b/sonytv.sh new file mode 100755 index 0000000..0e50dfd --- /dev/null +++ b/sonytv.sh @@ -0,0 +1,495 @@ +#!/bin/bash + +BOLD="\033[1m" +ITALIC="\033[3m" +STRIKE="\033[9m" +PLAIN="\033[0m" + +UNDERLINE="\033[4m" +RED="\033[31m" +MAGENTA="\033[35m" +GREEN="\033[32m" +YELLOW="\033[33m" +BLUE="\033[34m" +CYAN="\033[36m" +GREY="\033[2;37m" +LINK="$BLUE$UNDERLINE" + +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 @- < + + + + $arg + + + +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 + errorstr="TV returned '$(echo "$resultstr" | grep errorDescription | sed -e 's///;s,/dev/stderr +} + +function info() { + echo -e "$BOLD${CYAN}>> $PLAIN$CYAN$*$PLAIN" +} + +function register_device() { + local me myid initpsk opts + me=$(uname -n) + myid="12345" + initpsk=$1 + if [[ -z $initpsk ]]; then + action "Requesting registration from TV..." + curl -s "$URL/sony/accessControl" -o /dev/null -d @- <"$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 + info "UPnP info from TV:" + fullurl="$URL:52323/dmr.xml" + curlarg="" + 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 + echo "$res" + else + error "curl to $fullurl failed" + fi + exit $rv +elif [[ $wolok -eq 1 && $cmd == "on" ]]; then + if [[ $wolok -eq 1 ]]; then + n=0 + while [[ $n -lt 3 ]]; do + wakeonlan ${MAC} >/dev/null + n=$((n + 1)) + done + else + 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 + action "Changing channel to $BOLD$cname" + else + action "Changing channel to $BOLD$cname$PLAIN$GREEN ($cnum)" + 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 + info "Done" +elif [[ $cmd == "slowoff" ]]; then + if [[ -z ${arg[0]} ]]; then + waittime=1.5 + else + waittime=${arg[0]} + fi + if [[ -z ${arg[1]} ]]; then + count=60 + else + count=${arg[1]} + fi + # slowly drop volume + code="AAAAAQAAAAEAAAATAw==" + action "Slowly dropping volume on $HOST..." + 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="" + + action "Sending $what to $HOST${ntimes}..." + runcurl $reqtype $httpmethod "$method" $curlarg + info "Done" +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 < " 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 + action "Sending $what to $HOST${ntimes}..." + allresults="" + while [[ $n -lt $sendcount ]]; do + runcurl $reqtype $httpmethod "$method" $curlarg + rv=$? + if [[ $rv -eq 0 ]]; then + if [[ $sendcount -gt 1 ]]; then + echo -en "${YELLOW}*${BOLD}$((n + 1))${PLAIN}${YELLOW}* ${PLAIN}" + else + 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 + 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 + +