Git Product home page Git Product logo

echo-sonos's People

Contributors

abayliss avatar aladd134 avatar bachase avatar chriselsen avatar connor-knabe avatar elmedico27 avatar erlichson avatar flavioribeiro avatar jhmartin avatar jplourde5 avatar jvdimas avatar ketbra avatar matthowland avatar mshulman avatar nikb747 avatar pheintzelman avatar rgraciano avatar robnagler avatar taylorjason avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

echo-sonos's Issues

echo-sqs-proxy access denied

I setup the latest version of echo-sonos, created a directory "echo-sqs-proxy" on the same server running node-sonos-http-api and ran npm install --production. Retrieved new credentials and edited settings.json. Ran npm start with no errors. In options.js file I set useSQS to true. AmazonSQSFullAccess policy was already set up and working. Zipped up files to Lambda and saved.

When I ask sonos to run a command I see Access Denied error in the echo-sqs-proxy api directory.

Lambda error

Hi, apologies if this isn't the right place for this. I'm a complete newbie at this but have managed to make it through the steps so far so good. However at the Lambda test stage I get the following error thrown:

{ "errorMessage": "Cannot find module 'index'", "errorType": "Error", "stackTrace": [ "Function.Module._resolveFilename (module.js:338:15)", "Function.Module._load (module.js:280:25)", "Module.require (module.js:364:17)", "require (module.js:380:17)" ] }

Any idea what might be causing this?

Testing Issue - Almost done

Sorry for the newbie issue but I cannot determine how to get past step 11 - Test It Out
I am under the Amazon Skills Control Panel in the test section.

Copied the lambda/play_intent_testreq.json file contents into the JSON tab and get the following error when I click on the Ask Sonos Control

Unable to call remote endpoint because request is incorrect. Please verify all the fields in the request object.

I also tried typing in under text

Alexa, ask sonos to unmute in the Living Room and I get the following error

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

For my src.zip file I copies the src folder and renamed options.examplex.js to options.js. Using a text editor on my mac I entered the IP address of my server, my default room name as well as the amzn ID number and saved. I did not edit the authorization or password. I then used the code from the instructions (cd src; chmod a+r *.js; zip src.zip *.js) to create a zip file from within the folder. When I upload the zip file this is what appears after I save:

Lambda Management Console - Code Tab

Edit code inline (in the dropdown box)

'use strict';

var http = require('http');
var https = require('https');
var AWS = require('aws-sdk');
var dynamodb = null;

var options = require('./options');
var defaultMusicService = ((options.defaultMusicService != undefined) && (options.defaultMusicService > ''))?options.defaultMusicService:'presets';
var defaultRoom = (options.defaultRoom != undefined)?options.defaultRoom:'';

var serverUrl = '';
var clientUrl = '';
var sqsServer = null;
var sqsClient = null;

var AlexaSkill = require('./AlexaSkill');
var EchoSonos = function () {
AlexaSkill.call(this, options.appid);
};

var STATE_RESPONSES = [
"This is $currentTitle by $currentArtist",
"We're listening to $currentTitle by $currentArtist",
"$currentTitle by $currentArtist"
];

EchoSonos.prototype = Object.create(AlexaSkill.prototype);
EchoSonos.prototype.constructor = EchoSonos;

EchoSonos.prototype.intentHandlers = {

AlbumIntent: function (intent, session, response) {
    console.log("AlbumIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
    	musicHandler(room, service, '/album/', intent.slots.Name.value, response);
    });  
},

ArtistIntent: function (intent, session, response) {
    console.log("MusicIntent received for room " + intent.slots.Room.value);
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        musicHandler(room, service, '/song/', 'artist:' + intent.slots.Name.value, response);
    });  
},

TrackIntent: function (intent, session, response) {
    console.log("MusicIntent received for room " + intent.slots.Room.value);
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        musicHandler(room, service, '/song/', 'track:' + intent.slots.Name.value, response);
    });  
},

MusicIntent: function (intent, session, response) {
    console.log("MusicIntent received for room " + intent.slots.Room.value);
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        musicHandler(room, service, '/song/', intent.slots.Name.value, response);
    });  
},

MusicRadioIntent: function (intent, session, response) {
    console.log("MusicRadioIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        musicHandler(room, service, '/station/', intent.slots.Name.value, response);
    });  
},

PlayMoreByArtistIntent: function (intent, session, response) {
    console.log("PlayMoreByArtist received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        moreMusicHandler(room, service, '/song/', response);
    });  
},

PlayMoreLikeTrackIntent: function (intent, session, response) {
    console.log("PlayMoreLikeTrackIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        moreMusicHandler(room, service, '/station/', response);
    });  
},

SiriusXMStationIntent: function (intent, session, response) {
    console.log("SiriusXMStationIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        siriusXMHandler(room, intent.slots.Station.value, 'station', response);
    });
},

SiriusXMChannelIntent: function (intent, session, response) {
    console.log("SiriusXMChannelIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        siriusXMHandler(room, intent.slots.Channel.value, 'channel', response);
    });
},

PandoraMusicIntent: function (intent, session, response) {
    console.log("PandoraMusicIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        pandoraHandler(room, '/play/', intent.slots.Name.value, response);
    });
},

PandoraThumbsUpIntent: function (intent, session, response) {
    console.log("PandoraThumbsUpIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        pandoraHandler(room, '/thumbsup', '', response);
    });
},

PandoraThumbsDownIntent: function (intent, session, response) {
    console.log("PandoraThumbsDownIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        pandoraHandler(room, '/thumbsdown', '', response);
    });
},

PlayPresetIntent: function (intent, session, response) {
    console.log("PlayPresetIntent received");
    options.path = '/preset/' + encodeURIComponent(intent.slots.Preset.value.toLowerCase());
    httpreq(options, function(error) {
        genericResponse(error, response);
    });
},

PlaylistIntent: function (intent, session, response) {  
    console.log("PlaylistIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        playlistHandler(room, intent.slots.Preset.value, 'playlist', response);
    });
},

FavoriteIntent: function (intent, session, response) {
    console.log("FavoriteIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        playlistHandler(room, intent.slots.Preset.value, 'favorite', response);
    });
},

ChangeRoomIntent: function (intent, session, response) {
    console.log("ChangeRoomIntent received");
    if (!options.advancedMode) {
       	response.tell("This command does not work unless advanced mode is turned on");
    } else {
		changeCurrent('DefaultEcho', intent.slots.Room.value, '', function() {
    		genericResponse('', response);
    	});
    }
},

ChangeServiceIntent: function (intent, session, response) {
    console.log("ChangeSERVICEIntent received");
    if (!options.advancedMode) {
       	response.tell("This command does not work unless advanced mode is turned on");
    } else {
        changeCurrent('DefaultEcho', '', intent.slots.Service.value, function() {
	    	genericResponse('', response);
    	});
    }
},

ChangeRoomAndServiceIntent: function (intent, session, response) {
    console.log("ChangeRoomAndServiceIntent received");
    if (!options.advancedMode) {
       	response.tell("This command does not work unless advanced mode is turned on");
    } else {
        changeCurrent('DefaultEcho', intent.slots.Room.value, intent.slots.Service.value, function() {
	    	genericResponse('', response);
    	});
    }
},

ResumeAllIntent: function (intent, session, response) {
    console.log("ResumeAllIntent received");
    options.path = '/resumeAll';
    httpreq(options, function(error) {
        genericResponse(error, response);
    });
},

ResumeIntent: function (intent, session, response) {
    console.log("ResumeIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        options.path = '/' + encodeURIComponent(room) + '/play';
	    httpreq(options, function(error) {
    	    genericResponse(error, response);
   	 	});
	});
},

PauseAllIntent: function (intent, session, response) {
    console.log("PauseAllIntent received");
    options.path = '/pauseAll';
    httpreq(options, function(error) {
        genericResponse(error, response);
    });
},

PauseIntent: function (intent, session, response) {
    console.log("PauseIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        options.path = '/' + encodeURIComponent(room) + '/pause';
	    httpreq(options, function(error) {
    	    genericResponse(error, response);
    	});
    });
},

VolumeDownIntent: function (intent, session, response) {
    console.log("VolumeDownIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        volumeHandler(room, response, '-10');
    });
},

VolumeUpIntent: function (intent, session, response) {
    console.log("VolumeUpIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        volumeHandler(room, response, '+10');
    });
},

SetVolumeIntent: function (intent, session, response) {
    console.log("SetVolumeIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        volumeHandler(room, response, intent.slots.Percent.value);
    });
},

NextTrackIntent: function (intent, session, response) {
    console.log("NextTrackIntent received");

    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        actOnCoordinator(options, '/next', room,  function (error, responseBodyJson) {
	        genericResponse(error, response);
    	});
    });
},

PreviousTrackIntent: function (intent, session, response) {
    console.log("PreviousTrackIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        actOnCoordinator(options, '/previous', room,  function (error, responseBodyJson) {
	        genericResponse(error, response);
    	});
    });
},

WhatsPlayingIntent: function (intent, session, response) {
    console.log("WhatsPlayingIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        options.path = '/' + encodeURIComponent(room) + '/state';

	    httpreq(options, function (error, responseJson) {
            if (!error) {
	            responseJson = JSON.parse(responseJson);
 		        var randResponse = Math.floor(Math.random() * STATE_RESPONSES.length);
        	    var responseText = STATE_RESPONSES[randResponse].replace("$currentTitle", responseJson.currentTrack.title).replace("$currentArtist", responseJson.currentTrack.artist);
            	response.tell(responseText);
        	}
        	else { 
            	response.tell(error.message);
        	}
    	});
    });
},

MuteIntent: function (intent, session, response) {
    console.log("MuteIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        options.path = '/' + encodeURIComponent(room) + '/mute';
	    httpreq(options, function(error) {
    	    genericResponse(error, response);
    	});
    });
},

UnmuteIntent: function (intent, session, response) {
    console.log("UnmuteIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        options.path = '/' + encodeURIComponent(room) + '/unmute';
	    httpreq(options, function(error) {
    	    genericResponse(error, response);
    	});
    });
},

ClearQueueIntent: function (intent, session, response) {
    console.log("ClearQueueIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        actOnCoordinator(options, '/clearqueue', room,  function (error, responseBodyJson) {
	        genericResponse(error, response);
    	});
    });
},

RepeatIntent: function (intent, session, response) {
    console.log("RepeatIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
    	toggleHandler(room, intent.slots.Toggle.value, "repeat", response);
    });
},

ShuffleIntent: function (intent, session, response) {
    console.log("ShuffleIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        toggleHandler(room, intent.slots.Toggle.value, "shuffle", response);
    });
},

CrossfadeIntent: function (intent, session, response) {
    console.log("CrossfadeIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        toggleHandler(room, intent.slots.Toggle.value, "crossfade", response);
    });
},

UngroupIntent: function (intent, session, response) {
    console.log("UngroupIntent received");
    loadCurrentRoomAndService('DefaultEcho', intent.slots.Room.value, function(room, service) {
        options.path = '/' + encodeURIComponent(room) + '/isolate';
        httpreq(options, function(error) {
            genericResponse(error, response);
        });
    });
},

JoinGroupIntent: function (intent, session, response) {
    console.log("JoinGroupIntent received");
    options.path = '/' + encodeURIComponent(intent.slots.JoiningRoom.value) + '/join/' 
            + encodeURIComponent(intent.slots.PlayingRoom.value);
    httpreq(options, function(error) {
        genericResponse(error, response);
    });
}

}

/** Handles Apple Music, Spotify, Deezer, library, or presets. The default can be specified in options.js or changed if advanced mode is turned on */
function musicHandler(roomValue, service, cmdpath, name, response) {

if (service == 'presets') {
    options.path = '/preset/' + encodeURIComponent(name);
    httpreq(options, function(error) {
    	genericResponse(error, response);
    });
} else { 
    var skillPath = '/musicsearch/' + service.toLowerCase() + cmdpath + encodeURIComponent(name);
    var msgStart = (cmdpath.startsWith('/station'))?'Started ':'Queued and started ';
    var msgEnd = (cmdpath.startsWith('/station'))?' radio':'';

    actOnCoordinator(options, skillPath, roomValue, function(error, responseBodyJson) {
    	if (error) {
        	response.tell(error.message);
      	} else {
        	response.tell(msgStart + name + msgEnd);
        }
    });
}

}

/** Handles Apple Music - plays artist tracks or plays a radio station for the current track */
function moreMusicHandler(roomValue, service, cmdpath, response) {
options.path = '/' + encodeURIComponent(roomValue) + '/state';

httpreq(options, function (error, responseJson) {
    if (!error) {
        responseJson = JSON.parse(responseJson);
		console.log("Currently Playing = " + JSON.stringify(responseJson, null, 2));            
        if (responseJson.currentTrack.artist != undefined) {
       		var name = responseJson.currentTrack.artist;
        	if (cmdpath.startsWith('/station') && (['apple','spotify','deezer','elite'].indexOf(service) != -1)) {
            	name += ' ' + responseJson.currentTrack.title;
        	}    
            musicHandler(roomValue, service, cmdpath, name, response);
        } else {
        	response.tell("The current artist is not identified");
        }
    } else { 
        genericResponse(error, response);
    }
});

}

/** Handles SiriusXM Radio */
function siriusXMHandler(roomValue, name, type, response) {

var skillPath = '/siriusxm/' + encodeURIComponent(name.replace(' ','+'));

actOnCoordinator(options, skillPath, roomValue, function(error, responseBodyJson) {
	if (error) {
    	genericResponse(error, response);
	} else {
      	response.tell('Sirius XM ' + type + ' ' + name + ' started');
	}
});

}

/** Handles SiriusXM Radio */
function pandoraHandler(roomValue, cmdpath, name, response) {

var skillPath = '/pandora' + cmdpath + ((cmdpath=='/play/')?encodeURIComponent(name):'');

actOnCoordinator(options, skillPath, roomValue, function(error, responseBodyJson) {
	if (error) {
   		response.tell(error.message);
	} else {
  		if (cmdpath == '/play/') {
     		response.tell('Pandora ' + name + ' started');
  		} else {
    		genericResponse(error, response);
  		}  
  	}
});

}

/** Handles playlists and favorites */
function playlistHandler(roomValue, presetValue, skillName, response) {
var skillPath = '/' + skillName + '/' + encodeURIComponent(presetValue.toLowerCase());

// This first action queues up the playlist / favorite, and it shouldn't say anything unless there's an error
actOnCoordinator(options, skillPath, roomValue, function(error, responseBodyJson) {
    if (error) {
        genericResponse(error, response);
    }
});

// The 2nd action actually plays the playlist / favorite
actOnCoordinator(options, '/play', roomValue, function(error, responseBodyJson) {
    genericResponse(error, response, "Queued and started " + presetValue);
});

}

/** Handles all skills of the form /roomname/toggle/[on,off] */
function toggleHandler(roomValue, toggleValue, skillName, response) {
if (!toggleValue || (toggleValue != 'on' && toggleValue != 'off')) {
response.tell("I need to know if I should turn " + skillName + " on or off. Example: Alexa, tell Sonos to turn " + skillName + " on");
return;
}

options.path = '/' + encodeURIComponent(roomValue) + '/' + skillName + '/' + toggleValue;

httpreq(options, function(error) {
    if (!error) {
        response.tell("Turned " + skillName + " " + toggleValue + " in " + roomValue);
    }
    else { 
      response.tell(error.message);
    }
});

}

/** Handles up, down, & absolute volume for either an individual room or an entire group */
function volumeHandler(roomValue, response, volume) {
var roomAndGroup = parseRoomAndGroup(roomValue);

if (!roomAndGroup.room) {
    response.tell("Please specify a room. For example, turn the volume down in the KITCHEN");
    return;
}

if (!roomAndGroup.group) {
    options.path = '/' + encodeURIComponent(roomAndGroup.room) + '/volume/' + volume;

    httpreq(options, function(error) {
        genericResponse(error, response);
    });
}

else {
    actOnCoordinator(options, '/groupVolume/' + volume, roomAndGroup.room,  function (error, responseBodyJson) {
        genericResponse(error, response);
    });
}

}

/* Given a string roomArgument that either looks like "my room" or "my room group",

  • returns an object with two members:
  • obj.group: true if roomArgument ends with "group", false otherwise.
  • obj.room: if roomArgument is "my room group", returns "my room"
    */
    function parseRoomAndGroup(roomArgument) {
    var roomAndGroupParsed = new Object();
    roomAndGroupParsed.group = false;
    roomAndGroupParsed.room = false;
if (!roomArgument) {
    return roomAndGroupParsed;
}

var groupIndex = roomArgument.indexOf("group");

if (groupIndex && (groupIndex + 4 == (roomArgument.length - 1)) && roomArgument.length >= 7) {
    roomAndGroupParsed.group = true;
    roomAndGroupParsed.room = roomArgument.substr(0, groupIndex - 1);
}
else {
    roomAndGroupParsed.room = roomArgument;
}

return roomAndGroupParsed;

}

function isBlank(val)
{
return ((val == undefined) || (val == null) || (val == ''));
}

function changeCurrent(echoId, room, service, OnCompleteFun) {
var updateExpression = '';
var values = {};

if (options.advancedMode) {
	if (!isBlank(room) && !isBlank(service)) {
		updateExpression = "set currentRoom=:r, currentMusicService=:s";
		values = {":r":room, "s:":service};
	} else
	if (!isBlank(room)) {
		updateExpression = "set currentRoom=:r";
		values = {":r":room};
	} else
	if (!isBlank(service)) {
		updateExpression = "set currentMusicService=:s";
		values = {":s":service};
	}	

	if (updateExpression != '') {
		var docClient = new AWS.DynamoDB.DocumentClient();
		var params = {
			TableName: "echo-sonos",
			Key:{
    			"echoid": echoId
			},
			UpdateExpression: updateExpression,
			ExpressionAttributeValues:values,
			ReturnValues:"UPDATED_NEW"
		};

		console.log("Updating current defaults...");
		docClient.update(params, function(err, data) {
			if (err) {
    			console.error("Unable to update current defaults. Error JSON:", JSON.stringify(err, null, 2));
			} else {
    			console.log("Update of current defaults succeeded:", JSON.stringify(data, null, 2));
			}
			OnCompleteFun();
		});
	}
} else {
	console.error("Unable to change defaults when not in Advanced Mode");
}

}

function loadCurrentRoomAndService(echoId, room, OnCompleteFun) {
var service = '';

function checkDefaults()
{
	if (isBlank(room)) {
		room = defaultRoom;
	}
	if (isBlank(service)) {
		service = defaultMusicService;
	}
}


console.log("Advanced Mode = " + options.advancedMode);
if (options.advancedMode) {

	function addCurrent(OnCompleteFun)
	{
    	checkDefaults();
       				
    	var docClient = new AWS.DynamoDB.DocumentClient();
		var params = {
			TableName: "echo-sonos",
			Item:{
    			"echoid": echoId,
    			"currentRoom": room,
    			"currentMusicService": service
			}
		};

		console.log("Adding current settings record");
		docClient.put(params, function(err, data) {
			console.log("err=" + JSON.stringify(err, null, 2));			
			console.log("data=" + JSON.stringify(data, null, 2));			
			if (err) {
				console.error("Unable to add default. Error JSON:", JSON.stringify(err, null, 2));
			} else {
    			OnCompleteFun(room, service);
 			}
		});    				
	}

	function readCurrent(OnCompleteFun)
	{
    	var newRoom = '';
    	var newService = '';
    	var docClient = new AWS.DynamoDB.DocumentClient();
		var params = {
				TableName: "echo-sonos",
				Key:{
    				"echoid": echoId
				}
			};

		console.log("Reading current settings");
		docClient.get(params, function(err, data) {
			//console.log("err=" + JSON.stringify(err, null, 2));			
			//console.log("data=" + JSON.stringify(data, null, 2));			
			if (err || (data.Item == undefined)) {
				addCurrent(OnCompleteFun);
			} else {
		    	if (isBlank(room)) {
		    		room = data.Item.currentRoom;
		    	} else 
		    	if (room != data.Item.currentRoom) {
		    	  newRoom = room;
		    	}
		    	if (isBlank(service)) {
		    		service = data.Item.currentMusicService;
		    	} else
		    	if (service != data.Item.currentMusicService) {
		    		newService = service;
		    	}
				console.log("room=" + room +" newRoom=" + newRoom + "  service=" + service + " newService=" + newService);   		    	
		    	if (isBlank(newRoom) && isBlank(newService)) {
    				OnCompleteFun(room, service);
    			} else {
    				changeCurrent(echoId, newRoom, newService, function() {
        				OnCompleteFun(room, service);
    				});
    			}
 			}
		});    				
	}

    AWS.config.update({
        region: process.env.AWS_REGION,
        endpoint: "https://dynamodb." + process.env.AWS_REGION + ".amazonaws.com"
    });
    var dynamodb = new AWS.DynamoDB();

    dynamodb.listTables(function(err, data) {
		if (err) {
            console.log(err, err.stack);
		} else 
        if ((data.TableNames.length == 0) || (data.TableNames.indexOf("echo-sonos") == -1))  {
            var params = {
                TableName : "echo-sonos",
                KeySchema: [       
                    { AttributeName: "echoid", KeyType: "HASH"}  //Partition key
                ],
                AttributeDefinitions: [       
    				{ AttributeName: "echoid", AttributeType: "S" }
				],
				ProvisionedThroughput: {       
    				ReadCapacityUnits: 1, 
    				WriteCapacityUnits: 1
				}
			};

			console.log("Create echo-sonos table");
			dynamodb.createTable(params, function(err, data) {
				if (err) {
    				console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
				} else {
					params = {
                		TableName : "echo-sonos"
                	};
                
					dynamodb.waitFor('tableExists', params, function(err, data) {
						if (err) {
    						console.error("Unable to wait for table table. Error JSON:", JSON.stringify(err, null, 2));
						} else {
							addCurrent(OnCompleteFun);
						}
					});
				}
			});
        } else 
        if (isBlank(service) || isBlank(room)) {
        	readCurrent(OnCompleteFun);
        }
    });
} else {
    checkDefaults();
    OnCompleteFun(room, service);
}

}

function httpreq(options, responseCallback) {
if (options.useSQS) {
sqsServer.purgeQueue({QueueUrl:serverUrl}, function(err, data) {
console.log("sending SQS " + options.path);
sqsClient.sendMessage({
MessageBody: options.path,
QueueUrl: clientUrl
},
function(err, data) {
if (err) {
console.log('ERR', err);
} else {
console.log(data);
sqsServer.receiveMessage({
QueueUrl: serverUrl,
MaxNumberOfMessages: 1, // how many messages do we wanna retrieve?
VisibilityTimeout: 60, // seconds - how long we want a lock on this job
WaitTimeSeconds: 20 // seconds - how long should we wait for a message?
},
function(err, data) {
var message = data.Messages[0];
var response = message.Body;
if (!err) {
sqsServer.deleteMessage({
QueueUrl: serverUrl,
ReceiptHandle: message.ReceiptHandle
}, function(err, data) {
responseCallback(undefined, response);
if (err) {
console.log(err);
}
});
} else {
console.log(err);
responseCallback(err);
}
}
);
}
}
);
});
} else {
var transport = options.useHttps ? https : http;

	console.log("Sending " + (options.useHttps ? "HTTPS" : "HTTP" ) + " request to: " + options.path);

	var req = transport.request(options, function(httpResponse) {
    	var body = '';
    
    	httpResponse.on('data', function(data) {
        	body += data;
    	});
    
    	httpResponse.on('end', function() {
        	responseCallback(undefined, body);
    	});
	});

	req.on('error', function(e) {
    	responseCallback(e);
	});

	req.end();
}

}

// 1) grab /zones and find the coordinator for the room being asked for
// 2) perform an action on that coordinator
function actOnCoordinator(options, actionPath, room, onCompleteFun) {
options.path = '/zones';
console.log("getting zones...");

var handleZonesResponse = function (error, responseJson) {
    if (!error) { 
        responseJson = JSON.parse(responseJson);
        var coordinatorRoomName = findCoordinatorForRoom(responseJson, room);
        
        options.path = '/' + encodeURIComponent(coordinatorRoomName) + actionPath;
        console.log(options.path);
        httpreq(options, onCompleteFun);
    }    
    else { 
        onCompleteFun(error);
    }
}

httpreq(options, handleZonesResponse);

}

function genericResponse(error, response, success) {
if (!error) {
if (!success) {
response.tell("OK");
}
else {
response.tell(success);
}
}
else {
response.tell("The Lambda service encountered an error: " + error.message);
}
}

// Given a room name, returns the name of the coordinator for that room
function findCoordinatorForRoom(responseJson, room) {
console.log("finding coordinator for room: " + room);

for (var i = 0; i < responseJson.length; i++) {
    var zone = responseJson[i];

    for (var j = 0; j < zone.members.length; j++) {
        var member = zone.members[j];

        if ((member.roomName != undefined) && (member.roomName.toLowerCase() == room.toLowerCase())) {
            return zone.coordinator.roomName;
        }
    }
}

}

// Create the handler that responds to the Alexa Request.
exports.handler = function (event, context) {
// Create an instance of the EchoSonos skill.
var echoSonos = new EchoSonos();
if (options.useSQS) {
var region = process.env.AWS_REGION;
var arn = context.invokedFunctionArn;
var actLoc = arn.indexOf(region) + region.length + 1;
var accountId = arn.substring(actLoc,arn.indexOf(':',actLoc));
var baseSqsUrl = "https://sqs." + region + ".amazonaws.com/" + accountId;
serverUrl = baseSqsUrl + "/SQS-Proxy-Server";
clientUrl = baseSqsUrl + "/SQS-Proxy-Client";
sqsServer = new AWS.SQS({region : region});
sqsClient = new AWS.SQS({region : region});
}
echoSonos.execute(event, context);
};

Play Echo and Sonos Speakers Simultaneously?

I appreciate all of your work here. Is it possible to play the Echo and Sonos speakers in unison? I have a Sonos Play:1 and an Amazon Echo. I am not familiar with their protocols. I apologize for starting an issue just to ask a question, but this is clearly the most advanced work in the area.

Node SQS Listener

Have you considered leveraging SQS to remove the need for DynDNS and Firewall hole? This may be easier for people to secure, and AWS allows 1 Million SQS messages/mo for free.

A possible solution might be - a NodeJS SQS listener on the server/pi. When an event occurs, Lambda posts to the SNS queue. The listener pulls the message and calls the API locally.

Error when testing

Hi,

I get the following when running the Lambda test. Can someone please offer some help.

{
"errorMessage": "In strict mode code, functions can only be declared at top level or immediately within another function.",
"errorType": "SyntaxError",
"stackTrace": [
"Module._compile (module.js:439:25)",
"Object.Module._extensions..js (module.js:474:10)",
"Module.load (module.js:356:32)",
"Function.Module._load (module.js:312:12)",
"Module.require (module.js:364:17)",
"require (module.js:380:17)"
]
}

Lambda newbie issue - creating service

I am having issue creating the AWS Lambda service

I have created the zip file with my edited options.js, index.js, AlexaSkills.js. The zip files does not have a directory or anything else in it just the intended files. When I create the function I get the following message:

It looks like your Lambda function "sonos" is unable to be edited inline, so you need to re-upload any changes.

Lambda NOT recognizing/loading src.zip files

When I browse to the repos "lambda/src" directory containing the src.zip file the lambda function zip upload does NOT see the *.zip file which is 4k. I've made sure I am in the correct directory and tried multiple "zip" programs. Any idea what's up?

presets file has small bug, causes group presets to fail

If you edit the default presets.json file, and leave in the "uri" definitions, a long asynchronous series will fail in the middle. sonos.js does check for whether presets.uri is defined and, if so, attempts to actually set the URI accordingly. Sonos barfs on this, and it messes up all the calls that come later. Most importantly, the calls that are meant to define the coordinators of the other group members. Just delete the URI definitions, and everything works flawlessly.

Lambda Test Error

Getting the following error when running save and test after src.zip upload. Using Node js 4.3
Any help would be appreciated.

{
"errorMessage": "Unexpected token ILLEGAL",
"errorType": "SyntaxError",
"stackTrace": [
"Module._compile (module.js:373:25)",
"Object.Module._extensions..js (module.js:416:10)",
"Module.load (module.js:343:32)",
"Function.Module._load (module.js:300:12)",
"Module.require (module.js:353:17)",
"require (internal/module.js:12:17)",
"Object. (/var/task/index.js:8:15)",
"Module._compile (module.js:409:26)",
"Object.Module._extensions..js (module.js:416:10)"
]
}

lambda test error: Can't find ./options

{
"errorMessage": "Cannot find module './options'",
"errorType": "Error",
"stackTrace": [
"Function.Module._resolveFilename (module.js:338:15)",
"Function.Module._load (module.js:280:25)",
"Module.require (module.js:364:17)",
"require (module.js:380:17)",
"Object. (/var/task/index.js:5:15)",
"Module._compile (module.js:456:26)",
"Object.Module._extensions..js (module.js:474:10)",
"Module.load (module.js:356:32)",
"Function.Module._load (module.js:312:12)",
"Module.require (module.js:364:17)"
]
}

Alexa discovery not working

I am in the UK and have the lambda function testing correctly in EU West using the echo-sqs-proxy and I can test the Alexa skill successfully as well, with UK Language per previous issue.

{
"version": "1.0",
"response": {
"outputSpeech": {
"type": "PlainText",
"text": "OK"
},
"shouldEndSession": true
},
"sessionAttributes": {}
}

I can view the zones with IPofPi:5005/zones so that bit works too.

However Alexa cannot discover my devices.

audio player directives

So I noticed today the new "Audio Player" option under skill information on developer.amazon.com.

Here's the link to the amazon information about it.
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/custom-audioplayer-interface-reference

It seems it is looking to stream audio to the echo, but could we also use this to just control our Sonos commands? The part of it that looks useful is where it says if your skill was the last skill marked to be playing audio that you could then use any of the built in amazon commands next / previous / shuffle / stop / etc WITHOUT invoking the skill name! This would be nice to have if it's possible. I'm trying to read over it but wanted to share with those of you who may have a little better understanding than me.

Lamba crash

"Alexa, use Sonos to play test" works. But when I try a "Next track" utterance I get a lambda crash.
screen shot 2015-12-22 at 10 36 30 am

Event Source "Alexa Skills Kit" not listed

Have uploaded src.zip which contains index.js, AlexaSkill.js and options.js. Followed the Basic Excution Role creation. However, when I attempt to Add a source, my only choices are AWS IoT, Cloudwatch Events, Cloudwatch Logs, Dynamo DB, Kinesis, S3 and SNS. No Alexa Skills Kit. Can you advise on what I might be doing wrong? Thanks.

Node.js crashing

I've gotten to the point where I can ask Alexia to play test and it works sometimes and crashes sometimes. I cannot get her to execute any other commands except the basic global commands to work without crashing. I've attached the npm-debug log. Can you assist?
npm-debug.zip

Came to realize I need to eliminate rooms in presets I do not have. Once I did that all
works great.

Music Stations Presets

I have several Amazon Music and Pandora Stations in my Sonos Favorites. I also have several Sonos Playlists.

If I have Alexa "tell sonos to play MYFAVORITE" and the favorite is a playlist, sonos will group the rooms I've setup in presets.json, and starts playing in all the rooms. This works correctly.

If I have Alexa "tell sonos to play MYFAVORITE" and the favorite is a streaming music station, amazon or pandora, music will only be sent to the first room in the preset. No grouping or un-grouping of the rooms happens.

error - failed: Address family not supported by protocol

I am very new to all of this so my apologies for asking dumb questions. my first project is to connect my Pi2 to my Sonos system by following the following directions. https://github.com/rgraciano/echo-sonos

I successfully

Install node.js on a server on the same network as your Sonos.

Grab https://github.com/jishi/node-sonos-http-api and run it on that server.
Take the node-sonos-http-api/presets.json that I have here and drop it into your node-sonos-http-api root directory. Modify it to use your speaker names and your favorite stations. Don't worry about the "uri" field - it's unused. Make sure the preset names are lowercase (like "test" and "rock" in my example).

but when I try to test by hitting http://yourserverip:5005/zones it locks up

I also tried testing with the following and I get the "failed: Address family not supported by protocol" error

pi@raspberrypi ~ $ wget http://localhost:5005/resumeall
--2015-07-29 03:04:03-- http://localhost:5005/resumeall
Resolving localhost (localhost)... 127.0.0.1, ::1
Connecting to localhost (localhost)|127.0.0.1|:5005... failed: Connection refused.
Connecting to localhost (localhost)|::1|:5005... failed: Address family not supported by protocol.

Any thoughts?

Echo Dot?

Hi, can you please tell me if this will work with the Echo Dot?
Thanks,
Susan

utterances error

I received the following error when I copy and paste the utterances in to the sample utterances

Error: There was a problem with your request: Incorrect syntax: A value may not be supplied for the slot 'Name'. Occurred in sample 'MusicIntent play {coldplay|Name} in the {Room}' on line 21.

This happpens for several of the lines in the code?

Is there a newer file to copy utterances from?

Grouping and playing favorites don't work for me

I've been having problems with grouping my players in the house. I have 2 players and when I say to group them the music that was playing on one just stops and when I then open the app I do not see them grouped. Then I tell it to resume it continues playing on the original it was playing on. Also when I say to play a favorite (Pandora or Google music) station it just says ok and nothing happens. I'm more concerned with the grouping but being able to use both would be cool. Thanks to anyone that can help.

Lambda test failing with time out error

I've gotten all the way through the build process up to testing in Lambda, however I'm getting an error message on test:

"{
"errorMessage": "2016-06-06T03:10:19.163Z 2cfef79a-2b94-11e6-9fba-07cd6747ff2e Task timed out after 10.00 seconds"
}"

I'm not sure what additional information might be helpful, here's the log output as well:

START RequestId: 2cfef79a-2b94-11e6-9fba-07cd6747ff2e Version: $LATEST
2016-06-06T03:10:09.968Z 2cfef79a-2b94-11e6-9fba-07cd6747ff2e session applicationId: amzn1.echo-sdk-ams.app.b346e9df-6854-441e-8c24-fb366e0fde9f
2016-06-06T03:10:09.969Z 2cfef79a-2b94-11e6-9fba-07cd6747ff2e dispatch intent = PlayIntent
2016-06-06T03:10:09.970Z 2cfef79a-2b94-11e6-9fba-07cd6747ff2e PlayIntent received
2016-06-06T03:10:09.970Z 2cfef79a-2b94-11e6-9fba-07cd6747ff2e Sending HTTP request to: /preset/test
END RequestId: 2cfef79a-2b94-11e6-9fba-07cd6747ff2e
REPORT RequestId: 2cfef79a-2b94-11e6-9fba-07cd6747ff2e Duration: 10000.66 ms Billed Duration: 10000 ms Memory Size: 128 MB Max Memory Used: 16 MB
2016-06-06T03:10:19.163Z 2cfef79a-2b94-11e6-9fba-07cd6747ff2e Task timed out after 10.00 seconds

Lastly, here's the test request I'm running:

{
"session": {
"new": true,
"sessionId": "session1234",
"attributes": {},
"user": {
"userId": null
},
"application": {
"applicationId": "amzn1.echo-sdk-ams.app.b346e9df-6854-441e-8c24-fb366e0fde9f"
}
},
"version": "1.0",
"request": {
"intent": {
"slots": {
"Preset": {
"name": "Preset",
"value": "test"
}
},
"name": "PlayIntent"
},
"type": "IntentRequest",
"requestId": "request5678"
}

Any chance for help?

The remote endpoint could not be called

@jplourde5 This is odd behavior. If I ask sonos to play an album from the sonos library the album loads and plays.

Some albums get the lampda response "The remote endpoint could not be called, or the response it returned was invalid." Other albums get the correct lampda "Queued and started ALBUM NAME"

The same albums get the same response each time. I am not sure what could be the problem with the album names that get the error.

New Alexa Skills Kit For Node.js

This is not really an issue, but I think you node.js programmers will like this, if you don't already know.

Today we’re happy to announce the new alexa-sdk for Node.js to help you build skills faster and with less complexity.

https://developer.amazon.com/public/community/post/Tx213D2XQIYH864/Announcing-the-Alexa-Skills-Kit-for-Node-js?mkt_tok=eyJpIjoiWkRZek5HTXlOell4T1RVMSIsInQiOiJKK3F0cnB3Z25lNGdoeWEyZkpEQkN6NFJ3NDJpcFdZN3VoSW9scmJvMVZQeVcybW05cFc4TUNTMmhwR3ZjbGdrTXAzV3Y5VkVHaGk2ZWxlRk9IQVwvMGZkVlhsNjQzc0FLYUZwcWlUZ0ZlT289In0%3

TTS support

Could you please add support for TTS?

Example:

  •            Alexa, tell Sonos to say hello world.
    
  •            Alexa, tell Sonos to say I love you.
    
  •            Alexa, tell Sonos to say dinner is ready in living room.
    
  •            Alexa, tell Sonos to say good night in bedroom.
    

It can be used as a remote speaker. And if every room has an echo and sonos, they can be used as two-way radios. That will be cool.

Lambda Test Times out

I have tried several time and my Lambda test always times out. I even increased the duration to 30 sec. I am using Node js 4.3.

Any thoughts. Here is the log returned

START RequestId: c8054000-a37f-11e6-935a-93d6e8e04457 Version: $LATEST
2016-11-05T17:46:31.023Z c8054000-a37f-11e6-935a-93d6e8e04457 session applicationId: amzn1.ask.skill.49a8db9e-6db6-496f-be6a-046ccc40918b
2016-11-05T17:46:31.024Z c8054000-a37f-11e6-935a-93d6e8e04457 dispatch intent = UnmuteIntent
2016-11-05T17:46:31.024Z c8054000-a37f-11e6-935a-93d6e8e04457 UnmuteIntent received
2016-11-05T17:46:31.024Z c8054000-a37f-11e6-935a-93d6e8e04457 Advanced Mode = false
2016-11-05T17:46:31.081Z c8054000-a37f-11e6-935a-93d6e8e04457 Sending HTTP request to: /living%20room/unmute
END RequestId: c8054000-a37f-11e6-935a-93d6e8e04457
REPORT RequestId: c8054000-a37f-11e6-935a-93d6e8e04457 Duration: 37001.40 ms Billed Duration: 37000 ms Memory Size: 128 MB Max Memory Used: 11 MB
2016-11-05T17:47:06.345Z c8054000-a37f-11e6-935a-93d6e8e04457 Task timed out after 37.00 seconds

issue with intent schema, fairly new at this

First, everything has been working swimmingly through the initial node setup and the readiness for the outside world (ddns). I'm at the Alexa Skill creation part, and this is where I'm hanging up.

I've created the custom slots and copied in the appropriate info from the files. I've copy/pasted the intent schema and the utterances. However, when I go to save it, I get this error:

Error: There was a problem with your request: Error in sample on line 21 - 'MusicIntent play {coldplay|name} in the {Room}'. The given intent doesn't declare the slot 'name'.

Not really sure how to address this, and didn't (couldn't) find anything in searches related to this, so any guidance is super appreciated.

Thanks!

HTTPS + Basic Auth Request

This is probably more of a pebkac issue, but I've modified sonos-http-api to support ssl and basic auth for security reasons. Call me paranoid, but I don't want some script kiddie interrupting my sweet jams... I'm having a hell of a time editing the options and index Lambda json though to get it to make an https request and pass basic auth creds. Any ideas? The AWS error "logs" are next to useless.

Disregard. Some lame syntax issue on my end. Thanks for the amazing tool!

Add an onLaunch method

The app as is will throw an exception when onLaunch is triggered. Instead, add a simple prompt for the user to do something.

"There was a problem with the requested skills response"

I am receiving an error after implementing everything, Lambda, local node.js, and alexa skill. When testing lambda, I receive an a-okay.

"version": "1.0",
"response": {
"outputSpeech": {
"type": "PlainText",
"text": "OK"
},
"shouldEndSession": true
},
"sessionAttributes": {}
}

I originally thought that was the issue because I kept only being able to zip the three .js files in a folder. I do not see why my alexa skill isn't tying to the lambda code. Any ideas?

Lamba problems (socket hang up)

Tried it a few different times around with no luck.

When trying to run the blueprint I get the following:

{ "version": "1.0", "response": { "outputSpeech": { "type": "PlainText", "text": "The Lambda service encountered an error: socket hang up" }, "shouldEndSession": true }, "sessionAttributes": {} }

Similar issue as in #42 but he never shared his fix for it. The api works on external networks and that is not the problem.

Any thoughts what could be wrong?

Favorites and Presets load but do not play

I have this awesome setup working for most things, however when I tell Sonos "Alexa, tell Sonos to play favorite "MY Favorite" in the Living Room" it loads up the favorite in the Sonos app but does not start playing. Same thing happens with presets. Please help!

All sonos amps respond except one

I 4 sonos amps. 3 of the 4 respond except the master bedroom. I have checked the preset file and all looks to be OK. Any ideas?

pi@raspberrypi ~ $ wget http://localhost:5005/master/play
--2015-08-11 03:08:41-- http://localhost:5005/master/play
Resolving localhost (localhost)... 127.0.0.1, ::1
Connecting to localhost (localhost)|127.0.0.1|:5005... connected.
HTTP request sent, awaiting response... 200 OK
Length: 37 [application/json]
Saving to: `play.20'

100%[======================================>] 37 --.-K/s in 0s

2015-08-11 03:08:41 (836 KB/s) - `play.20' saved [37/37]

wrong sonos controlled by node-sonos-http-api

I run the test preset which successfully plays my kitchen Sonos.
Then I try "next" and "what's playing" and /next and /state get called.
They don't work and I can tell from the Lambda logs that it's trying to control a different Sonos in my house.
I verify by running /next and /state in my browser and they control a different Sonos.

I've looked at the node-sonos-http-api README (but not the source yet) and it says that actions are usually /{room name}/{action}. It doesn't say what happens when there is no /{room name}/.
That Sonos may be my master or a random default?

I'm no expert on Alexa, but I think we may need a "slot" for the room name, or hardcoded paths.

systemctl echo-sonos.service

If there is any interest, I have created a systemctl file for echo-sonos.service for anyone who plans to run this as a server task. It works well on a Raspberry Pi 2 and makes a handle little Internet appliance.

Groups Broken

When I ask Alexa to play a preset the sonos groups are broken. So if I have three rooms in the players entry of a preset and those three rooms are grouped, when I ask to play the preset the rooms are no longer grouped.

Is this by design?

Is there a way to avoid this?

Andy Adler

Are aliases possible for Room names?

First, a big thanks to Ryan for doing the heavy lifting here! This is very cool that Alexa can control my Sonos system.

The basic functionality is working at this point, but I'm running into a number of problems that I think are mostly related to my Sonos room names. I have a fairly large number (18) of Sonos Connect:Amps in my system, and to make it easier to find the one(s) I want in the Sonos iOS app, I have prefixed my room names so they sort in a logical order in the ROOMS list in Sonos. For example, I have all of the bedroom Connect:Amps starting with the number "1". This works quite well in the Sonos app where you see a list of all the rooms, but it's not very good for Echo Sonos because you have to remember exactly what the room name is. Also, apparently the Amazon Developer Console's Service Simulator doesn't support numbers in the Utterance.

So I'm wondering if the Alexa Skill system supports the concept of aliases? If I could have the ROOMS custom Slot populated with the actual room name that Node Sonos HTTP API needs, but also give aliases that Alexa would understand, that would solve my problem without compromising ease of use in the Sonos iOS app. I'm guessing there's a way to do this built into Alexa Skills... allowing multiple names for a given object is critical for a voice control app's ease of use. I'd appreciate any pointers for resolving this. Thanks!

Build-in slot type AMAZON.LITERAL is forbidden

Great work! Just trying to set this up in the UK now that the Echo has been announced. I've hit an initial problem trying to save the Interaction Model, which looks related to the fact that I'm using a different locale, although this will also become an issue within the US shortly. When I attempt to save the Interaction Model I receive the following message:

Error: There was a problem with your request: The build-in slot type AMAZON.LITERAL is forbidden in current locale

Digging a little further, I find:

English (US) skills using the AMAZON.LITERAL slot type should be updated to use custom slots. Starting November 30, 2016, any English (US) skill using AMAZON.LITERAL will no longer pass certification.

English (UK) and German skills do not support AMAZON.LITERAL and cannot use the AMAZON.LITERAL slot type.

Does anyone have an intent schema that works around this issue?

Thanks,

Lambda error

I'm getting the following error when I test:

Execution result:
{
"errorMessage": "Unexpected token <",
"errorType": "SyntaxError",
"stackTrace": [
"Module._compile (module.js:439:25)",
"Object.Module._extensions..js (module.js:474:10)",
"Module.load (module.js:356:32)",
"Function.Module._load (module.js:312:12)",
"Module.require (module.js:364:17)",
"require (module.js:380:17)"
]
}

log output:
START RequestId: 1f792b59-5027-11e6-88ff-fdf244a4bc7d Version: $LATEST
Syntax error in module 'index': SyntaxError
at Module._compile (module.js:439:25)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.require (module.js:364:17)
at require (module.js:380:17)
END RequestId: 1f792b59-5027-11e6-88ff-fdf244a4bc7d
REPORT RequestId: 1f792b59-5027-11e6-88ff-fdf244a4bc7d Duration: 0.38 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 15 MB

Default rooms

There's a general desire to be able to act on the system without always specifying which room to act on.

Eg, issue #16 - it would be nice for JoinGroup to be able to look up what room is currently the coordinator and default to that. It would not work in a scenario in which multiple groups are playing at the same time, but there's no way around that except to specify a room.

Functions like next, previous, and so on would also benefit from this feature.

Lambda is giving this error

{
"errorMessage": "Unexpected token ILLEGAL",
"errorType": "SyntaxError",
"stackTrace": [
"Module._compile (module.js:373:25)",
"Object.Module._extensions..js (module.js:416:10)",
"Module.load (module.js:343:32)",
"Function.Module._load (module.js:300:12)",
"Module.require (module.js:353:17)",
"require (internal/module.js:12:17)"
]
}

lamda time out every other request

For some reason the lamda has starting timing out every other request. I put debug statements in the node server on my machine and its not getting the request. I put a trace filter on my firewall and I can confirm the request never hits the firewall when this happens. I am starting to debug the lambda but I wanted to know if anyone else had this problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.