-
Notifications
You must be signed in to change notification settings - Fork 4
Concurrent user issue #8
Changes from 5 commits
3143eb6
5f51236
c260820
068c90f
27c78d3
9db66f9
139229c
611adcc
18376a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ | |
], | ||
"linebreak-style": [ | ||
"error", | ||
"windows" | ||
"linux" | ||
], | ||
"quotes": [ | ||
"error", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,8 +11,25 @@ module.change_code = 0; | |
|
||
let app = new alexa.app('boiler'); | ||
|
||
const controlService = (userId) => { | ||
let context = { userId }; | ||
const controlService = (request) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'arrow function syntax (=>)' is only available in ES6 (use 'esversion: 6'). |
||
console.log('*******************************'); | ||
console.log(`UserId: ${request.userId}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'template literal syntax' is only available in ES6 (use 'esversion: 6'). |
||
console.log('Data'); | ||
console.log(request.data); | ||
console.log('Context'); | ||
console.log(request.context); | ||
if (request.data.context) { | ||
console.log(`Deep UserId: ${request.data.context.System.user.userId}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'template literal syntax' is only available in ES6 (use 'esversion: 6'). |
||
} | ||
console.log('*******************************'); | ||
|
||
let userId = request.userId || request.data.session.user.userId; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz). |
||
let source = 'user'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz). |
||
if (!request.data.context) { | ||
source = 'callback'; | ||
} | ||
let context = { userId: userId, source: source }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz). |
||
console.log(`Creating context for source: ${context.source}, user: ${context.userId}...`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'template literal syntax' is only available in ES6 (use 'esversion: 6'). |
||
let repository; | ||
if (process.env.THERMOSTAT_REPOSITORY === 'dynamodb') { | ||
repository = new DynamodbThermostatRepository(); | ||
|
@@ -44,7 +61,7 @@ const say = (response, messages) => { | |
|
||
app.launch(async (request, response) => { | ||
console.log('Launching...'); | ||
let service = controlService(request.userId); | ||
let service = controlService(request); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz). |
||
try { | ||
let messages = await service.launch(); | ||
say(response, messages); | ||
|
@@ -57,7 +74,7 @@ app.launch(async (request, response) => { | |
app.intent('TempIntent', { | ||
'utterances': ['what the temperature is', 'the temperature', 'how hot it is'] | ||
}, async (request, response) => { | ||
let service = controlService(request.userId); | ||
let service = controlService(request); | ||
try { | ||
let messages = await service.status(); | ||
say(response, messages); | ||
|
@@ -70,7 +87,7 @@ app.intent('TempIntent', { | |
app.intent('TurnUpIntent', { | ||
'utterances': ['to increase', 'to turn up', 'set warmer', 'set higher'] | ||
}, async (request, response) => { | ||
let service = controlService(request.userId); | ||
let service = controlService(request); | ||
try { | ||
let messages = await service.turnUp(); | ||
say(response, messages); | ||
|
@@ -83,7 +100,7 @@ app.intent('TurnUpIntent', { | |
app.intent('TurnDownIntent', { | ||
'utterances': ['to decrease', 'to turn down', 'set cooler', 'set lower'] | ||
}, async (request, response) => { | ||
let service = controlService(request.userId); | ||
let service = controlService(request); | ||
try { | ||
let messages = await service.turnDown(); | ||
say(response, messages); | ||
|
@@ -99,7 +116,7 @@ app.intent('SetTempIntent', { | |
}, | ||
'utterances': ['to set to {temp} degrees', 'to set the temperature to {temp} degrees', 'to set the temp to {temp} degrees'] | ||
}, async (request, response) => { | ||
let service = controlService(request.userId); | ||
let service = controlService(request); | ||
try { | ||
let messages = await service.setTemperature(request.slot('temp'), request.slot('duration')); | ||
say(response, messages); | ||
|
@@ -114,12 +131,11 @@ app.intent('TurnIntent', { | |
'onoff': 'ONOFF' | ||
}, | ||
'utterances': ['to turn {onoff}', 'to turn heating {onoff}', 'to turn the heating {onoff}'] | ||
}, async (request, response) => { | ||
}, async (request, response) => { | ||
let onOff = request.slot('onoff'); | ||
let duration = request.slot('duration'); | ||
// this could be a callback from a step function | ||
let userId = request.userId || request.data.session.user.userId; | ||
let service = controlService(userId); | ||
let service = controlService(request); | ||
try { | ||
let messages = await service.turn(onOff, duration); | ||
say(response, messages); | ||
|
@@ -143,7 +159,7 @@ app.intent('AMAZON.StopIntent', { | |
'slots': {}, | ||
'utterances': [] | ||
}, async (request, response) => { | ||
let service = controlService(request.userId); | ||
let service = controlService(request); | ||
try { | ||
let messages = await service.turn('off'); | ||
say(response, messages); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,16 +20,18 @@ class ControlService { | |
|
||
async obtainThermostat() { | ||
let thermostat = await this._thermostatRepository.find(this._context.userId); | ||
if (!thermostat) { | ||
thermostat = await this._thermostatRepository.find('template'); | ||
if (thermostat) { | ||
thermostat.userId = this._context.userId; | ||
} | ||
else { | ||
thermostat = { userId: this._context.userId, executionId: null }; | ||
} | ||
await this._thermostatRepository.add(thermostat); | ||
if (thermostat) { | ||
return thermostat; | ||
} | ||
|
||
thermostat = await this._thermostatRepository.find('template'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing semicolon. |
||
if (thermostat) { | ||
thermostat.userId = this._context.userId; | ||
} | ||
else { | ||
thermostat = { userId: this._context.userId, executionId: null }; | ||
} | ||
await this._thermostatRepository.add(thermostat); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected an assignment or function call and instead saw an expression. |
||
return thermostat; | ||
} | ||
|
||
|
@@ -48,27 +50,35 @@ class ControlService { | |
|
||
async launch() { | ||
let client = await this.login(); | ||
if (await client.online()) { | ||
return 'Thermostat is online'; | ||
} else { | ||
return 'Sorry, the thermostat is offline at the moment.'; | ||
try { | ||
if (await client.online()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected ')' to match '(' from line 54 and instead saw 'client'. |
||
return 'Thermostat is online'; | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected an assignment or function call and instead saw an expression. |
||
return 'Sorry, the thermostat is offline at the moment.'; | ||
} | ||
} finally { | ||
await client.logout(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected an assignment or function call and instead saw an expression. |
||
} | ||
} | ||
|
||
async status() { | ||
console.log('Requesting status...'); | ||
let client = await this.login(); | ||
await this.verifyOnline(client); | ||
let device = await client.device(); | ||
this.verifyContactable(device); | ||
|
||
let messages = []; | ||
messages.push(`The current temperature is ${this.speakTemperature(device.currentTemperature)} degrees.`); | ||
messages.push(`The target is ${this.speakTemperature(device.targetTemperature)} degrees.`); | ||
await this.determineIfHolding(device, messages); | ||
|
||
this.logStatus(device); | ||
return messages; | ||
try { | ||
await this.verifyOnline(client); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected an assignment or function call and instead saw an expression. |
||
let device = await client.device(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz). |
||
this.verifyContactable(device); | ||
|
||
let messages = []; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz). |
||
messages.push(`The current temperature is ${this.speakTemperature(device.currentTemperature)} degrees.`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'template literal syntax' is only available in ES6 (use 'esversion: 6'). |
||
messages.push(`The target is ${this.speakTemperature(device.targetTemperature)} degrees.`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'template literal syntax' is only available in ES6 (use 'esversion: 6'). |
||
await this.determineIfHolding(device, messages); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected an assignment or function call and instead saw an expression. |
||
|
||
this.logStatus(device); | ||
return messages; | ||
} finally { | ||
await client.logout(); | ||
} | ||
} | ||
|
||
async determineIfHolding(device, messages, qualifier = '') { | ||
|
@@ -90,51 +100,61 @@ class ControlService { | |
async turnUp() { | ||
console.log('Turning up...'); | ||
let client = await this.login(); | ||
await this.verifyOnline(client); | ||
let device = await client.device(); | ||
this.verifyContactable(device); | ||
|
||
if (device.status == 'on') { | ||
throw 'The heating is already on.'; | ||
} | ||
try { | ||
await this.verifyOnline(client); | ||
let device = await client.device(); | ||
this.verifyContactable(device); | ||
|
||
let t = device.targetTemperature + 0.5; | ||
await client.setTemperature(t); | ||
let updatedDevice = await client.device(); | ||
if (device.status == 'on') { | ||
throw 'The heating is already on.'; | ||
} | ||
|
||
let t = device.targetTemperature + 0.5; | ||
await client.setTemperature(t); | ||
let updatedDevice = await client.device(); | ||
|
||
let messages = []; | ||
messages.push(`The target temperature is now ${this.speakTemperature(updatedDevice.targetTemperature)} degrees.`); | ||
await this.determineIfHolding(updatedDevice, messages, 'now'); | ||
let messages = []; | ||
messages.push(`The target temperature is now ${this.speakTemperature(updatedDevice.targetTemperature)} degrees.`); | ||
await this.determineIfHolding(updatedDevice, messages, 'now'); | ||
|
||
this.logStatus(device); | ||
return messages; | ||
this.logStatus(device); | ||
return messages; | ||
} finally { | ||
await client.logout(); | ||
} | ||
} | ||
|
||
async turnDown() { | ||
console.log('Turning down...'); | ||
let client = await this.login(); | ||
await this.verifyOnline(client); | ||
let device = await client.device(); | ||
this.verifyContactable(device); | ||
|
||
let t = device.targetTemperature - 1.0; | ||
await client.setTemperature(t); | ||
let updatedDevice = await client.device(); | ||
|
||
let messages = []; | ||
messages.push(`The target temperature is now ${this.speakTemperature(updatedDevice.targetTemperature)} degrees.`); | ||
await this.determineIfHolding(updatedDevice, messages, 'still'); | ||
|
||
this.logStatus(updatedDevice); | ||
return messages; | ||
try { | ||
await this.verifyOnline(client); | ||
let device = await client.device(); | ||
this.verifyContactable(device); | ||
|
||
let t = device.targetTemperature - 1.0; | ||
await client.setTemperature(t); | ||
let updatedDevice = await client.device(); | ||
|
||
let messages = []; | ||
messages.push(`The target temperature is now ${this.speakTemperature(updatedDevice.targetTemperature)} degrees.`); | ||
await this.determineIfHolding(updatedDevice, messages, 'still'); | ||
|
||
this.logStatus(updatedDevice); | ||
return messages; | ||
} finally { | ||
await client.logout(); | ||
} | ||
} | ||
|
||
async turn(onOff, duration) { | ||
console.log(`Turning ${onOff}...`); | ||
|
||
let t = process.env.DEFAULT_ON_TEMP || '20'; | ||
let thermostat = await this.obtainThermostat(); | ||
let t = thermostat.defaultOnTemp; | ||
if (onOff === 'off') { | ||
t = process.env.DEFAULT_OFF_TEMP || '14'; | ||
t = thermostat.defaultOffTemp; | ||
} | ||
|
||
return this.setTemperature(t, duration); | ||
|
@@ -143,41 +163,45 @@ class ControlService { | |
async setTemperature(targetTemperature, forDuration) { | ||
console.log(`Setting temperature to ${targetTemperature}...`); | ||
let client = await this.login(); | ||
await this.verifyOnline(client); | ||
let device = await client.device(); | ||
this.verifyContactable(device); | ||
|
||
await client.setTemperature(targetTemperature); | ||
let updatedDevice = await client.device(); | ||
|
||
let messages = []; | ||
messages.push(`The target temperature is now ${this.speakTemperature(updatedDevice.targetTemperature)} degrees.`); | ||
this.logStatus(updatedDevice); | ||
|
||
let duration = forDuration || process.env.DEFAULT_DURATION; | ||
|
||
let intent = await this._holdStrategy.holdIfRequiredFor(duration); | ||
return messages.concat(this.summarize(intent, updatedDevice)); | ||
try { | ||
await this.verifyOnline(client); | ||
let device = await client.device(); | ||
this.verifyContactable(device); | ||
|
||
await client.setTemperature(targetTemperature); | ||
let updatedDevice = await client.device(); | ||
|
||
let messages = []; | ||
messages.push(`The target temperature is now ${this.speakTemperature(updatedDevice.targetTemperature)} degrees.`); | ||
this.logStatus(updatedDevice); | ||
|
||
if (this._context.source === 'user') { | ||
let thermostat = await this.obtainThermostat(); | ||
let duration = forDuration || thermostat.defaultDuration; | ||
let intent = await this._holdStrategy.holdIfRequiredFor(duration); | ||
return messages.concat(this.summarize(intent, updatedDevice)); | ||
} | ||
return messages; | ||
} finally { | ||
await client.logout(); | ||
} | ||
} | ||
|
||
summarize(intent, updatedDevice) { | ||
let messages = []; | ||
if (intent.holding) { | ||
let durationText = this.speakDuration(intent.duration); | ||
console.log(`Holding for ${durationText} {${intent.executionId}}`); | ||
if (!intent.holding) { | ||
if (updatedDevice.status == 'on') { | ||
messages.push(`The heating is now on and will turn off in ${durationText}`); | ||
} | ||
else { | ||
messages.push(`The heating will turn off in ${durationText}`); | ||
return ['The heating is now on.']; | ||
} | ||
return []; | ||
} | ||
else { | ||
if (updatedDevice.status == 'on') { | ||
messages.push('The heating is now on.'); | ||
} | ||
|
||
let durationText = this.speakDuration(intent.duration); | ||
console.log(`Holding for ${durationText} {${intent.executionId}}`); | ||
if (updatedDevice.status == 'on') { | ||
return [`The heating is now on and will turn off in ${durationText}`]; | ||
} | ||
return messages; | ||
|
||
return [`The heating will turn off in ${durationText}`]; | ||
} | ||
|
||
logStatus(device) { | ||
|
@@ -193,9 +217,8 @@ class ControlService { | |
} | ||
|
||
speakTemperature(temp) { | ||
let t = parseFloat(temp); | ||
if (parseFloat(t.toFixed(0)) != t) return t.toFixed(1); | ||
else return t.toFixed(0); | ||
if (parseFloat(temp.toFixed(0)) != temp) return temp.toFixed(1); | ||
else return temp.toFixed(0); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,10 @@ class ThermostatRepository { | |
options: { | ||
username: process.env.USERNAME, | ||
password: process.env.PASSWORD | ||
} | ||
}, | ||
defaultOnTemp: parseFloat(process.env.DEFAULT_ON_TEMP || '20'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'process' is not defined. |
||
defaultOffTemp: parseFloat(process.env.DEFAULT_OFF_TEMP || '14'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'process' is not defined. |
||
defaultDuration: process.env.DEFAULT_DURATION || 'PT1H' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'process' is not defined. |
||
}; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'console' is not defined.
'template literal syntax' is only available in ES6 (use 'esversion: 6').