From b1af5d442dfb73b5c08ff96a3f3c299c30da6d7c Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 5 Oct 2020 11:40:17 -0600 Subject: [PATCH 1/3] Fixed #5632 - Improved value resolution --- lib/api/alexa/index.js | 20 ++++++-------------- lib/api/googlehome/index.js | 3 ++- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index 2a5fd4ef6cd..3c31bf1ce00 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -1,5 +1,6 @@ 'use strict'; +var _ = require('lodash'); var moment = require('moment'); function configure (app, wares, ctx, env) { @@ -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); @@ -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; diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js index b44715b25eb..cd42aa0ff37 100644 --- a/lib/api/googlehome/index.js +++ b/lib/api/googlehome/index.js @@ -1,5 +1,6 @@ 'use strict'; +var _ = require('lodash'); var moment = require('moment'); function configure (app, wares, ctx, env) { @@ -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); From c08b4d1abaa2b98253e53755a3481e8485c2c173 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 12 Oct 2020 21:44:06 -0600 Subject: [PATCH 2/3] More value resolution improvements --- ...add-virtual-assistant-support-to-plugin.md | 5 ++- lib/plugins/ar2.js | 5 +-- lib/plugins/basalprofile.js | 18 ++++------ lib/plugins/cob.js | 8 +++-- lib/plugins/dbsize.js | 10 ++++-- lib/plugins/iob.js | 5 +-- lib/plugins/loop.js | 12 ++++--- lib/plugins/openaps.js | 11 +++--- lib/plugins/pump.js | 2 +- lib/plugins/rawbg.js | 5 +-- lib/plugins/upbat.js | 5 +-- lib/plugins/xdripjs.js | 35 +++++++++++-------- 12 files changed, 67 insertions(+), 54 deletions(-) diff --git a/docs/plugins/add-virtual-assistant-support-to-plugin.md b/docs/plugins/add-virtual-assistant-support-to-plugin.md index 60ac1d1957b..6c581013b9e 100644 --- a/docs/plugins/add-virtual-assistant-support-to-plugin.md +++ b/docs/plugins/add-virtual-assistant-support-to-plugin.md @@ -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. diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js index 133c5b8d3c9..ab8675a0342 100644 --- a/lib/plugins/ar2.js +++ b/lib/plugins/ar2.js @@ -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; diff --git a/lib/plugins/basalprofile.js b/lib/plugins/basalprofile.js index 4347a7005ec..806dde5859d 100644 --- a/lib/plugins/basalprofile.js +++ b/lib/plugins/basalprofile.js @@ -2,6 +2,7 @@ var times = require('../times'); var moment = require('moment'); var consts = require('../constants'); +var _ = require('lodash'); function init (ctx) { @@ -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: [ @@ -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, diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index c6d4c4fdf8f..1527da7d3f6 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -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, '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 ] }); diff --git a/lib/plugins/dbsize.js b/lib/plugins/dbsize.js index 1698fa050b3..c76e36cb9e8 100644 --- a/lib/plugins/dbsize.js +++ b/lib/plugins/dbsize.js @@ -1,6 +1,7 @@ 'use strict'; var levels = require('../levels'); +var _ = require('lodash'); function init (ctx) { var translate = ctx.language.translate; @@ -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); diff --git a/lib/plugins/iob.js b/lib/plugins/iob.js index 96bea03b3ff..cdcc15706e3 100644 --- a/lib/plugins/iob.js +++ b/lib/plugins/iob.js @@ -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) ] }); } diff --git a/lib/plugins/loop.js b/lib/plugins/loop.js index 46d16738787..e7d3ae91c93 100644 --- a/lib/plugins/loop.js +++ b/lib/plugins/loop.js @@ -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')); @@ -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)) diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 037680960d2..cf5e240ce99 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -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); @@ -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); diff --git a/lib/plugins/pump.js b/lib/plugins/pump.js index 7e71c21e1b1..52dc7ade769 100644 --- a/lib/plugins/pump.js +++ b/lib/plugins/pump.js @@ -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: [ diff --git a/lib/plugins/rawbg.js b/lib/plugins/rawbg.js index 3248126b046..a784f49363f 100644 --- a/lib/plugins/rawbg.js +++ b/lib/plugins/rawbg.js @@ -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); diff --git a/lib/plugins/upbat.js b/lib/plugins/upbat.js index dc603054ecb..71547eca6a2 100644 --- a/lib/plugins/upbat.js +++ b/lib/plugins/upbat.js @@ -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); diff --git a/lib/plugins/xdripjs.js b/lib/plugins/xdripjs.js index dc44aad2988..c8a8f33cc85 100644 --- a/lib/plugins/xdripjs.js +++ b/lib/plugins/xdripjs.js @@ -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, '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)) ] }); @@ -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(), @@ -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') ); } @@ -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)) ] }); } From b1b209ac4ac926409c1b2a4945804572e680e258 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sun, 18 Oct 2020 16:50:38 -0600 Subject: [PATCH 3/3] Fixed a couple object paths --- lib/plugins/cob.js | 2 +- lib/plugins/xdripjs.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index 1527da7d3f6..250614ecfd6 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -293,7 +293,7 @@ function init (ctx) { function virtAsstCOBHandler (next, slots, sbx) { var response = ''; - var cob = _.get(sbx, 'sbx.properties.cob.cob'); + var cob = _.get(sbx, 'properties.cob.cob'); var pwd = _.get(slots, 'pwd.value'); var value = cob ? cob : 0; if (pwd) { diff --git a/lib/plugins/xdripjs.js b/lib/plugins/xdripjs.js index c8a8f33cc85..dd5b55eb816 100644 --- a/lib/plugins/xdripjs.js +++ b/lib/plugins/xdripjs.js @@ -324,7 +324,7 @@ function init(ctx) { function virtAsstGenericCGMHandler(translateItem, field, next, sbx) { var response; - var state = _.get(sbx, 'sbx.properties.sensorState.'+field); + var state = _.get(sbx, 'properties.sensorState.'+field); if (state) { response = translate('virtAsstCGM'+translateItem, { params:[