#!/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=2.0 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