Skip to content

Commit

Permalink
Use lodash.get() in virtual assistant API endpoints (v2) (#6199)
Browse files Browse the repository at this point in the history
* Fixed #5632 - Improved value resolution

* More value resolution improvements

* Fixed a couple object paths
  • Loading branch information
inventor96 authored Oct 20, 2020
1 parent d9e63fb commit 76b9de9
Show file tree
Hide file tree
Showing 14 changed files with 75 additions and 69 deletions.
5 changes: 2 additions & 3 deletions docs/plugins/add-virtual-assistant-support-to-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ There are 2 types of handlers that you can supply:

A plugin can expose multiple intent handlers (e.g. useful when it can supply multiple kinds of metrics). Each intent handler should be structured as follows:
+ `intent` - This is the intent this handler is built for. Right now, the templates used by both Alexa and Google Home use only the `"MetricNow"` intent (used for getting the present value of the requested metric)
+ `metrics` - An array of metric name(s) the handler will supply. e.g. "What is my `metric`" - iob, bg, cob, etc. Make sure to add the metric name and its synonyms to the list of metrics used by the virtual assistant(s).
- **IMPORTANT NOTE:** There is no protection against overlapping metric names, so PLEASE make sure your metric name is unique!
- Note: Although this value *is* an array, you really should only supply one (unique) value, and then add aliases or synonyms to that value in the list of metrics for the virtual assistant. We keep this value as an array for backwards compatibility.
+ `metrics` - An array of metric name(s) the handler will supply. e.g. "What is my `metric`" - iob, bg, cob, etc. Although this value *is* an array, you really should only supply one (unique) value, and then add aliases or synonyms to that value in the list of metrics for the virtual assistant. We keep this value as an array for backwards compatibility.
- **IMPORTANT NOTE:** There is no protection against overlapping metric names, so PLEASE make sure your metric name is unique!
+ `intenthandler` - This is a callback function that receives 3 arguments:
- `callback` Call this at the end of your function. It requires 2 arguments:
- `title` - Title of the handler. This is the value that will be displayed on the Alexa card (for devices with a screen). The Google Home response doesn't currently display a card, so it doesn't use this value.
Expand Down
20 changes: 6 additions & 14 deletions lib/api/alexa/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

var _ = require('lodash');
var moment = require('moment');

function configure (app, wares, ctx, env) {
Expand All @@ -18,7 +19,7 @@ function configure (app, wares, ctx, env) {

api.post('/alexa', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) {
console.log('Incoming request from Alexa');
var locale = req.body.request.locale;
var locale = _.get(req, 'body.request.locale');
if(locale){
if(locale.length > 2) {
locale = locale.substr(0, 2);
Expand Down Expand Up @@ -78,19 +79,10 @@ function configure (app, wares, ctx, env) {
function handleIntent(intentName, slots, next) {
var metric;
if (slots) {
if (slots.metric
&& slots.metric.resolutions
&& slots.metric.resolutions.resolutionsPerAuthority
&& slots.metric.resolutions.resolutionsPerAuthority.length
&& slots.metric.resolutions.resolutionsPerAuthority[0].status
&& slots.metric.resolutions.resolutionsPerAuthority[0].status.code
&& slots.metric.resolutions.resolutionsPerAuthority[0].status.code == "ER_SUCCESS_MATCH"
&& slots.metric.resolutions.resolutionsPerAuthority[0].values
&& slots.metric.resolutions.resolutionsPerAuthority[0].values.length
&& slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value
&& slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value.name
){
metric = slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value.name;
var slotStatus = _.get(slots, 'metric.resolutions.resolutionsPerAuthority[0].status.code');
var slotName = _.get(slots, 'metric.resolutions.resolutionsPerAuthority[0].values[0].value.name');
if (slotStatus == "ER_SUCCESS_MATCH" && slotName) {
metric = slotName;
} else {
next(translate('virtAsstUnknownIntentTitle'), translate('virtAsstUnknownIntentText'));
return;
Expand Down
3 changes: 2 additions & 1 deletion lib/api/googlehome/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

var _ = require('lodash');
var moment = require('moment');

function configure (app, wares, ctx, env) {
Expand All @@ -18,7 +19,7 @@ function configure (app, wares, ctx, env) {

api.post('/googlehome', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) {
console.log('Incoming request from Google Home');
var locale = req.body.queryResult.languageCode;
var locale = _.get(req, 'body.queryResult.languageCode');
if(locale){
if(locale.length > 2) {
locale = locale.substr(0, 2);
Expand Down
5 changes: 3 additions & 2 deletions lib/plugins/ar2.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ function init (ctx) {
};

function virtAsstAr2Handler (next, slots, sbx) {
if (sbx.properties.ar2.forecast.predicted) {
var forecast = sbx.properties.ar2.forecast.predicted;
var predicted = _.get(sbx, 'properties.ar2.forecast.predicted');
if (predicted) {
var forecast = predicted;
var max = forecast[0].mgdl;
var min = forecast[0].mgdl;
var maxForecastMills = forecast[0].mills;
Expand Down
18 changes: 7 additions & 11 deletions lib/plugins/basalprofile.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
var times = require('../times');
var moment = require('moment');
var consts = require('../constants');
var _ = require('lodash');

function init (ctx) {

Expand Down Expand Up @@ -114,13 +115,13 @@ function init (ctx) {
function basalMessage(slots, sbx) {
var basalValue = sbx.data.profile.getTempBasal(sbx.time);
var response = translate('virtAsstUnknown');
var preamble = '';
var pwd = _.get(slots, 'pwd.value');
var preamble = pwd ? translate('virtAsstPreamble3person', {
params: [
pwd
]
}) : translate('virtAsstPreamble');
if (basalValue.treatment) {
preamble = (slots && slots.pwd && slots.pwd.value) ? translate('virtAsstPreamble3person', {
params: [
slots.pwd.value
]
}) : translate('virtAsstPreamble');
var minutesLeft = moment(basalValue.treatment.endmills).from(moment(sbx.time));
response = translate('virtAsstBasalTemp', {
params: [
Expand All @@ -130,11 +131,6 @@ function init (ctx) {
]
});
} else {
preamble = (slots && slots.pwd && slots.pwd.value) ? translate('virtAsstPreamble3person', {
params: [
slots.pwd.value
]
}) : translate('virtAsstPreamble');
response = translate('virtAsstBasal', {
params: [
preamble,
Expand Down
8 changes: 5 additions & 3 deletions lib/plugins/cob.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,13 @@ function init (ctx) {

function virtAsstCOBHandler (next, slots, sbx) {
var response = '';
var value = (sbx.properties.cob && sbx.properties.cob.cob) ? sbx.properties.cob.cob : 0;
if (slots && slots.pwd && slots.pwd.value) {
var cob = _.get(sbx, 'properties.cob.cob');
var pwd = _.get(slots, 'pwd.value');
var value = cob ? cob : 0;
if (pwd) {
response = translate('virtAsstCob3person', {
params: [
slots.pwd.value.replace('\'s', '')
pwd.replace('\'s', '')
, value
]
});
Expand Down
10 changes: 7 additions & 3 deletions lib/plugins/dbsize.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var levels = require('../levels');
var _ = require('lodash');

function init (ctx) {
var translate = ctx.language.translate;
Expand Down Expand Up @@ -117,11 +118,14 @@ function init (ctx) {
};

function virtAsstDatabaseSizeHandler (next, slots, sbx) {
if (sbx.properties.dbsize.display) {
var display = _.get(sbx, 'properties.dbsize.display');
var dataSize = _.get(sbx, 'properties.dbsize.details.dataSize');
var dataPercentage = _.get(sbx, 'properties.dbsize.dataPercentage');
if (display) {
var response = translate('virtAsstDatabaseSize', {
params: [
sbx.properties.dbsize.details.dataSize
, sbx.properties.dbsize.dataPercentage
dataSize
, dataPercentage
]
});
next(translate('virtAsstTitleDatabaseSize'), response);
Expand Down
5 changes: 3 additions & 2 deletions lib/plugins/iob.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,11 @@ function init(ctx) {
}

function getIob(sbx) {
if (sbx.properties.iob && sbx.properties.iob.iob !== 0) {
var iob = _.get(sbx, 'properties.iob.iob');
if (iob !== 0) {
return translate('virtAsstIobUnits', {
params: [
utils.toFixed(sbx.properties.iob.iob)
utils.toFixed(iob)
]
});
}
Expand Down
12 changes: 7 additions & 5 deletions lib/plugins/loop.js
Original file line number Diff line number Diff line change
Expand Up @@ -529,13 +529,14 @@ function init (ctx) {
};

function virtAsstForecastHandler (next, slots, sbx) {
if (sbx.properties.loop.lastLoop.predicted) {
var forecast = sbx.properties.loop.lastLoop.predicted.values;
var predicted = _.get(sbx, 'properties.loop.lastLoop.predicted');
if (predicted) {
var forecast = predicted.values;
var max = forecast[0];
var min = forecast[0];
var maxForecastIndex = Math.min(6, forecast.length);

var startPrediction = moment(sbx.properties.loop.lastLoop.predicted.startDate);
var startPrediction = moment(predicted.startDate);
var endPrediction = startPrediction.clone().add(maxForecastIndex * 5, 'minutes');
if (endPrediction.valueOf() < sbx.time) {
next(translate('virtAsstTitleLoopForecast'), translate('virtAsstForecastUnavailable'));
Expand Down Expand Up @@ -573,8 +574,9 @@ function init (ctx) {
}

function virtAsstLastLoopHandler (next, slots, sbx) {
if (sbx.properties.loop.lastLoop) {
console.log(JSON.stringify(sbx.properties.loop.lastLoop));
var lastLoop = _.get(sbx, 'properties.loop.lastLoop')
if (lastLoop) {
console.log(JSON.stringify(lastLoop));
var response = translate('virtAsstLastLoop', {
params: [
moment(sbx.properties.loop.lastOkMoment).from(moment(sbx.time))
Expand Down
11 changes: 6 additions & 5 deletions lib/plugins/openaps.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,10 +560,11 @@ function init (ctx) {
};

function virtAsstForecastHandler (next, slots, sbx) {
if (sbx.properties.openaps && sbx.properties.openaps.lastEventualBG) {
var lastEventualBG = _.get(sbx, 'properties.openaps.lastEventualBG');
if (lastEventualBG) {
var response = translate('virtAsstOpenAPSForecast', {
params: [
sbx.properties.openaps.lastEventualBG
lastEventualBG
]
});
next(translate('virtAsstTitleOpenAPSForecast'), response);
Expand All @@ -573,11 +574,11 @@ function init (ctx) {
}

function virtAsstLastLoopHandler (next, slots, sbx) {
if (sbx.properties.openaps.lastLoopMoment) {
console.log(JSON.stringify(sbx.properties.openaps.lastLoopMoment));
var lastLoopMoment = _.get(sbx, 'properties.openaps.lastLoopMoment');
if (lastLoopMoment) {
var response = translate('virtAsstLastLoop', {
params: [
moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time))
moment(lastLoopMoment).from(moment(sbx.time))
]
});
next(translate('virtAsstTitleLastLoop'), response);
Expand Down
2 changes: 1 addition & 1 deletion lib/plugins/pump.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ function init (ctx) {
};

function virtAsstReservoirHandler (next, slots, sbx) {
var reservoir = sbx.properties.pump.pump.reservoir;
var reservoir = _.get(sbx, 'properties.pump.pump.reservoir');
if (reservoir || reservoir === 0) {
var response = translate('virtAsstReservoir', {
params: [
Expand Down
5 changes: 3 additions & 2 deletions lib/plugins/rawbg.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,11 @@ function init (ctx) {
};

function virtAsstRawBGHandler (next, slots, sbx) {
if (sbx.properties.rawbg.mgdl) {
var rawBg = _.get(sbx, 'properties.rawbg.mgdl');
if (rawBg) {
var response = translate('virtAsstRawBG', {
params: [
sbx.properties.rawbg.mgdl
rawBg
]
});
next(translate('virtAsstTitleRawBG'), response);
Expand Down
5 changes: 3 additions & 2 deletions lib/plugins/upbat.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,11 @@ function init(ctx) {
};

function virtAsstUploaderBatteryHandler (next, slots, sbx) {
if (sbx.properties.upbat.display) {
var upBat = _.get(sbx, 'properties.upbat.display');
if (upBat) {
var response = translate('virtAsstUploaderBattery', {
params: [
sbx.properties.upbat.display
upBat
]
});
next(translate('virtAsstTitleUploaderBattery'), response);
Expand Down
35 changes: 20 additions & 15 deletions lib/plugins/xdripjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,11 @@ function init(ctx) {

function virtAsstGenericCGMHandler(translateItem, field, next, sbx) {
var response;
if (sbx.properties.sensorState && sbx.properties.sensorState[field]) {
var state = _.get(sbx, 'properties.sensorState.'+field);
if (state) {
response = translate('virtAsstCGM'+translateItem, {
params:[
sbx.properties.sensorState[field]
state
, moment(sbx.properties.sensorState.lastStateTime).from(moment(sbx.time))
]
});
Expand Down Expand Up @@ -355,10 +356,11 @@ function init(ctx) {
, metrics: ['cgm session age']
, intentHandler: function(next, slots, sbx){
var response;
var lastSessionStart = _.get(sbx, 'properties.sensorState.lastSessionStart');
// session start is only valid if in a session
if (sbx.properties.sensorState && sbx.properties.sensorState.lastSessionStart) {
if (sbx.properties.sensorState.lastState != 0x1) {
var duration = moment.duration(moment().diff(moment(sbx.properties.sensorState.lastSessionStart)));
if (lastSessionStart) {
if (_.get(sbx, 'properties.sensorState.lastState') != 0x1) {
var duration = moment.duration(moment().diff(moment(lastSessionStart)));
response = translate('virtAsstCGMSessAge', {
params: [
duration.days(),
Expand All @@ -384,10 +386,11 @@ function init(ctx) {
intent: 'MetricNow'
, metrics: ['cgm tx age']
, intentHandler: function(next, slots, sbx){
var lastTxActivation = _.get(sbx, 'properties.sensorState.lastTxActivation');
next(
translate('virtAsstTitleCGMTxAge'),
(sbx.properties.sensorState && sbx.properties.sensorState.lastTxActivation)
? translate('virtAsstCGMTxAge', {params:[moment().diff(moment(sbx.properties.sensorState.lastTxActivation), 'days')]})
lastTxActivation
? translate('virtAsstCGMTxAge', {params:[moment().diff(moment(lastTxActivation), 'days')]})
: translate('virtAsstUnknown')
);
}
Expand All @@ -402,22 +405,24 @@ function init(ctx) {
, metrics: ['cgm battery']
, intentHandler: function(next, slots, sbx){
var response;
var sensor = sbx.properties.sensorState;
if (sensor && (sensor.lastVoltageA || sensor.lastVoltageB)) {
if (sensor.lastVoltageA && sensor.lastVoltageB) {
var lastVoltageA = _.get(sbx, 'properties.sensorState.lastVoltageA');
var lastVoltageB = _.get(sbx, 'properties.sensorState.lastVoltageB');
var lastBatteryTimestamp = _.get(sbx, 'properties.sensorState.lastBatteryTimestamp');
if (lastVoltageA || lastVoltageB) {
if (lastVoltageA && lastVoltageB) {
response = translate('virtAsstCGMBattTwo', {
params:[
(sensor.lastVoltageA / 100)
, (sensor.lastVoltageB / 100)
, moment(sensor.lastBatteryTimestamp).from(moment(sbx.time))
(lastVoltageA / 100)
, (lastVoltageB / 100)
, moment(lastBatteryTimestamp).from(moment(sbx.time))
]
});
} else {
var finalValue = sensor.lastVoltageA ? sensor.lastVoltageA : sensor.lastVoltageB;
var finalValue = lastVoltageA ? lastVoltageA : lastVoltageB;
response = translate('virtAsstCGMBattOne', {
params:[
(finalValue / 100)
, moment(sensor.lastBatteryTimestamp).from(moment(sbx.time))
, moment(lastBatteryTimestamp).from(moment(sbx.time))
]
});
}
Expand Down

0 comments on commit 76b9de9

Please sign in to comment.