#!/bin/bash . ${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 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="$HOST returned '$(echo "$resultstr" | grep errorDescription | sed -e 's///;s,"$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="" notify "Obtaining UPnP info from $HOST" 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 ok info "Results:" echo "$res" else fail error "curl to $fullurl failed" fi exit $rv elif [[ $wolok -eq 1 && $cmd == "on" ]]; then notify "Sending wake-on-lan packet to $HOST" if [[ $wolok -eq 1 ]]; then n=0 while [[ $n -lt 3 ]]; do wakeonlan ${MAC} >/dev/null n=$((n + 1)) done ok else fail 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 notify "Changing channel to $BOLD$cname" else notify "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 ok elif [[ $cmd == "slowoff" ]]; then if [[ -z ${arg[0]} ]]; then waittime=2.0 else waittime=${arg[0]} fi if [[ -z ${arg[1]} ]]; then count=60 else count=${arg[1]} fi # slowly drop volume code="AAAAAQAAAAEAAAATAw==" notify "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="" notify "Sending $what to $HOST${ntimes}..." runcurl $reqtype $httpmethod "$method" $curlarg ok 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 csecho -n "$GREEN" "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 csecho -n "$YELLOW" "*^b$((n + 1))^p* " else echo 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 fail 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