mirror of
https://github.com/thorsten-gehrig/alexa-remote-control.git
synced 2024-11-22 08:49:02 +01:00
commit
c8c5ed7c70
10
README.md
10
README.md
@ -16,6 +16,11 @@ TMP - location of the temp dir
|
|||||||
OATHTOOL - command line for oathtool MFA
|
OATHTOOL - command line for oathtool MFA
|
||||||
MFA_SECRET- the MFA secret
|
MFA_SECRET- the MFA secret
|
||||||
SPEAKVOL - the volume for speak messages
|
SPEAKVOL - the volume for speak messages
|
||||||
|
NORMALVOL - if no current playing volume can be determined, fall back to normal volume
|
||||||
|
VOLMAXAGE - max. age in minutes before volume is re-read from API
|
||||||
|
DEVICEVOLNAME - a list of device names with specific volume settings (space separated)
|
||||||
|
DEVICEVOLSPEAK - a list of speak volume levels - matching the devices above
|
||||||
|
DEVICEVOLNORMAL - a list of normal volume levels- matching the devices above
|
||||||
```
|
```
|
||||||
You will very likely want to set the language to:
|
You will very likely want to set the language to:
|
||||||
```
|
```
|
||||||
@ -26,7 +31,7 @@ export LANGUAGE='de,en-US;q=0.7,en;q=0.3'
|
|||||||
alexa-remote-control [-d <device>|ALL] -e <pause|play|next|prev|fwd|rwd|shuffle|repeat|vol:<0-100>> |
|
alexa-remote-control [-d <device>|ALL] -e <pause|play|next|prev|fwd|rwd|shuffle|repeat|vol:<0-100>> |
|
||||||
-b [list|<"AA:BB:CC:DD:EE:FF">] | -q | -n | -r <"station name"|stationid> |
|
-b [list|<"AA:BB:CC:DD:EE:FF">] | -q | -n | -r <"station name"|stationid> |
|
||||||
-s <trackID|'Artist' 'Album'> | -t <ASIN> | -u <seedID> | -v <queueID> |
|
-s <trackID|'Artist' 'Album'> | -t <ASIN> | -u <seedID> | -v <queueID> |
|
||||||
-w <playlistId> | -i | -p | -P | -S | -a | -l | -h |
|
-w <playlistId> | -i | -p | -P | -S | -a | -z | -l | -h |
|
||||||
-m <multiroom_device> [device_1 .. device_X] | -lastalexa
|
-m <multiroom_device> [device_1 .. device_X] | -lastalexa
|
||||||
|
|
||||||
-e : run command, additional SEQUENCECMDs:
|
-e : run command, additional SEQUENCECMDs:
|
||||||
@ -48,11 +53,12 @@ alexa-remote-control [-d <device>|ALL] -e <pause|play|next|prev|fwd|rwd|shuffle|
|
|||||||
-a : list available devices
|
-a : list available devices
|
||||||
-m : delete multiroom and/or create new multiroom containing devices
|
-m : delete multiroom and/or create new multiroom containing devices
|
||||||
-lastalexa : print device that received the last voice command
|
-lastalexa : print device that received the last voice command
|
||||||
|
-z : print current volume level
|
||||||
-l : logoff
|
-l : logoff
|
||||||
-h : help
|
-h : help
|
||||||
```
|
```
|
||||||
|
|
||||||
There's also a "plain" version, which lacks some functionality (-i, -p, -P, -S and no radio station names and no routines) but doesn't require 'jq' for JSON processing.
|
There's also a "plain" version, which lacks some functionality (-z, -i, -p, -P, -S and no radio station names and no routines) but doesn't require 'jq' for JSON processing.
|
||||||
|
|
||||||
In order to use MFA, one needs to obtain the MFA_SECRET from Amazon account:
|
In order to use MFA, one needs to obtain the MFA_SECRET from Amazon account:
|
||||||
1. You should have MFA using an App already working before proceeding
|
1. You should have MFA using an App already working before proceeding
|
||||||
|
@ -46,6 +46,8 @@
|
|||||||
# 2019-08-05: v0.14 added Volume setting via routine, and $SPEAKVOL
|
# 2019-08-05: v0.14 added Volume setting via routine, and $SPEAKVOL
|
||||||
# 2019-11-18: v0.14a download 200 routines instead of only the first 20
|
# 2019-11-18: v0.14a download 200 routines instead of only the first 20
|
||||||
# 2019-12-23: v0.14b Trigger routines by either utterance or routine name
|
# 2019-12-23: v0.14b Trigger routines by either utterance or routine name
|
||||||
|
# 2019-12-30: v0.15 re-worked the volume setting for TTS commands
|
||||||
|
# 2020-01-03: v0.15a introduce some proper "get_volume"
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
#
|
#
|
||||||
@ -99,6 +101,14 @@ SET_SPEAKVOL="30"
|
|||||||
# if no current playing volume can be determined, fall back to normal volume
|
# if no current playing volume can be determined, fall back to normal volume
|
||||||
SET_NORMALVOL="10"
|
SET_NORMALVOL="10"
|
||||||
|
|
||||||
|
# max. age in minutes before volume is read from API
|
||||||
|
SET_VOLMAXAGE="30"
|
||||||
|
|
||||||
|
# Device specific volumes (overriding the above)
|
||||||
|
SET_DEVICEVOLNAME="EchoDot2ndGen Echo1stGen"
|
||||||
|
SET_DEVICEVOLSPEAK="100 30"
|
||||||
|
SET_DEVICEVOLNORMAL="100 20"
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
# nothing to configure below here
|
# nothing to configure below here
|
||||||
#
|
#
|
||||||
@ -118,6 +128,10 @@ TMP=${TMP:-$SET_TMP}
|
|||||||
OATHTOOL=${OATHTOOL:-$SET_OATHTOOL}
|
OATHTOOL=${OATHTOOL:-$SET_OATHTOOL}
|
||||||
SPEAKVOL=${SPEAKVOL:-$SET_SPEAKVOL}
|
SPEAKVOL=${SPEAKVOL:-$SET_SPEAKVOL}
|
||||||
NORMALVOL=${NORMALVOL:-$SET_NORMALVOL}
|
NORMALVOL=${NORMALVOL:-$SET_NORMALVOL}
|
||||||
|
VOLMAXAGE=${VOLMAXAGE:-$SET_VOLMAXAGE}
|
||||||
|
DEVICEVOLNAME=${DEVICEVOLNAME:-$SET_DEVICEVOLNAME}
|
||||||
|
DEVICEVOLSPEAK=${DEVICEVOLSPEAK:-$SET_DEVICEVOLSPEAK}
|
||||||
|
DEVICEVOLNORMAL=${DEVICEVOLNORMAL:-$SET_DEVICEVOLNORMAL}
|
||||||
|
|
||||||
COOKIE="${TMP}/.alexa.cookie"
|
COOKIE="${TMP}/.alexa.cookie"
|
||||||
DEVLIST="${TMP}/.alexa.devicelist.json"
|
DEVLIST="${TMP}/.alexa.devicelist.json"
|
||||||
@ -145,13 +159,14 @@ CHILD=""
|
|||||||
PLIST=""
|
PLIST=""
|
||||||
BLUETOOTH=""
|
BLUETOOTH=""
|
||||||
LASTALEXA=""
|
LASTALEXA=""
|
||||||
|
GETVOL=""
|
||||||
|
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
echo "$0 [-d <device>|ALL] -e <pause|play|next|prev|fwd|rwd|shuffle|repeat|vol:<0-100>> |"
|
echo "$0 [-d <device>|ALL] -e <pause|play|next|prev|fwd|rwd|shuffle|repeat|vol:<0-100>> |"
|
||||||
echo " -b [list|<\"AA:BB:CC:DD:EE:FF\">] | -q | -r <\"station name\"|stationid> |"
|
echo " -b [list|<\"AA:BB:CC:DD:EE:FF\">] | -q | -n | -r <\"station name\"|stationid> |"
|
||||||
echo " -s <trackID|'Artist' 'Album'> | -t <ASIN> | -u <seedID> | -v <queueID> | -w <playlistId> |"
|
echo " -s <trackID|'Artist' 'Album'> | -t <ASIN> | -u <seedID> | -v <queueID> | -w <playlistId> |"
|
||||||
echo " -i | -p | -P | -S | -a | -m <multiroom_device> [device_1 .. device_X] | -lastalexa | -l | -h"
|
echo " -i | -p | -P | -S | -a | -m <multiroom_device> [device_1 .. device_X] | -lastalexa | -z | -l | -h"
|
||||||
echo
|
echo
|
||||||
echo " -e : run command, additional SEQUENCECMDs:"
|
echo " -e : run command, additional SEQUENCECMDs:"
|
||||||
echo " weather,traffic,flashbriefing,goodmorning,singasong,tellstory,speak:'<text>',automation:'<routine name>'"
|
echo " weather,traffic,flashbriefing,goodmorning,singasong,tellstory,speak:'<text>',automation:'<routine name>'"
|
||||||
@ -171,6 +186,7 @@ usage()
|
|||||||
echo " -a : list available devices"
|
echo " -a : list available devices"
|
||||||
echo " -m : delete multiroom and/or create new multiroom containing devices"
|
echo " -m : delete multiroom and/or create new multiroom containing devices"
|
||||||
echo " -lastalexa : print device that received the last voice command"
|
echo " -lastalexa : print device that received the last voice command"
|
||||||
|
echo " -z : print current volume level"
|
||||||
echo " -l : logoff"
|
echo " -l : logoff"
|
||||||
echo " -h : help"
|
echo " -h : help"
|
||||||
}
|
}
|
||||||
@ -311,6 +327,9 @@ while [ "$#" -gt 0 ] ; do
|
|||||||
-lastalexa)
|
-lastalexa)
|
||||||
LASTALEXA="true"
|
LASTALEXA="true"
|
||||||
;;
|
;;
|
||||||
|
-z)
|
||||||
|
GETVOL="true"
|
||||||
|
;;
|
||||||
-h|-\?|--help)
|
-h|-\?|--help)
|
||||||
usage
|
usage
|
||||||
exit 0
|
exit 0
|
||||||
@ -540,6 +559,7 @@ set_var()
|
|||||||
|
|
||||||
DEVICETYPE=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .deviceType' ${DEVLIST})
|
DEVICETYPE=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .deviceType' ${DEVLIST})
|
||||||
DEVICESERIALNUMBER=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .serialNumber' ${DEVLIST})
|
DEVICESERIALNUMBER=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .serialNumber' ${DEVLIST})
|
||||||
|
DEVICEFAMILY=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .deviceFamily' ${DEVLIST})
|
||||||
|
|
||||||
# customerId is now retrieved from the logged in user
|
# customerId is now retrieved from the logged in user
|
||||||
# the customerId in the device list is always from the user registering the device initially
|
# the customerId in the device list is always from the user registering the device initially
|
||||||
@ -589,16 +609,52 @@ if [ -n "${SEQUENCECMD}" ] ; then
|
|||||||
else
|
else
|
||||||
# the speak command is treated differently in that the wolume gets set to $SPEAKVOL
|
# the speak command is treated differently in that the wolume gets set to $SPEAKVOL
|
||||||
if [ -n "${TTS}" ] ; then
|
if [ -n "${TTS}" ] ; then
|
||||||
|
if [ "${DEVICEFAMILY}" = "WHA" ] ; then
|
||||||
|
echo "Skipping unsupported command: ${COMMAND} on dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} family:${DEVICEFAMILY}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
SVOL=$SPEAKVOL
|
||||||
|
|
||||||
|
# Not using arrays here in order to be compatible with non-Bash
|
||||||
|
# Get the list position of the current device type
|
||||||
|
IDX=0
|
||||||
|
for D in $DEVICEVOLNAME ; do
|
||||||
|
if [ "${D}" = "${DEVICE}" ] ; then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
IDX=$((IDX+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
# get the speak volume at that position
|
||||||
|
C=0
|
||||||
|
for D in $DEVICEVOLSPEAK ; do
|
||||||
|
if [ $C -eq $IDX ] ; then
|
||||||
|
if [ -n "${D}" ] ; then SVOL=$D ; fi
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
C=$((C+1))
|
||||||
|
done
|
||||||
|
|
||||||
# try to retrieve the "currently playing" volume
|
# try to retrieve the "currently playing" volume
|
||||||
VOL=$(${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
VOL=$(get_volume)
|
||||||
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
||||||
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
||||||
"https://${ALEXA}/api/media/state?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | grep 'volume' | sed -r 's/^.*"volume":\s*([0-9]+)[^0-9]*$/\1/g')
|
|
||||||
|
|
||||||
if [ -z "${VOL}" ] ; then VOL=$NORMALVOL ; fi
|
if [ -z "${VOL}" ] ; then
|
||||||
|
# get the normal volume of the current device type
|
||||||
|
C=0
|
||||||
|
for D in $DEVICEVOLNORMAL; do
|
||||||
|
if [ $C -eq $IDX ] ; then
|
||||||
|
VOL=$D
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
C=$((C+1))
|
||||||
|
done
|
||||||
|
# if the volume is still undefined, use $NORMALVOL
|
||||||
|
if [ -z "${VOL}" ] ; then
|
||||||
|
VOL=$NORMALVOL
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
ALEXACMD='{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.SerialNode\",\"nodesToExecute\":[{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\",\"value\":\"'${SPEAKVOL}'\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"'${SEQUENCECMD}'\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\"'${TTS}'}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\",\"value\":\"'${VOL}'\"}}]}}","status":"ENABLED"}'
|
ALEXACMD='{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.SerialNode\",\"nodesToExecute\":[{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\",\"value\":\"'${SVOL}'\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"'${SEQUENCECMD}'\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\"'${TTS}'}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\",\"value\":\"'${VOL}'\"}}]}}","status":"ENABLED"}'
|
||||||
else
|
else
|
||||||
ALEXACMD='{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"'${SEQUENCECMD}'\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\"'${SEQUENCEVAL}'}}}","status":"ENABLED"}'
|
ALEXACMD='{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"'${SEQUENCECMD}'\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\"'${SEQUENCEVAL}'}}}","status":"ENABLED"}'
|
||||||
fi
|
fi
|
||||||
@ -780,6 +836,49 @@ show_queue()
|
|||||||
"https://${ALEXA}/api/np/queue?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | jq '.'
|
"https://${ALEXA}/api/np/queue?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | jq '.'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# current volume level
|
||||||
|
#
|
||||||
|
get_volume()
|
||||||
|
{
|
||||||
|
VOLFILE=$(find "${TMP}/.alexa.volume.${DEVICESERIALNUMBER}" -mmin -${VOLMAXAGE} 2>/dev/null)
|
||||||
|
if [ -z "${VOLFILE}" ] ; then
|
||||||
|
# first, try the volume setting of /media/state of the device
|
||||||
|
VOL=$(${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
||||||
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
||||||
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
||||||
|
"https://${ALEXA}/api/media/state?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | jq -r --arg device "${DEVICESERIALNUMBER}" '"\($device) \(.volume) \(.muted)"')
|
||||||
|
|
||||||
|
VOLCHECK=$(echo "${VOL}" | cut -d' ' -f2)
|
||||||
|
# if we didn't get a proper volume, try the LemurDevice
|
||||||
|
if [ "$VOLCHECK" = "0" -o "$VOLCHECK" = "null" -o -z "$VOLCHECK" ] ; then
|
||||||
|
PARENTID=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .parentClusters[0]' ${DEVLIST})
|
||||||
|
if [ "$PARENTID" != "null" ] ; then
|
||||||
|
PARENTDEVICE=$(jq --arg serial ${PARENTID} -r '.devices[] | select(.serialNumber == $serial) | .deviceType' ${DEVLIST})
|
||||||
|
|
||||||
|
VOL=$( ${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
||||||
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
||||||
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
||||||
|
"https://${ALEXA}/api/np/player?deviceSerialNumber=${PARENTID}&deviceType=${PARENTDEVICE}" | jq -r '.playerInfo.lemurVolume.memberVolume | to_entries[] | "\(.key) \(.value.volume) \(.value.muted)"')
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# write volume and mute state to file
|
||||||
|
OIFS=$IFS
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
set -o noglob
|
||||||
|
for LINE in $VOL ; do
|
||||||
|
SERIAL=$(echo "${LINE}" | cut -d' ' -f1)
|
||||||
|
VOLUME=$(echo "${LINE}" | cut -d' ' -f2)
|
||||||
|
MUTED=$(echo "${LINE}" | cut -d' ' -f3)
|
||||||
|
echo "${VOLUME} ${MUTED}" > "${TMP}/.alexa.volume.${SERIAL}"
|
||||||
|
done
|
||||||
|
IFS=$OIFS
|
||||||
|
fi
|
||||||
|
cut -d' ' -f1 "${TMP}/.alexa.volume.${DEVICESERIALNUMBER}"
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# show notifications and alarms
|
# show notifications and alarms
|
||||||
#
|
#
|
||||||
@ -880,9 +979,10 @@ ${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Con
|
|||||||
rm -f ${DEVLIST}
|
rm -f ${DEVLIST}
|
||||||
rm -f ${COOKIE}
|
rm -f ${COOKIE}
|
||||||
rm -f ${TMP}/.alexa.*.list
|
rm -f ${TMP}/.alexa.*.list
|
||||||
|
rm -f ${TMP}/.alexa.volume.*
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ -z "$LASTALEXA" -a -z "$BLUETOOTH" -a -z "$LEMUR" -a -z "$PLIST" -a -z "$HIST" -a -z "$SEEDID" -a -z "$ASIN" -a -z "$PRIME" -a -z "$TYPE" -a -z "$QUEUE" -a -z "$NOTIFICATIONS" -a -z "$LIST" -a -z "$COMMAND" -a -z "$STATIONID" -a -z "$SONG" -a -n "$LOGOFF" ] ; then
|
if [ -z "$LASTALEXA" -a -z "$BLUETOOTH" -a -z "$LEMUR" -a -z "$PLIST" -a -z "$HIST" -a -z "$SEEDID" -a -z "$ASIN" -a -z "$PRIME" -a -z "$TYPE" -a -z "$QUEUE" -a -z "$NOTIFICATIONS" -a -z "$LIST" -a -z "$COMMAND" -a -z "$STATIONID" -a -z "$SONG" -a -z "$GETVOL" -a -n "$LOGOFF" ] ; then
|
||||||
echo "only logout option present, logging off ..."
|
echo "only logout option present, logging off ..."
|
||||||
log_off
|
log_off
|
||||||
exit 0
|
exit 0
|
||||||
@ -913,9 +1013,9 @@ if [ ! -f ${DEVLIST} ] ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$COMMAND" -o -n "$QUEUE" ] ; then
|
if [ -n "$COMMAND" -o -n "$QUEUE" -o -n "$GETVOL" ] ; then
|
||||||
if [ "${DEVICE}" = "ALL" ] ; then
|
if [ "${DEVICE}" = "ALL" ] ; then
|
||||||
for DEVICE in $(jq -r '.devices[] | select( .deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" or .deviceFamily == "WHA") | .accountName' ${DEVLIST} | sed -r 's/ /%20/g') ; do
|
for DEVICE in $( jq -r '.devices[] | select( ( .deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" or .deviceFamily == "WHA" ) and .online == true ) | .accountName' ${DEVLIST} | sed -r 's/ /%20/g') ; do
|
||||||
set_var
|
set_var
|
||||||
if [ -n "$COMMAND" ] ; then
|
if [ -n "$COMMAND" ] ; then
|
||||||
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
|
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
|
||||||
@ -923,6 +1023,9 @@ if [ -n "$COMMAND" -o -n "$QUEUE" ] ; then
|
|||||||
# in order to prevent a "Rate exceeded" we need to delay the command
|
# in order to prevent a "Rate exceeded" we need to delay the command
|
||||||
sleep 1
|
sleep 1
|
||||||
echo
|
echo
|
||||||
|
elif [ -n "$GETVOL" ] ; then
|
||||||
|
echo "get volume for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
||||||
|
get_volume
|
||||||
else
|
else
|
||||||
echo "queue info for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
echo "queue info for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
||||||
show_queue
|
show_queue
|
||||||
@ -935,6 +1038,9 @@ if [ -n "$COMMAND" -o -n "$QUEUE" ] ; then
|
|||||||
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
|
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
|
||||||
run_cmd
|
run_cmd
|
||||||
echo
|
echo
|
||||||
|
elif [ -n "$GETVOL" ] ; then
|
||||||
|
echo "get volume for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
||||||
|
get_volume
|
||||||
else
|
else
|
||||||
echo "queue info for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
echo "queue info for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
||||||
show_queue
|
show_queue
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# Amazon Alexa Remote Control (PLAIN shell)
|
# Amazon Alexa Remote Control (PLAIN shell)
|
||||||
# alex(at)loetzimmer.de
|
# alex(at)loetzimmer.de
|
||||||
#
|
#
|
||||||
# 2019-11-18: v0.14a (for updates see http://blog.loetzimmer.de/2017/10/amazon-alexa-hort-auf-die-shell-echo.html)
|
# 2019-12-30: v0.15 (for updates see http://blog.loetzimmer.de/2017/10/amazon-alexa-hort-auf-die-shell-echo.html)
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
#
|
#
|
||||||
@ -56,6 +56,11 @@ SET_SPEAKVOL="30"
|
|||||||
# if no current playing volume can be determined, fall back to normal volume
|
# if no current playing volume can be determined, fall back to normal volume
|
||||||
SET_NORMALVOL="10"
|
SET_NORMALVOL="10"
|
||||||
|
|
||||||
|
# Device specific volumes (overriding the above)
|
||||||
|
SET_DEVICEVOLNAME="EchoDot2ndGen Echo1stGen"
|
||||||
|
SET_DEVICEVOLSPEAK="100 30"
|
||||||
|
SET_DEVICEVOLNORMAL="100 20"
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
# nothing to configure below here
|
# nothing to configure below here
|
||||||
#
|
#
|
||||||
@ -75,6 +80,9 @@ TMP=${TMP:-$SET_TMP}
|
|||||||
OATHTOOL=${OATHTOOL:-$SET_OATHTOOL}
|
OATHTOOL=${OATHTOOL:-$SET_OATHTOOL}
|
||||||
SPEAKVOL=${SPEAKVOL:-$SET_SPEAKVOL}
|
SPEAKVOL=${SPEAKVOL:-$SET_SPEAKVOL}
|
||||||
NORMALVOL=${NORMALVOL:-$SET_NORMALVOL}
|
NORMALVOL=${NORMALVOL:-$SET_NORMALVOL}
|
||||||
|
DEVICEVOLNAME=${DEVICEVOLNAME:-$SET_DEVICEVOLNAME}
|
||||||
|
DEVICEVOLSPEAK=${DEVICEVOLSPEAK:-$SET_DEVICEVOLSPEAK}
|
||||||
|
DEVICEVOLNORMAL=${DEVICEVOLNORMAL:-$SET_DEVICEVOLNORMAL}
|
||||||
|
|
||||||
COOKIE="${TMP}/.alexa.cookie"
|
COOKIE="${TMP}/.alexa.cookie"
|
||||||
DEVLIST="${TMP}/.alexa.devicelist.json"
|
DEVLIST="${TMP}/.alexa.devicelist.json"
|
||||||
@ -508,6 +516,8 @@ set_var()
|
|||||||
ATTR="deviceFamily"
|
ATTR="deviceFamily"
|
||||||
FAMILY=$(grep ${ATTR}\| ${DEVTXT} | sed "s/^.*${ATTR}|//" | sed 's/ /_/g')
|
FAMILY=$(grep ${ATTR}\| ${DEVTXT} | sed "s/^.*${ATTR}|//" | sed 's/ /_/g')
|
||||||
|
|
||||||
|
ATTR="online"
|
||||||
|
ONLINE=$(grep ${ATTR}\: ${DEVTXT} | sed "s/^.*${ATTR}://")
|
||||||
|
|
||||||
if [ -z "${DEVICE}" ] ; then
|
if [ -z "${DEVICE}" ] ; then
|
||||||
# if no device was supplied, use the first Echo(dot) in device list
|
# if no device was supplied, use the first Echo(dot) in device list
|
||||||
@ -569,6 +579,24 @@ set_var()
|
|||||||
C=$((C+1))
|
C=$((C+1))
|
||||||
done
|
done
|
||||||
|
|
||||||
|
C=0
|
||||||
|
for F in $FAMILY ; do
|
||||||
|
if [ $C -eq $IDX ] ; then
|
||||||
|
DEVICEFAMILY=$F
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
C=$((C+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
C=0
|
||||||
|
for O in $ONLINE ; do
|
||||||
|
if [ $C -eq $IDX ] ; then
|
||||||
|
DEVICESTATE=$O
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
C=$((C+1))
|
||||||
|
done
|
||||||
|
|
||||||
if [ -z "${DEVICESERIALNUMBER}" ] ; then
|
if [ -z "${DEVICESERIALNUMBER}" ] ; then
|
||||||
echo "ERROR: unkown device dev:${DEVICE}"
|
echo "ERROR: unkown device dev:${DEVICE}"
|
||||||
exit 1
|
exit 1
|
||||||
@ -584,6 +612,31 @@ run_cmd()
|
|||||||
if [ -n "${SEQUENCECMD}" ] ; then
|
if [ -n "${SEQUENCECMD}" ] ; then
|
||||||
# the speak command is treated differently in that the wolume gets set to $SPEAKVOL
|
# the speak command is treated differently in that the wolume gets set to $SPEAKVOL
|
||||||
if [ -n "${TTS}" ] ; then
|
if [ -n "${TTS}" ] ; then
|
||||||
|
if [ "${DEVICEFAMILY}" = "WHA" ] ; then
|
||||||
|
echo "Skipping unsupported command: ${COMMAND} on dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} family:${DEVICEFAMILY}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
SVOL=$SPEAKVOL
|
||||||
|
|
||||||
|
# Not using arrays here in order to be compatible with non-Bash
|
||||||
|
# Get the list position of the current device type
|
||||||
|
IDX=0
|
||||||
|
for D in $DEVICEVOLNAME ; do
|
||||||
|
if [ "${D}" = "${DEVICE}" ] ; then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
IDX=$((IDX+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
# get the speak volume at that position
|
||||||
|
C=0
|
||||||
|
for D in $DEVICEVOLSPEAK ; do
|
||||||
|
if [ $C -eq $IDX ] ; then
|
||||||
|
if [ -n "${D}" ] ; then SVOL=$D ; fi
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
C=$((C+1))
|
||||||
|
done
|
||||||
|
|
||||||
# try to retrieve the "currently playing" volume
|
# try to retrieve the "currently playing" volume
|
||||||
VOL=$(${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
VOL=$(${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
||||||
@ -591,9 +644,26 @@ if [ -n "${SEQUENCECMD}" ] ; then
|
|||||||
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
||||||
"https://${ALEXA}/api/media/state?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | grep 'volume' | sed -r 's/^.*"volume":\s*([0-9]+)[^0-9]*$/\1/g')
|
"https://${ALEXA}/api/media/state?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | grep 'volume' | sed -r 's/^.*"volume":\s*([0-9]+)[^0-9]*$/\1/g')
|
||||||
|
|
||||||
if [ -z "${VOL}" ] ; then VOL=$NORMALVOL ; fi
|
# in order to prevent a "Rate exceeded" we need to delay the command
|
||||||
|
sleep 1
|
||||||
|
|
||||||
ALEXACMD='{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.SerialNode\",\"nodesToExecute\":[{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\",\"value\":\"'${SPEAKVOL}'\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"'${SEQUENCECMD}'\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\"'${TTS}'}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\",\"value\":\"'${VOL}'\"}}]}}","status":"ENABLED"}'
|
if [ -z "${VOL}" ] ; then
|
||||||
|
# get the normal volume of the current device type
|
||||||
|
C=0
|
||||||
|
for D in $DEVICEVOLNORMAL; do
|
||||||
|
if [ $C -eq $IDX ] ; then
|
||||||
|
VOL=$D
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
C=$((C+1))
|
||||||
|
done
|
||||||
|
# if the volume is still undefined, use $NORMALVOL
|
||||||
|
if [ -z "${VOL}" ] ; then
|
||||||
|
VOL=$NORMALVOL
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ALEXACMD='{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.SerialNode\",\"nodesToExecute\":[{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\",\"value\":\"'${SVOL}'\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"'${SEQUENCECMD}'\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\"'${TTS}'}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\",\"value\":\"'${VOL}'\"}}]}}","status":"ENABLED"}'
|
||||||
else
|
else
|
||||||
ALEXACMD='{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"'${SEQUENCECMD}'\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\"'${SEQUENCEVAL}'}}}","status":"ENABLED"}'
|
ALEXACMD='{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"'${SEQUENCECMD}'\",\"operationPayload\":{\"deviceType\":\"'${DEVICETYPE}'\",\"deviceSerialNumber\":\"'${DEVICESERIALNUMBER}'\",\"customerId\":\"'${MEDIAOWNERCUSTOMERID}'\",\"locale\":\"'${TTS_LOCALE}'\"'${SEQUENCEVAL}'}}}","status":"ENABLED"}'
|
||||||
fi
|
fi
|
||||||
@ -849,16 +919,18 @@ if [ -n "$COMMAND" -o -n "$QUEUE" ] ; then
|
|||||||
if [ "${DEVICE}" = "ALL" ] ; then
|
if [ "${DEVICE}" = "ALL" ] ; then
|
||||||
while IFS= read -r DEVICE ; do
|
while IFS= read -r DEVICE ; do
|
||||||
set_var
|
set_var
|
||||||
if [ -n "$COMMAND" ] ; then
|
if [ "$DEVICESTATE" = "true" ] ; then
|
||||||
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
|
if [ -n "$COMMAND" ] ; then
|
||||||
run_cmd
|
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
|
||||||
# in order to prevent a "Rate exceeded" we need to delay the command
|
run_cmd
|
||||||
sleep 1
|
# in order to prevent a "Rate exceeded" we need to delay the command
|
||||||
echo
|
sleep 1
|
||||||
else
|
echo
|
||||||
echo "queue info for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
else
|
||||||
show_queue
|
echo "queue info for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
||||||
echo
|
show_queue
|
||||||
|
echo
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done < ${DEVALL}
|
done < ${DEVALL}
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user