├── auth_token.sh ├── refresh_token.sh ├── auth_code.sh ├── README.md └── alexa.sh /auth_token.sh: -------------------------------------------------------------------------------- 1 | CLIENT_ID="" 2 | CLIENT_SECRET="" 3 | CODE="" 4 | GRANT_TYPE="authorization_code" 5 | REDIRECT_URI="https://localhost:9745/authresponse" 6 | 7 | curl -X POST --data "grant_type=${GRANT_TYPE}&code=${CODE}&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&redirect_uri=${REDIRECT_URI}" https://api.amazon.com/auth/o2/token | tee auth_token.log | python -c "import sys,json;t1=open('token.dat','w');t2=open('refresh.dat','w');x=sys.stdin.readline(); t1.write(json.loads(x)['access_token']);t2.write(json.loads(x)['refresh_token']);" 8 | -------------------------------------------------------------------------------- /refresh_token.sh: -------------------------------------------------------------------------------- 1 | REFRESH=`cat refresh.dat` 2 | CLIENT_ID="" 3 | CLIENT_SECRET="" 4 | GRANT_TYPE="refresh_token" 5 | REDIRECT_URI="https://localhost:9745/authresponse" 6 | 7 | curl -X POST --data "grant_type=${GRANT_TYPE}&refresh_token=${REFRESH}&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&redirect_uri=${REDIRECT_URI}" https://api.amazon.com/auth/o2/token | tee refresh_token.log | python -c "import sys,json;t1=open('token.dat','w');t2=open('refresh.dat','w');x=sys.stdin.readline(); t1.write(json.loads(x)['access_token']);t2.write(json.loads(x)['refresh_token']);" 8 | -------------------------------------------------------------------------------- /auth_code.sh: -------------------------------------------------------------------------------- 1 | CLIENT_ID="" 2 | DEVICE_TYPE_ID="test_device" 3 | DEVICE_SERIAL_NUMBER=123 4 | REDIRECT_URI="https://localhost:9745/authresponse" 5 | RESPONSE_TYPE="code" 6 | SCOPE="alexa:all" 7 | SCOPE_DATA="{\"alexa:all\": {\"productID\": \"$DEVICE_TYPE_ID\", \"productInstanceAttributes\": {\"deviceSerialNumber\": \"${DEVICE_SERIAL_NUMBER}\"}}}" 8 | 9 | function urlencode() { 10 | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"' 11 | } 12 | 13 | AUTH_URL="https://www.amazon.com/ap/oa?client_id=${CLIENT_ID}&scope=$(echo $SCOPE | urlencode)&scope_data=$(echo $SCOPE_DATA | urlencode)&response_type=${RESPONSE_TYPE}&redirect_uri=$(echo $REDIRECT_URI | urlencode)" 14 | 15 | echo "URL: ${AUTH_URL}" 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AlexaNotificationCurl 2 | Some curl scripts to allow interfacing with Alexa using text as input. 3 | 4 |

Demo

5 | https://youtu.be/WLPApYslQVM 6 | 7 | I'm using this along with OpenCV to do face recognition and then let me know who is at the front door: 8 | "Simon says, Joe is at the front door." 9 | 10 | Initially, I just used my Alexa bluetooth and espeak (very bad sound), but I wanted it to sound like Alexa. So, I wrote this... 11 | 12 |

Credits

13 | Motivated by Miguel Mota 14 | https://miguelmota.com/blog/alexa-voice-service-with-curl 15 | 16 |

The way this works:

17 | - The text given to alexa.sh is converted into an wav file and sent to the alexa voice service. 18 | - The response is then piped to a 'play' command (espeak) to give the response. 19 | 20 |

Requirements:

21 | You will need 22 | - curl 23 | - sox (Ubuntu packages: sox libsox-fmt-mp3) 24 | - pico2wav (Ubuntu package: libttspico-utils) 25 | - espeak (Not used in current version) 26 | NOTE: You could change the alexa.sh to use a different speech module, but I've found pico2wav to be pretty good. 27 | 28 |

How to use:

29 | 30 | 1. Follow the instructions from Miguel here: 31 | https://miguelmota.com/blog/alexa-voice-service-authentication/ 32 | This sets up the service authentication. 33 | 2. Replace the CLIENT_ID in the auth_code.sh file 34 | 3. Run auth_code.sh (./auth_code.sh) 35 | 4. Copy/paste the given URL into a browser and login to your amazon account 36 | 5. Look for the code= in the authresponse in the url of the 'failed' webpage 37 | 6. Replace CLIENT_ID, CLIENT_SECRET, and CODE in the auth_token.sh file 38 | 7. Run the auth_token.sh (./auth_token.sh) 39 | 40 | If all goes well, you will then have two files: token.dat and refresh.dat 41 | 42 | For the next hour, you will be able to run the alexa.sh command. If an hour passes, you'll need to run the refresh_token.sh, then run alexa.sh 43 | NOTE: Be sure to update refresh_token.sh with your CLIENT_ID and CLIENT_SECRET 44 | 45 | I setup the refresh_token.sh to run every hour in cron, then I don't worry about it again. 46 | 47 | Note: The steps 1-7 above should only be needed once. The refresh_token should be able to keep an active token from that point on. 48 | 49 |

Sample:

50 | ./alexa.sh "Tell me a joke" 51 | 52 |

Troubleshooting:

53 | Look at the various log files for errors. Also, I 'tee' out the audio sent and audio response. 54 | -------------------------------------------------------------------------------- /alexa.sh: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # First we creat a bunch of variables to hold data. 3 | ############################################################ 4 | QUESTION=${1} 5 | 6 | # Auth token (replace with yours). 7 | TOKEN=`cat token.dat` 8 | 9 | # Boundary name, must be unique so it does not conflict with any data. 10 | BOUNDARY="BOUNDARY1234" 11 | BOUNDARY_DASHES="--" 12 | 13 | # Newline characters. 14 | NEWLINE='\r\n'; 15 | 16 | # Metadata headers. 17 | METADATA_CONTENT_DISPOSITION="Content-Disposition: form-data; name=\"metadata\""; 18 | METADATA_CONTENT_TYPE="Content-Type: application/json; charset=UTF-8"; 19 | 20 | # Metadata JSON body. 21 | METADATA="{\ 22 | \"messageHeader\": {},\ 23 | \"messageBody\": {\ 24 | \"profile\": \"alexa-close-talk\",\ 25 | \"locale\": \"en-us\",\ 26 | \"format\": \"audio/L16; rate=16000; channels=1\"\ 27 | }\ 28 | }" 29 | 30 | # Audio headers. 31 | AUDIO_CONTENT_TYPE="Content-Type: audio/L16; rate=16000; channels=1"; 32 | AUDIO_CONTENT_DISPOSITION="Content-Disposition: form-data; name=\"audio\""; 33 | 34 | ############################################################ 35 | # Then we start composing the body using the variables. 36 | ############################################################ 37 | 38 | # Compose the start of the request body, which contains the metadata headers and 39 | # metadata JSON body as the first part of the multipart body. 40 | # Then it starts of the second part with the audio headers. The binary audio 41 | # will come later as you will see. 42 | POST_DATA_START=" 43 | ${BOUNDARY_DASHES}${BOUNDARY}${NEWLINE}${METADATA_CONTENT_DISPOSITION}${NEWLINE}\ 44 | ${METADATA_CONTENT_TYPE}\ 45 | ${NEWLINE}${NEWLINE}${METADATA}${NEWLINE}${NEWLINE}${BOUNDARY_DASHES}${BOUNDARY}${NEWLINE}\ 46 | ${AUDIO_CONTENT_DISPOSITION}${NEWLINE}${AUDIO_CONTENT_TYPE}${NEWLINE}" 47 | 48 | # Compose the end of the request body, basically just adding the end boundary. 49 | POST_DATA_END="${NEWLINE}${NEWLINE}${BOUNDARY_DASHES}${BOUNDARY}${BOUNDARY_DASHES}${NEWLINE}" 50 | 51 | ############################################################ 52 | # Now we create a request body file to hold everything including the binary audio data. 53 | ############################################################ 54 | 55 | # Write metadata to a file which will contain the multipart request body content. 56 | echo -e $POST_DATA_START > multipart_body.txt 57 | 58 | # Here we append the binary audio data to request body file 59 | # by spitting out the contents. We do it this way so that 60 | # the encoding do not get messed with. 61 | #cat $AUDIO_FILENAME >> multipart_body.txt 62 | echo "Question: ${QUESTION}" 63 | echo "Creating voice..." 64 | #espeak -v en-us "${QUESTION}" --stdout | tee espeak.out | sox - -c 1 -r 16000 -e signed -b 16 -t wav - >> multipart_body.txt 65 | rm /tmp/pipe.wav 66 | ln -s /dev/stdout /tmp/pipe.wav 67 | pico2wave -w /tmp/pipe.wav "${QUESTION}" | tee pico2wav.wav | sox - -c 1 -r 16000 -e signed -b 16 -t wav - >> multipart_body.txt 68 | 69 | # Then we append closing boundary to request body file. 70 | echo -e $POST_DATA_END >> multipart_body.txt 71 | 72 | ############################################################ 73 | # Finally we get to compose the cURL request command 74 | # passing it the generated request body file as the multipart body. 75 | ############################################################ 76 | 77 | # Compose cURL command and write to output file. 78 | echo "Making request..." 79 | curl -s -X POST \ 80 | -H "Authorization: Bearer ${TOKEN}" \ 81 | -H "Content-Type: multipart/form-data; boundary=${BOUNDARY}" \ 82 | --data-binary @multipart_body.txt \ 83 | https://access-alexa-na.amazon.com/v1/avs/speechrecognizer/recognize \ 84 | | perl -pe 'BEGIN{undef $/;} s/--.*Content-Type: audio\/mpeg.*(ID3.*)--.*--/$1/smg' \ 85 | | tee response.mp3 | play -t mp3 -q - 86 | --------------------------------------------------------------------------------