lordpengwin / muzak

Amazon Echo Skill for Logitech/Squeezebox Media Server
MIT License
35 stars 16 forks source link

creating lambda function #5

Open glacket opened 7 years ago

glacket commented 7 years ago

I guess im not understanding how to create the lambda function. What do i code do i use for the body of the function. Can you please give an example. Also the readme alludes to install squeezenode within muzak folder on a linux box. Can this be done on a pi? does it always have to be running. does muzak need to be running as a bridge on the network between echo and squeezeserver?

MikeDeSantis commented 7 years ago

Hey glacket, Hopefully I can save you some time. There is a bit of a learning curve to dealing with AWS Lambda and Alexa skills.

The body of the function is the text taken directly from muzak.js. I added some functionality that has not yet been incorporated from the pull request - look at my fork for the update.

Muzak is run on AWS when the "Alexa Open Muzak" command is issued; nothing needs to be run locally to use muzak.

The config.js file gets zipped and uploaded to AWS. This points back to your password protected Squeezebox Server through a DNS entry you've created with FreeDNS.afraid.org (or any dynamic dns host), over port 9000 that you've opened on your router.

Some of my notes:

For creating the Alexa skill: https://developer.amazon.com/edw/home.html#/ Use all files in muzak's dir \speechAssets to configure the Interaction Model of the skill you're creating. Then use the skill ID in the config.js file.
The Configuration tab's "AWS Lambda ARN (North America)" format:
arn:aws:lambda:us-east-1:xxxxxxxxxxxx:function:squeezebox.

For creating the Function: https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions?display=lis In the configuration tab: make sure to pick Runtime: Node.js 4.3 Handler: "muzak.handler" Role: "service-role/lambda_basic_execution".

NPM installer for Windows: https://nodejs.org/download/release/latest/ NPM Command from a cmd shell: (easiest to specify the full path to NPM, use quotes to handle the space in Program Files)
"C:\Program Files\node-v7.0.0-win-x64\npm" install

The AWS parts must be done in the order described in the How To Use section!

glacket commented 7 years ago

Hi Mike, I really appreciate your reply. For the npm installer, i have npm installed in program files and i copied muzak to c:\temp\muzak and squeezenode to c:\temp\muzak\node_modules/squeezenode-lordpengwin. If i am going to run "c:\temp\muzak\node_modules/squeezenode-lordpengwin\npm" install wouldnt i need to create a windows environment variable or install npm into c:\temp\muzak\node_modules/squeezenode-lordpengwin? The instructions are requesting that i download the prerquisites for squeezenode using npm install, correct, not prerequsites for npm itself. I tried that and it needs git.

MikeDeSantis commented 7 years ago

Glacket, No environment variable necessary. Because you're running the command from the target directory, specifying a full path to NPM you are all set. Correct - you need dependencies of squeezenode, not npm via git.

When you open the cmd shell, cd to (in your case): c:\temp\muzak\node_modules\squeezenode-lordpengwin

Then issue command: (assuming you got the 64 bit version and installed it appropriately) "C:\Program Files\node-v7.0.0-win-x64\npm" install

image

-Mike

glacket commented 7 years ago

Thanks for the description. I understand that now. I noticed you specified an interactive model configuration but I wanted to know if the smarthome skill type can be used so I don't have to say "alexa tell muzak".........

glacket commented 7 years ago

i guess the default smarthome api would not work because it doesn't have the interaction utterances for squeezebox, so i am guessing i have to use the custom interaction model. At that point is there still a way around the "alexa ask muzak" utterance?

MikeDeSantis commented 7 years ago

Correct, OOTB api doesn't have the utterances necessary. You have to invoke muzak somehow and 'open' I thought was your only way in. 'tell' works too? I'm new to this as well.

For 'open' you start an interactive mode session w/o having to invoke Alexa between each thing you say: -Alex open muzak -Play living room -Volume 75 <Player living room set to volume 75>

What I really want is simple to conceive but not to implement... "Alexa play Zac Brown on the living room squeezebox" or "Alexa play Daft Punk Get Lucky on the living room squeezebox"

glacket commented 7 years ago

I didnt realize there were multiple invocations either. I understood the interaction model, but i am having trouble with the ARN. My skill id is this amzn1.ask.skill.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. I took the character string xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, removed the hyphens and added to North America AWS format so it looks like arn:aws:lambda:us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:function:squeezebox, but i am getting an Invalid ARN error. I also tried it with the version added to the end and still no luck. Is "function" a variable i need to specify as well?

glacket commented 7 years ago

heres the example from amazon. arn:aws:lambda:region:account-id:function:function-name. It looks like the first function is static and the second "function" is the variable.

MikeDeSantis commented 7 years ago

My Lambda ARN is: arn:aws:lambda:us-east-1:xxxxxxxxxxxx:function:squeezebox 12 digits between us-east-1: ... :function which is the function's ID.

image

My lambda function is called "squeezebox" image

-Mike

glacket commented 7 years ago

I created the function and added the arn number. I am trying to upload the zip file to lambda. According to the read me the zip name can be muzak or lambda and it needs to contain the node_modules directory muzak.js config.js. Is this what did as well?

glacket commented 7 years ago

I configured config.js and uploaded node_modules directory muzak.js config.js as muzak.zip. The code size now resembles yours, about 973kb. I am now trying to test the skill and i get the following response from lambda. The remote endpoint could not be called, or the response it returned was invalid. Should the test work if i did everything correctly?

MikeDeSantis commented 7 years ago

zip needs to contain the node_modules directory muzak.js config.js

Yes, this is exactly what I did.

The remote endpoint could not be called, or the response it returned was invalid.

I got this a few times when I didn't issue a valid utterance to test. I think I also got this before my squeezebox server's port was forwarded. Make sure you can ping your SBS from the Internet with a service like www.canyouseeme.org. Also, the service simulator test should just be the function invocation without the 'Alexa' or muzak invocations on the front; IE just "play living room".

Expected Lambda Response: { "version": "1.0", "response": { "outputSpeech": { "type": "PlainText", "text": "Playing Upper Deck squeezebox" }, "card": { "content": "SessionSpeechlet - Playing Living Room squeezebox", "title": "SessionSpeechlet - Start Player", "type": "Simple" }, "reprompt": { "outputSpeech": { "type": "PlainText" } }, "shouldEndSession": true }, "sessionAttributes": { "player": "living room" } }

glacket commented 7 years ago

I can ping my server and connect to it remotely just fine. it looks like the problem is on the Lambda side. I must have messed something up in the script. Here is the log error from lambda not being able to load the module. I am going to try recreating the function again.

Unable to import module 'muzak': Error at Function.Module._resolveFilename (module.js:325:15) at Function.Module._load (module.js:276:25) at Module.require (module.js:353:17) at require (internal/module.js:12:17) at Object. (/var/task/muzak.js:8:21) at Module._compile (module.js:409:26) at Object.Module._extensions..js (module.js:416:10) at Module.load (module.js:343:32) at Function.Module._load (module.js:300:12) at Module.require (module.js:353:17)

glacket commented 7 years ago

Ok, I am stumped. I cannot get the muzak module to load in Lambda when trigged via aws. Here is a quick rundown of the basic process I did.

Unzipped muzak-master to c:\temp\muzak Unzipped squeezenode zip to c:\temp\muzak\node_modules/squeezenode-lordpengwin Initialized npm install from c:\temp\muzak\node_modules/squeezenode-lordpengwin directory Npm install downloaded squeezenode dependencies to c:\temp\muzak\node_modules/squeezenode-lordpengwin\node_modules Modified config.js with the string from the APP ID amzn1.ask.skill.(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)--------> amzn1.echo-sdk-ams.app. (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) Modified all connection info in config.js and saved file, never touched muzak.js Using 7-zip, zipped up muzak.js, config.js and node_modules folder which has squeezenode and dependencies Created function with “Squeezebox” as the name Alexa skill kit as the trigger Runtime node.js 4.3 Handler “muzak.handler” Exisiting role “lambda_basic_execution” Uploaded muzak.zip for the code The function has a notation stating “This function contains external libraries”. I am guessing the external libraries are the node_modules\squeezenode-lordpengwin folders from the zip. I switch to AWS and test using the utterance “play Kitchen” and I receive “The remote endpoint could not be called, or the response it returned was invalid.”

Here is what I get from lambda streaming log

Unable to import module 'muzak': Error at Function.Module._resolveFilename (module.js:325:15) at Function.Module._load (module.js:276:25) at Module.require (module.js:353:17) at require (internal/module.js:12:17) at Object. (/var/task/muzak.js:8:21) at Module._compile (module.js:409:26) at Object.Module._extensions..js (module.js:416:10) at Module.load (module.js:343:32) at Function.Module._load (module.js:300:12) at Module.require (module.js:353:17)

tmn103 commented 7 years ago

Have you got the server address in config.js set to the FreeDNS (or similar) address?

When I was having the same problem, it turned out that I'd made a silly mistake and entered my internal IP address as opposed to external.

glacket commented 7 years ago

Hi tmn103, yes i am using dyndns as my dynamic name resolution host. in the config.js file i have "http://xxx.dyndns.org". prior to that i confirmed that the address was reachable from the internet

glacket commented 7 years ago

I am sure it is something stupid that i forgot to do. i've recreated the function at least 10 times using the original mast file and also using Mikes branch and no difference.

glacket commented 7 years ago

I have noticed that when i check the code for the squeezebox function, i only see the muzak.js code, not the config.js code. Am i suppose to see both. Should i upload config.js, music.js and Node_modules separately?

glacket commented 7 years ago

Im not sure if custom slots has anything to do with it. My custom slot and values are below

Type Values
PLAYERS Office | Kitchen | Dining Room | living room |

glacket commented 7 years ago

I tested custom slots with no spaces, got the same error

MikeDeSantis commented 7 years ago

The only issue I ran into with custom slots is that my players can not have an ampersand '&' in them.

Everything looks good in your rundown of actions taken. I don't see anything that you missed.

I was getting the same error until I figured out that the handler had to be muzak.handler, which is why I put it in my notes. I'm sure there are a few different issues that would generate that response. You did keep the .js file the same name, "muzak.js" correct?

I too only have muzak.js code visible in my Lambda function - you do not need to upload an individual config.js instance as it's handled through the zip file. You may want to retry the zipping using the following command instead of 7-zip. Not that there's anything wrong with doing it that way, but it's one of the only differences that I can see between what I did and what you did. Low probability of helping but something to try I suppose.

cd C:\muzak _zip -r muzak.zip muzak.js config.js nodemodules

DON'T GIVE UP! You are definitely close. It's such a thrill when you break through and have the voice integration with Squeezebox Server!

-Mike

glacket commented 7 years ago

Is that zip command on Linux. it is not built into windows to my knowledge. in your squeezenode-lordpengwin directory do you have another node_modules directory? I do and it appears that's where the dependencies for squeezenode are stored. is that the correct file structure?

glacket commented 7 years ago

I kept muzak.js the same. it looks like it finds it but stops at trying to compile it. I'm wondering if it may have something to do with npm permissions. not sure how to check that. I just made sure "everyone" has access to all files and unchecked readonly on the node_modules folder. I also tried send to "compressed zip" file in windows and same error. I also tried setting the wrong handler on purpose and got a similar error but it did progress as far. it never got to the compile stage.

MikeDeSantis commented 7 years ago

glacket - you've put in the time and I'm sure you are very close to a solution... sometimes the last 5% is the hardest, right? On Monday I'll try to post my .zip file here somehow (from my fork) with the config.js missing. Add your network specific version of config.js and uploading to create your lambda function should work.

glacket commented 7 years ago

I appreciate all your help Mike. thanks.

MikeDeSantis commented 7 years ago

Here is a mostly complete zip file, just missing config.js. Customize your copy of config.js per the main page's instructions and add it to this zip, then upload to create your Lambda function.

This code is of my fork, 11/12/16 before the pull request (hopefully) incorporates it into the trunk.

muzak.zip

-Mike

glacket commented 7 years ago

It worked! Thanks for uploading you configuration. for some reason yours worked after I commented out the application id check line. not sure why though. I don't know what id muzak.js is referencing. I thought it was my config.js but I have that set correctly. did you mention that you had added additional utterances to your branch?

MikeDeSantis commented 7 years ago

Awesome! Yes, there are a lot of utterance combinations that I added. Are they not available in the fork code? Here they are at any rate. utterences.txt

glacket commented 7 years ago

that's my fault. i forgot i could just look at the utterances, however when i add them it gives the following error. I'm guessing its not specified in the muzak.js, but I'm using the one in the zip file you sent.

There was a problem with your request: The intent 'RandomizePlayer' was not found in the domain definition. Occurred in sample 'RandomizePlayer randomize' on line 57.

MikeDeSantis commented 7 years ago

Sorry, should have included this file as well. Update your intents.json. (Can't upload a json for some reason, dl and rename intents.json.txt to just intents.json) intents.json.txt

glacket commented 7 years ago

not your fault man. That worked. Its my fault for not understanding json that well. I didn't realize utterances was calling intents as a dependency. I thought it was hitting lambda. Its really freakin cool. too bad the core utterances are already used by alexa integrated services other wise this could probably be implemented into the amazon HA bridge. If you haven't used that yet, I recommend it. its basically a hue bridge emulator that can run on a rpi and directly control lights and the Logitech harmony hub with having to say "Alexa Open" or "alexa tell". I can just say "alexa, turn on fireplace or alexa, turn on tv or open garage door. its almost like tony stark at this point.

tmn103 commented 7 years ago

Thanks for the updated version. This will be much better with play, pause capabilities etc.

I’ve got it working using the Service Simulator to test, but it doesn’t seem to work when I speak to Alexa.

Can I just confirm that the process should be: Alexa, open Muzak play bedroom (pause bedroom etc.)

I get a noise from Alexa after opening Muzak, but then no response to any requests!

glacket commented 7 years ago

I didn't realize the service simulator test was live. It was actually controlling squeeze server during testing. it should have done the same for you during testing. were you able to match the app id? I had to disable the app id check on the version Mike uploaded. That was the only way I got it to work currently.

MikeDeSantis commented 7 years ago

LOL yes, testing through the simulator actually controls your server. I realized that after receiving a text asking if I knew the squeezeboxes were going nuts.

I had to change my invocation to "Alexa open squeezebox". It was easier to change for my personal fork rather than get my family to remember "muzak". If you're using my code tmn103 you'll have to use my invocation.

glacket I'll have to look into the HA bridge, sounds fantastic!

tmn103 commented 7 years ago

I’ve not changed the app id check, how would I do that?

I’ve changed the invocation to “squeezebox”, but it still won’t react to voice commands.

glacket commented 7 years ago

It might be case sensitive. Have you tried "Squeezebox" too? For the app id, i had to comment out this line by putting 2 forward slashes in front of it for example;

//if (event.session.application.applicationId !== config.alexaAppID) { context.fail("Invalid Application ID");

glacket commented 7 years ago

if you go into the dashboard in lambda, click the invocation errors box and on the invocation tab click on logs. you should see, the actual error message you are getting.

tmn103 commented 7 years ago

I'm not getting anything in the log from when I speak to Alexa, the only entries are from simulated testing.

glacket commented 7 years ago

then it sounds like AWS isnt even hitting lambda. You should always get a log file in lambda unless nothing is happening.

tmn103 commented 7 years ago

Got it working. Seems that the problem was I had the skill configured as English (US) and not English (UK).

Thanks again for the new functions, much more usable now.

TooUnCool commented 7 years ago

Sorry to reopen this after so long, but I am just revisiting this after failing to get it working a few months ago.

On the assumption that I need to put the lambda ARN in the config.js file and I am correct that it goes inside the curly brackets after "var config =", can someone give me an example of what that should look like?

....as you might notice, I am rather new to all this and what seems to be "bleeding obvious" to all of you, most certainly isn't for me!

andlo commented 6 years ago

I am looking for that too....I cant get it working, and think this is the reason...

GeoffAtHome commented 6 years ago

An issue that I have run into several times is that is the local in the Alexa app is set differently from where it is in the console (https://developer.amazon.com) then the skill will not be found. For example with the end-point set to arn:aws:lambda:eu-west-1 - the skill will be found if the app is set to UK but NOT if the skill is set to US. If the lambda function is not deployed to right location you will run into this problem.