From 202402fbc42c08f058174fd35bb97bd9823ee273 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Fri, 6 Sep 2019 17:40:46 -0600 Subject: [PATCH 01/48] Copied work done by mdomox --- README.md | 4 ++ docs/plugins/googlehome-plugin.md | 34 +++++++++ lib/api/googlehome/index.js | 115 ++++++++++++++++++++++++++++++ lib/api/index.js | 4 ++ lib/plugins/basalprofile.js | 14 ++++ lib/plugins/cob.js | 19 +++++ lib/plugins/googlehome.js | 59 +++++++++++++++ lib/plugins/iob.js | 15 ++++ lib/plugins/openaps.js | 24 +++++++ lib/server/bootevent.js | 4 ++ 10 files changed, 292 insertions(+) create mode 100644 docs/plugins/googlehome-plugin.md create mode 100644 lib/api/googlehome/index.js create mode 100644 lib/plugins/googlehome.js diff --git a/README.md b/README.md index fd85b987107..b6d12295d03 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ Community maintained fork of the - [`override` (Override Mode)](#override-override-mode) - [`xdrip-js` (xDrip-js)](#xdrip-js-xdrip-js) - [`alexa` (Amazon Alexa)](#alexa-amazon-alexa) + - [`googlehome` (Google Home/DialogFLow)](#googlehome-google-homedialogflow) - [`speech` (Speech)](#speech-speech) - [`cors` (CORS)](#cors-cors) - [Extended Settings](#extended-settings) @@ -511,6 +512,9 @@ To learn more about the Nightscout API, visit https://YOUR-SITE.com/api-docs.htm ##### `alexa` (Amazon Alexa) Integration with Amazon Alexa, [detailed setup instructions](docs/plugins/alexa-plugin.md) +##### `googlehome` (Google Home/DialogFLow) + Integration with Google Home (via DialogFlow), [detailed setup instructions](docs/plugins/googlehome-plugin.md) + ##### `speech` (Speech) Speech synthesis plugin. When enabled, speaks out the blood glucose values, IOB and alarms. Note you have to set the LANGUAGE setting on the server to get all translated alarms. diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md new file mode 100644 index 00000000000..6bc55b01e62 --- /dev/null +++ b/docs/plugins/googlehome-plugin.md @@ -0,0 +1,34 @@ +Nightscout Google Home/DialogFlow Plugin +======================================== + +## Overview + +To add Google Home support for your Nightscout site, here's what you need to do: + +1. Activate the `googlehome` plugin on your Nightscout site, so your site will respond correctly to Google's requests. +2. Create a custom DialogFlow agent that points at your site and defines certain questions you want to be able to ask. (You'll copy and paste a basic template for this, to keep things simple.) +3. Create desired integrations with DialogFlow + + +## Activate the Nightscout Google Home Plugin + +1. Your Nightscout site needs to be new enough that it supports the `googlehome` plugin. . +2. Add `googlehome` to the list of plugins in your `ENABLE` setting. ([Environment variables](https://github.com/nightscout/cgm-remote-monitor#environment) are set in the configuration section for your monitor. Typically Azure, Heroku, etc.) + +## Create Your DialogFlow Agent + +### Signin to DialogFlow + +- Sign in to DialogFlow with your Google account (https://console.dialogflow.com/api-client/#/login). If you don't already have one, signup with Google. + +### Create a new custom DialogFlow agent + +1. Select "Create new agent" in the main menu bar. +2. Input a custom name for your agent and click "CREATE". +3. Download the simple agent template : ( https://drive.google.com/drive/folders/18z2kQSEInvH4O_jfjB4Qh8z9508P9Oao?usp=sharing ) +4. Select IMPORT FROM ZIP , in order to import the template. +5. SAVE +6. Go to "Fullfillment" menu and enter details about your webhook. +7. SAVE +8. Go to "Integration" menu and select your desired integration. +9. Follow instructions for each desired integration. \ No newline at end of file diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js new file mode 100644 index 00000000000..a833b4abab3 --- /dev/null +++ b/lib/api/googlehome/index.js @@ -0,0 +1,115 @@ +'use strict'; + +var _ = require('lodash'); +var moment = require('moment'); + +function configure (app, wares, ctx, env) { + var express = require('express'); + var api = express.Router(); + var entries = ctx.entries; + var translate = ctx.language.translate; + + // invoke common middleware + api.use(wares.sendJSONStatus); + // text body types get handled as raw buffer stream + api.use(wares.bodyParser.raw()); + // json body types get handled as parsed json + api.use(wares.bodyParser.json()); + + ctx.plugins.eachEnabledPlugin(function each(plugin) { + if (plugin.googleHome) { + if (plugin.googleHome.intentHandlers) { + console.log('Plugin ' + plugin.name + ' is Google Home enabled'); + _.each(plugin.googleHome.intentHandlers, function (handler) { + if (handler) { + ctx.googleHome.configureIntentHandler(handler.intent, handler.intentHandler, handler.routableSlot, handler.slots); + } + }); + } + } else { + console.log('Plugin ' + plugin.name + ' is not Google Home enabled'); + } + }); + + ctx.googleHome.configureIntentHandler('CurrentMetric', function (result, next, sbx) { + entries.list({count: 1}, function(err, records) { + var response = ''; + if (records && records.length > 0) { + var direction = ''; + if (records[0].direction === 'FortyFiveDown') { + direction = ' and slightly dropping'; + } else if (records[0].direction === 'FortyFiveUp') { + direction = ' and slightly rising'; + } else if (records[0].direction === 'Flat') { + direction = ' and holding'; + } else if (records[0].direction === 'SingleUp') { + direction = ' and rising'; + } else if (records[0].direction === 'SingleDown') { + direction = ' and dropping'; + } else if (records[0].direction === 'DoubleDown') { + direction = ' and rapidly dropping'; + } else if (records[0].direction === 'DoubleUp') { + direction = ' and rapidly rising'; + } + response = buildPreamble(result.parameters); + response += sbx.scaleMgdl(records[0].sgv) + direction + ' as of ' + moment(records[0].date).from(moment(sbx.time)); + } else { + response = buildPreamble(result.parameters) + 'unknown'; + } + next(response); + }); + }, 'metric', ['bg', 'blood glucose', 'blood sugar', 'number']); + + api.post('/googlehome', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) { + console.log('Incoming request from Google Home'); + onIntent(req.body, function (response) { + res.json(ctx.googleHome.buildResponse(response)); + next(); + }); + }); + + function buildPreamble(parameters) { + var preamble = ''; + if (parameters && parameters.givenName) { + preamble = parameters.givenName + '\'s current '; + } else { + preamble = 'Your current '; + } + if (parameters && parameters.readingType) { + preamble += parameters.readingType + ' is '; + } else { + preamble += 'blood glucose is '; + } + return preamble; + } + + function onIntent(body, next) { + console.log('Received intent request'); + console.log(JSON.stringify(body)); + handleIntent(body, next); + } + + // https://docs.api.ai/docs/webhook#section-format-of-request-to-the-service + function handleIntent(body, next) { + var displayName = body.queryResult.intent.displayName; + var metric = body.queryResult.parameters ? body.queryResult.parameters.metric : null; + var handler = ctx.googleHome.getIntentHandler(displayName, metric); + if (handler) { + var sbx = initializeSandbox(); + handler(body.queryResult, next, sbx); + } else { + next('I\'m sorry I don\'t know what you\'re asking for'); + } + } + + function initializeSandbox() { + var sbx = require('../../sandbox')(); + sbx.serverInit(env, ctx); + ctx.plugins.setProperties(sbx); + return sbx; + } + + return api; +} + +module.exports = configure; \ No newline at end of file diff --git a/lib/api/index.js b/lib/api/index.js index 47a8a7bac3d..943ee2b6b14 100644 --- a/lib/api/index.js +++ b/lib/api/index.js @@ -65,6 +65,10 @@ function create (env, ctx) { app.all('/alexa*', require('./alexa/')(app, wares, ctx, env)); } + if (ctx.googleHome) { + app.all('/googlehome*', require('./googlehome/')(app, wares, ctx, env)); + } + return app; } diff --git a/lib/plugins/basalprofile.js b/lib/plugins/basalprofile.js index db47e2bf279..b1e97d816be 100644 --- a/lib/plugins/basalprofile.js +++ b/lib/plugins/basalprofile.js @@ -156,6 +156,20 @@ function init (ctx) { }] }; + function googleHomeCurrentBasalhandler (result, next, sbx) { + var pwd = result.parameters && result.parameters.givenName ? result.parameters.givenName : null; + next(basalMessage(pwd, sbx)); + } + + basal.googleHome = { + intentHandlers: [{ + intent: 'CurrentMetric' + , routableSlot:'metric' + , slots:['basal', 'current basal'] + , intentHandler: googleHomeCurrentBasalhandler + }] + }; + return basal; } diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index bc769197c2b..7bd5b422b26 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -308,6 +308,25 @@ function init (ctx) { }] }; + function googleHomeCOBHandler(result, next, sbx) { + var preamble = result && result.parameters && result.parameters.givenName ? result.parameters.givenName + ' has' : 'You have'; + var value = 'no'; + if (sbx.properties.cob && sbx.properties.cob.cob !== 0) { + value = Math.round(sbx.properties.cob.cob); + } + var response = preamble + ' ' + value + ' carbohydrates on board'; + next(response); + } + + cob.googleHome = { + intentHandlers: [{ + intent: 'CurrentMetric' + , routableSlot:'metric' + , slots:['cob', 'carbs on board', 'carbohydrates on board', 'carbohydrates'] + , intentHandler: googleHomeCOBHandler + }] + }; + return cob; } diff --git a/lib/plugins/googlehome.js b/lib/plugins/googlehome.js new file mode 100644 index 00000000000..42da3f14b14 --- /dev/null +++ b/lib/plugins/googlehome.js @@ -0,0 +1,59 @@ + +function init(env, ctx) { + + console.log('Configuring Google Home...'); + + function googleHome() { + return googleHome; + } + + var intentHandlers = {}; + + googleHome.configureIntentHandler = function configureIntentHandler(intent, handler, routableSlot, slotValues) { + if (!intentHandlers[intent]) { + intentHandlers[intent] = {}; + } + if (routableSlot && slotValues) { + for (var i = 0, len = slotValues.length; i < len; i++) { + if (!intentHandlers[intent][routableSlot]) { + intentHandlers[intent][routableSlot] = {}; + } + if (!intentHandlers[intent][routableSlot][slotValues[i]]) { + intentHandlers[intent][routableSlot][slotValues[i]] = {}; + } + intentHandlers[intent][routableSlot][slotValues[i]].handler = handler; + } + } else { + intentHandlers[intent].handler = handler; + } + }; + + googleHome.getIntentHandler = function getIntentHandler(intentName, metric) { + if (intentName && intentHandlers[intentName]) { + if (metric && intentHandlers[intentName]['metric'] && + intentHandlers[intentName]['metric'][metric] && + intentHandlers[intentName]['metric'][metric].handler) { + return intentHandlers[intentName]['metric'][metric].handler; + } else if (intentHandlers[intentName].handler) { + return intentHandlers[intentName].handler; + } else { + return null; + } + } else { + return null; + } + + }; + + googleHome.buildResponse = function buildResponse(output) { + return { + fulfillmentText: output + // , fulfillmentMessages: [output] + , source: 'Nightscout' + }; + }; + + return googleHome; + } + + module.exports = init; \ No newline at end of file diff --git a/lib/plugins/iob.js b/lib/plugins/iob.js index f9bf082d0f4..f4f1d5e05cc 100644 --- a/lib/plugins/iob.js +++ b/lib/plugins/iob.js @@ -288,6 +288,21 @@ function init(ctx) { }] }; + function googleHomeIOBIntentHandler(result, next, sbx) { + var preamble = result && result.parameters && result.parameters.givenName ? result.parameters.givenName + ' has ' : 'You have '; + var message = preamble + getIob(sbx) + ' insulin on board'; + next(message); + } + + iob.googleHome = { + intentHandlers: [{ + intent: 'CurrentMetric' + , routableSlot: 'metric' + , slots: ['iob', 'insulin on board', 'insulin'] + , intentHandler: googleHomeIOBIntentHandler + }] + }; + return iob; } diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 27b7a31ae95..1e03ce218ce 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -543,6 +543,30 @@ function init (ctx) { }] }; + function googleHomeForecastHandler(response, next, sbx) { + if (sbx.properties.openaps && sbx.properties.openaps.lastEventualBG) { + var response = 'The Open APS eventual BG is ' + sbx.properties.openaps.lastEventualBG; + next(response); + } + } + + function googleHomeLastLoopHandler (response, next, sbx) { + var response = 'The last successful loop was ' + moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time)); + next(response); + } + + openaps.googleHome = { + intentHandlers: [{ + intent: 'CurrentMetric' + , routableSlot: 'metric' + , slots: ['openaps', 'openaps forecast', 'forecast'] + , intentHandler: googleHomeForecastHandler + }, { + intent: 'LastLoop' + , intentHandler: googleHomeLastLoopHandler + }] + }; + function statusClass (prop, prefs, sbx) { var level = statusLevel(prop, prefs, sbx); return levels.toStatusClass(level); diff --git a/lib/server/bootevent.js b/lib/server/bootevent.js index 9e53c4f77ac..11eb624720f 100644 --- a/lib/server/bootevent.js +++ b/lib/server/bootevent.js @@ -182,6 +182,10 @@ function boot (env, language) { ctx.alexa = require('../plugins/alexa')(env, ctx); } + if (env.settings.isEnabled('googlehome')) { + ctx.googleHome = require('../plugins/googlehome')(env, ctx); + } + next( ); } From e36a6f1e162fd8340ca594f875c75133f6ec16d1 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Fri, 6 Sep 2019 17:55:08 -0600 Subject: [PATCH 02/48] Updates and fixes to CONTRIBUTING.md --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ede1c7e88c8..e00200d5713 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -202,13 +202,13 @@ Also if you can't code, it's possible to contribute by improving the documentati | Release coordination 0.11.x: | [@PieterGit] | | Issue/Pull request coordination: | Please volunteer | | Cleaning up git fork spam: | Please volunteer | -| Documentation writers: | [@andrew-warrington][@unsoluble] [@tynbendad] [@danamlewis] [@rarneson] | +| Documentation writers: | [@andrew-warrington] [@unsoluble] [@tynbendad] [@danamlewis] [@rarneson] | ### Plugin contributors | Contribution area | List of developers | List of testers | ------------------------------------- | -------------------- | -------------------- | -| [`alexa` (Amazon Alexa)](README.md#alexa-amazon-alexa)| Please volunteer | Please volunteer | +| [`alexa` (Amazon Alexa)](README.md#alexa-amazon-alexa)| [@inventor96] | Please volunteer | | [`ar2` (AR2 Forecasting)](README.md#ar2-ar2-forecasting)| Please volunteer | Please volunteer | | [`basal` (Basal Profile)](README.md#basal-basal-profile)| Please volunteer | Please volunteer | | [`boluscalc` (Bolus Wizard)](README.md#boluscalc-bolus-wizard)| Please volunteer | Please volunteer | @@ -223,7 +223,7 @@ Also if you can't code, it's possible to contribute by improving the documentati | [`direction` (BG Direction)](README.md#direction-bg-direction)| Please volunteer | Please volunteer | | [`errorcodes` (CGM Error Codes)](README.md#errorcodes-cgm-error-codes)| Please volunteer | Please volunteer | | [`food` (Custom Foods)](README.md#food-custom-foods)| Please volunteer | Please volunteer | -| [`googlehome` (Google Home)](README.md#google-home) |[@mdomox] [@rickfriele] | [@mcdafydd] [@oteroos] [@jamieowendexcom] | +| [`googlehome` (Google Home/DialogFLow)](README.md#googlehome-google-homedialogflow)| [@mdomox] [@rickfriele] [@inventor96] | [@mcdafydd] [@oteroos] [@jamieowendexcom] | | [`iage` (Insulin Age)](README.md#iage-insulin-age)| Please volunteer | Please volunteer | | [`iob` (Insulin-on-Board)](README.md#iob-insulin-on-board)| Please volunteer | Please volunteer | | [`loop` (Loop)](README.md#loop-loop)| Please volunteer | Please volunteer | @@ -234,7 +234,7 @@ Also if you can't code, it's possible to contribute by improving the documentati | [`rawbg` (Raw BG)](README.md#rawbg-raw-bg)| [@jpcunningh] | Please volunteer | | [`sage` (Sensor Age)](README.md#sage-sensor-age)| @jpcunningh | Please volunteer | | [`simplealarms` (Simple BG Alarms)](README.md#simplealarms-simple-bg-alarms)| Please volunteer | Please volunteer | -| [`speech` (Speech)](README.md#speech-speech) | [@sulkaharo] | Please volunteer | +| [`speech` (Speech)](README.md#speech-speech)| [@sulkaharo] | Please volunteer | | [`timeago` (Time Ago)](README.md#timeago-time-ago)| Please volunteer | Please volunteer | | [`treatmentnotify` (Treatment Notifications)](README.md#treatmentnotify-treatment-notifications)| Please volunteer | Please volunteer | | [`upbat` (Uploader Battery)](README.md#upbat-uploader-battery)| [@jpcunningh] | Please volunteer | @@ -251,7 +251,7 @@ Languages with less than 90% coverage will be removed in a future Nightscout ver | Čeština (`cs`) |Please volunteer|OK | | Deutsch (`de`) |[@viderehh] [@herzogmedia] |OK | | Dansk (`dk`) | [@janrpn] |OK | -| Ελληνικά `(el`)|Please volunteer|Needs attention: 68.5%| +| Ελληνικά `el`)|Please volunteer|Needs attention: 68.5%| | English (`en`)|Please volunteer|OK| | Español (`es`) |Please volunteer|OK| | Suomi (`fi`)|[@sulkaharo] |OK| From 93f8eb9d6590b1cacda07729f17dcd06267b46ea Mon Sep 17 00:00:00 2001 From: inventor96 Date: Fri, 6 Sep 2019 18:10:47 -0600 Subject: [PATCH 03/48] Spacing unification --- lib/language.js | 210 ++++++++++++++++++++++++------------------------ 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/lib/language.js b/lib/language.js index b7c826d3a73..55b80756418 100644 --- a/lib/language.js +++ b/lib/language.js @@ -13378,32 +13378,32 @@ function init() { , zh_cn: '并且你有 %1 的活性胰岛素.' , zh_tw: 'and you have %1 insulin on board.' }, - 'alexaIobIntent': { - bg: 'Máte %1 jednotek aktivního inzulínu' - , cs: 'You have %1 insulin on board' - , de: 'Du hast noch %1 Insulin wirkend' - , dk: 'Du har %1 insulin i kroppen' - , el: 'You have %1 insulin on board' - , en: 'You have %1 insulin on board' - , es: 'Tienes %1 insulina activa' - , fi: 'Sinulla on %1 aktiivista insuliinia' - , fr: 'You have %1 insulin on board' - , he: 'You have %1 insulin on board' - , hr: 'You have %1 insulin on board' - , it: 'Tu hai %1 insulina attiva' - , ko: 'You have %1 insulin on board' - , nb: 'You have %1 insulin on board' - , pl: 'Masz %1 aktywnej insuliny' - , pt: 'You have %1 insulin on board' - , ro: 'Aveți %1 insulină activă' - , ru: 'вы имеете %1 инсулина в организме' - , sk: 'You have %1 insulin on board' - , sv: 'You have %1 insulin on board' - , nl: 'You have %1 insulin on board' - , tr: 'Sizde %1 aktif insülin var' - , zh_cn: '你有 %1 的活性胰岛素' - , zh_tw: 'You have %1 insulin on board' - }, + 'alexaIobIntent': { + bg: 'Máte %1 jednotek aktivního inzulínu' + , cs: 'You have %1 insulin on board' + , de: 'Du hast noch %1 Insulin wirkend' + , dk: 'Du har %1 insulin i kroppen' + , el: 'You have %1 insulin on board' + , en: 'You have %1 insulin on board' + , es: 'Tienes %1 insulina activa' + , fi: 'Sinulla on %1 aktiivista insuliinia' + , fr: 'You have %1 insulin on board' + , he: 'You have %1 insulin on board' + , hr: 'You have %1 insulin on board' + , it: 'Tu hai %1 insulina attiva' + , ko: 'You have %1 insulin on board' + , nb: 'You have %1 insulin on board' + , pl: 'Masz %1 aktywnej insuliny' + , pt: 'You have %1 insulin on board' + , ro: 'Aveți %1 insulină activă' + , ru: 'вы имеете %1 инсулина в организме' + , sk: 'You have %1 insulin on board' + , sv: 'You have %1 insulin on board' + , nl: 'You have %1 insulin on board' + , tr: 'Sizde %1 aktif insülin var' + , zh_cn: '你有 %1 的活性胰岛素' + , zh_tw: 'You have %1 insulin on board' + }, 'alexaIobUnits': { bg: '%1 units of' , cs: '%1 jednotek' @@ -13508,74 +13508,74 @@ function init() { , zh_cn: '否' , zh_tw: 'no' }, - 'alexaUploadBattery': { - bg: 'Your uploader battery is at %1' - ,cs: 'Baterie mobilu má %1' - , en: 'Your uploader battery is at %1' - , hr: 'Your uploader battery is at %1' - , de: 'Der Akku deines Uploader Handys ist bei %1' - , dk: 'Din uploaders batteri er %1' - , ko: 'Your uploader battery is at %1' - , nl: 'De batterij van je mobiel is bij %l' - ,zh_cn: '你的手机电池电量是 %1 ' - , sv: 'Din uppladdares batteri är %1' - , fi: 'Lähettimen paristoa jäljellä %1' - , ro: 'Bateria uploaderului este la %1' - , pl: 'Twoja bateria ma %1' - , ru: 'батарея загрузчика %1' - , tr: 'Yükleyici piliniz %1' - }, - 'alexaReservoir': { - bg: 'You have %1 units remaining' - , cs: 'V zásobníku zbývá %1 jednotek' - , en: 'You have %1 units remaining' - , hr: 'You have %1 units remaining' - , de: 'Du hast %1 Einheiten übrig' - , dk: 'Du har %1 enheder tilbage' - , ko: 'You have %1 units remaining' - , nl: 'Je hebt nog %l eenheden in je reservoir' - ,zh_cn: '你剩余%1 U的胰岛素' - , sv: 'Du har %1 enheter kvar' - , fi: '%1 yksikköä insuliinia jäljellä' - , ro: 'Mai aveți %1 unități rămase' - , pl: 'W zbiorniku pozostało %1 jednostek' - , ru: 'остается %1 ед' - , tr: '%1 birim kaldı' - }, - 'alexaPumpBattery': { - bg: 'Your pump battery is at %1 %2' - , cs: 'Baterie v pumpě má %1 %2' - , en: 'Your pump battery is at %1 %2' - , hr: 'Your pump battery is at %1 %2' - , de: 'Der Batteriestand deiner Pumpe ist bei %1 %2' - , dk: 'Din pumpes batteri er %1 %2' - , ko: 'Your pump battery is at %1 %2' - , nl: 'Je pomp batterij is bij %1 %2' - ,zh_cn: '你的泵电池电量是%1 %2' - , sv: 'Din pumps batteri är %1 %2' - , fi: 'Pumppu on %1 %2' - , ro: 'Bateria pompei este la %1 %2' - , pl: 'Bateria pompy jest w %1 %2' - , ru: 'батарея помпы %1 %2' - , tr: 'Pompa piliniz %1 %2' - }, - 'alexaLastLoop': { - bg: 'The last successful loop was %1' - , cs: 'Poslední úšpěšné provedení smyčky %1' - , en: 'The last successful loop was %1' - , hr: 'The last successful loop was %1' - , de: 'Der letzte erfolgreiche Loop war %1' - , dk: 'Seneste successfulde loop var %1' - , ko: 'The last successful loop was %1' - , nl: 'De meest recente goede loop was %1' - ,zh_cn: '最后一次成功闭环的是在%1' - , sv: 'Senaste lyckade loop var %1' - , fi: 'Viimeisin onnistunut loop oli %1' - , ro: 'Ultima decizie loop implementată cu succes a fost %1' - , pl: 'Ostatnia pomyślna pętla była %1' - , ru: 'недавний успешный цикл был %1' - , tr: 'Son başarılı döngü %1 oldu' - }, + 'alexaUploadBattery': { + bg: 'Your uploader battery is at %1' + , cs: 'Baterie mobilu má %1' + , en: 'Your uploader battery is at %1' + , hr: 'Your uploader battery is at %1' + , de: 'Der Akku deines Uploader Handys ist bei %1' + , dk: 'Din uploaders batteri er %1' + , ko: 'Your uploader battery is at %1' + , nl: 'De batterij van je mobiel is bij %l' + , zh_cn: '你的手机电池电量是 %1 ' + , sv: 'Din uppladdares batteri är %1' + , fi: 'Lähettimen paristoa jäljellä %1' + , ro: 'Bateria uploaderului este la %1' + , pl: 'Twoja bateria ma %1' + , ru: 'батарея загрузчика %1' + , tr: 'Yükleyici piliniz %1' + }, + 'alexaReservoir': { + bg: 'You have %1 units remaining' + , cs: 'V zásobníku zbývá %1 jednotek' + , en: 'You have %1 units remaining' + , hr: 'You have %1 units remaining' + , de: 'Du hast %1 Einheiten übrig' + , dk: 'Du har %1 enheder tilbage' + , ko: 'You have %1 units remaining' + , nl: 'Je hebt nog %l eenheden in je reservoir' + , zh_cn: '你剩余%1 U的胰岛素' + , sv: 'Du har %1 enheter kvar' + , fi: '%1 yksikköä insuliinia jäljellä' + , ro: 'Mai aveți %1 unități rămase' + , pl: 'W zbiorniku pozostało %1 jednostek' + , ru: 'остается %1 ед' + , tr: '%1 birim kaldı' + }, + 'alexaPumpBattery': { + bg: 'Your pump battery is at %1 %2' + , cs: 'Baterie v pumpě má %1 %2' + , en: 'Your pump battery is at %1 %2' + , hr: 'Your pump battery is at %1 %2' + , de: 'Der Batteriestand deiner Pumpe ist bei %1 %2' + , dk: 'Din pumpes batteri er %1 %2' + , ko: 'Your pump battery is at %1 %2' + , nl: 'Je pomp batterij is bij %1 %2' + , zh_cn: '你的泵电池电量是%1 %2' + , sv: 'Din pumps batteri är %1 %2' + , fi: 'Pumppu on %1 %2' + , ro: 'Bateria pompei este la %1 %2' + , pl: 'Bateria pompy jest w %1 %2' + , ru: 'батарея помпы %1 %2' + , tr: 'Pompa piliniz %1 %2' + }, + 'alexaLastLoop': { + bg: 'The last successful loop was %1' + , cs: 'Poslední úšpěšné provedení smyčky %1' + , en: 'The last successful loop was %1' + , hr: 'The last successful loop was %1' + , de: 'Der letzte erfolgreiche Loop war %1' + , dk: 'Seneste successfulde loop var %1' + , ko: 'The last successful loop was %1' + , nl: 'De meest recente goede loop was %1' + , zh_cn: '最后一次成功闭环的是在%1' + , sv: 'Senaste lyckade loop var %1' + , fi: 'Viimeisin onnistunut loop oli %1' + , ro: 'Ultima decizie loop implementată cu succes a fost %1' + , pl: 'Ostatnia pomyślna pętla była %1' + , ru: 'недавний успешный цикл был %1' + , tr: 'Son başarılı döngü %1 oldu' + }, 'alexaLoopNotAvailable': { bg: 'Loop plugin does not seem to be enabled' , cs: 'Plugin smyčka není patrně povolený' @@ -13585,7 +13585,7 @@ function init() { , dk: 'Loop plugin lader ikke til at være slået til' , ko: 'Loop plugin does not seem to be enabled' , nl: 'De Loop plugin is niet geactiveerd' - ,zh_cn: 'Loop插件看起来没有被启用' + , zh_cn: 'Loop插件看起来没有被启用' , sv: 'Loop plugin verkar inte vara aktiverad' , fi: 'Loop plugin ei ole aktivoitu' , ro: 'Extensia loop pare a fi dezactivată' @@ -13602,7 +13602,7 @@ function init() { , dk: 'Ifølge Loops forudsigelse forventes du at blive %1 i den næste %2' , ko: 'According to the loop forecast you are expected to be %1 over the next %2' , nl: 'Volgens de Loop voorspelling is je waarde %1 over de volgnede %2' - ,zh_cn: '根据loop的预测,在接下来的%2你的血糖将会是%1' + , zh_cn: '根据loop的预测,在接下来的%2你的血糖将会是%1' , sv: 'Enligt Loops förutsägelse förväntas du bli %1 inom %2' , fi: 'Ennusteen mukaan olet %1 seuraavan %2 ajan' , ro: 'Potrivit previziunii date de loop se estiemază %1 pentru următoarele %2' @@ -13619,7 +13619,7 @@ function init() { , dk: 'Det er ikke muligt at forudsige md de tilgængelige data' , ko: 'Unable to forecast with the data that is available' , nl: 'Niet mogelijk om een voorspelling te doen met de data die beschikbaar is' - ,zh_cn: '血糖数据不可用,无法预测未来走势' + , zh_cn: '血糖数据不可用,无法预测未来走势' , sv: 'Förutsägelse ej möjlig med tillgänlig data' , fi: 'Ennusteet eivät ole toiminnassa puuttuvan tiedon vuoksi' , ro: 'Estimarea este imposibilă pe baza datelor disponibile' @@ -13628,13 +13628,13 @@ function init() { , tr: 'Mevcut verilerle tahmin edilemedi' }, 'alexaRawBG': { - en: 'Your raw bg is %1' + en: 'Your raw bg is %1' , cs: 'Raw glykémie je %1' , de: 'Dein Rohblutzucker ist %1' , dk: 'Dit raw blodsukker er %1' , ko: 'Your raw bg is %1' , nl: 'Je raw bloedwaarde is %1' - ,zh_cn: '你的血糖是 %1' + , zh_cn: '你的血糖是 %1' , sv: 'Ditt raw blodsocker är %1' , fi: 'Suodattamaton verensokeriarvo on %1' , ro: 'Glicemia brută este %1' @@ -13651,12 +13651,12 @@ function init() { , dk: 'OpenAPS forventet blodsukker er %1' , ko: 'The OpenAPS Eventual BG is %1' , nl: 'OpenAPS uiteindelijke bloedglucose van %1' - ,zh_cn: 'OpenAPS 预测最终血糖是 %1' + , zh_cn: 'OpenAPS 预测最终血糖是 %1' , sv: 'OpenAPS slutgiltigt blodsocker är %1' , fi: 'OpenAPS verensokeriarvio on %1' , ro: 'Glicemia estimată de OpenAPS este %1' - ,bg: 'The OpenAPS Eventual BG is %1' - ,hr: 'The OpenAPS Eventual BG is %1' + , bg: 'The OpenAPS Eventual BG is %1' + , hr: 'The OpenAPS Eventual BG is %1' , pl: 'Glikemia prognozowana przez OpenAPS wynosi %1' , ru: 'OpenAPS прогнозирует ваш СК как %1 ' , tr: 'OpenAPS tarafından tahmin edilen kan şekeri %1' @@ -13668,12 +13668,12 @@ function init() { , dk: '%1 %2 gram aktive kulhydrater' , ko: '%1 %2 carbohydrates on board' , nl: '%1 %2 actieve koolhydraten' - ,zh_cn: '%1 %2 活性碳水化合物' + , zh_cn: '%1 %2 活性碳水化合物' , sv: '%1 %2 gram aktiva kolhydrater' , fi: '%1 %2 aktiivista hiilihydraattia' , ro: '%1 %2 carbohidrați activi în corp' - ,bg: '%1 %2 carbohydrates on board' - ,hr: '%1 %2 carbohydrates on board' + , bg: '%1 %2 carbohydrates on board' + , hr: '%1 %2 carbohydrates on board' , pl: '%1 %2 aktywnych węglowodanów' , ru: '%1 $2 активных углеводов' , tr: '%1 %2 aktif karbonhidrat' From 3b183a2137cc7fd8f5f16b21880ec7fd5e5ac669 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Fri, 6 Sep 2019 23:53:17 -0600 Subject: [PATCH 04/48] One more fix for CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e00200d5713..a1ac0799d58 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -232,7 +232,7 @@ Also if you can't code, it's possible to contribute by improving the documentati | [`profile` (Treatment Profile)](README.md#profile-treatment-profile)| Please volunteer | Please volunteer | | [`pump` (Pump Monitoring)](README.md#pump-pump-monitoring)| Please volunteer | Please volunteer | | [`rawbg` (Raw BG)](README.md#rawbg-raw-bg)| [@jpcunningh] | Please volunteer | -| [`sage` (Sensor Age)](README.md#sage-sensor-age)| @jpcunningh | Please volunteer | +| [`sage` (Sensor Age)](README.md#sage-sensor-age)| [@jpcunningh] | Please volunteer | | [`simplealarms` (Simple BG Alarms)](README.md#simplealarms-simple-bg-alarms)| Please volunteer | Please volunteer | | [`speech` (Speech)](README.md#speech-speech)| [@sulkaharo] | Please volunteer | | [`timeago` (Time Ago)](README.md#timeago-time-ago)| Please volunteer | Please volunteer | From a7bf320042338e39a07e0f296503e815f2d13778 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 00:06:32 -0600 Subject: [PATCH 05/48] Minor code formatting improvements --- lib/api/alexa/index.js | 278 +++++++++++++++++++------------------- lib/plugins/alexa.js | 4 +- lib/plugins/googlehome.js | 95 +++++++------ 3 files changed, 187 insertions(+), 190 deletions(-) diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index 65f477ad85d..241460d1cb0 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -4,156 +4,154 @@ var moment = require('moment'); var _each = require('lodash/each'); function configure (app, wares, ctx, env) { - var entries = ctx.entries; - var express = require('express') - , api = express.Router( ); - var translate = ctx.language.translate; - - // invoke common middleware - api.use(wares.sendJSONStatus); - // text body types get handled as raw buffer stream - api.use(wares.bodyParser.raw()); - // json body types get handled as parsed json - api.use(wares.bodyParser.json()); - - ctx.plugins.eachEnabledPlugin(function each(plugin){ - if (plugin.alexa) { - if (plugin.alexa.intentHandlers) { - console.log(plugin.name + ' is Alexa enabled'); - _each(plugin.alexa.intentHandlers, function (route) { - if (route) { - ctx.alexa.configureIntentHandler(route.intent, route.intentHandler, route.routableSlot, route.slots); - } - }); - } - if (plugin.alexa.rollupHandlers) { - console.log(plugin.name + ' is Alexa rollup enabled'); - _each(plugin.alexa.rollupHandlers, function (route) { - console.log('Route'); - console.log(route); - if (route) { - ctx.alexa.addToRollup(route.rollupGroup, route.rollupHandler, route.rollupName); - } - }); - } - } else { - console.log('Plugin ' + plugin.name + ' is not Alexa enabled'); - } - }); - - api.post('/alexa', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) { - console.log('Incoming request from Alexa'); - var locale = req.body.request.locale; - if(locale){ - if(locale.length > 2) { - locale = locale.substr(0, 2); - } - ctx.language.set(locale); - moment.locale(locale); - } - - switch (req.body.request.type) { - case 'IntentRequest': - onIntent(req.body.request.intent, function (title, response) { - res.json(ctx.alexa.buildSpeechletResponse(title, response, '', 'true')); - next( ); - }); - break; - case 'LaunchRequest': - onLaunch(req.body.request.intent, function (title, response) { - res.json(ctx.alexa.buildSpeechletResponse(title, response, '', 'true')); - next( ); - }); - break; - case 'SessionEndedRequest': - onSessionEnded(req.body.request.intent, function (alexaResponse) { - res.json(alexaResponse); - next( ); - }); - break; - } - }); - - ctx.alexa.addToRollup('Status', function bgRollupHandler(slots, sbx, callback) { - entries.list({count: 1}, function (err, records) { - var direction; - if (translate(records[0].direction)) { - direction = translate(records[0].direction); - } else { - direction = records[0].direction; - } - var status = translate('alexaStatus', { - params: [ - sbx.scaleMgdl(records[0].sgv), - direction, - moment(records[0].date).from(moment(sbx.time)) - ] - }); - //var status = sbx.scaleMgdl(records[0].sgv) + direction + ' as of ' + moment(records[0].date).from(moment(sbx.time)) + '.'; - callback(null, {results: status, priority: -1}); + var entries = ctx.entries; + var express = require('express') + , api = express.Router( ); + var translate = ctx.language.translate; + + // invoke common middleware + api.use(wares.sendJSONStatus); + // text body types get handled as raw buffer stream + api.use(wares.bodyParser.raw()); + // json body types get handled as parsed json + api.use(wares.bodyParser.json()); + + ctx.plugins.eachEnabledPlugin(function each(plugin){ + if (plugin.alexa) { + if (plugin.alexa.intentHandlers) { + console.log(plugin.name + ' is Alexa enabled'); + _each(plugin.alexa.intentHandlers, function (route) { + if (route) { + ctx.alexa.configureIntentHandler(route.intent, route.intentHandler, route.routableSlot, route.slots); + } }); - // console.log('BG results called'); - // callback(null, 'BG results'); - }, 'BG Status'); - - ctx.alexa.configureIntentHandler('MetricNow', function ( callback, slots, sbx, locale) { - entries.list({count: 1}, function(err, records) { - var direction; - if(translate(records[0].direction)){ - direction = translate(records[0].direction); - } else { - direction = records[0].direction; - } - var status = translate('alexaStatus', { - params: [ - sbx.scaleMgdl(records[0].sgv), - direction, - moment(records[0].date).from(moment(sbx.time))] - }); - //var status = sbx.scaleMgdl(records[0].sgv) + direction + ' as of ' + moment(records[0].date).from(moment(sbx.time)); - callback('Current blood glucose', status); + } + if (plugin.alexa.rollupHandlers) { + console.log(plugin.name + ' is Alexa rollup enabled'); + _each(plugin.alexa.rollupHandlers, function (route) { + console.log('Route'); + console.log(route); + if (route) { + ctx.alexa.addToRollup(route.rollupGroup, route.rollupHandler, route.rollupName); + } }); - }, 'metric', ['bg', 'blood glucose', 'number']); - - ctx.alexa.configureIntentHandler('NSStatus', function(callback, slots, sbx, locale) { - ctx.alexa.getRollup('Status', sbx, slots, locale, function (status) { - callback('Full status', status); - }); - }); - - - function onLaunch() { - console.log('Session launched'); + } + } else { + console.log('Plugin ' + plugin.name + ' is not Alexa enabled'); } - - function onIntent(intent, next) { - console.log('Received intent request'); - console.log(JSON.stringify(intent)); - handleIntent(intent.name, intent.slots, next); + }); + + api.post('/alexa', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) { + console.log('Incoming request from Alexa'); + var locale = req.body.request.locale; + if(locale){ + if(locale.length > 2) { + locale = locale.substr(0, 2); + } + ctx.language.set(locale); + moment.locale(locale); } - function onSessionEnded() { - console.log('Session ended'); + switch (req.body.request.type) { + case 'IntentRequest': + onIntent(req.body.request.intent, function (title, response) { + res.json(ctx.alexa.buildSpeechletResponse(title, response, '', 'true')); + next( ); + }); + break; + case 'LaunchRequest': + onLaunch(req.body.request.intent, function (title, response) { + res.json(ctx.alexa.buildSpeechletResponse(title, response, '', 'true')); + next( ); + }); + break; + case 'SessionEndedRequest': + onSessionEnded(req.body.request.intent, function (alexaResponse) { + res.json(alexaResponse); + next( ); + }); + break; } + }); + + ctx.alexa.addToRollup('Status', function bgRollupHandler(slots, sbx, callback) { + entries.list({count: 1}, function (err, records) { + var direction; + if (translate(records[0].direction)) { + direction = translate(records[0].direction); + } else { + direction = records[0].direction; + } + var status = translate('alexaStatus', { + params: [ + sbx.scaleMgdl(records[0].sgv), + direction, + moment(records[0].date).from(moment(sbx.time)) + ] + }); + + callback(null, {results: status, priority: -1}); + }); + }, 'BG Status'); + + ctx.alexa.configureIntentHandler('MetricNow', function ( callback, slots, sbx, locale) { + entries.list({count: 1}, function(err, records) { + var direction; + if(translate(records[0].direction)){ + direction = translate(records[0].direction); + } else { + direction = records[0].direction; + } + var status = translate('alexaStatus', { + params: [ + sbx.scaleMgdl(records[0].sgv), + direction, + moment(records[0].date).from(moment(sbx.time))] + }); + + callback('Current blood glucose', status); + }); + }, 'metric', ['bg', 'blood glucose', 'number']); - function handleIntent(intentName, slots, next) { - var handler = ctx.alexa.getIntentHandler(intentName, slots); - if (handler){ - var sbx = initializeSandbox(); - handler(next, slots, sbx); - } else { - next('Unknown Intent', 'I\'m sorry I don\'t know what you\'re asking for'); - } + ctx.alexa.configureIntentHandler('NSStatus', function(callback, slots, sbx, locale) { + ctx.alexa.getRollup('Status', sbx, slots, locale, function (status) { + callback('Full status', status); + }); + }); + + + function onLaunch() { + console.log('Session launched'); + } + + function onIntent(intent, next) { + console.log('Received intent request'); + console.log(JSON.stringify(intent)); + handleIntent(intent.name, intent.slots, next); + } + + function onSessionEnded() { + console.log('Session ended'); + } + + function handleIntent(intentName, slots, next) { + var handler = ctx.alexa.getIntentHandler(intentName, slots); + if (handler){ + var sbx = initializeSandbox(); + handler(next, slots, sbx); + } else { + next('Unknown Intent', 'I\'m sorry I don\'t know what you\'re asking for'); } + } - function initializeSandbox() { - var sbx = require('../../sandbox')(); - sbx.serverInit(env, ctx); - ctx.plugins.setProperties(sbx); - return sbx; - } + function initializeSandbox() { + var sbx = require('../../sandbox')(); + sbx.serverInit(env, ctx); + ctx.plugins.setProperties(sbx); + return sbx; + } - return api; + return api; } module.exports = configure; diff --git a/lib/plugins/alexa.js b/lib/plugins/alexa.js index 38ae449c249..bfb8cf6308f 100644 --- a/lib/plugins/alexa.js +++ b/lib/plugins/alexa.js @@ -1,8 +1,8 @@ var _ = require('lodash'); var async = require('async'); -function init(env, ctx) { - console.log('Configuring Alexa.'); +function init (env, ctx) { + console.log('Configuring Alexa...'); function alexa() { return alexa; } diff --git a/lib/plugins/googlehome.js b/lib/plugins/googlehome.js index 42da3f14b14..655b6a485ff 100644 --- a/lib/plugins/googlehome.js +++ b/lib/plugins/googlehome.js @@ -1,59 +1,58 @@ -function init(env, ctx) { +function init (env, ctx) { - console.log('Configuring Google Home...'); - - function googleHome() { - return googleHome; + console.log('Configuring Google Home...'); + function googleHome() { + return googleHome; + } + + var intentHandlers = {}; + + googleHome.configureIntentHandler = function configureIntentHandler(intent, handler, routableSlot, slotValues) { + if (!intentHandlers[intent]) { + intentHandlers[intent] = {}; } - - var intentHandlers = {}; - - googleHome.configureIntentHandler = function configureIntentHandler(intent, handler, routableSlot, slotValues) { - if (!intentHandlers[intent]) { - intentHandlers[intent] = {}; - } - if (routableSlot && slotValues) { - for (var i = 0, len = slotValues.length; i < len; i++) { - if (!intentHandlers[intent][routableSlot]) { - intentHandlers[intent][routableSlot] = {}; - } - if (!intentHandlers[intent][routableSlot][slotValues[i]]) { - intentHandlers[intent][routableSlot][slotValues[i]] = {}; - } - intentHandlers[intent][routableSlot][slotValues[i]].handler = handler; + if (routableSlot && slotValues) { + for (var i = 0, len = slotValues.length; i < len; i++) { + if (!intentHandlers[intent][routableSlot]) { + intentHandlers[intent][routableSlot] = {}; } - } else { - intentHandlers[intent].handler = handler; - } - }; - - googleHome.getIntentHandler = function getIntentHandler(intentName, metric) { - if (intentName && intentHandlers[intentName]) { - if (metric && intentHandlers[intentName]['metric'] && - intentHandlers[intentName]['metric'][metric] && - intentHandlers[intentName]['metric'][metric].handler) { - return intentHandlers[intentName]['metric'][metric].handler; - } else if (intentHandlers[intentName].handler) { - return intentHandlers[intentName].handler; - } else { - return null; + if (!intentHandlers[intent][routableSlot][slotValues[i]]) { + intentHandlers[intent][routableSlot][slotValues[i]] = {}; } + intentHandlers[intent][routableSlot][slotValues[i]].handler = handler; + } + } else { + intentHandlers[intent].handler = handler; + } + }; + + googleHome.getIntentHandler = function getIntentHandler(intentName, metric) { + if (intentName && intentHandlers[intentName]) { + if (metric && intentHandlers[intentName]['metric'] && + intentHandlers[intentName]['metric'][metric] && + intentHandlers[intentName]['metric'][metric].handler) { + return intentHandlers[intentName]['metric'][metric].handler; + } else if (intentHandlers[intentName].handler) { + return intentHandlers[intentName].handler; } else { return null; } - - }; - - googleHome.buildResponse = function buildResponse(output) { - return { - fulfillmentText: output - // , fulfillmentMessages: [output] - , source: 'Nightscout' - }; + } else { + return null; + } + + }; + + googleHome.buildResponse = function buildResponse(output) { + return { + fulfillmentText: output +// , fulfillmentMessages: [output] + , source: 'Nightscout' }; - - return googleHome; - } + }; + + return googleHome; +} module.exports = init; \ No newline at end of file From ce00c945b034100d57201cf6d8f0fa030ef02cc4 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 00:25:29 -0600 Subject: [PATCH 06/48] One more time... --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1ac0799d58..79266e47c82 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -223,7 +223,7 @@ Also if you can't code, it's possible to contribute by improving the documentati | [`direction` (BG Direction)](README.md#direction-bg-direction)| Please volunteer | Please volunteer | | [`errorcodes` (CGM Error Codes)](README.md#errorcodes-cgm-error-codes)| Please volunteer | Please volunteer | | [`food` (Custom Foods)](README.md#food-custom-foods)| Please volunteer | Please volunteer | -| [`googlehome` (Google Home/DialogFLow)](README.md#googlehome-google-homedialogflow)| [@mdomox] [@rickfriele] [@inventor96] | [@mcdafydd] [@oteroos] [@jamieowendexcom] | +| [`googlehome` (Google Home/DialogFlow)](README.md#googlehome-google-homedialogflow)| [@mdomox] [@rickfriele] [@inventor96] | [@mcdafydd] [@oteroos] [@jamieowendexcom] | | [`iage` (Insulin Age)](README.md#iage-insulin-age)| Please volunteer | Please volunteer | | [`iob` (Insulin-on-Board)](README.md#iob-insulin-on-board)| Please volunteer | Please volunteer | | [`loop` (Loop)](README.md#loop-loop)| Please volunteer | Please volunteer | From efa35c46160bb0bbf21a47171502b2f59257d754 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 17:51:31 -0600 Subject: [PATCH 07/48] Renamed Alexa stuff to virtAsst for generic-ness --- lib/api/alexa/index.js | 16 +++++++------- lib/language.js | 38 ++++++++++++++++---------------- lib/plugins/ar2.js | 6 ++--- lib/plugins/basalprofile.js | 22 +++++++++--------- lib/plugins/cob.js | 6 ++--- lib/plugins/iob.js | 18 +++++++-------- lib/plugins/loop.js | 10 ++++----- lib/plugins/openaps.js | 14 ++++++------ lib/plugins/pump.js | 14 ++++++------ lib/plugins/rawbg.js | 6 ++--- lib/plugins/upbat.js | 6 ++--- tests/ar2.test.js | 6 ++--- tests/basalprofileplugin.test.js | 10 ++++----- tests/cob.test.js | 6 ++--- tests/iob.test.js | 10 ++++----- tests/loop.test.js | 8 +++---- tests/openaps.test.js | 8 +++---- tests/pump.test.js | 8 +++---- tests/rawbg.test.js | 6 ++--- tests/upbat.test.js | 6 ++--- 20 files changed, 112 insertions(+), 112 deletions(-) diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index 241460d1cb0..cd46a1acdd9 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -17,18 +17,18 @@ function configure (app, wares, ctx, env) { api.use(wares.bodyParser.json()); ctx.plugins.eachEnabledPlugin(function each(plugin){ - if (plugin.alexa) { - if (plugin.alexa.intentHandlers) { - console.log(plugin.name + ' is Alexa enabled'); - _each(plugin.alexa.intentHandlers, function (route) { + if (plugin.virtAsst) { + if (plugin.virtAsst.intentHandlers) { + console.log('Plugin ' + plugin.name + ' supports Virtual Assistants'); + _each(plugin.virtAsst.intentHandlers, function (route) { if (route) { ctx.alexa.configureIntentHandler(route.intent, route.intentHandler, route.routableSlot, route.slots); } }); } - if (plugin.alexa.rollupHandlers) { - console.log(plugin.name + ' is Alexa rollup enabled'); - _each(plugin.alexa.rollupHandlers, function (route) { + if (plugin.virtAsst.rollupHandlers) { + console.log('Plugin ' + plugin.name + ' supports rollups for Virtual Assistants'); + _each(plugin.virtAsst.rollupHandlers, function (route) { console.log('Route'); console.log(route); if (route) { @@ -37,7 +37,7 @@ function configure (app, wares, ctx, env) { }); } } else { - console.log('Plugin ' + plugin.name + ' is not Alexa enabled'); + console.log('Plugin ' + plugin.name + ' does not support Virtual Assistants'); } }); diff --git a/lib/language.js b/lib/language.js index 55b80756418..f1560e122ef 100644 --- a/lib/language.js +++ b/lib/language.js @@ -13274,7 +13274,7 @@ function init() { , zh_cn: '快速上升' , zh_tw: 'rapidly rising' }, - 'alexaStatus': { + 'virtAsstStatus': { bg: '%1 and %2 as of %3.' , cs: '%1 %2 čas %3.' , de: '%1 und bis %3 %2.' @@ -13300,7 +13300,7 @@ function init() { , zh_cn: '%1 和 %2 到 %3.' , zh_tw: '%1 and %2 as of %3.' }, - 'alexaBasal': { + 'virtAsstBasal': { bg: '%1 současný bazál je %2 jednotek za hodinu' , cs: '%1 current basal is %2 units per hour' , de: '%1 aktuelle Basalrate ist %2 Einheiten je Stunde' @@ -13326,7 +13326,7 @@ function init() { , zh_cn: '%1 当前基础率是 %2 U/小时' , zh_tw: '%1 current basal is %2 units per hour' }, - 'alexaBasalTemp': { + 'virtAsstBasalTemp': { bg: '%1 dočasný bazál %2 jednotek za hodinu skončí %3' , cs: '%1 temp basal of %2 units per hour will end %3' , de: '%1 temporäre Basalrate von %2 Einheiten endet %3' @@ -13352,7 +13352,7 @@ function init() { , zh_cn: '%1 临时基础率 %2 U/小时将会在 %3结束' , zh_tw: '%1 temp basal of %2 units per hour will end %3' }, - 'alexaIob': { + 'virtAsstIob': { bg: 'a máte %1 jednotek aktivního inzulínu.' , cs: 'and you have %1 insulin on board.' , de: 'und du hast %1 Insulin wirkend.' @@ -13378,7 +13378,7 @@ function init() { , zh_cn: '并且你有 %1 的活性胰岛素.' , zh_tw: 'and you have %1 insulin on board.' }, - 'alexaIobIntent': { + 'virtAsstIobIntent': { bg: 'Máte %1 jednotek aktivního inzulínu' , cs: 'You have %1 insulin on board' , de: 'Du hast noch %1 Insulin wirkend' @@ -13404,7 +13404,7 @@ function init() { , zh_cn: '你有 %1 的活性胰岛素' , zh_tw: 'You have %1 insulin on board' }, - 'alexaIobUnits': { + 'virtAsstIobUnits': { bg: '%1 units of' , cs: '%1 jednotek' , de: 'noch %1 Einheiten' @@ -13430,7 +13430,7 @@ function init() { , zh_cn: '%1 单位' , zh_tw: '%1 units of' }, - 'alexaPreamble': { + 'virtAsstPreamble': { bg: 'Your' , cs: 'Vaše' , de: 'Deine' @@ -13456,7 +13456,7 @@ function init() { , zh_cn: '你的' , zh_tw: 'Your' }, - 'alexaPreamble3person': { + 'virtAsstPreamble3person': { bg: '%1 has a ' , cs: '%1 má ' , de: '%1 hat eine' @@ -13482,7 +13482,7 @@ function init() { , zh_cn: '%1 有一个 ' , zh_tw: '%1 has a ' }, - 'alexaNoInsulin': { + 'virtAsstNoInsulin': { bg: 'no' , cs: 'žádný' , de: 'kein' @@ -13508,7 +13508,7 @@ function init() { , zh_cn: '否' , zh_tw: 'no' }, - 'alexaUploadBattery': { + 'virtAsstUploadBattery': { bg: 'Your uploader battery is at %1' , cs: 'Baterie mobilu má %1' , en: 'Your uploader battery is at %1' @@ -13525,7 +13525,7 @@ function init() { , ru: 'батарея загрузчика %1' , tr: 'Yükleyici piliniz %1' }, - 'alexaReservoir': { + 'virtAsstReservoir': { bg: 'You have %1 units remaining' , cs: 'V zásobníku zbývá %1 jednotek' , en: 'You have %1 units remaining' @@ -13542,7 +13542,7 @@ function init() { , ru: 'остается %1 ед' , tr: '%1 birim kaldı' }, - 'alexaPumpBattery': { + 'virtAsstPumpBattery': { bg: 'Your pump battery is at %1 %2' , cs: 'Baterie v pumpě má %1 %2' , en: 'Your pump battery is at %1 %2' @@ -13559,7 +13559,7 @@ function init() { , ru: 'батарея помпы %1 %2' , tr: 'Pompa piliniz %1 %2' }, - 'alexaLastLoop': { + 'virtAsstLastLoop': { bg: 'The last successful loop was %1' , cs: 'Poslední úšpěšné provedení smyčky %1' , en: 'The last successful loop was %1' @@ -13576,7 +13576,7 @@ function init() { , ru: 'недавний успешный цикл был %1' , tr: 'Son başarılı döngü %1 oldu' }, - 'alexaLoopNotAvailable': { + 'virtAsstLoopNotAvailable': { bg: 'Loop plugin does not seem to be enabled' , cs: 'Plugin smyčka není patrně povolený' , en: 'Loop plugin does not seem to be enabled' @@ -13593,7 +13593,7 @@ function init() { , ru: 'плагин ЗЦ Loop не активирован ' , tr: 'Döngü eklentisi etkin görünmüyor' }, - 'alexaLoopForecast': { + 'virtAsstLoopForecast': { bg: 'According to the loop forecast you are expected to be %1 over the next %2' , cs: 'Podle přepovědi smyčky je očekávána glykémie %1 během následujících %2' , en: 'According to the loop forecast you are expected to be %1 over the next %2' @@ -13610,7 +13610,7 @@ function init() { , ru: 'по прогнозу алгоритма ЗЦ ожидается %1 за последующие %2' , tr: 'Döngü tahminine göre sonraki %2 ye göre %1 olması bekleniyor' }, - 'alexaForecastUnavailable': { + 'virtAsstForecastUnavailable': { bg: 'Unable to forecast with the data that is available' , cs: 'S dostupnými daty přepověď není možná' , en: 'Unable to forecast with the data that is available' @@ -13627,7 +13627,7 @@ function init() { , ru: 'прогноз при таких данных невозможен' , tr: 'Mevcut verilerle tahmin edilemedi' }, - 'alexaRawBG': { + 'virtAsstRawBG': { en: 'Your raw bg is %1' , cs: 'Raw glykémie je %1' , de: 'Dein Rohblutzucker ist %1' @@ -13644,7 +13644,7 @@ function init() { , ru: 'ваши необработанные данные RAW %1' , tr: 'Ham kan şekeriniz %1' }, - 'alexaOpenAPSForecast': { + 'virtAsstOpenAPSForecast': { en: 'The OpenAPS Eventual BG is %1' , cs: 'OpenAPS Eventual BG je %1' , de: 'Der von OpenAPS vorhergesagte Blutzucker ist %1' @@ -13661,7 +13661,7 @@ function init() { , ru: 'OpenAPS прогнозирует ваш СК как %1 ' , tr: 'OpenAPS tarafından tahmin edilen kan şekeri %1' }, - 'alexaCOB': { + 'virtAsstCOB': { en: '%1 %2 carbohydrates on board' , cs: '%1 %2 aktivních sachridů' , de: '%1 %2 Gramm Kohlenhydrate wirkend.' diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js index e25a2b36229..24fe192cac3 100644 --- a/lib/plugins/ar2.js +++ b/lib/plugins/ar2.js @@ -146,7 +146,7 @@ function init (ctx) { return result.points; }; - function alexaAr2Handler (next, slots, sbx) { + function virtAsstAr2Handler (next, slots, sbx) { if (sbx.properties.ar2.forecast.predicted) { var forecast = sbx.properties.ar2.forecast.predicted; var max = forecast[0].mgdl; @@ -170,12 +170,12 @@ function init (ctx) { } } - ar2.alexa = { + ar2.virtAsst = { intentHandlers: [{ intent: 'MetricNow' , routableSlot: 'metric' , slots: ['ar2 forecast', 'forecast'] - , intentHandler: alexaAr2Handler + , intentHandler: virtAsstAr2Handler }] }; diff --git a/lib/plugins/basalprofile.js b/lib/plugins/basalprofile.js index b1e97d816be..10f27145fdc 100644 --- a/lib/plugins/basalprofile.js +++ b/lib/plugins/basalprofile.js @@ -105,13 +105,13 @@ function init (ctx) { var response = 'Unable to determine current basal'; var preamble = ''; if (basalValue.treatment) { - preamble = (slots && slots.pwd && slots.pwd.value) ? translate('alexaPreamble3person', { + preamble = (slots && slots.pwd && slots.pwd.value) ? translate('virtAsstPreamble3person', { params: [ slots.pwd.value ] - }) : translate('alexaPreamble'); + }) : translate('virtAsstPreamble'); var minutesLeft = moment(basalValue.treatment.endmills).from(moment(sbx.time)); - response = translate('alexaBasalTemp', { + response = translate('virtAsstBasalTemp', { params: [ preamble, basalValue.totalbasal, @@ -119,12 +119,12 @@ function init (ctx) { ] }); } else { - preamble = (slots && slots.pwd && slots.pwd.value) ? translate('alexaPreamble3person', { + preamble = (slots && slots.pwd && slots.pwd.value) ? translate('virtAsstPreamble3person', { params: [ slots.pwd.value ] - }) : translate('alexaPreamble'); - response = translate('alexaBasal', { + }) : translate('virtAsstPreamble'); + response = translate('virtAsstBasal', { params: [ preamble, basalValue.totalbasal @@ -134,25 +134,25 @@ function init (ctx) { return response; } - function alexaRollupCurrentBasalHandler (slots, sbx, callback) { + function virtAsstRollupCurrentBasalHandler (slots, sbx, callback) { callback(null, {results: basalMessage(slots, sbx), priority: 1}); } - function alexaCurrentBasalhandler (next, slots, sbx) { + function virtAsstCurrentBasalhandler (next, slots, sbx) { next('Current Basal', basalMessage(slots, sbx)); } - basal.alexa = { + basal.virtAsst = { rollupHandlers: [{ rollupGroup: 'Status' , rollupName: 'current basal' - , rollupHandler: alexaRollupCurrentBasalHandler + , rollupHandler: virtAsstRollupCurrentBasalHandler }], intentHandlers: [{ intent: 'MetricNow' , routableSlot:'metric' , slots:['basal', 'current basal'] - , intentHandler: alexaCurrentBasalhandler + , intentHandler: virtAsstCurrentBasalhandler }] }; diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index 7bd5b422b26..8706e182444 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -289,7 +289,7 @@ function init (ctx) { }); }; - function alexaCOBHandler (next, slots, sbx) { + function virtAsstCOBHandler (next, slots, sbx) { var preamble = (slots && slots.pwd && slots.pwd.value) ? slots.pwd.value.replace('\'s', '') + ' has' : 'You have'; var value = 'no'; if (sbx.properties.cob && sbx.properties.cob.cob !== 0) { @@ -299,12 +299,12 @@ function init (ctx) { next('Current COB', response); } - cob.alexa = { + cob.virtAsst = { intentHandlers: [{ intent: 'MetricNow' , routableSlot: 'metric' , slots: ['cob', 'carbs on board', 'carbohydrates on board'] - , intentHandler: alexaCOBHandler + , intentHandler: virtAsstCOBHandler }] }; diff --git a/lib/plugins/iob.js b/lib/plugins/iob.js index f4f1d5e05cc..0b9a5ff5576 100644 --- a/lib/plugins/iob.js +++ b/lib/plugins/iob.js @@ -243,9 +243,9 @@ function init(ctx) { }; - function alexaIOBIntentHandler (callback, slots, sbx) { + function virtAsstIOBIntentHandler (callback, slots, sbx) { - var message = translate('alexaIobIntent', { + var message = translate('virtAsstIobIntent', { params: [ //preamble, getIob(sbx) @@ -255,9 +255,9 @@ function init(ctx) { callback('Current IOB', message); } - function alexaIOBRollupHandler (slots, sbx, callback) { + function virtAsstIOBRollupHandler (slots, sbx, callback) { var iob = getIob(sbx); - var message = translate('alexaIob', { + var message = translate('virtAsstIob', { params: [iob] }); callback(null, {results: message, priority: 2}); @@ -265,26 +265,26 @@ function init(ctx) { function getIob(sbx) { if (sbx.properties.iob && sbx.properties.iob.iob !== 0) { - return translate('alexaIobUnits', { + return translate('virtAsstIobUnits', { params: [ utils.toFixed(sbx.properties.iob.iob) ] }); } - return translate('alexaNoInsulin'); + return translate('virtAsstNoInsulin'); } - iob.alexa = { + iob.virtAsst = { rollupHandlers: [{ rollupGroup: 'Status' , rollupName: 'current iob' - , rollupHandler: alexaIOBRollupHandler + , rollupHandler: virtAsstIOBRollupHandler }] , intentHandlers: [{ intent: 'MetricNow' , routableSlot: 'metric' , slots: ['iob', 'insulin on board'] - , intentHandler: alexaIOBIntentHandler + , intentHandler: virtAsstIOBIntentHandler }] }; diff --git a/lib/plugins/loop.js b/lib/plugins/loop.js index fc8dcbb3282..c94e969a7ca 100644 --- a/lib/plugins/loop.js +++ b/lib/plugins/loop.js @@ -431,7 +431,7 @@ function init (ctx) { } }; - function alexaForecastHandler (next, slots, sbx) { + function virtAsstForecastHandler (next, slots, sbx) { if (sbx.properties.loop.lastLoop.predicted) { var forecast = sbx.properties.loop.lastLoop.predicted.values; var max = forecast[0]; @@ -465,21 +465,21 @@ function init (ctx) { } } - function alexaLastLoopHandler (next, slots, sbx) { + function virtAsstLastLoopHandler (next, slots, sbx) { console.log(JSON.stringify(sbx.properties.loop.lastLoop)); var response = 'The last successful loop was ' + moment(sbx.properties.loop.lastOkMoment).from(moment(sbx.time)); next('Last loop', response); } - loop.alexa = { + loop.virtAsst = { intentHandlers: [{ intent: 'MetricNow' , routableSlot: 'metric' , slots: ['loop forecast', 'forecast'] - , intentHandler: alexaForecastHandler + , intentHandler: virtAsstForecastHandler }, { intent: 'LastLoop' - , intentHandler: alexaLastLoopHandler + , intentHandler: virtAsstLastLoopHandler }] }; diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 1e03ce218ce..1ae4741285e 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -510,9 +510,9 @@ function init (ctx) { } }; - function alexaForecastHandler (next, slots, sbx) { + function virtAsstForecastHandler (next, slots, sbx) { if (sbx.properties.openaps && sbx.properties.openaps.lastEventualBG) { - var response = translate('alexaOpenAPSForecast', { + var response = translate('virtAsstOpenAPSForecast', { params: [ sbx.properties.openaps.lastEventualBG ] @@ -521,9 +521,9 @@ function init (ctx) { } } - function alexaLastLoopHandler (next, slots, sbx) { + function virtAsstLastLoopHandler (next, slots, sbx) { console.log(JSON.stringify(sbx.properties.openaps.lastLoopMoment)); - var response = translate('alexaLastLoop', { + var response = translate('virtAsstLastLoop', { params: [ moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time)) ] @@ -531,15 +531,15 @@ function init (ctx) { next('Last loop', response); } - openaps.alexa = { + openaps.virtAsst = { intentHandlers: [{ intent: 'MetricNow' , routableSlot: 'metric' , slots: ['openaps forecast', 'forecast'] - , intentHandler: alexaForecastHandler + , intentHandler: virtAsstForecastHandler }, { intent: 'LastLoop' - , intentHandler: alexaLastLoopHandler + , intentHandler: virtAsstLastLoopHandler }] }; diff --git a/lib/plugins/pump.js b/lib/plugins/pump.js index 842d8536b6b..b63c69bb2c3 100644 --- a/lib/plugins/pump.js +++ b/lib/plugins/pump.js @@ -135,8 +135,8 @@ function init (ctx) { }); }; - function alexaReservoirHandler (next, slots, sbx) { - var response = translate('alexaReservoir', { + function virtAsstReservoirHandler (next, slots, sbx) { + var response = translate('virtAsstReservoir', { params: [ sbx.properties.pump.pump.reservoir ] @@ -144,10 +144,10 @@ function init (ctx) { next('Remaining insulin', response); } - function alexaBatteryHandler (next, slots, sbx) { + function virtAsstBatteryHandler (next, slots, sbx) { var battery = _.get(sbx, 'properties.pump.data.battery'); if (battery) { - var response = translate('alexaPumpBattery', { + var response = translate('virtAsstPumpBattery', { params: [ battery.value, battery.unit @@ -159,13 +159,13 @@ function init (ctx) { } } - pump.alexa = { + pump.virtAsst = { intentHandlers:[{ intent: 'InsulinRemaining', - intentHandler: alexaReservoirHandler + intentHandler: virtAsstReservoirHandler }, { intent: 'PumpBattery', - intentHandler: alexaBatteryHandler + intentHandler: virtAsstBatteryHandler }] }; diff --git a/lib/plugins/rawbg.js b/lib/plugins/rawbg.js index f19e669f63b..2bfea16ba73 100644 --- a/lib/plugins/rawbg.js +++ b/lib/plugins/rawbg.js @@ -106,17 +106,17 @@ function init (ctx) { return display; }; - function alexaRawBGHandler (next, slots, sbx) { + function virtAsstRawBGHandler (next, slots, sbx) { var response = 'Your raw bg is ' + sbx.properties.rawbg.mgdl; next('Current Raw BG', response); } - rawbg.alexa = { + rawbg.virtAsst = { intentHandlers: [{ intent: 'MetricNow' , routableSlot:'metric' , slots:['raw bg', 'raw blood glucose'] - , intentHandler: alexaRawBGHandler + , intentHandler: virtAsstRawBGHandler }] }; diff --git a/lib/plugins/upbat.js b/lib/plugins/upbat.js index eda42a3901f..72c3bce2021 100644 --- a/lib/plugins/upbat.js +++ b/lib/plugins/upbat.js @@ -221,15 +221,15 @@ function init() { }); }; - function alexaUploaderBatteryHandler (next, slots, sbx) { + function virtAsstUploaderBatteryHandler (next, slots, sbx) { var response = 'Your uploader battery is at ' + sbx.properties.upbat.display; next('Uploader battery', response); } - upbat.alexa = { + upbat.virtAsst = { intentHandlers: [{ intent: 'UploaderBattery' - , intentHandler: alexaUploaderBatteryHandler + , intentHandler: virtAsstUploaderBatteryHandler }] }; diff --git a/tests/ar2.test.js b/tests/ar2.test.js index 9dbf6de14cd..8fee3ec1c63 100644 --- a/tests/ar2.test.js +++ b/tests/ar2.test.js @@ -147,16 +147,16 @@ describe('ar2', function ( ) { done(); }); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var now = Date.now(); var before = now - FIVE_MINS; ctx.ddata.sgvs = [{mgdl: 100, mills: before}, {mgdl: 105, mills: now}]; var sbx = prepareSandbox(); - ar2.alexa.intentHandlers.length.should.equal(1); + ar2.virtAsst.intentHandlers.length.should.equal(1); - ar2.alexa.intentHandlers[0].intentHandler(function next(title, response) { + ar2.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('AR2 Forecast'); response.should.equal('You are expected to be between 109 and 120 over the in 30 minutes'); done(); diff --git a/tests/basalprofileplugin.test.js b/tests/basalprofileplugin.test.js index 0bcfd3bc268..fa97f84274e 100644 --- a/tests/basalprofileplugin.test.js +++ b/tests/basalprofileplugin.test.js @@ -77,7 +77,7 @@ describe('basalprofile', function ( ) { }); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var data = {}; var ctx = { @@ -92,14 +92,14 @@ describe('basalprofile', function ( ) { var sbx = sandbox.clientInit(ctx, time, data); sbx.data.profile = profile; - basal.alexa.intentHandlers.length.should.equal(1); - basal.alexa.rollupHandlers.length.should.equal(1); + basal.virtAsst.intentHandlers.length.should.equal(1); + basal.virtAsst.rollupHandlers.length.should.equal(1); - basal.alexa.intentHandlers[0].intentHandler(function next(title, response) { + basal.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current Basal'); response.should.equal('Your current basal is 0.175 units per hour'); - basal.alexa.rollupHandlers[0].rollupHandler([], sbx, function callback (err, response) { + basal.virtAsst.rollupHandlers[0].rollupHandler([], sbx, function callback (err, response) { should.not.exist(err); response.results.should.equal('Your current basal is 0.175 units per hour'); response.priority.should.equal(1); diff --git a/tests/cob.test.js b/tests/cob.test.js index dbbecda0b67..54fbcb6c50d 100644 --- a/tests/cob.test.js +++ b/tests/cob.test.js @@ -97,7 +97,7 @@ describe('COB', function ( ) { }); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var data = { treatments: [{ carbs: '8' @@ -110,9 +110,9 @@ describe('COB', function ( ) { var sbx = sandbox.clientInit(ctx, Date.now(), data); cob.setProperties(sbx); - cob.alexa.intentHandlers.length.should.equal(1); + cob.virtAsst.intentHandlers.length.should.equal(1); - cob.alexa.intentHandlers[0].intentHandler(function next(title, response) { + cob.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current COB'); response.should.equal('You have 8 carbohydrates on board'); done(); diff --git a/tests/iob.test.js b/tests/iob.test.js index 30872e4fb4d..b6c5c2430ec 100644 --- a/tests/iob.test.js +++ b/tests/iob.test.js @@ -10,7 +10,7 @@ describe('IOB', function() { var iob = require('../lib/plugins/iob')(ctx); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var sbx = { properties: { @@ -20,14 +20,14 @@ describe('IOB', function() { } }; - iob.alexa.intentHandlers.length.should.equal(1); - iob.alexa.rollupHandlers.length.should.equal(1); + iob.virtAsst.intentHandlers.length.should.equal(1); + iob.virtAsst.rollupHandlers.length.should.equal(1); - iob.alexa.intentHandlers[0].intentHandler(function next(title, response) { + iob.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current IOB'); response.should.equal('You have 1.50 units of insulin on board'); - iob.alexa.rollupHandlers[0].rollupHandler([], sbx, function callback (err, response) { + iob.virtAsst.rollupHandlers[0].rollupHandler([], sbx, function callback (err, response) { should.not.exist(err); response.results.should.equal('and you have 1.50 units of insulin on board.'); response.priority.should.equal(2); diff --git a/tests/loop.test.js b/tests/loop.test.js index 9c65ff9bdd1..8506de4555b 100644 --- a/tests/loop.test.js +++ b/tests/loop.test.js @@ -243,7 +243,7 @@ describe('loop', function ( ) { done(); }); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var ctx = { settings: { units: 'mg/dl' @@ -255,13 +255,13 @@ describe('loop', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); loop.setProperties(sbx); - loop.alexa.intentHandlers.length.should.equal(2); + loop.virtAsst.intentHandlers.length.should.equal(2); - loop.alexa.intentHandlers[0].intentHandler(function next(title, response) { + loop.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Loop Forecast'); response.should.equal('According to the loop forecast you are expected to be between 147 and 149 over the next in 25 minutes'); - loop.alexa.intentHandlers[1].intentHandler(function next(title, response) { + loop.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { title.should.equal('Last loop'); response.should.equal('The last successful loop was a few seconds ago'); done(); diff --git a/tests/openaps.test.js b/tests/openaps.test.js index ed3dd6d3b9f..9bfc5161969 100644 --- a/tests/openaps.test.js +++ b/tests/openaps.test.js @@ -370,7 +370,7 @@ describe('openaps', function ( ) { done(); }); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var ctx = { settings: { units: 'mg/dl' @@ -382,13 +382,13 @@ describe('openaps', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); openaps.setProperties(sbx); - openaps.alexa.intentHandlers.length.should.equal(2); + openaps.virtAsst.intentHandlers.length.should.equal(2); - openaps.alexa.intentHandlers[0].intentHandler(function next(title, response) { + openaps.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Loop Forecast'); response.should.equal('The OpenAPS Eventual BG is 125'); - openaps.alexa.intentHandlers[1].intentHandler(function next(title, response) { + openaps.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { title.should.equal('Last loop'); response.should.equal('The last successful loop was 2 minutes ago'); done(); diff --git a/tests/pump.test.js b/tests/pump.test.js index c6def822058..afc96481976 100644 --- a/tests/pump.test.js +++ b/tests/pump.test.js @@ -254,7 +254,7 @@ describe('pump', function ( ) { done(); }); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var ctx = { settings: { units: 'mg/dl' @@ -266,13 +266,13 @@ describe('pump', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); pump.setProperties(sbx); - pump.alexa.intentHandlers.length.should.equal(2); + pump.virtAsst.intentHandlers.length.should.equal(2); - pump.alexa.intentHandlers[0].intentHandler(function next(title, response) { + pump.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Remaining insulin'); response.should.equal('You have 86.4 units remaining'); - pump.alexa.intentHandlers[1].intentHandler(function next(title, response) { + pump.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { title.should.equal('Pump battery'); response.should.equal('Your pump battery is at 1.52 volts'); done(); diff --git a/tests/rawbg.test.js b/tests/rawbg.test.js index ab91d2bf722..48c21186cc5 100644 --- a/tests/rawbg.test.js +++ b/tests/rawbg.test.js @@ -35,16 +35,16 @@ describe('Raw BG', function ( ) { }); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var sandbox = require('../lib/sandbox')(); var sbx = sandbox.clientInit(ctx, Date.now(), data); rawbg.setProperties(sbx); - rawbg.alexa.intentHandlers.length.should.equal(1); + rawbg.virtAsst.intentHandlers.length.should.equal(1); - rawbg.alexa.intentHandlers[0].intentHandler(function next(title, response) { + rawbg.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current Raw BG'); response.should.equal('Your raw bg is 113'); diff --git a/tests/upbat.test.js b/tests/upbat.test.js index 9b48c3b845e..515d1a8d218 100644 --- a/tests/upbat.test.js +++ b/tests/upbat.test.js @@ -93,7 +93,7 @@ describe('Uploader Battery', function ( ) { upbat.updateVisualisation(sbx); }); - it('should handle alexa requests', function (done) { + it('should handle virtAsst requests', function (done) { var ctx = { settings: {} @@ -106,9 +106,9 @@ describe('Uploader Battery', function ( ) { var upbat = require('../lib/plugins/upbat')(ctx); upbat.setProperties(sbx); - upbat.alexa.intentHandlers.length.should.equal(1); + upbat.virtAsst.intentHandlers.length.should.equal(1); - upbat.alexa.intentHandlers[0].intentHandler(function next(title, response) { + upbat.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Uploader battery'); response.should.equal('Your uploader battery is at 20%'); From 51c8d2cddadfa1337a7da13278083bc17e75a645 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 18:39:55 -0600 Subject: [PATCH 08/48] Corrected missed translate() text --- lib/api/alexa/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index cd46a1acdd9..f54eeba6fa3 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -82,7 +82,7 @@ function configure (app, wares, ctx, env) { } else { direction = records[0].direction; } - var status = translate('alexaStatus', { + var status = translate('virtAsstStatus', { params: [ sbx.scaleMgdl(records[0].sgv), direction, @@ -102,7 +102,7 @@ function configure (app, wares, ctx, env) { } else { direction = records[0].direction; } - var status = translate('alexaStatus', { + var status = translate('virtAsstStatus', { params: [ sbx.scaleMgdl(records[0].sgv), direction, From 58162c218322f670e6c396eb7aa78ca3691605af Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 19:30:35 -0600 Subject: [PATCH 09/48] Updated googlehome plugin to mimic the alexa plugin --- lib/api/alexa/index.js | 4 +- lib/api/googlehome/index.js | 194 +++++++++++++++++++----------------- lib/plugins/googlehome.js | 85 ++++++++++++---- 3 files changed, 170 insertions(+), 113 deletions(-) diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index f54eeba6fa3..61f343a38f6 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -94,7 +94,7 @@ function configure (app, wares, ctx, env) { }); }, 'BG Status'); - ctx.alexa.configureIntentHandler('MetricNow', function ( callback, slots, sbx, locale) { + ctx.alexa.configureIntentHandler('MetricNow', function (callback, slots, sbx, locale) { entries.list({count: 1}, function(err, records) { var direction; if(translate(records[0].direction)){ @@ -113,7 +113,7 @@ function configure (app, wares, ctx, env) { }); }, 'metric', ['bg', 'blood glucose', 'number']); - ctx.alexa.configureIntentHandler('NSStatus', function(callback, slots, sbx, locale) { + ctx.alexa.configureIntentHandler('NSStatus', function (callback, slots, sbx, locale) { ctx.alexa.getRollup('Status', sbx, slots, locale, function (status) { callback('Full status', status); }); diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js index a833b4abab3..5cd791d0488 100644 --- a/lib/api/googlehome/index.js +++ b/lib/api/googlehome/index.js @@ -1,115 +1,123 @@ 'use strict'; -var _ = require('lodash'); var moment = require('moment'); +var _each = require('lodash/each'); function configure (app, wares, ctx, env) { - var express = require('express'); - var api = express.Router(); - var entries = ctx.entries; - var translate = ctx.language.translate; + var entries = ctx.entries; + var express = require('express') + , api = express.Router( ); + var translate = ctx.language.translate; - // invoke common middleware - api.use(wares.sendJSONStatus); - // text body types get handled as raw buffer stream - api.use(wares.bodyParser.raw()); - // json body types get handled as parsed json - api.use(wares.bodyParser.json()); + // invoke common middleware + api.use(wares.sendJSONStatus); + // text body types get handled as raw buffer stream + api.use(wares.bodyParser.raw()); + // json body types get handled as parsed json + api.use(wares.bodyParser.json()); - ctx.plugins.eachEnabledPlugin(function each(plugin) { - if (plugin.googleHome) { - if (plugin.googleHome.intentHandlers) { - console.log('Plugin ' + plugin.name + ' is Google Home enabled'); - _.each(plugin.googleHome.intentHandlers, function (handler) { - if (handler) { - ctx.googleHome.configureIntentHandler(handler.intent, handler.intentHandler, handler.routableSlot, handler.slots); - } - }); - } - } else { - console.log('Plugin ' + plugin.name + ' is not Google Home enabled'); + ctx.plugins.eachEnabledPlugin(function each(plugin){ + if (plugin.virtAsst) { + if (plugin.virtAsst.intentHandlers) { + console.log('Plugin ' + plugin.name + ' supports Virtual Assistants'); + _each(plugin.virtAsst.intentHandlers, function (route) { + if (route) { + ctx.googleHome.configureIntentHandler(route.intent, route.intentHandler, route.routableSlot, route.slots); + } + }); } - }); - - ctx.googleHome.configureIntentHandler('CurrentMetric', function (result, next, sbx) { - entries.list({count: 1}, function(err, records) { - var response = ''; - if (records && records.length > 0) { - var direction = ''; - if (records[0].direction === 'FortyFiveDown') { - direction = ' and slightly dropping'; - } else if (records[0].direction === 'FortyFiveUp') { - direction = ' and slightly rising'; - } else if (records[0].direction === 'Flat') { - direction = ' and holding'; - } else if (records[0].direction === 'SingleUp') { - direction = ' and rising'; - } else if (records[0].direction === 'SingleDown') { - direction = ' and dropping'; - } else if (records[0].direction === 'DoubleDown') { - direction = ' and rapidly dropping'; - } else if (records[0].direction === 'DoubleUp') { - direction = ' and rapidly rising'; + if (plugin.virtAsst.rollupHandlers) { + console.log('Plugin ' + plugin.name + ' supports rollups for Virtual Assistants'); + _each(plugin.virtAsst.rollupHandlers, function (route) { + console.log('Route'); + console.log(route); + if (route) { + ctx.googleHome.addToRollup(route.rollupGroup, route.rollupHandler, route.rollupName); } - response = buildPreamble(result.parameters); - response += sbx.scaleMgdl(records[0].sgv) + direction + ' as of ' + moment(records[0].date).from(moment(sbx.time)); - } else { - response = buildPreamble(result.parameters) + 'unknown'; - } - next(response); - }); - }, 'metric', ['bg', 'blood glucose', 'blood sugar', 'number']); - - api.post('/googlehome', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) { - console.log('Incoming request from Google Home'); - onIntent(req.body, function (response) { - res.json(ctx.googleHome.buildResponse(response)); - next(); - }); - }); - - function buildPreamble(parameters) { - var preamble = ''; - if (parameters && parameters.givenName) { - preamble = parameters.givenName + '\'s current '; - } else { - preamble = 'Your current '; + }); } - if (parameters && parameters.readingType) { - preamble += parameters.readingType + ' is '; - } else { - preamble += 'blood glucose is '; + } else { + console.log('Plugin ' + plugin.name + ' does not support Virtual Assistants'); + } + }); + + 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; + if(locale){ + if(locale.length > 2) { + locale = locale.substr(0, 2); } - return preamble; + ctx.language.set(locale); + moment.locale(locale); } - function onIntent(body, next) { - console.log('Received intent request'); - console.log(JSON.stringify(body)); - handleIntent(body, next); + var handler = ctx.googleHome.getIntentHandler(req.body.queryResult.intent.displayName, req.body.queryResult.parameters); + if (handler){ + var sbx = initializeSandbox(); + handler(function (title, response) { + res.json(ctx.googleHome.buildSpeechletResponse(response, false)); + next( ); + }, req.body.queryResult.parameters, sbx); + } else { + res.json(ctx.googleHome.buildSpeechletResponse('I\'m sorry. I don\'t know what you\'re asking for. Could you say that again?', true)); + next( ); } + }); - // https://docs.api.ai/docs/webhook#section-format-of-request-to-the-service - function handleIntent(body, next) { - var displayName = body.queryResult.intent.displayName; - var metric = body.queryResult.parameters ? body.queryResult.parameters.metric : null; - var handler = ctx.googleHome.getIntentHandler(displayName, metric); - if (handler) { - var sbx = initializeSandbox(); - handler(body.queryResult, next, sbx); + ctx.googleHome.addToRollup('Status', function bgRollupHandler(slots, sbx, callback) { + entries.list({count: 1}, function (err, records) { + var direction; + if (translate(records[0].direction)) { + direction = translate(records[0].direction); } else { - next('I\'m sorry I don\'t know what you\'re asking for'); + direction = records[0].direction; } - } + var status = translate('virtAsstStatus', { + params: [ + sbx.scaleMgdl(records[0].sgv), + direction, + moment(records[0].date).from(moment(sbx.time)) + ] + }); + + callback(null, {results: status, priority: -1}); + }); + }, 'BG Status'); - function initializeSandbox() { - var sbx = require('../../sandbox')(); - sbx.serverInit(env, ctx); - ctx.plugins.setProperties(sbx); - return sbx; - } + ctx.googleHome.configureIntentHandler('MetricNow', function (callback, slots, sbx, locale) { + entries.list({count: 1}, function(err, records) { + var direction; + if(translate(records[0].direction)){ + direction = translate(records[0].direction); + } else { + direction = records[0].direction; + } + var status = translate('virtAsstStatus', { + params: [ + sbx.scaleMgdl(records[0].sgv), + direction, + moment(records[0].date).from(moment(sbx.time))] + }); + + callback('Current blood glucose', status); + }); + }, 'metric', ['bg', 'blood glucose', 'number']); + + ctx.googleHome.configureIntentHandler('NSStatus', function (callback, slots, sbx, locale) { + ctx.googleHome.getRollup('Status', sbx, slots, locale, function (status) { + callback('Full status', status); + }); + }); + + function initializeSandbox() { + var sbx = require('../../sandbox')(); + sbx.serverInit(env, ctx); + ctx.plugins.setProperties(sbx); + return sbx; + } - return api; + return api; } module.exports = configure; \ No newline at end of file diff --git a/lib/plugins/googlehome.js b/lib/plugins/googlehome.js index 655b6a485ff..27f7d98c7ac 100644 --- a/lib/plugins/googlehome.js +++ b/lib/plugins/googlehome.js @@ -1,20 +1,26 @@ +var _ = require('lodash'); +var async = require('async'); function init (env, ctx) { - console.log('Configuring Google Home...'); function googleHome() { return googleHome; } - var intentHandlers = {}; + var rollup = {}; + // This configures a router/handler. A routable slot the name of a slot that you wish to route on and the slotValues + // are the values that determine the routing. This allows for specific intent handlers based on the value of a + // specific slot. Routing is only supported on one slot for now. + // There is no protection for a previously configured handler - one plugin can overwrite the handler of another + // plugin. googleHome.configureIntentHandler = function configureIntentHandler(intent, handler, routableSlot, slotValues) { - if (!intentHandlers[intent]) { + if (! intentHandlers[intent]) { intentHandlers[intent] = {}; } if (routableSlot && slotValues) { for (var i = 0, len = slotValues.length; i < len; i++) { - if (!intentHandlers[intent][routableSlot]) { + if (! intentHandlers[intent][routableSlot]) { intentHandlers[intent][routableSlot] = {}; } if (!intentHandlers[intent][routableSlot][slotValues[i]]) { @@ -27,32 +33,75 @@ function init (env, ctx) { } }; - googleHome.getIntentHandler = function getIntentHandler(intentName, metric) { + // This function retrieves a handler based on the intent name and slots requested. + googleHome.getIntentHandler = function getIntentHandler(intentName, slots) { if (intentName && intentHandlers[intentName]) { - if (metric && intentHandlers[intentName]['metric'] && - intentHandlers[intentName]['metric'][metric] && - intentHandlers[intentName]['metric'][metric].handler) { - return intentHandlers[intentName]['metric'][metric].handler; - } else if (intentHandlers[intentName].handler) { + if (slots) { + var slotKeys = Object.keys(slots); + for (var i = 0, len = slotKeys.length; i < len; i++) { + if (intentHandlers[intentName][slotKeys[i]] && slots[slotKeys[i]].value && + intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value] && + intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value].handler) { + + return intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value].handler; + } + } + } + if (intentHandlers[intentName].handler) { return intentHandlers[intentName].handler; - } else { - return null; } + return null; } else { return null; } }; - googleHome.buildResponse = function buildResponse(output) { + googleHome.addToRollup = function(rollupGroup, handler, rollupName) { + if (!rollup[rollupGroup]) { + console.log('Creating the rollup group: ', rollupGroup); + rollup[rollupGroup] = []; + } + rollup[rollupGroup].push({handler: handler, name: rollupName}); + }; + + googleHome.getRollup = function(rollupGroup, sbx, slots, locale, callback) { + var handlers = _.map(rollup[rollupGroup], 'handler'); + console.log('Rollup array for ', rollupGroup); + console.log(rollup[rollupGroup]); + var nHandlers = []; + _.each(handlers, function (handler) { + nHandlers.push(handler.bind(null, slots, sbx)); + }); + async.parallelLimit(nHandlers, 10, function(err, results) { + if (err) { + console.error('Error: ', err); + } + callback(_.map(_.orderBy(results, ['priority'], ['asc']), 'results').join(' ')); + }); + }; + + // This creates the expected Google Home response + googleHome.buildSpeechletResponse = function buildSpeechletResponse(output, expectUserResponse) { return { - fulfillmentText: output -// , fulfillmentMessages: [output] - , source: 'Nightscout' + payload: { + google: { + expectUserResponse: expectUserResponse, + richResponse: { + items: [ + { + simpleResponse: { + textToSpeech: output + } + } + ] + } + } + } }; }; return googleHome; } - - module.exports = init; \ No newline at end of file + +module.exports = init; \ No newline at end of file From b39eb8f672cea607119e9af1bed85d30e1b12f57 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 19:49:32 -0600 Subject: [PATCH 10/48] Changed order of operations --- lib/api/googlehome/index.js | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js index 5cd791d0488..5de70cae25e 100644 --- a/lib/api/googlehome/index.js +++ b/lib/api/googlehome/index.js @@ -41,30 +41,6 @@ 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; - if(locale){ - if(locale.length > 2) { - locale = locale.substr(0, 2); - } - ctx.language.set(locale); - moment.locale(locale); - } - - var handler = ctx.googleHome.getIntentHandler(req.body.queryResult.intent.displayName, req.body.queryResult.parameters); - if (handler){ - var sbx = initializeSandbox(); - handler(function (title, response) { - res.json(ctx.googleHome.buildSpeechletResponse(response, false)); - next( ); - }, req.body.queryResult.parameters, sbx); - } else { - res.json(ctx.googleHome.buildSpeechletResponse('I\'m sorry. I don\'t know what you\'re asking for. Could you say that again?', true)); - next( ); - } - }); - ctx.googleHome.addToRollup('Status', function bgRollupHandler(slots, sbx, callback) { entries.list({count: 1}, function (err, records) { var direction; @@ -117,6 +93,30 @@ function configure (app, wares, ctx, env) { return sbx; } + 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; + if(locale){ + if(locale.length > 2) { + locale = locale.substr(0, 2); + } + ctx.language.set(locale); + moment.locale(locale); + } + + var handler = ctx.googleHome.getIntentHandler(req.body.queryResult.intent.displayName, req.body.queryResult.parameters); + if (handler){ + var sbx = initializeSandbox(); + handler(function (title, response) { + res.json(ctx.googleHome.buildSpeechletResponse(response, false)); + next( ); + }, req.body.queryResult.parameters, sbx); + } else { + res.json(ctx.googleHome.buildSpeechletResponse('I\'m sorry. I don\'t know what you\'re asking for. Could you say that again?', true)); + next( ); + } + }); + return api; } From 8a200151e0b6ef12171d9b6be9efb8a4c92bd214 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 20:10:27 -0600 Subject: [PATCH 11/48] Fixed parameter referencing in googlehome --- lib/api/googlehome/index.js | 48 ++++++++++++++++++------------------- lib/plugins/googlehome.js | 18 +++++++------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js index 5de70cae25e..5cd791d0488 100644 --- a/lib/api/googlehome/index.js +++ b/lib/api/googlehome/index.js @@ -41,6 +41,30 @@ 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; + if(locale){ + if(locale.length > 2) { + locale = locale.substr(0, 2); + } + ctx.language.set(locale); + moment.locale(locale); + } + + var handler = ctx.googleHome.getIntentHandler(req.body.queryResult.intent.displayName, req.body.queryResult.parameters); + if (handler){ + var sbx = initializeSandbox(); + handler(function (title, response) { + res.json(ctx.googleHome.buildSpeechletResponse(response, false)); + next( ); + }, req.body.queryResult.parameters, sbx); + } else { + res.json(ctx.googleHome.buildSpeechletResponse('I\'m sorry. I don\'t know what you\'re asking for. Could you say that again?', true)); + next( ); + } + }); + ctx.googleHome.addToRollup('Status', function bgRollupHandler(slots, sbx, callback) { entries.list({count: 1}, function (err, records) { var direction; @@ -93,30 +117,6 @@ function configure (app, wares, ctx, env) { return sbx; } - 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; - if(locale){ - if(locale.length > 2) { - locale = locale.substr(0, 2); - } - ctx.language.set(locale); - moment.locale(locale); - } - - var handler = ctx.googleHome.getIntentHandler(req.body.queryResult.intent.displayName, req.body.queryResult.parameters); - if (handler){ - var sbx = initializeSandbox(); - handler(function (title, response) { - res.json(ctx.googleHome.buildSpeechletResponse(response, false)); - next( ); - }, req.body.queryResult.parameters, sbx); - } else { - res.json(ctx.googleHome.buildSpeechletResponse('I\'m sorry. I don\'t know what you\'re asking for. Could you say that again?', true)); - next( ); - } - }); - return api; } diff --git a/lib/plugins/googlehome.js b/lib/plugins/googlehome.js index 27f7d98c7ac..2f721cf887d 100644 --- a/lib/plugins/googlehome.js +++ b/lib/plugins/googlehome.js @@ -33,17 +33,17 @@ function init (env, ctx) { } }; - // This function retrieves a handler based on the intent name and slots requested. - googleHome.getIntentHandler = function getIntentHandler(intentName, slots) { + // This function retrieves a handler based on the intent name and parameters requested. + googleHome.getIntentHandler = function getIntentHandler(intentName, parameters) { if (intentName && intentHandlers[intentName]) { - if (slots) { - var slotKeys = Object.keys(slots); - for (var i = 0, len = slotKeys.length; i < len; i++) { - if (intentHandlers[intentName][slotKeys[i]] && slots[slotKeys[i]].value && - intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value] && - intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value].handler) { + if (parameters) { + var parameterKeys = Object.keys(parameters); + for (var i = 0, len = parameterKeys.length; i < len; i++) { + if (intentHandlers[intentName][parameterKeys[i]] && parameters[parameterKeys[i]] && + intentHandlers[intentName][parameterKeys[i]][parameters[parameterKeys[i]]] && + intentHandlers[intentName][parameterKeys[i]][parameters[parameterKeys[i]]].handler) { - return intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value].handler; + return intentHandlers[intentName][parameterKeys[i]][parameters[parameterKeys[i]]].handler; } } } From 90562a336de375147230a4fe0b239cccba92272e Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 20:21:28 -0600 Subject: [PATCH 12/48] Yet another CONTRIBUTING fix --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 79266e47c82..a4674b241bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -251,7 +251,7 @@ Languages with less than 90% coverage will be removed in a future Nightscout ver | Čeština (`cs`) |Please volunteer|OK | | Deutsch (`de`) |[@viderehh] [@herzogmedia] |OK | | Dansk (`dk`) | [@janrpn] |OK | -| Ελληνικά `el`)|Please volunteer|Needs attention: 68.5%| +| Ελληνικά (`el`)|Please volunteer|Needs attention: 68.5%| | English (`en`)|Please volunteer|OK| | Español (`es`) |Please volunteer|OK| | Suomi (`fi`)|[@sulkaharo] |OK| From 855b64dac02fa482884595d5a6d938610c51bea6 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 20:30:52 -0600 Subject: [PATCH 13/48] Removed extra google stuff --- lib/plugins/basalprofile.js | 14 -------------- lib/plugins/cob.js | 19 ------------------- lib/plugins/iob.js | 15 --------------- lib/plugins/openaps.js | 24 ------------------------ 4 files changed, 72 deletions(-) diff --git a/lib/plugins/basalprofile.js b/lib/plugins/basalprofile.js index 10f27145fdc..5d29cda3d13 100644 --- a/lib/plugins/basalprofile.js +++ b/lib/plugins/basalprofile.js @@ -156,20 +156,6 @@ function init (ctx) { }] }; - function googleHomeCurrentBasalhandler (result, next, sbx) { - var pwd = result.parameters && result.parameters.givenName ? result.parameters.givenName : null; - next(basalMessage(pwd, sbx)); - } - - basal.googleHome = { - intentHandlers: [{ - intent: 'CurrentMetric' - , routableSlot:'metric' - , slots:['basal', 'current basal'] - , intentHandler: googleHomeCurrentBasalhandler - }] - }; - return basal; } diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index 8706e182444..51af7391e40 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -308,25 +308,6 @@ function init (ctx) { }] }; - function googleHomeCOBHandler(result, next, sbx) { - var preamble = result && result.parameters && result.parameters.givenName ? result.parameters.givenName + ' has' : 'You have'; - var value = 'no'; - if (sbx.properties.cob && sbx.properties.cob.cob !== 0) { - value = Math.round(sbx.properties.cob.cob); - } - var response = preamble + ' ' + value + ' carbohydrates on board'; - next(response); - } - - cob.googleHome = { - intentHandlers: [{ - intent: 'CurrentMetric' - , routableSlot:'metric' - , slots:['cob', 'carbs on board', 'carbohydrates on board', 'carbohydrates'] - , intentHandler: googleHomeCOBHandler - }] - }; - return cob; } diff --git a/lib/plugins/iob.js b/lib/plugins/iob.js index 0b9a5ff5576..12d4548e81e 100644 --- a/lib/plugins/iob.js +++ b/lib/plugins/iob.js @@ -288,21 +288,6 @@ function init(ctx) { }] }; - function googleHomeIOBIntentHandler(result, next, sbx) { - var preamble = result && result.parameters && result.parameters.givenName ? result.parameters.givenName + ' has ' : 'You have '; - var message = preamble + getIob(sbx) + ' insulin on board'; - next(message); - } - - iob.googleHome = { - intentHandlers: [{ - intent: 'CurrentMetric' - , routableSlot: 'metric' - , slots: ['iob', 'insulin on board', 'insulin'] - , intentHandler: googleHomeIOBIntentHandler - }] - }; - return iob; } diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 1ae4741285e..e28bf1453ce 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -543,30 +543,6 @@ function init (ctx) { }] }; - function googleHomeForecastHandler(response, next, sbx) { - if (sbx.properties.openaps && sbx.properties.openaps.lastEventualBG) { - var response = 'The Open APS eventual BG is ' + sbx.properties.openaps.lastEventualBG; - next(response); - } - } - - function googleHomeLastLoopHandler (response, next, sbx) { - var response = 'The last successful loop was ' + moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time)); - next(response); - } - - openaps.googleHome = { - intentHandlers: [{ - intent: 'CurrentMetric' - , routableSlot: 'metric' - , slots: ['openaps', 'openaps forecast', 'forecast'] - , intentHandler: googleHomeForecastHandler - }, { - intent: 'LastLoop' - , intentHandler: googleHomeLastLoopHandler - }] - }; - function statusClass (prop, prefs, sbx) { var level = statusLevel(prop, prefs, sbx); return levels.toStatusClass(level); From 223806701c3069076a974ac22f3dc4f3542d1392 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 21:55:42 -0600 Subject: [PATCH 14/48] Migrated standalone intents to MetricNow intent --- lib/plugins/basalprofile.js | 4 ++-- lib/plugins/pump.js | 31 ++++++++++++++++++++++++------- lib/plugins/upbat.js | 17 +++++++++++++---- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/lib/plugins/basalprofile.js b/lib/plugins/basalprofile.js index 5d29cda3d13..06a2ebd288d 100644 --- a/lib/plugins/basalprofile.js +++ b/lib/plugins/basalprofile.js @@ -150,8 +150,8 @@ function init (ctx) { }], intentHandlers: [{ intent: 'MetricNow' - , routableSlot:'metric' - , slots:['basal', 'current basal'] + , routableSlot: 'metric' + , slots: ['basal', 'current basal'] , intentHandler: virtAsstCurrentBasalhandler }] }; diff --git a/lib/plugins/pump.js b/lib/plugins/pump.js index b63c69bb2c3..6b8c0a7c76e 100644 --- a/lib/plugins/pump.js +++ b/lib/plugins/pump.js @@ -160,13 +160,30 @@ function init (ctx) { } pump.virtAsst = { - intentHandlers:[{ - intent: 'InsulinRemaining', - intentHandler: virtAsstReservoirHandler - }, { - intent: 'PumpBattery', - intentHandler: virtAsstBatteryHandler - }] + intentHandlers:[ + { + // backwards compatibility + intent: 'InsulinRemaining', + intentHandler: virtAsstReservoirHandler + } + , { + // backwards compatibility + intent: 'PumpBattery', + intentHandler: virtAsstBatteryHandler + } + , { + intent: 'MetricNow' + , routableSlot: 'metric' + , slots: ['pump reservoir'] + , intentHandler: virtAsstReservoirHandler + } + , { + intent: 'MetricNow' + , routableSlot: 'metric' + , slots: ['pump battery'] + , intentHandler: virtAsstBatteryHandler + } + ] }; function statusClass (level) { diff --git a/lib/plugins/upbat.js b/lib/plugins/upbat.js index 72c3bce2021..b21bc190a77 100644 --- a/lib/plugins/upbat.js +++ b/lib/plugins/upbat.js @@ -227,10 +227,19 @@ function init() { } upbat.virtAsst = { - intentHandlers: [{ - intent: 'UploaderBattery' - , intentHandler: virtAsstUploaderBatteryHandler - }] + intentHandlers: [ + { + // for backwards compatibility + intent: 'UploaderBattery' + , intentHandler: virtAsstUploaderBatteryHandler + } + , { + intent: 'MetricNow' + , routableSlot: 'metric' + , slots: ['uploader battery'] + , intentHandler: virtAsstUploaderBatteryHandler + } + ] }; return upbat; From b3a47b36e02d70af40bbe0099186e5cd7b321381 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 23:39:17 -0600 Subject: [PATCH 15/48] Simplified route handling --- lib/api/alexa/index.js | 10 ++++---- lib/api/googlehome/index.js | 4 ++-- lib/plugins/alexa.js | 47 +++++++++++++------------------------ lib/plugins/ar2.js | 3 +-- lib/plugins/basalprofile.js | 4 +--- lib/plugins/cob.js | 3 +-- lib/plugins/googlehome.js | 44 ++++++++++++---------------------- lib/plugins/iob.js | 3 +-- lib/plugins/loop.js | 3 +-- lib/plugins/openaps.js | 3 +-- lib/plugins/pump.js | 6 ++--- lib/plugins/rawbg.js | 3 +-- lib/plugins/upbat.js | 3 +-- 13 files changed, 48 insertions(+), 88 deletions(-) diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index 61f343a38f6..c919d4544ff 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -22,7 +22,7 @@ function configure (app, wares, ctx, env) { console.log('Plugin ' + plugin.name + ' supports Virtual Assistants'); _each(plugin.virtAsst.intentHandlers, function (route) { if (route) { - ctx.alexa.configureIntentHandler(route.intent, route.intentHandler, route.routableSlot, route.slots); + ctx.alexa.configureIntentHandler(route.intent, route.intentHandler, route.metrics); } }); } @@ -111,7 +111,7 @@ function configure (app, wares, ctx, env) { callback('Current blood glucose', status); }); - }, 'metric', ['bg', 'blood glucose', 'number']); + }, ['bg', 'blood glucose', 'number']); ctx.alexa.configureIntentHandler('NSStatus', function (callback, slots, sbx, locale) { ctx.alexa.getRollup('Status', sbx, slots, locale, function (status) { @@ -135,12 +135,12 @@ function configure (app, wares, ctx, env) { } function handleIntent(intentName, slots, next) { - var handler = ctx.alexa.getIntentHandler(intentName, slots); + var handler = ctx.alexa.getIntentHandler(intentName, slots.metric.value); if (handler){ var sbx = initializeSandbox(); handler(next, slots, sbx); } else { - next('Unknown Intent', 'I\'m sorry I don\'t know what you\'re asking for'); + next('Unknown Intent', 'I\'m sorry. I don\'t know what you\'re asking for.'); } } @@ -154,4 +154,4 @@ function configure (app, wares, ctx, env) { return api; } -module.exports = configure; +module.exports = configure; \ No newline at end of file diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js index 5cd791d0488..35571e94193 100644 --- a/lib/api/googlehome/index.js +++ b/lib/api/googlehome/index.js @@ -22,7 +22,7 @@ function configure (app, wares, ctx, env) { console.log('Plugin ' + plugin.name + ' supports Virtual Assistants'); _each(plugin.virtAsst.intentHandlers, function (route) { if (route) { - ctx.googleHome.configureIntentHandler(route.intent, route.intentHandler, route.routableSlot, route.slots); + ctx.googleHome.configureIntentHandler(route.intent, route.intentHandler, route.metrics); } }); } @@ -102,7 +102,7 @@ function configure (app, wares, ctx, env) { callback('Current blood glucose', status); }); - }, 'metric', ['bg', 'blood glucose', 'number']); + }, ['bg', 'blood glucose', 'number']); ctx.googleHome.configureIntentHandler('NSStatus', function (callback, slots, sbx, locale) { ctx.googleHome.getRollup('Status', sbx, slots, locale, function (status) { diff --git a/lib/plugins/alexa.js b/lib/plugins/alexa.js index bfb8cf6308f..65721cd3193 100644 --- a/lib/plugins/alexa.js +++ b/lib/plugins/alexa.js @@ -9,52 +9,38 @@ function init (env, ctx) { var intentHandlers = {}; var rollup = {}; - // This configures a router/handler. A routable slot the name of a slot that you wish to route on and the slotValues - // are the values that determine the routing. This allows for specific intent handlers based on the value of a - // specific slot. Routing is only supported on one slot for now. - // There is no protection for a previously configured handler - one plugin can overwrite the handler of another - // plugin. - alexa.configureIntentHandler = function configureIntentHandler(intent, handler, routableSlot, slotValues) { - if (! intentHandlers[intent]) { + // There is no protection for a previously handled metric - one plugin can overwrite the handler of another plugin. + alexa.configureIntentHandler = function configureIntentHandler(intent, handler, metrics) { + if (!intentHandlers[intent]) { intentHandlers[intent] = {}; } - if (routableSlot && slotValues) { - for (var i = 0, len = slotValues.length; i < len; i++) { - if (! intentHandlers[intent][routableSlot]) { - intentHandlers[intent][routableSlot] = {}; + if (metrics) { + for (var i = 0, len = metrics.length; i < len; i++) { + if (!intentHandlers[intent]) { + intentHandlers[intent] = {}; } - if (!intentHandlers[intent][routableSlot][slotValues[i]]) { - intentHandlers[intent][routableSlot][slotValues[i]] = {}; + if (!intentHandlers[intent][metrics[i]]) { + intentHandlers[intent][metrics[i]] = {}; } - intentHandlers[intent][routableSlot][slotValues[i]].handler = handler; + intentHandlers[intent][metrics[i]].handler = handler; } } else { intentHandlers[intent].handler = handler; } }; - // This function retrieves a handler based on the intent name and slots requested. - alexa.getIntentHandler = function getIntentHandler(intentName, slots) { + // This function retrieves a handler based on the intent name and metric requested. + alexa.getIntentHandler = function getIntentHandler(intentName, metric) { if (intentName && intentHandlers[intentName]) { - if (slots) { - var slotKeys = Object.keys(slots); - for (var i = 0, len = slotKeys.length; i < len; i++) { - if (intentHandlers[intentName][slotKeys[i]] && slots[slotKeys[i]].value && - intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value] && - intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value].handler) { - - return intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value].handler; - } - } - } - if (intentHandlers[intentName].handler) { + if (intentHandlers[intentName][metric] && intentHandlers[intentName][metric].handler) { + return intentHandlers[intentName][metric].handler + } else if (intentHandlers[intentName].handler) { return intentHandlers[intentName].handler; } return null; } else { return null; } - }; alexa.addToRollup = function(rollupGroup, handler, rollupName) { @@ -63,7 +49,6 @@ function init (env, ctx) { rollup[rollupGroup] = []; } rollup[rollupGroup].push({handler: handler, name: rollupName}); - // status = _.orderBy(status, ['priority'], ['asc']) }; alexa.getRollup = function(rollupGroup, sbx, slots, locale, callback) { @@ -110,4 +95,4 @@ function init (env, ctx) { return alexa; } -module.exports = init; +module.exports = init; \ No newline at end of file diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js index 24fe192cac3..78b0d10e0ba 100644 --- a/lib/plugins/ar2.js +++ b/lib/plugins/ar2.js @@ -173,8 +173,7 @@ function init (ctx) { ar2.virtAsst = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['ar2 forecast', 'forecast'] + , metrics: ['ar2 forecast', 'forecast'] , intentHandler: virtAsstAr2Handler }] }; diff --git a/lib/plugins/basalprofile.js b/lib/plugins/basalprofile.js index 06a2ebd288d..e229ff0fac4 100644 --- a/lib/plugins/basalprofile.js +++ b/lib/plugins/basalprofile.js @@ -150,8 +150,7 @@ function init (ctx) { }], intentHandlers: [{ intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['basal', 'current basal'] + , metrics: ['basal', 'current basal'] , intentHandler: virtAsstCurrentBasalhandler }] }; @@ -159,5 +158,4 @@ function init (ctx) { return basal; } - module.exports = init; diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index 51af7391e40..3bed71a6c36 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -302,8 +302,7 @@ function init (ctx) { cob.virtAsst = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['cob', 'carbs on board', 'carbohydrates on board'] + , metrics: ['cob', 'carbs on board', 'carbohydrates on board'] , intentHandler: virtAsstCOBHandler }] }; diff --git a/lib/plugins/googlehome.js b/lib/plugins/googlehome.js index 2f721cf887d..b0d5230ff0d 100644 --- a/lib/plugins/googlehome.js +++ b/lib/plugins/googlehome.js @@ -9,52 +9,38 @@ function init (env, ctx) { var intentHandlers = {}; var rollup = {}; - // This configures a router/handler. A routable slot the name of a slot that you wish to route on and the slotValues - // are the values that determine the routing. This allows for specific intent handlers based on the value of a - // specific slot. Routing is only supported on one slot for now. - // There is no protection for a previously configured handler - one plugin can overwrite the handler of another - // plugin. - googleHome.configureIntentHandler = function configureIntentHandler(intent, handler, routableSlot, slotValues) { - if (! intentHandlers[intent]) { + // There is no protection for a previously handled metric - one plugin can overwrite the handler of another plugin. + googleHome.configureIntentHandler = function configureIntentHandler(intent, handler, metrics) { + if (!intentHandlers[intent]) { intentHandlers[intent] = {}; } - if (routableSlot && slotValues) { - for (var i = 0, len = slotValues.length; i < len; i++) { - if (! intentHandlers[intent][routableSlot]) { - intentHandlers[intent][routableSlot] = {}; + if (metrics) { + for (var i = 0, len = metrics.length; i < len; i++) { + if (! intentHandlers[intent]) { + intentHandlers[intent] = {}; } - if (!intentHandlers[intent][routableSlot][slotValues[i]]) { - intentHandlers[intent][routableSlot][slotValues[i]] = {}; + if (!intentHandlers[intent][metrics[i]]) { + intentHandlers[intent][metrics[i]] = {}; } - intentHandlers[intent][routableSlot][slotValues[i]].handler = handler; + intentHandlers[intent][metrics[i]].handler = handler; } } else { intentHandlers[intent].handler = handler; } }; - // This function retrieves a handler based on the intent name and parameters requested. - googleHome.getIntentHandler = function getIntentHandler(intentName, parameters) { + // This function retrieves a handler based on the intent name and metric requested. + googleHome.getIntentHandler = function getIntentHandler(intentName, metric) { if (intentName && intentHandlers[intentName]) { - if (parameters) { - var parameterKeys = Object.keys(parameters); - for (var i = 0, len = parameterKeys.length; i < len; i++) { - if (intentHandlers[intentName][parameterKeys[i]] && parameters[parameterKeys[i]] && - intentHandlers[intentName][parameterKeys[i]][parameters[parameterKeys[i]]] && - intentHandlers[intentName][parameterKeys[i]][parameters[parameterKeys[i]]].handler) { - - return intentHandlers[intentName][parameterKeys[i]][parameters[parameterKeys[i]]].handler; - } - } - } - if (intentHandlers[intentName].handler) { + if (intentHandlers[intentName][metric] && intentHandlers[intentName][metric].handler) { + return intentHandlers[intentName][metric].handler + } else if (intentHandlers[intentName].handler) { return intentHandlers[intentName].handler; } return null; } else { return null; } - }; googleHome.addToRollup = function(rollupGroup, handler, rollupName) { diff --git a/lib/plugins/iob.js b/lib/plugins/iob.js index 12d4548e81e..567968cd5e2 100644 --- a/lib/plugins/iob.js +++ b/lib/plugins/iob.js @@ -282,8 +282,7 @@ function init(ctx) { }] , intentHandlers: [{ intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['iob', 'insulin on board'] + , metrics: ['iob', 'insulin on board'] , intentHandler: virtAsstIOBIntentHandler }] }; diff --git a/lib/plugins/loop.js b/lib/plugins/loop.js index c94e969a7ca..7b30eafb644 100644 --- a/lib/plugins/loop.js +++ b/lib/plugins/loop.js @@ -474,8 +474,7 @@ function init (ctx) { loop.virtAsst = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['loop forecast', 'forecast'] + , metrics: ['loop forecast', 'forecast'] , intentHandler: virtAsstForecastHandler }, { intent: 'LastLoop' diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index e28bf1453ce..0865b3352fe 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -534,8 +534,7 @@ function init (ctx) { openaps.virtAsst = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['openaps forecast', 'forecast'] + , metrics: ['openaps forecast', 'forecast'] , intentHandler: virtAsstForecastHandler }, { intent: 'LastLoop' diff --git a/lib/plugins/pump.js b/lib/plugins/pump.js index 6b8c0a7c76e..a2d95a68c9d 100644 --- a/lib/plugins/pump.js +++ b/lib/plugins/pump.js @@ -173,14 +173,12 @@ function init (ctx) { } , { intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['pump reservoir'] + , metrics: ['pump reservoir'] , intentHandler: virtAsstReservoirHandler } , { intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['pump battery'] + , metrics: ['pump battery'] , intentHandler: virtAsstBatteryHandler } ] diff --git a/lib/plugins/rawbg.js b/lib/plugins/rawbg.js index 2bfea16ba73..91ebdb849dd 100644 --- a/lib/plugins/rawbg.js +++ b/lib/plugins/rawbg.js @@ -114,8 +114,7 @@ function init (ctx) { rawbg.virtAsst = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot:'metric' - , slots:['raw bg', 'raw blood glucose'] + , metrics:['raw bg', 'raw blood glucose'] , intentHandler: virtAsstRawBGHandler }] }; diff --git a/lib/plugins/upbat.js b/lib/plugins/upbat.js index b21bc190a77..509d9347f89 100644 --- a/lib/plugins/upbat.js +++ b/lib/plugins/upbat.js @@ -235,8 +235,7 @@ function init() { } , { intent: 'MetricNow' - , routableSlot: 'metric' - , slots: ['uploader battery'] + , metrics: ['uploader battery'] , intentHandler: virtAsstUploaderBatteryHandler } ] From 79f021701140c3ff0d00226f7d180ed041d8b60a Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 7 Sep 2019 23:55:26 -0600 Subject: [PATCH 16/48] Added logging --- lib/plugins/alexa.js | 10 +++++++--- lib/plugins/googlehome.js | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/plugins/alexa.js b/lib/plugins/alexa.js index 65721cd3193..d41aa567885 100644 --- a/lib/plugins/alexa.js +++ b/lib/plugins/alexa.js @@ -16,29 +16,33 @@ function init (env, ctx) { } if (metrics) { for (var i = 0, len = metrics.length; i < len; i++) { - if (!intentHandlers[intent]) { - intentHandlers[intent] = {}; - } if (!intentHandlers[intent][metrics[i]]) { intentHandlers[intent][metrics[i]] = {}; } + console.log('Storing handler for intent \'' + intent + '\' for metric \'' + metrics[i] + '\''); intentHandlers[intent][metrics[i]].handler = handler; } } else { + console.log('Storing handler for intent \'' + intent + '\''); intentHandlers[intent].handler = handler; } }; // This function retrieves a handler based on the intent name and metric requested. alexa.getIntentHandler = function getIntentHandler(intentName, metric) { + console.log('Looking for handler for intent \'' + intentName + '\' for metric \'' + metric + '\''); if (intentName && intentHandlers[intentName]) { if (intentHandlers[intentName][metric] && intentHandlers[intentName][metric].handler) { + console.log('Found!'); return intentHandlers[intentName][metric].handler } else if (intentHandlers[intentName].handler) { + console.log('Found!'); return intentHandlers[intentName].handler; } + console.log('Not found!'); return null; } else { + console.log('Not found!'); return null; } }; diff --git a/lib/plugins/googlehome.js b/lib/plugins/googlehome.js index b0d5230ff0d..8e8181512c8 100644 --- a/lib/plugins/googlehome.js +++ b/lib/plugins/googlehome.js @@ -16,29 +16,33 @@ function init (env, ctx) { } if (metrics) { for (var i = 0, len = metrics.length; i < len; i++) { - if (! intentHandlers[intent]) { - intentHandlers[intent] = {}; - } if (!intentHandlers[intent][metrics[i]]) { intentHandlers[intent][metrics[i]] = {}; } + console.log('Storing handler for intent \'' + intent + '\' for metric \'' + metrics[i] + '\''); intentHandlers[intent][metrics[i]].handler = handler; } } else { + console.log('Storing handler for intent \'' + intent + '\''); intentHandlers[intent].handler = handler; } }; // This function retrieves a handler based on the intent name and metric requested. googleHome.getIntentHandler = function getIntentHandler(intentName, metric) { + console.log('Looking for handler for intent \'' + intentName + '\' for metric \'' + metric + '\''); if (intentName && intentHandlers[intentName]) { if (intentHandlers[intentName][metric] && intentHandlers[intentName][metric].handler) { + console.log('Found!'); return intentHandlers[intentName][metric].handler } else if (intentHandlers[intentName].handler) { + console.log('Found!'); return intentHandlers[intentName].handler; } + console.log('Not found!'); return null; } else { + console.log('Not found!'); return null; } }; From cc56ef822dbbb91feec6950e8376abddd2c7d9ee Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sun, 8 Sep 2019 00:03:32 -0600 Subject: [PATCH 17/48] Added forgotten path selector --- lib/api/googlehome/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js index 35571e94193..a18a2b17371 100644 --- a/lib/api/googlehome/index.js +++ b/lib/api/googlehome/index.js @@ -52,7 +52,7 @@ function configure (app, wares, ctx, env) { moment.locale(locale); } - var handler = ctx.googleHome.getIntentHandler(req.body.queryResult.intent.displayName, req.body.queryResult.parameters); + var handler = ctx.googleHome.getIntentHandler(req.body.queryResult.intent.displayName, req.body.queryResult.parameters.metric); if (handler){ var sbx = initializeSandbox(); handler(function (title, response) { From 0b1ce34b25b5f0483697aae1a523e08882c84100 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sun, 8 Sep 2019 00:48:28 -0600 Subject: [PATCH 18/48] Separated instructions for adding virtual assistant support in a plugin --- ...add-virtual-assistant-support-to-plugin.md | 52 +++++++++++++++ docs/plugins/alexa-plugin.md | 63 ++----------------- docs/plugins/googlehome-plugin.md | 6 +- 3 files changed, 61 insertions(+), 60 deletions(-) create mode 100644 docs/plugins/add-virtual-assistant-support-to-plugin.md diff --git a/docs/plugins/add-virtual-assistant-support-to-plugin.md b/docs/plugins/add-virtual-assistant-support-to-plugin.md new file mode 100644 index 00000000000..eccb9b4ae33 --- /dev/null +++ b/docs/plugins/add-virtual-assistant-support-to-plugin.md @@ -0,0 +1,52 @@ +Adding Virtual Assistant Support to a Plugin +========================================= + +To add virtual assistant support to a plugin, the `init` method should return an object that contains a `virtAsst` key. Here is an example: + +```javascript +iob.virtAsst = { + intentHandlers: [{ + intent: "MetricNow" + , metrics: ["iob"] + , intentHandler: virtAsstIOBIntentHandler + }] + , rollupHandlers: [{ + rollupGroup: "Status" + , rollupName: "current iob" + , rollupHandler: virtAsstIOBRollupHandler + }] +}; +``` + +There are 2 types of handlers that you will need to supply: +* Intent handler - enables you to "teach" the virtual assistant how to respond to a user's question. +* A rollup handler - enables you to create a command that aggregates information from multiple plugins. This would be akin to the a "flash briefing". An example would be a status report that contains your current bg, iob, and your current basal. + +### Intent Handlers + +A plugin can expose multiple intent handlers (e.g. useful when it can supply multiple kinds of metrics). ++ `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. This remains an array type for backwards compatibility. ++ `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. The Google Home response doesn't currently display a card, so it doesn't use this value. + - `text` - This is text that the virtual assistant should speak (and show, if the user is using a device with a screen). + - `slots` - These are the slots (Alexa) or parameters (Google Home) that the virtual assistant detected. + - `sandbox` - This is the Nightscout sandbox that allows access to various functions. + +### Rollup handlers + +A plugin can also expose multiple rollup handlers ++ `rollupGroup` - This is the key that is used to aggregate the responses when the intent is invoked ++ `rollupName` - This is the name of the handler. Primarily used for debugging ++ `rollupHandler` - this is a callback function that receives 3 arguments + - `slots` - These are the values of the slots. Make sure to add these values to the appropriate custom slot + - `sandbox` - This is the nightscout sandbox that allows access to various functions. + - `callback` - + - `error` - This would be an error message + - `response` - A simple object that expects a `results` string and a `priority` integer. Results should be the text (speech) that is added to the rollup and priority affects where in the rollup the text should be added. The lowest priority is spoken first. An example callback: + ```javascript + callback(null, {results: "Hello world", priority: 1}); + ``` diff --git a/docs/plugins/alexa-plugin.md b/docs/plugins/alexa-plugin.md index a5dcb886e9c..73466678a17 100644 --- a/docs/plugins/alexa-plugin.md +++ b/docs/plugins/alexa-plugin.md @@ -41,9 +41,9 @@ To add Alexa support for a plugin, [check this out](#adding-alexa-support-to-a-p ### Get an Amazon Developer account -- Sign up for a free [Amazon Developer account](https://developer.amazon.com/) if you don't already have one. -- [Register](https://developer.amazon.com/docs/devconsole/test-your-skill.html#h2_register) your Alexa-enabled device with your Developer account. -- Sign in and go to the [Alexa developer portal](https://developer.amazon.com/alexa). +1. Sign up for a free [Amazon Developer account](https://developer.amazon.com/) if you don't already have one. +1. [Register](https://developer.amazon.com/docs/devconsole/test-your-skill.html#h2_register) your Alexa-enabled device with your Developer account. +1. Sign in and go to the [Alexa developer portal](https://developer.amazon.com/alexa). ### Create a new Alexa skill @@ -291,59 +291,4 @@ If your device is [registered](https://developer.amazon.com/docs/devconsole/test ## Adding Alexa support to a plugin -This document assumes some familiarity with the Alexa interface. You can find more information [here](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/getting-started-guide). - -To add alexa support to a plugin the ``init`` should return an object that contains an "alexa" key. Here is an example: - -```javascript -var iob = { - name: 'iob' - , label: 'Insulin-on-Board' - , pluginType: 'pill-major' - , alexa : { - rollupHandlers: [{ - rollupGroup: "Status" - , rollupName: "current iob" - , rollupHandler: alexaIOBRollupHandler - }] - , intentHandlers: [{ - intent: "MetricNow" - , routableSlot: "metric" - , slots: ["iob", "insulin on board"] - , intentHandler: alexaIOBIntentHandler - }] - } -}; -``` - -There are 2 types of handlers that you will need to supply: -* Intent handler - enables you to "teach" Alexa how to respond to a user's question. -* A rollup handler - enables you to create a command that aggregates information from multiple plugins. This would be akin to the Alexa "flash briefing". An example would be a status report that contains your current bg, iob, and your current basal. - -### Intent Handlers - -A plugin can expose multiple intent handlers. -+ ``intent`` - this is the intent in the "intent schema" above -+ ``routeableSlot`` - This enables routing by a slot name to the appropriate intent handler for overloaded intents e.g. "What is my " - iob, bg, cob, etc. This value should match the slot named in the "intent schema" -+ ``slots`` - These are the values of the slots. Make sure to add these values to the appropriate custom slot -+ ``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 - - ``text`` - This is text that Alexa should speak. - - ``slots`` - these are the slots that Alexa detected - - ``sandbox`` - This is the nightscout sandbox that allows access to various functions. - -### Rollup handlers - -A plugin can also expose multiple rollup handlers -+ ``rollupGroup`` - This is the key that is used to aggregate the responses when the intent is invoked -+ ``rollupName`` - This is the name of the handler. Primarily used for debugging -+ ``rollupHandler`` - this is a callback function that receives 3 arguments - - ``slots`` - These are the values of the slots. Make sure to add these values to the appropriate custom slot - - ``sandbox`` - This is the nightscout sandbox that allows access to various functions. - - ``callback`` - - - ``error`` - This would be an error message - - ``response`` - A simple object that expects a ``results`` string and a ``priority`` integer. Results should be the text (speech) that is added to the rollup and priority affects where in the rollup the text should be added. The lowest priority is spoken first. An example callback: - ```javascript - callback(null, {results: "Hello world", priority: 1}); - ``` +See [Adding Virtual Assistant Support to a Plugin](add-virtual-assistant-support-to-plugin.md) \ No newline at end of file diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 6bc55b01e62..e4ae349832a 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -31,4 +31,8 @@ To add Google Home support for your Nightscout site, here's what you need to do: 6. Go to "Fullfillment" menu and enter details about your webhook. 7. SAVE 8. Go to "Integration" menu and select your desired integration. -9. Follow instructions for each desired integration. \ No newline at end of file +9. Follow instructions for each desired integration. + +## Adding Google Home support to a plugin + +See [Adding Virtual Assistant Support to a Plugin](add-virtual-assistant-support-to-plugin.md) \ No newline at end of file From 0d85439030c8457a0164c2cbd868d0ea1a70bb79 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sun, 8 Sep 2019 00:56:10 -0600 Subject: [PATCH 19/48] A few typo fixes --- ...add-virtual-assistant-support-to-plugin.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/plugins/add-virtual-assistant-support-to-plugin.md b/docs/plugins/add-virtual-assistant-support-to-plugin.md index eccb9b4ae33..764cfc7c4ea 100644 --- a/docs/plugins/add-virtual-assistant-support-to-plugin.md +++ b/docs/plugins/add-virtual-assistant-support-to-plugin.md @@ -1,7 +1,7 @@ Adding Virtual Assistant Support to a Plugin ========================================= -To add virtual assistant support to a plugin, the `init` method should return an object that contains a `virtAsst` key. Here is an example: +To add virtual assistant support to a plugin, the `init` method of the plugin should return an object that contains a `virtAsst` key. Here is an example: ```javascript iob.virtAsst = { @@ -19,21 +19,21 @@ iob.virtAsst = { ``` There are 2 types of handlers that you will need to supply: -* Intent handler - enables you to "teach" the virtual assistant how to respond to a user's question. -* A rollup handler - enables you to create a command that aggregates information from multiple plugins. This would be akin to the a "flash briefing". An example would be a status report that contains your current bg, iob, and your current basal. +* Intent handler - Enables you to "teach" the virtual assistant how to respond to a user's question. +* A rollup handler - Enables you to create a command that aggregates information from multiple plugins. This would be akin to the a "flash briefing". An example would be a status report that contains your current bg, iob, and your current basal. ### Intent Handlers -A plugin can expose multiple intent handlers (e.g. useful when it can supply multiple kinds of metrics). +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. This remains an array type for backwards compatibility. -+ `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. The Google Home response doesn't currently display a card, so it doesn't use this value. - - `text` - This is text that the virtual assistant should speak (and show, if the user is using a device with a screen). - - `slots` - These are the slots (Alexa) or parameters (Google Home) that the virtual assistant detected. + - 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. ++ `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. + - `text` - This is text that the virtual assistant should speak (and show, for devices with a screen). + - `slots` - These are the slots (Alexa) or parameters (Google Home) that the virtual assistant detected (e.g. `pwd` as seen in the templates is a slot/parameter. `metric` is technically a slot, too). - `sandbox` - This is the Nightscout sandbox that allows access to various functions. ### Rollup handlers @@ -41,7 +41,7 @@ A plugin can expose multiple intent handlers (e.g. useful when it can supply mul A plugin can also expose multiple rollup handlers + `rollupGroup` - This is the key that is used to aggregate the responses when the intent is invoked + `rollupName` - This is the name of the handler. Primarily used for debugging -+ `rollupHandler` - this is a callback function that receives 3 arguments ++ `rollupHandler` - This is a callback function that receives 3 arguments - `slots` - These are the values of the slots. Make sure to add these values to the appropriate custom slot - `sandbox` - This is the nightscout sandbox that allows access to various functions. - `callback` - From f74d6a8c956d598d979a1b2f1aea33ebd2b0158c Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sun, 8 Sep 2019 01:00:33 -0600 Subject: [PATCH 20/48] Improved logging --- lib/api/alexa/index.js | 6 +++--- lib/api/googlehome/index.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index c919d4544ff..6669a894823 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -19,7 +19,7 @@ function configure (app, wares, ctx, env) { ctx.plugins.eachEnabledPlugin(function each(plugin){ if (plugin.virtAsst) { if (plugin.virtAsst.intentHandlers) { - console.log('Plugin ' + plugin.name + ' supports Virtual Assistants'); + console.log('Alexa: Plugin ' + plugin.name + ' supports Virtual Assistants'); _each(plugin.virtAsst.intentHandlers, function (route) { if (route) { ctx.alexa.configureIntentHandler(route.intent, route.intentHandler, route.metrics); @@ -27,7 +27,7 @@ function configure (app, wares, ctx, env) { }); } if (plugin.virtAsst.rollupHandlers) { - console.log('Plugin ' + plugin.name + ' supports rollups for Virtual Assistants'); + console.log('Alexa: Plugin ' + plugin.name + ' supports rollups for Virtual Assistants'); _each(plugin.virtAsst.rollupHandlers, function (route) { console.log('Route'); console.log(route); @@ -37,7 +37,7 @@ function configure (app, wares, ctx, env) { }); } } else { - console.log('Plugin ' + plugin.name + ' does not support Virtual Assistants'); + console.log('Alexa: Plugin ' + plugin.name + ' does not support Virtual Assistants'); } }); diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js index a18a2b17371..b03ac42bfe3 100644 --- a/lib/api/googlehome/index.js +++ b/lib/api/googlehome/index.js @@ -19,7 +19,7 @@ function configure (app, wares, ctx, env) { ctx.plugins.eachEnabledPlugin(function each(plugin){ if (plugin.virtAsst) { if (plugin.virtAsst.intentHandlers) { - console.log('Plugin ' + plugin.name + ' supports Virtual Assistants'); + console.log('Google Home: Plugin ' + plugin.name + ' supports Virtual Assistants'); _each(plugin.virtAsst.intentHandlers, function (route) { if (route) { ctx.googleHome.configureIntentHandler(route.intent, route.intentHandler, route.metrics); @@ -27,7 +27,7 @@ function configure (app, wares, ctx, env) { }); } if (plugin.virtAsst.rollupHandlers) { - console.log('Plugin ' + plugin.name + ' supports rollups for Virtual Assistants'); + console.log('Google Home: Plugin ' + plugin.name + ' supports rollups for Virtual Assistants'); _each(plugin.virtAsst.rollupHandlers, function (route) { console.log('Route'); console.log(route); @@ -37,7 +37,7 @@ function configure (app, wares, ctx, env) { }); } } else { - console.log('Plugin ' + plugin.name + ' does not support Virtual Assistants'); + console.log('Google Home: Plugin ' + plugin.name + ' does not support Virtual Assistants'); } }); From c266cab040474c252217576558d59370373f6579 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 9 Sep 2019 17:52:55 -0600 Subject: [PATCH 21/48] Updated Google Home plugin instructions --- .../googlehome-nightscout-template.zip | Bin 0 -> 12637 bytes docs/plugins/googlehome-plugin.md | 50 ++++++++++-------- 2 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 docs/plugins/googlehome-nightscout-template.zip diff --git a/docs/plugins/googlehome-nightscout-template.zip b/docs/plugins/googlehome-nightscout-template.zip new file mode 100644 index 0000000000000000000000000000000000000000..2cc2216888e07fa04e3090c9e89c6a5402a489ac GIT binary patch literal 12637 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

F(EV~D=}c@g z+Vlm>94&AM*+VSY5jM@6sv>bzM@b4O1}yAOgi2u%MawCRhP`8Im8G7_J0#K6LD_dE zu}1Q-0%lxD25e=4b}KxY8gQ%mkj=Buk^RC`@WAl=eX9QFgLC&qD(xQ1gZ2Mfx@_Nz zZtt}J!y2OA)o)!C0Y)O^qTUi_Y5Gr=^{4hgfPA0-k^4vF8o+eVJ!F`wc(^YYLDec5 z`Q)9Ia{X*KyIRu|{**$}?8SXGJ%{=;#S$6ORLoAU$jK?-c-wlQ<*-*=c+GMJ8>8aA zV5;H5%ndNB{V@_ve3%vs$w!itE*B7A)`cdl${L@}>b@47z}AklA}kJ&v{E)}zuy*F zWvTawZMi_1z>Cl4Ci(-Mde&Ce=Qod^^u#lN*OzBA`BZ{0K=Y&DM>KX?8>drg<{gNq z*YtJHV}Fpm)@{z%TXyqH*YX#N1}UBxHxn2;say5Us$oCj;-N225wxjd*G$>ZN{E`S zpT+VJ=1ceI(FI+OD`);VHRG0G1yNe`ViO6y<%>Ub*S&~5xJlTn&NEwYm2Ek^h@tn) zB1Ip;qdVUM5b~RL)fijxnd0UVPk}6-&;Kf)sBilAqUhf|dGJP^Zx6QrgaYgTo>TwB zQGj}7N4GDBQI1P$p>>2$>4~xC*MkEdF{!hs4o$yq5PkD7mjSI$NhxpfZHfBPCv8=( zt7#kw;-#Dk-n7zhEC{WcuJ#PZ3Ivj|NW$j+Y|bh|A5;OhlIz)3?1> z>sjQ~i5SJXiwXu!oWdOm9~W>K8i&N0uDF6k6Nfgdy-U_hgsd|M1W-T_b;(p@vZ-VsfWBz#{K!MNlA7KPztDc^ z2YlW@4?xR+U)Td}=ev#Fs{Trgz?TdZ0OVOX8`ci*x0b-8G6DcI z;PFU6REmT3_s2%fm7@UcS#dAqs~UhUx9`ZdJ+#%Y?LH{*0vikjgV&-4+n!5NzDL+? z5Y%L%0mxYwzm1F9AiGb$n-ROsECfK!fWJEc^?-}=-HQC83h<_u10Zr1K8An^aFnH6V0zQbPIUG|>M+E(cT4!WlRhn$5&_CSN|v0K>9 zD%3?6Xoz+389LO4_}kGBs=9oDqi4Vc=nsJ1dzjv>#jlDBobl)Y;%4F845;n?!%_!E zH;^Yl7i7Sx8GloceP!(C;&H&?GvN3qP|E;LX}ihz!zjCPfxW&rd=`kib2I|NVIkW) R5Qq`^?Ts8anwYl!`afE$LbU(@ literal 0 HcmV?d00001 diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index e4ae349832a..148ecd0dfa9 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -5,33 +5,41 @@ Nightscout Google Home/DialogFlow Plugin To add Google Home support for your Nightscout site, here's what you need to do: -1. Activate the `googlehome` plugin on your Nightscout site, so your site will respond correctly to Google's requests. -2. Create a custom DialogFlow agent that points at your site and defines certain questions you want to be able to ask. (You'll copy and paste a basic template for this, to keep things simple.) -3. Create desired integrations with DialogFlow - +1. [Activate the `googlehome` plugin](#activate-the-nightscout-google-home-plugin) on your Nightscout site, so your site will respond correctly to Google's requests. +1. [Create a custom DialogFlow agent](#create-your-dialogflow-agent) that points at your site and defines certain questions you want to be able to ask. ## Activate the Nightscout Google Home Plugin -1. Your Nightscout site needs to be new enough that it supports the `googlehome` plugin. . -2. Add `googlehome` to the list of plugins in your `ENABLE` setting. ([Environment variables](https://github.com/nightscout/cgm-remote-monitor#environment) are set in the configuration section for your monitor. Typically Azure, Heroku, etc.) +1. Your Nightscout site needs to be new enough that it supports the `googlehome` plugin. It needs to be [version VERSION_NUMBER (VERSION_NAME)](https://github.com/nightscout/cgm-remote-monitor/releases/tag/VERSION_NUMBER) or later. See [updating my version](https://github.com/nightscout/cgm-remote-monitor#updating-my-version) if you need a newer version. +1. Add `googlehome` to the list of plugins in your `ENABLE` setting. ([Environment variables](https://github.com/nightscout/cgm-remote-monitor#environment) are set in the configuration section for your monitor. Typically Azure, Heroku, etc.) ## Create Your DialogFlow Agent -### Signin to DialogFlow - -- Sign in to DialogFlow with your Google account (https://console.dialogflow.com/api-client/#/login). If you don't already have one, signup with Google. - -### Create a new custom DialogFlow agent - -1. Select "Create new agent" in the main menu bar. -2. Input a custom name for your agent and click "CREATE". -3. Download the simple agent template : ( https://drive.google.com/drive/folders/18z2kQSEInvH4O_jfjB4Qh8z9508P9Oao?usp=sharing ) -4. Select IMPORT FROM ZIP , in order to import the template. -5. SAVE -6. Go to "Fullfillment" menu and enter details about your webhook. -7. SAVE -8. Go to "Integration" menu and select your desired integration. -9. Follow instructions for each desired integration. +1. Download the [Google Home Nightscout agent template](googlehome-nightscout-template.zip). +1. [Sign in to Google's Action Console](https://console.actions.google.com) +1. Click on the "New Project" button. +1. If prompted, agree to the Terms of Service. +1. Give your project a name (e.g. "Nightscout") and then click "Create project". +1. Click any of the "development experience" options (it really doesn't matter). +1. Click on the "Develop" tab at the top of the sreen +1. Click on "Invocation" in the left navigation pane. +1. Set the display name (e.g. "Nightscout") and set your Google Assistant voice. + - Unfortunately, the name needs to be two words, and has to be unique across all of Google, even though you won't be publishing for everyone on Google to use. So you'll have to be creative in the name since "Night Scout" is already taken. +1. Click "Save" in the upper right corner. +1. Navigate to "Actions" in the left nagivation pane, then click on the "Add your first action" button. +1. Make sure you're on "Cutom intent" and then click "Build" to open DialogFlow in a new tab. +1. Sign in with the same Google account you used to sign in to the Actions Console. + - You'll have to go through the account setup steps if this is your first time using DialogFlow. +1. Verify the name for your agent (e.g. "Nightscout") and click "CREATE". +1. In the navigation pane on the left, click the gear icon next to your agent name. +1. Click on the "Export and Import" tab in the main area of the page. +1. Click the "IMPORT FROM ZIP" button. +1. Select the template file downloaded in step 1. +1. Type "IMPORT" where requested and then click the "IMPORT" button. +1. After the import finishes, click the "DONE" button followed by the "SAVE" button. +1. In the navigation pane on the left, click on "Fulfillment". +1. Enable the toggle for "Webhook" and then fill in the URL field with your Nightscout URL: `https://YOUR-NIGHTSCOUT-SITE/api/v1/googlehome` +1. Scroll down to the bottom of the page and click the "SAVE" button. ## Adding Google Home support to a plugin From 895407dc19b6995ca6427cce155b22cac4657466 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 9 Sep 2019 17:56:15 -0600 Subject: [PATCH 22/48] Attempt to trigger download of template file --- docs/plugins/googlehome-plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 148ecd0dfa9..50b7e56ae22 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -15,7 +15,7 @@ To add Google Home support for your Nightscout site, here's what you need to do: ## Create Your DialogFlow Agent -1. Download the [Google Home Nightscout agent template](googlehome-nightscout-template.zip). +1. Download the [Google Home Nightscout agent template](googlehome-nightscout-template.zip?raw=true). 1. [Sign in to Google's Action Console](https://console.actions.google.com) 1. Click on the "New Project" button. 1. If prompted, agree to the Terms of Service. From 478b25bdd320823bd5c2a7c8cda3634c1f53aef0 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 9 Sep 2019 17:59:48 -0600 Subject: [PATCH 23/48] Small wording tweaks --- docs/plugins/googlehome-plugin.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 50b7e56ae22..a2aebe0fd5e 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -15,8 +15,9 @@ To add Google Home support for your Nightscout site, here's what you need to do: ## Create Your DialogFlow Agent -1. Download the [Google Home Nightscout agent template](googlehome-nightscout-template.zip?raw=true). +1. Download the [Nightscout agent template for Google Home](googlehome-nightscout-template.zip?raw=true). 1. [Sign in to Google's Action Console](https://console.actions.google.com) + - Make sure to use the same account that is connected to your Google Home device, Android smartphone, Android tablet, etc. 1. Click on the "New Project" button. 1. If prompted, agree to the Terms of Service. 1. Give your project a name (e.g. "Nightscout") and then click "Create project". @@ -41,6 +42,8 @@ To add Google Home support for your Nightscout site, here's what you need to do: 1. Enable the toggle for "Webhook" and then fill in the URL field with your Nightscout URL: `https://YOUR-NIGHTSCOUT-SITE/api/v1/googlehome` 1. Scroll down to the bottom of the page and click the "SAVE" button. +That's it! Now try asking Google "Hey Google, ask Nightscout how am I doing?" + ## Adding Google Home support to a plugin See [Adding Virtual Assistant Support to a Plugin](add-virtual-assistant-support-to-plugin.md) \ No newline at end of file From c562e7d06a633beeab911ef411f4b91e254ea9fa Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 9 Sep 2019 20:32:12 -0600 Subject: [PATCH 24/48] Updated Alexa plugin documentation --- docs/plugins/alexa-plugin.md | 135 +++++++++++++++++------------------ 1 file changed, 66 insertions(+), 69 deletions(-) diff --git a/docs/plugins/alexa-plugin.md b/docs/plugins/alexa-plugin.md index 73466678a17..65930f6954b 100644 --- a/docs/plugins/alexa-plugin.md +++ b/docs/plugins/alexa-plugin.md @@ -73,20 +73,6 @@ To get up and running with a basic interaction model, which will allow you to as "How am I doing" ] }, - { - "name": "UploaderBattery", - "slots": [], - "samples": [ - "How is my uploader battery" - ] - }, - { - "name": "PumpBattery", - "slots": [], - "samples": [ - "How is my pump battery" - ] - }, { "name": "LastLoop", "slots": [], @@ -107,25 +93,22 @@ To get up and running with a basic interaction model, which will allow you to as } ], "samples": [ - "What is my {metric}", - "What my {metric} is", - "What is {pwd} {metric}" + "how is {metric}", + "how is my {metric}", + "how is {pwd} {metric}", + "how my {metric} is", + "what is {metric}", + "how much {metric} do I have", + "how much {metric} does {pwd} have", + "how much {metric} I have", + "what is my {metric}", + "what my {metric} is", + "what is {pwd} {metric}" ] }, { - "name": "InsulinRemaining", - "slots": [ - { - "name": "pwd", - "type": "AMAZON.US_FIRST_NAME" - } - ], - "samples": [ - "How much insulin do I have left", - "How much insulin do I have remaining", - "How much insulin does {pwd} have left", - "How much insulin does {pwd} have remaining" - ] + "name": "AMAZON.NavigateHomeIntent", + "samples": [] } ], "types": [ @@ -134,77 +117,91 @@ To get up and running with a basic interaction model, which will allow you to as "values": [ { "name": { - "value": "bg" - } - }, - { - "name": { - "value": "blood glucose" - } - }, - { - "name": { - "value": "number" - } - }, - { - "name": { - "value": "iob" - } - }, - { - "name": { - "value": "insulin on board" - } - }, - { - "name": { - "value": "current basal" - } - }, - { - "name": { - "value": "basal" + "value": "uploader battery", + "synonyms": [ + "uploader battery remaining", + "uploader battery power" + ] } }, { "name": { - "value": "cob" + "value": "pump reservoir", + "synonyms": [ + "remaining insulin", + "insulin remaining", + "insulin is left", + "insulin left", + "insulin in my pump", + "insulin" + ] } }, { "name": { - "value": "carbs on board" + "value": "pump battery", + "synonyms": [ + "pump battery remaining", + "pump battery power" + ] } }, { "name": { - "value": "carbohydrates on board" + "value": "bg", + "synonyms": [ + "number", + "blood sugar", + "blood glucose" + ] } }, { "name": { - "value": "loop forecast" + "value": "iob", + "synonyms": [ + "insulin on board" + ] } }, { "name": { - "value": "ar2 forecast" + "value": "basal", + "synonyms": [ + "current basil", + "basil", + "current basal" + ] } }, { "name": { - "value": "forecast" + "value": "cob", + "synonyms": [ + "carbs", + "carbs on board", + "carboydrates", + "carbohydrates on board" + ] } }, { "name": { - "value": "raw bg" + "value": "forecast", + "synonyms": [ + "ar2 forecast", + "loop forecast" + ] } }, { "name": { - "value": "raw blood glucose" + "value": "raw bg", + "synonyms": [ + "raw number", + "raw blood sugar", + "raw blood glucose" + ] } } ] From 3563158aaea64ab7de47c87d010f4e847f1b95e8 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Tue, 10 Sep 2019 00:06:24 -0600 Subject: [PATCH 25/48] Updated test files --- tests/ar2.test.js | 2 -- tests/basalprofileplugin.test.js | 3 --- tests/cob.test.js | 2 -- tests/iob.test.js | 3 --- tests/loop.test.js | 2 -- tests/openaps.test.js | 2 -- tests/pump.test.js | 16 +++++++++++++--- tests/rawbg.test.js | 2 -- tests/upbat.test.js | 12 ++++++++---- 9 files changed, 21 insertions(+), 23 deletions(-) diff --git a/tests/ar2.test.js b/tests/ar2.test.js index 8fee3ec1c63..6e62b6be20a 100644 --- a/tests/ar2.test.js +++ b/tests/ar2.test.js @@ -154,8 +154,6 @@ describe('ar2', function ( ) { ctx.ddata.sgvs = [{mgdl: 100, mills: before}, {mgdl: 105, mills: now}]; var sbx = prepareSandbox(); - ar2.virtAsst.intentHandlers.length.should.equal(1); - ar2.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('AR2 Forecast'); response.should.equal('You are expected to be between 109 and 120 over the in 30 minutes'); diff --git a/tests/basalprofileplugin.test.js b/tests/basalprofileplugin.test.js index fa97f84274e..3f1e5d5cfd3 100644 --- a/tests/basalprofileplugin.test.js +++ b/tests/basalprofileplugin.test.js @@ -92,9 +92,6 @@ describe('basalprofile', function ( ) { var sbx = sandbox.clientInit(ctx, time, data); sbx.data.profile = profile; - basal.virtAsst.intentHandlers.length.should.equal(1); - basal.virtAsst.rollupHandlers.length.should.equal(1); - basal.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current Basal'); response.should.equal('Your current basal is 0.175 units per hour'); diff --git a/tests/cob.test.js b/tests/cob.test.js index 54fbcb6c50d..8d1f2fdd5c6 100644 --- a/tests/cob.test.js +++ b/tests/cob.test.js @@ -110,8 +110,6 @@ describe('COB', function ( ) { var sbx = sandbox.clientInit(ctx, Date.now(), data); cob.setProperties(sbx); - cob.virtAsst.intentHandlers.length.should.equal(1); - cob.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current COB'); response.should.equal('You have 8 carbohydrates on board'); diff --git a/tests/iob.test.js b/tests/iob.test.js index b6c5c2430ec..b10cfd0bcde 100644 --- a/tests/iob.test.js +++ b/tests/iob.test.js @@ -20,9 +20,6 @@ describe('IOB', function() { } }; - iob.virtAsst.intentHandlers.length.should.equal(1); - iob.virtAsst.rollupHandlers.length.should.equal(1); - iob.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current IOB'); response.should.equal('You have 1.50 units of insulin on board'); diff --git a/tests/loop.test.js b/tests/loop.test.js index 8506de4555b..2b3585c172f 100644 --- a/tests/loop.test.js +++ b/tests/loop.test.js @@ -255,8 +255,6 @@ describe('loop', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); loop.setProperties(sbx); - loop.virtAsst.intentHandlers.length.should.equal(2); - loop.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Loop Forecast'); response.should.equal('According to the loop forecast you are expected to be between 147 and 149 over the next in 25 minutes'); diff --git a/tests/openaps.test.js b/tests/openaps.test.js index 9bfc5161969..8d864428fe5 100644 --- a/tests/openaps.test.js +++ b/tests/openaps.test.js @@ -382,8 +382,6 @@ describe('openaps', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); openaps.setProperties(sbx); - openaps.virtAsst.intentHandlers.length.should.equal(2); - openaps.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Loop Forecast'); response.should.equal('The OpenAPS Eventual BG is 125'); diff --git a/tests/pump.test.js b/tests/pump.test.js index afc96481976..5f924662d86 100644 --- a/tests/pump.test.js +++ b/tests/pump.test.js @@ -266,8 +266,6 @@ describe('pump', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); pump.setProperties(sbx); - pump.virtAsst.intentHandlers.length.should.equal(2); - pump.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Remaining insulin'); response.should.equal('You have 86.4 units remaining'); @@ -275,7 +273,19 @@ describe('pump', function ( ) { pump.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { title.should.equal('Pump battery'); response.should.equal('Your pump battery is at 1.52 volts'); - done(); + + pump.virtAsst.intentHandlers[2].intentHandler(function next(title, response) { + title.should.equal('Remaining insulin'); + response.should.equal('You have 86.4 units remaining'); + + pump.virtAsst.intentHandlers[3].intentHandler(function next(title, response) { + title.should.equal('Pump battery'); + response.should.equal('Your pump battery is at 1.52 volts'); + done(); + }, [], sbx); + + }, [], sbx); + }, [], sbx); }, [], sbx); diff --git a/tests/rawbg.test.js b/tests/rawbg.test.js index 48c21186cc5..b541d9b4427 100644 --- a/tests/rawbg.test.js +++ b/tests/rawbg.test.js @@ -42,8 +42,6 @@ describe('Raw BG', function ( ) { rawbg.setProperties(sbx); - rawbg.virtAsst.intentHandlers.length.should.equal(1); - rawbg.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current Raw BG'); response.should.equal('Your raw bg is 113'); diff --git a/tests/upbat.test.js b/tests/upbat.test.js index 515d1a8d218..d575dc9d8bd 100644 --- a/tests/upbat.test.js +++ b/tests/upbat.test.js @@ -106,13 +106,17 @@ describe('Uploader Battery', function ( ) { var upbat = require('../lib/plugins/upbat')(ctx); upbat.setProperties(sbx); - upbat.virtAsst.intentHandlers.length.should.equal(1); - upbat.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Uploader battery'); response.should.equal('Your uploader battery is at 20%'); - - done(); + + upbat.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { + title.should.equal('Uploader battery'); + response.should.equal('Your uploader battery is at 20%'); + + done(); + }, [], sbx); + }, [], sbx); }); From 0a48c1d81a2ca724e3f112c8c91c692a7533c6c0 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Tue, 10 Sep 2019 00:14:21 -0600 Subject: [PATCH 26/48] Re-added handler count tests so devs are prompted to write tests for new handlers --- tests/ar2.test.js | 2 ++ tests/basalprofileplugin.test.js | 3 +++ tests/cob.test.js | 2 ++ tests/iob.test.js | 3 +++ tests/loop.test.js | 2 ++ tests/openaps.test.js | 2 ++ tests/pump.test.js | 2 ++ tests/rawbg.test.js | 2 ++ tests/upbat.test.js | 2 ++ 9 files changed, 20 insertions(+) diff --git a/tests/ar2.test.js b/tests/ar2.test.js index 6e62b6be20a..8fee3ec1c63 100644 --- a/tests/ar2.test.js +++ b/tests/ar2.test.js @@ -154,6 +154,8 @@ describe('ar2', function ( ) { ctx.ddata.sgvs = [{mgdl: 100, mills: before}, {mgdl: 105, mills: now}]; var sbx = prepareSandbox(); + ar2.virtAsst.intentHandlers.length.should.equal(1); + ar2.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('AR2 Forecast'); response.should.equal('You are expected to be between 109 and 120 over the in 30 minutes'); diff --git a/tests/basalprofileplugin.test.js b/tests/basalprofileplugin.test.js index 3f1e5d5cfd3..fa97f84274e 100644 --- a/tests/basalprofileplugin.test.js +++ b/tests/basalprofileplugin.test.js @@ -92,6 +92,9 @@ describe('basalprofile', function ( ) { var sbx = sandbox.clientInit(ctx, time, data); sbx.data.profile = profile; + basal.virtAsst.intentHandlers.length.should.equal(1); + basal.virtAsst.rollupHandlers.length.should.equal(1); + basal.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current Basal'); response.should.equal('Your current basal is 0.175 units per hour'); diff --git a/tests/cob.test.js b/tests/cob.test.js index 8d1f2fdd5c6..54fbcb6c50d 100644 --- a/tests/cob.test.js +++ b/tests/cob.test.js @@ -110,6 +110,8 @@ describe('COB', function ( ) { var sbx = sandbox.clientInit(ctx, Date.now(), data); cob.setProperties(sbx); + cob.virtAsst.intentHandlers.length.should.equal(1); + cob.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current COB'); response.should.equal('You have 8 carbohydrates on board'); diff --git a/tests/iob.test.js b/tests/iob.test.js index b10cfd0bcde..b6c5c2430ec 100644 --- a/tests/iob.test.js +++ b/tests/iob.test.js @@ -20,6 +20,9 @@ describe('IOB', function() { } }; + iob.virtAsst.intentHandlers.length.should.equal(1); + iob.virtAsst.rollupHandlers.length.should.equal(1); + iob.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current IOB'); response.should.equal('You have 1.50 units of insulin on board'); diff --git a/tests/loop.test.js b/tests/loop.test.js index 2b3585c172f..8506de4555b 100644 --- a/tests/loop.test.js +++ b/tests/loop.test.js @@ -255,6 +255,8 @@ describe('loop', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); loop.setProperties(sbx); + loop.virtAsst.intentHandlers.length.should.equal(2); + loop.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Loop Forecast'); response.should.equal('According to the loop forecast you are expected to be between 147 and 149 over the next in 25 minutes'); diff --git a/tests/openaps.test.js b/tests/openaps.test.js index 8d864428fe5..9bfc5161969 100644 --- a/tests/openaps.test.js +++ b/tests/openaps.test.js @@ -382,6 +382,8 @@ describe('openaps', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); openaps.setProperties(sbx); + openaps.virtAsst.intentHandlers.length.should.equal(2); + openaps.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Loop Forecast'); response.should.equal('The OpenAPS Eventual BG is 125'); diff --git a/tests/pump.test.js b/tests/pump.test.js index 5f924662d86..483d5a49316 100644 --- a/tests/pump.test.js +++ b/tests/pump.test.js @@ -266,6 +266,8 @@ describe('pump', function ( ) { var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses}); pump.setProperties(sbx); + pump.virtAsst.intentHandlers.length.should.equal(4); + pump.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Remaining insulin'); response.should.equal('You have 86.4 units remaining'); diff --git a/tests/rawbg.test.js b/tests/rawbg.test.js index b541d9b4427..48c21186cc5 100644 --- a/tests/rawbg.test.js +++ b/tests/rawbg.test.js @@ -42,6 +42,8 @@ describe('Raw BG', function ( ) { rawbg.setProperties(sbx); + rawbg.virtAsst.intentHandlers.length.should.equal(1); + rawbg.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Current Raw BG'); response.should.equal('Your raw bg is 113'); diff --git a/tests/upbat.test.js b/tests/upbat.test.js index d575dc9d8bd..cac1439160c 100644 --- a/tests/upbat.test.js +++ b/tests/upbat.test.js @@ -106,6 +106,8 @@ describe('Uploader Battery', function ( ) { var upbat = require('../lib/plugins/upbat')(ctx); upbat.setProperties(sbx); + upbat.virtAsst.intentHandlers.length.should.equal(2); + upbat.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('Uploader battery'); response.should.equal('Your uploader battery is at 20%'); From 658ca161b7c2806a3b5c8a98370c837fda0597e2 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Tue, 10 Sep 2019 16:07:35 -0600 Subject: [PATCH 27/48] Updated Alexa documentation --- docs/plugins/alexa-plugin.md | 236 +++--------------- docs/plugins/alexa-templates/en-us.json | 212 ++++++++++++++++ .../interacting-with-virtual-assistants.md | 56 +++++ 3 files changed, 309 insertions(+), 195 deletions(-) create mode 100644 docs/plugins/alexa-templates/en-us.json create mode 100644 docs/plugins/interacting-with-virtual-assistants.md diff --git a/docs/plugins/alexa-plugin.md b/docs/plugins/alexa-plugin.md index 65930f6954b..41b14966136 100644 --- a/docs/plugins/alexa-plugin.md +++ b/docs/plugins/alexa-plugin.md @@ -58,159 +58,9 @@ To add Alexa support for a plugin, [check this out](#adding-alexa-support-to-a-p Your Alexa skill's "interaction model" defines how your spoken questions get translated into requests to your Nightscout site, and how your Nightscout site's responses get translated into the audio responses that Alexa says back to you. -To get up and running with a basic interaction model, which will allow you to ask Alexa a few basic questions about your Nightscout site, you can copy and paste the configuration code below. - -```json -{ - "interactionModel": { - "languageModel": { - "invocationName": "nightscout", - "intents": [ - { - "name": "NSStatus", - "slots": [], - "samples": [ - "How am I doing" - ] - }, - { - "name": "LastLoop", - "slots": [], - "samples": [ - "When was my last loop" - ] - }, - { - "name": "MetricNow", - "slots": [ - { - "name": "metric", - "type": "LIST_OF_METRICS" - }, - { - "name": "pwd", - "type": "AMAZON.US_FIRST_NAME" - } - ], - "samples": [ - "how is {metric}", - "how is my {metric}", - "how is {pwd} {metric}", - "how my {metric} is", - "what is {metric}", - "how much {metric} do I have", - "how much {metric} does {pwd} have", - "how much {metric} I have", - "what is my {metric}", - "what my {metric} is", - "what is {pwd} {metric}" - ] - }, - { - "name": "AMAZON.NavigateHomeIntent", - "samples": [] - } - ], - "types": [ - { - "name": "LIST_OF_METRICS", - "values": [ - { - "name": { - "value": "uploader battery", - "synonyms": [ - "uploader battery remaining", - "uploader battery power" - ] - } - }, - { - "name": { - "value": "pump reservoir", - "synonyms": [ - "remaining insulin", - "insulin remaining", - "insulin is left", - "insulin left", - "insulin in my pump", - "insulin" - ] - } - }, - { - "name": { - "value": "pump battery", - "synonyms": [ - "pump battery remaining", - "pump battery power" - ] - } - }, - { - "name": { - "value": "bg", - "synonyms": [ - "number", - "blood sugar", - "blood glucose" - ] - } - }, - { - "name": { - "value": "iob", - "synonyms": [ - "insulin on board" - ] - } - }, - { - "name": { - "value": "basal", - "synonyms": [ - "current basil", - "basil", - "current basal" - ] - } - }, - { - "name": { - "value": "cob", - "synonyms": [ - "carbs", - "carbs on board", - "carboydrates", - "carbohydrates on board" - ] - } - }, - { - "name": { - "value": "forecast", - "synonyms": [ - "ar2 forecast", - "loop forecast" - ] - } - }, - { - "name": { - "value": "raw bg", - "synonyms": [ - "raw number", - "raw blood sugar", - "raw blood glucose" - ] - } - } - ] - } - ] - } - } -} -``` +To get up and running with an interaction model, which will allow you to ask Alexa a few basic questions about your Nightscout site, you can copy and paste the configuration code for your language from [the list of templates](alexa-templates/). + +- If you're language doesn't have a template, please consider starting with [the en-us template](alexa-templates/en-us.json), then [modifying it to work with your language](#adding-support-for-additional-languages), and [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. Select "JSON Editor" in the left-hand menu on your skill's edit page (which you should be on if you followed the above instructions). Replace everything in the textbox with the above code. Then click "Save Model" at the top. A success message should appear indicating that the model was saved. @@ -239,53 +89,49 @@ After you enable testing, you can also use the Alexa Simulator in the left colum ##### What questions can you ask it? -*Forecast:* - -- "Alexa, ask Nightscout how am I doing" -- "Alexa, ask Nightscout how I'm doing" - -*Uploader Battery:* - -- "Alexa, ask Nightscout how is my uploader battery" - -*Pump Battery:* - -- "Alexa, ask Nightscout how is my pump battery" - -*Metrics:* - -- "Alexa, ask Nightscout what my bg is" -- "Alexa, ask Nightscout what my blood glucose is" -- "Alexa, ask Nightscout what my number is" -- "Alexa, ask Nightscout what is my insulin on board" -- "Alexa, ask Nightscout what is my basal" -- "Alexa, ask Nightscout what is my current basal" -- "Alexa, ask Nightscout what is my cob" -- "Alexa, ask Nightscout what is Charlie's carbs on board" -- "Alexa, ask Nightscout what is Sophie's carbohydrates on board" -- "Alexa, ask Nightscout what is Harper's loop forecast" -- "Alexa, ask Nightscout what is Alicia's ar2 forecast" -- "Alexa, ask Nightscout what is Peter's forecast" -- "Alexa, ask Nightscout what is Arden's raw bg" -- "Alexa, ask Nightscout what is Dana's raw blood glucose" - -*Insulin Remaining:* - -- "Alexa, ask Nightscout how much insulin do I have left" -- "Alexa, ask Nightscout how much insulin do I have remaining" -- "Alexa, ask Nightscout how much insulin does Dana have left? -- "Alexa, ask Nightscout how much insulin does Arden have remaining? - -*Last Loop:* - -- "Alexa, ask Nightscout when was my last loop" - -(Note: all the formats with specific names will respond to questions for any first name. You don't need to configure anything with your PWD's name.) +See [Interacting with Virtual Assistants](interacting-with-virtual-assistants.md) for details on what you can do with Alexa. ### Activate the skill on your Echo or other device If your device is [registered](https://developer.amazon.com/docs/devconsole/test-your-skill.html#h2_register) with your developer account, you should be able to use your skill right away. Try it by asking Alexa one of the above questions using your device. +## Adding support for additional languages + +If the translations in Nightscout are configured correctly for the desired language code, Nightscout *should* automatically respond in that language after following the steps below + +If you add support for another language, please consider [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. You can export your translated template by going to the "JSON Editor" in the left navigation pane. + +1. Open the Build tab of your Alexa Skill. + - Get to your list of Alexa Skills at [https://developer.amazon.com/alexa/console/ask] and click on the name of the skill. +1. Click on the language drop-down box in the upper right corner of the window. +1. Click "Language settings". +1. Add your desired language. +1. Click the "Save" button. +1. Navigate to "CUSTOM" in the left navigation pane. +1. Select your new language in the language drop-down box. +1. Go to "JSON Editor" (just above "Interfaces" in the left navigation pane). +1. Remove the existing contents in the text box, and copy and paste the configuration code from a familiar language in [the list of templates](alexa-templates/). +1. Click "Save Model". +1. Click the "Add" button next to the "Slot Types" section in the left pane. +1. Click the radio button for "Use an existing slot type from Alexa's built-in library" +1. In the search box just below that option, search for "first name" +1. If your language has an option, click the "Add Slot Type" button for that option. + - If your language doesn't have an option, you won't be able to ask Nightscout a question that includes a name. +1. For each Intent listed in the left navigation pane (e.g. "NSStatus" and "MetricNow"): + 1. Click on the Intent name. + 1. Scroll down to the "Slots" section + 1. If there's a slot with the name "pwd", change the slot type to the one found above. + - If you didn't find one above, you'll have to see if another language gets close enough for you, or delete the slot. + 1. If there's a slot with the name "metric", click the "Edit Dialog" link on the right. This is where you set Alexa's questions and your answers if you happen to ask a question about metrics but don't include which metric you want to know. + 1. Set the "Alexa speech prompts" in your language, and remove the old ones. + 1. Under "User utterances", set the phrases you would say in response to the questions Alexa would pose from the previous step. MAKE SURE that your example phrases include where you would say the name of the metric. You do this by typing the left brace (`{`) and then selecting `metric` in the popup. + 1. For each Sample Utterance, add an equivalent phrase in your language. If the phrase you're replacing has a `metric` slot, make sure to include that in your replacement phrase. Same goes for the `pwd` slot, unless you had to delete that slot in the previous step, in which case you need to modify the phrase to not use a first name, or not make a replacement phrase. Delete the phrase you're replacing. +1. Navigate to the "LIST_OF_METRICS" under the Slot Types section. +1. For each metric listed, add synonyms in your language, and delete the old synonyms. + - What ever you do, **DO NOT** change the text in the "VALUE" column! Only change the synonyms. +1. Click "Save Model" at the top, and then click on "Build Model". +1. You should be good to go! Feel free to try it out using the "Test" tab near the top of the window, or start asking your Alexa-enabled device some questions. + ## Adding Alexa support to a plugin See [Adding Virtual Assistant Support to a Plugin](add-virtual-assistant-support-to-plugin.md) \ No newline at end of file diff --git a/docs/plugins/alexa-templates/en-us.json b/docs/plugins/alexa-templates/en-us.json new file mode 100644 index 00000000000..bb1ff0932c5 --- /dev/null +++ b/docs/plugins/alexa-templates/en-us.json @@ -0,0 +1,212 @@ +{ + "interactionModel": { + "languageModel": { + "invocationName": "nightscout", + "intents": [ + { + "name": "NSStatus", + "slots": [], + "samples": [ + "How am I doing" + ] + }, + { + "name": "LastLoop", + "slots": [], + "samples": [ + "When was my last loop" + ] + }, + { + "name": "MetricNow", + "slots": [ + { + "name": "metric", + "type": "LIST_OF_METRICS", + "samples": [ + "what {pwd} {metric} is", + "what my {metric} is", + "how {pwd} {metric} is", + "how my {metric} is", + "how much {metric} does {pwd} have", + "how much {metric} I have", + "how much {metric}", + "{pwd} {metric}", + "{metric}", + "my {metric}" + ] + }, + { + "name": "pwd", + "type": "AMAZON.US_FIRST_NAME" + } + ], + "samples": [ + "how is {metric}", + "how is my {metric}", + "how is {pwd} {metric}", + "how my {metric} is", + "what is {metric}", + "how much {metric} do I have", + "how much {metric} does {pwd} have", + "how much {metric} I have", + "what is my {metric}", + "what my {metric} is", + "what is {pwd} {metric}" + ] + }, + { + "name": "AMAZON.NavigateHomeIntent", + "samples": [] + } + ], + "types": [ + { + "name": "LIST_OF_METRICS", + "values": [ + { + "name": { + "value": "uploader battery", + "synonyms": [ + "uploader battery remaining", + "uploader battery power" + ] + } + }, + { + "name": { + "value": "pump reservoir", + "synonyms": [ + "remaining insulin", + "insulin remaining", + "insulin is left", + "insulin left", + "insulin in my pump", + "insulin" + ] + } + }, + { + "name": { + "value": "pump battery", + "synonyms": [ + "pump battery remaining", + "pump battery power" + ] + } + }, + { + "name": { + "value": "bg", + "synonyms": [ + "number", + "blood sugar", + "blood glucose" + ] + } + }, + { + "name": { + "value": "iob", + "synonyms": [ + "insulin on board" + ] + } + }, + { + "name": { + "value": "basal", + "synonyms": [ + "current basil", + "basil", + "current basal" + ] + } + }, + { + "name": { + "value": "cob", + "synonyms": [ + "carbs", + "carbs on board", + "carboydrates", + "carbohydrates on board" + ] + } + }, + { + "name": { + "value": "forecast", + "synonyms": [ + "ar2 forecast", + "loop forecast" + ] + } + }, + { + "name": { + "value": "raw bg", + "synonyms": [ + "raw number", + "raw blood sugar", + "raw blood glucose" + ] + } + } + ] + } + ] + }, + "dialog": { + "intents": [ + { + "name": "MetricNow", + "confirmationRequired": false, + "prompts": {}, + "slots": [ + { + "name": "metric", + "type": "LIST_OF_METRICS", + "confirmationRequired": false, + "elicitationRequired": true, + "prompts": { + "elicitation": "Elicit.Slot.1421281086569.34001419564" + } + }, + { + "name": "pwd", + "type": "AMAZON.US_FIRST_NAME", + "confirmationRequired": false, + "elicitationRequired": false, + "prompts": {} + } + ] + } + ], + "delegationStrategy": "ALWAYS" + }, + "prompts": [ + { + "id": "Elicit.Slot.1421281086569.34001419564", + "variations": [ + { + "type": "PlainText", + "value": "What metric are you looking for?" + }, + { + "type": "PlainText", + "value": "What value are you looking for?" + }, + { + "type": "PlainText", + "value": "What metric do you want to know?" + }, + { + "type": "PlainText", + "value": "What value do you want to know?" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/docs/plugins/interacting-with-virtual-assistants.md b/docs/plugins/interacting-with-virtual-assistants.md new file mode 100644 index 00000000000..e22cd9f2e87 --- /dev/null +++ b/docs/plugins/interacting-with-virtual-assistants.md @@ -0,0 +1,56 @@ +Interacting with Virtual Assistants +=================================== + +# Alexa vs. Google Home + +Although these example phrases reference Alexa, the exact same questions could be asked of Google. +Just replace "Alexa, ask Nightscout ..." with "Hey Google, ask *your action's name* ..." + +# What questions can you ask it? + +This list is not meant to be comprehensive, nor does it include every way you can ask the questions. In the respective console for your virtual assistant, check the example phrases for each `intent`, and the values (including synonyms) of the "metric" `slot` (Alexa) or `entity` (Google Home). You can also just experiement with asking different questions to see what works. + +*Forecast:* + +- "Alexa, ask Nightscout how am I doing" +- "Alexa, ask Nightscout how I'm doing" + +*Uploader Battery:* + +- "Alexa, ask Nightscout how is my uploader battery" + +*Pump Battery:* + +- "Alexa, ask Nightscout how is my pump battery" + +*Metrics:* + +- "Alexa, ask Nightscout what my bg is" +- "Alexa, ask Nightscout what my blood glucose is" +- "Alexa, ask Nightscout what my number is" +- "Alexa, ask Nightscout what is my insulin on board" +- "Alexa, ask Nightscout what is my basal" +- "Alexa, ask Nightscout what is my current basal" +- "Alexa, ask Nightscout what is my cob" +- "Alexa, ask Nightscout what is Charlie's carbs on board" +- "Alexa, ask Nightscout what is Sophie's carbohydrates on board" +- "Alexa, ask Nightscout what is Harper's loop forecast" +- "Alexa, ask Nightscout what is Alicia's ar2 forecast" +- "Alexa, ask Nightscout what is Peter's forecast" +- "Alexa, ask Nightscout what is Arden's raw bg" +- "Alexa, ask Nightscout what is Dana's raw blood glucose" + +*Insulin Remaining:* + +- "Alexa, ask Nightscout how much insulin do I have left" +- "Alexa, ask Nightscout how much insulin do I have remaining" +- "Alexa, ask Nightscout how much insulin does Dana have left? +- "Alexa, ask Nightscout how much insulin does Arden have remaining? + +*Last Loop:* + +- "Alexa, ask Nightscout when was my last loop" + +## A note about names + +All the formats with specific names will respond to questions for any first name. You don't need to configure anything with your PWD's name. \ No newline at end of file From 2b3d783d7055de6410e2eedd38fe5f1276be759d Mon Sep 17 00:00:00 2001 From: inventor96 Date: Tue, 10 Sep 2019 16:11:56 -0600 Subject: [PATCH 28/48] Small typo fix --- docs/plugins/alexa-plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/alexa-plugin.md b/docs/plugins/alexa-plugin.md index 41b14966136..9c6e9ecbc4c 100644 --- a/docs/plugins/alexa-plugin.md +++ b/docs/plugins/alexa-plugin.md @@ -62,7 +62,7 @@ To get up and running with an interaction model, which will allow you to ask Ale - If you're language doesn't have a template, please consider starting with [the en-us template](alexa-templates/en-us.json), then [modifying it to work with your language](#adding-support-for-additional-languages), and [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. -Select "JSON Editor" in the left-hand menu on your skill's edit page (which you should be on if you followed the above instructions). Replace everything in the textbox with the above code. Then click "Save Model" at the top. A success message should appear indicating that the model was saved. +Select "JSON Editor" in the left-hand menu on your skill's edit page (which you should be on if you followed the above instructions). Replace everything in the textbox with the code from your chosen template. Then click "Save Model" at the top. A success message should appear indicating that the model was saved. Next you need to build your custom model. Click "Build Model" at the top of the same page. It'll take a minute to build, and then you should see another success message, "Build Successful". From 73d4e049364986345db6ff9a5a6eda6395c3b5b4 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Tue, 10 Sep 2019 16:14:06 -0600 Subject: [PATCH 29/48] Clarification --- docs/plugins/interacting-with-virtual-assistants.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/interacting-with-virtual-assistants.md b/docs/plugins/interacting-with-virtual-assistants.md index e22cd9f2e87..a9f2541d8d8 100644 --- a/docs/plugins/interacting-with-virtual-assistants.md +++ b/docs/plugins/interacting-with-virtual-assistants.md @@ -8,7 +8,7 @@ Just replace "Alexa, ask Nightscout ..." with "Hey Google, ask *your action's na # What questions can you ask it? -This list is not meant to be comprehensive, nor does it include every way you can ask the questions. In the respective console for your virtual assistant, check the example phrases for each `intent`, and the values (including synonyms) of the "metric" `slot` (Alexa) or `entity` (Google Home). You can also just experiement with asking different questions to see what works. +This list is not meant to be comprehensive, nor does it include every way you can ask the questions. To get the full picture, in the respective console for your virtual assistant, check the example phrases for each `intent`, and the values (including synonyms) of the "metric" `slot` (Alexa) or `entity` (Google Home). You can also just experiement with asking different questions to see what works. *Forecast:* From f946f4f634777100d8177c46fc43fe07e1d62f4f Mon Sep 17 00:00:00 2001 From: inventor96 Date: Tue, 10 Sep 2019 16:22:06 -0600 Subject: [PATCH 30/48] Further clarifications and typos --- docs/plugins/alexa-plugin.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/plugins/alexa-plugin.md b/docs/plugins/alexa-plugin.md index 9c6e9ecbc4c..dd2be406559 100644 --- a/docs/plugins/alexa-plugin.md +++ b/docs/plugins/alexa-plugin.md @@ -97,7 +97,7 @@ If your device is [registered](https://developer.amazon.com/docs/devconsole/test ## Adding support for additional languages -If the translations in Nightscout are configured correctly for the desired language code, Nightscout *should* automatically respond in that language after following the steps below +If the translations in Nightscout are configured correctly for the desired language code, Nightscout *should* automatically respond in that language after following the steps below. If you add support for another language, please consider [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. You can export your translated template by going to the "JSON Editor" in the left navigation pane. @@ -120,17 +120,18 @@ If you add support for another language, please consider [making a pull request] 1. For each Intent listed in the left navigation pane (e.g. "NSStatus" and "MetricNow"): 1. Click on the Intent name. 1. Scroll down to the "Slots" section - 1. If there's a slot with the name "pwd", change the slot type to the one found above. + 1. If there's a slot with the name "pwd", change the Slot Type to the one found above. - If you didn't find one above, you'll have to see if another language gets close enough for you, or delete the slot. 1. If there's a slot with the name "metric", click the "Edit Dialog" link on the right. This is where you set Alexa's questions and your answers if you happen to ask a question about metrics but don't include which metric you want to know. 1. Set the "Alexa speech prompts" in your language, and remove the old ones. 1. Under "User utterances", set the phrases you would say in response to the questions Alexa would pose from the previous step. MAKE SURE that your example phrases include where you would say the name of the metric. You do this by typing the left brace (`{`) and then selecting `metric` in the popup. - 1. For each Sample Utterance, add an equivalent phrase in your language. If the phrase you're replacing has a `metric` slot, make sure to include that in your replacement phrase. Same goes for the `pwd` slot, unless you had to delete that slot in the previous step, in which case you need to modify the phrase to not use a first name, or not make a replacement phrase. Delete the phrase you're replacing. + 1. Click on the Intent name (just to the left of "metric") to return to the previous screen. + 1. For each Sample Utterance, add an equivalent phrase in your language. If the phrase you're replacing has a `metric` slot, make sure to include that in your replacement phrase. Same goes for the `pwd` slot, unless you had to delete that slot a couple steps ago, in which case you need to modify the phrase to not use a first name, or not make a replacement phrase. After you've entered your replacement phrase, delete the phrase you're replacing. 1. Navigate to the "LIST_OF_METRICS" under the Slot Types section. 1. For each metric listed, add synonyms in your language, and delete the old synonyms. - What ever you do, **DO NOT** change the text in the "VALUE" column! Only change the synonyms. 1. Click "Save Model" at the top, and then click on "Build Model". -1. You should be good to go! Feel free to try it out using the "Test" tab near the top of the window, or start asking your Alexa-enabled device some questions. +1. You should be good to go! Feel free to try it out using the "Test" tab near the top of the window, or start asking your Alexa-enabled device some questions. See [Interacting with Virtual Assistants](interacting-with-virtual-assistants.md) for details on what you can do with Alexa. ## Adding Alexa support to a plugin From 6ff8aa39b7e714db0835cf20563d990f27d3345d Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 22:54:47 -0600 Subject: [PATCH 31/48] Added language info to Google Home plugin doc --- docs/plugins/alexa-plugin.md | 2 +- docs/plugins/google-home-templates/en-us.zip | Bin 0 -> 12265 bytes .../googlehome-nightscout-template.zip | Bin 12637 -> 0 bytes docs/plugins/googlehome-plugin.md | 57 +++++++++++++++++- 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 docs/plugins/google-home-templates/en-us.zip delete mode 100644 docs/plugins/googlehome-nightscout-template.zip diff --git a/docs/plugins/alexa-plugin.md b/docs/plugins/alexa-plugin.md index dd2be406559..452d14fe5d2 100644 --- a/docs/plugins/alexa-plugin.md +++ b/docs/plugins/alexa-plugin.md @@ -129,7 +129,7 @@ If you add support for another language, please consider [making a pull request] 1. For each Sample Utterance, add an equivalent phrase in your language. If the phrase you're replacing has a `metric` slot, make sure to include that in your replacement phrase. Same goes for the `pwd` slot, unless you had to delete that slot a couple steps ago, in which case you need to modify the phrase to not use a first name, or not make a replacement phrase. After you've entered your replacement phrase, delete the phrase you're replacing. 1. Navigate to the "LIST_OF_METRICS" under the Slot Types section. 1. For each metric listed, add synonyms in your language, and delete the old synonyms. - - What ever you do, **DO NOT** change the text in the "VALUE" column! Only change the synonyms. + - What ever you do, **DO NOT** change the text in the "VALUE" column! Nightscout will be looking for these exact values. Only change the synonyms. 1. Click "Save Model" at the top, and then click on "Build Model". 1. You should be good to go! Feel free to try it out using the "Test" tab near the top of the window, or start asking your Alexa-enabled device some questions. See [Interacting with Virtual Assistants](interacting-with-virtual-assistants.md) for details on what you can do with Alexa. diff --git a/docs/plugins/google-home-templates/en-us.zip b/docs/plugins/google-home-templates/en-us.zip new file mode 100644 index 0000000000000000000000000000000000000000..71dc40256bf9958fba2cef7d4c1cd35f4d25e718 GIT binary patch literal 12265 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

F(EV~D=}c@g z+Vlm>94&AM*+VSY5jM@6sv>bzM@b4O1}yAOgi2u%MawCRhP`8Im8G7_J0#K6LD_dE zu}1Q-0%lxD25e=4b}KxY8gQ%mkj=Buk^RC`@WAl=eX9QFgLC&qD(xQ1gZ2Mfx@_Nz zZtt}J!y2OA)o)!C0Y)O^qTUi_Y5Gr=^{4hgfPA0-k^4vF8o+eVJ!F`wc(^YYLDec5 z`Q)9Ia{X*KyIRu|{**$}?8SXGJ%{=;#S$6ORLoAU$jK?-c-wlQ<*-*=c+GMJ8>8aA zV5;H5%ndNB{V@_ve3%vs$w!itE*B7A)`cdl${L@}>b@47z}AklA}kJ&v{E)}zuy*F zWvTawZMi_1z>Cl4Ci(-Mde&Ce=Qod^^u#lN*OzBA`BZ{0K=Y&DM>KX?8>drg<{gNq z*YtJHV}Fpm)@{z%TXyqH*YX#N1}UBxHxn2;say5Us$oCj;-N225wxjd*G$>ZN{E`S zpT+VJ=1ceI(FI+OD`);VHRG0G1yNe`ViO6y<%>Ub*S&~5xJlTn&NEwYm2Ek^h@tn) zB1Ip;qdVUM5b~RL)fijxnd0UVPk}6-&;Kf)sBilAqUhf|dGJP^Zx6QrgaYgTo>TwB zQGj}7N4GDBQI1P$p>>2$>4~xC*MkEdF{!hs4o$yq5PkD7mjSI$NhxpfZHfBPCv8=( zt7#kw;-#Dk-n7zhEC{WcuJ#PZ3Ivj|NW$j+Y|bh|A5;OhlIz)3?1> z>sjQ~i5SJXiwXu!oWdOm9~W>K8i&N0uDF6k6Nfgdy-U_hgsd|M1W-T_b;(p@vZ-VsfWBz#{K!MNlA7KPztDc^ z2YlW@4?xR+U)Td}=ev#Fs{Trgz?TdZ0OVOX8`ci*x0b-8G6DcI z;PFU6REmT3_s2%fm7@UcS#dAqs~UhUx9`ZdJ+#%Y?LH{*0vikjgV&-4+n!5NzDL+? z5Y%L%0mxYwzm1F9AiGb$n-ROsECfK!fWJEc^?-}=-HQC83h<_u10Zr1K8An^aFnH6V0zQbPIUG|>M+E(cT4!WlRhn$5&_CSN|v0K>9 zD%3?6Xoz+389LO4_}kGBs=9oDqi4Vc=nsJ1dzjv>#jlDBobl)Y;%4F845;n?!%_!E zH;^Yl7i7Sx8GloceP!(C;&H&?GvN3qP|E;LX}ihz!zjCPfxW&rd=`kib2I|NVIkW) R5Qq`^?Ts8anwYl!`afE$LbU(@ diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index a2aebe0fd5e..6faa0ef2c4a 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -15,7 +15,8 @@ To add Google Home support for your Nightscout site, here's what you need to do: ## Create Your DialogFlow Agent -1. Download the [Nightscout agent template for Google Home](googlehome-nightscout-template.zip?raw=true). +1. Download the agent template in your language for Google Home [here](google-home-templates/). + - If you're language doesn't have a template, please consider starting with [the en-us template](google-home-templates/en-us.zip), then [modifying it to work with your language](#adding-support-for-additional-languages), and [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. 1. [Sign in to Google's Action Console](https://console.actions.google.com) - Make sure to use the same account that is connected to your Google Home device, Android smartphone, Android tablet, etc. 1. Click on the "New Project" button. @@ -42,7 +43,59 @@ To add Google Home support for your Nightscout site, here's what you need to do: 1. Enable the toggle for "Webhook" and then fill in the URL field with your Nightscout URL: `https://YOUR-NIGHTSCOUT-SITE/api/v1/googlehome` 1. Scroll down to the bottom of the page and click the "SAVE" button. -That's it! Now try asking Google "Hey Google, ask Nightscout how am I doing?" +That's it! Now try asking Google "Hey Google, ask *your agent's name* how am I doing?" + +### What questions can you ask it? + +See [Interacting with Virtual Assistants](interacting-with-virtual-assistants.md) for details on what you can do with Google Home. + +## Adding support for additional languages + +If the translations in Nightscout are configured correctly for the desired language code, Nightscout *should* automatically respond in that language after following the steps below. + +If you add support for another language, please consider [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. You can export your translated template by going to the settings of your DialogFlow agent (the gear icon next to the project's name in the left nagivation pane), going to the "Export and Import" tab, and clicking "EXPORT AS ZIP". + +1. Open your DialogFlow agent. + - Get to your list of agents at [https://console.dialogflow.com/api-client/#/agents] and click on the name of your Nightscout agent. +1. Click on the "Languages" tab. +1. Click the "Add Additional Language" drop-down box. +1. Select your desired language. +1. Click the "SAVE" button. + - Note the new language code below the agent's name. e.g. if you're using the English template and you added Spanish, you would see two buttons: "en" and "es". +1. Click on "Intents" in the left navigation pane. +1. For each intent in the list (excluding those that start with "Default" in the name): + 1. Click on the intent name. + 1. Note the phrases used in the "Training phrases" section, especially colored blocks (e.g. `metric` or `pwd`). + 1. Click on the new language code (beneath the agent name near the top of the navigation pane). + 1. Add equivalent or similar training phrases as those you noted a couple steps ago. + - If the phrase in the orginal language has a colored block with a word in it, that needs to be included. When adding the phrase to the new language, follow these steps to add the colored block: + 1. When typing that part of the training phrase, don't translate the word in the block; just keep it as-is. + 1. After typing the phrase (DON'T push the Enter key yet!) highlight/select the word. + 1. A box will pop up with a list of parameter types, some of which end with a colon (`:`) and a parameter name. Click the option that has the same parameter name as the word you're working with (e.g. if the word is "metric", you would select the option that ends with ":metric"). + 1. Press the Enter key to add the phrase. + 1. Click the "SAVE" button. + 1. Go back and forth between your starting language and your new language, adding equivalent phrase(s) to the new language. Continue once you've added all the equivalent phrases you can think of. + 1. Scroll down to the "Action and parameters" section. + 1. If any of the items in that list have the "REQUIRED" option checked, click the "Define prompts..." link on the right side of that item. + 1. Add phrases that Google will ask if you happen to say something similar to a training phrase, but don't include this parameter (e.g. if you ask about a metric but don't say what metric you want to know about). + 1. Click "CLOSE". + 1. Scroll down to the "Responses" section. + 1. Set just one phrase here. This will be what Google says if it has technical difficulties getting a response from your Nightscout website. + 1. Click the "SAVE" button at the top of the window. +1. Click on the "Entities" section in the navigation pane. +1. For each entity listed: + 1. Click the entity name. + 1. Switch to the starting language (beneath the agent name near the top of the left navigation pane). + 1. Click the menu icon to the right of the "SAVE" button and click "Switch to raw mode". + 1. Select all the text in the text box and copy it. + 1. Switch back to your new language. + 1. Click the menu icon to the right of the "SAVE" button and click "Switch to raw mode". + 1. In the text box, paste the text you just copied. + 1. Click the menu icon to the right of the "SAVE" button and click "Switch to editor mode". + 1. For each item in the list, replace the items on the RIGHT side of the list with equivalent words and phrases in your language. + - What ever you do, **DO NOT** change the values on the left side of the list. Nightscout will be looking for these exact values. Only change the items on the right side of the list. + 1. Click the "SAVE" button. +1. You should be good to go! Feel free to try it out using the "Test" tab near the top of the window, or start asking your Alexa-enabled device some questions. See [Interacting with Virtual Assistants](interacting-with-virtual-assistants.md) for details on what you can do with Alexa. ## Adding Google Home support to a plugin From 92d2f703b16ca1946893eecf5a6939786b9d32a2 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 22:56:10 -0600 Subject: [PATCH 32/48] URL correction --- docs/plugins/googlehome-plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 6faa0ef2c4a..85ddf2468b5 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -56,7 +56,7 @@ If the translations in Nightscout are configured correctly for the desired langu If you add support for another language, please consider [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. You can export your translated template by going to the settings of your DialogFlow agent (the gear icon next to the project's name in the left nagivation pane), going to the "Export and Import" tab, and clicking "EXPORT AS ZIP". 1. Open your DialogFlow agent. - - Get to your list of agents at [https://console.dialogflow.com/api-client/#/agents] and click on the name of your Nightscout agent. + - Get to your list of agents at (https://console.dialogflow.com/api-client/#/agents) and click on the name of your Nightscout agent. 1. Click on the "Languages" tab. 1. Click the "Add Additional Language" drop-down box. 1. Select your desired language. From 41c03352856a1da4850c5dd4f87ab6d27a18e6b2 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 22:57:33 -0600 Subject: [PATCH 33/48] URL fix v2 --- docs/plugins/alexa-plugin.md | 2 +- docs/plugins/googlehome-plugin.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/alexa-plugin.md b/docs/plugins/alexa-plugin.md index 452d14fe5d2..8ba8188143e 100644 --- a/docs/plugins/alexa-plugin.md +++ b/docs/plugins/alexa-plugin.md @@ -102,7 +102,7 @@ If the translations in Nightscout are configured correctly for the desired langu If you add support for another language, please consider [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. You can export your translated template by going to the "JSON Editor" in the left navigation pane. 1. Open the Build tab of your Alexa Skill. - - Get to your list of Alexa Skills at [https://developer.amazon.com/alexa/console/ask] and click on the name of the skill. + - Get to your list of Alexa Skills at https://developer.amazon.com/alexa/console/ask and click on the name of the skill. 1. Click on the language drop-down box in the upper right corner of the window. 1. Click "Language settings". 1. Add your desired language. diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 85ddf2468b5..6b4d5ca372f 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -56,7 +56,7 @@ If the translations in Nightscout are configured correctly for the desired langu If you add support for another language, please consider [making a pull request](/CONTRIBUTING.md) or [submitting an issue](https://github.com/nightscout/cgm-remote-monitor/issues) with your translated template to share it with others. You can export your translated template by going to the settings of your DialogFlow agent (the gear icon next to the project's name in the left nagivation pane), going to the "Export and Import" tab, and clicking "EXPORT AS ZIP". 1. Open your DialogFlow agent. - - Get to your list of agents at (https://console.dialogflow.com/api-client/#/agents) and click on the name of your Nightscout agent. + - Get to your list of agents at https://console.dialogflow.com/api-client/#/agents and click on the name of your Nightscout agent. 1. Click on the "Languages" tab. 1. Click the "Add Additional Language" drop-down box. 1. Select your desired language. From f188f4f58b758f1d57cd61287e25f34bbcd80ca9 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 22:59:06 -0600 Subject: [PATCH 34/48] Wording clarification --- docs/plugins/googlehome-plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 6b4d5ca372f..5a8c46ecf77 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -63,7 +63,7 @@ If you add support for another language, please consider [making a pull request] 1. Click the "SAVE" button. - Note the new language code below the agent's name. e.g. if you're using the English template and you added Spanish, you would see two buttons: "en" and "es". 1. Click on "Intents" in the left navigation pane. -1. For each intent in the list (excluding those that start with "Default" in the name): +1. For each intent in the list (NOT icluding those that start with "Default" in the name): 1. Click on the intent name. 1. Note the phrases used in the "Training phrases" section, especially colored blocks (e.g. `metric` or `pwd`). 1. Click on the new language code (beneath the agent name near the top of the navigation pane). From 071d98024cb8a9270d879d700b206a3e54d69902 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 22:59:34 -0600 Subject: [PATCH 35/48] Ugh... --- docs/plugins/googlehome-plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 5a8c46ecf77..fed3b842bc5 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -63,7 +63,7 @@ If you add support for another language, please consider [making a pull request] 1. Click the "SAVE" button. - Note the new language code below the agent's name. e.g. if you're using the English template and you added Spanish, you would see two buttons: "en" and "es". 1. Click on "Intents" in the left navigation pane. -1. For each intent in the list (NOT icluding those that start with "Default" in the name): +1. For each intent in the list (NOT including those that start with "Default" in the name): 1. Click on the intent name. 1. Note the phrases used in the "Training phrases" section, especially colored blocks (e.g. `metric` or `pwd`). 1. Click on the new language code (beneath the agent name near the top of the navigation pane). From 313bb60f3c97cef94bbdf9b2a778df3f06f2fb49 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 23:05:07 -0600 Subject: [PATCH 36/48] Minor instruction fix --- docs/plugins/googlehome-plugin.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index fed3b842bc5..ae3b267f0da 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -65,13 +65,14 @@ If you add support for another language, please consider [making a pull request] 1. Click on "Intents" in the left navigation pane. 1. For each intent in the list (NOT including those that start with "Default" in the name): 1. Click on the intent name. - 1. Note the phrases used in the "Training phrases" section, especially colored blocks (e.g. `metric` or `pwd`). + 1. Note the phrases used in the "Training phrases" section. + - If the phrase has a colored block (e.g. `metric` or `pwd`), click the phrase (but NOT the colored block) and note the "PARAMETER NAME" of the item with the same-colored "ENTITY". 1. Click on the new language code (beneath the agent name near the top of the navigation pane). 1. Add equivalent or similar training phrases as those you noted a couple steps ago. - If the phrase in the orginal language has a colored block with a word in it, that needs to be included. When adding the phrase to the new language, follow these steps to add the colored block: 1. When typing that part of the training phrase, don't translate the word in the block; just keep it as-is. 1. After typing the phrase (DON'T push the Enter key yet!) highlight/select the word. - 1. A box will pop up with a list of parameter types, some of which end with a colon (`:`) and a parameter name. Click the option that has the same parameter name as the word you're working with (e.g. if the word is "metric", you would select the option that ends with ":metric"). + 1. A box will pop up with a list of parameter types, some of which end with a colon (`:`) and a parameter name. Click the option that has the same parameter name as the one you determined just a few steps ago. 1. Press the Enter key to add the phrase. 1. Click the "SAVE" button. 1. Go back and forth between your starting language and your new language, adding equivalent phrase(s) to the new language. Continue once you've added all the equivalent phrases you can think of. From 67ae84deecfaecdfc9c2a86164b28fbf22c54356 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 23:06:33 -0600 Subject: [PATCH 37/48] Sub steps fix --- docs/plugins/googlehome-plugin.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index ae3b267f0da..8d287d8be71 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -77,9 +77,10 @@ If you add support for another language, please consider [making a pull request] 1. Click the "SAVE" button. 1. Go back and forth between your starting language and your new language, adding equivalent phrase(s) to the new language. Continue once you've added all the equivalent phrases you can think of. 1. Scroll down to the "Action and parameters" section. - 1. If any of the items in that list have the "REQUIRED" option checked, click the "Define prompts..." link on the right side of that item. - 1. Add phrases that Google will ask if you happen to say something similar to a training phrase, but don't include this parameter (e.g. if you ask about a metric but don't say what metric you want to know about). - 1. Click "CLOSE". + 1. If any of the items in that list have the "REQUIRED" option checked: + 1. Click the "Define prompts..." link on the right side of that item. + 1. Add phrases that Google will ask if you happen to say something similar to a training phrase, but don't include this parameter (e.g. if you ask about a metric but don't say what metric you want to know about). + 1. Click "CLOSE". 1. Scroll down to the "Responses" section. 1. Set just one phrase here. This will be what Google says if it has technical difficulties getting a response from your Nightscout website. 1. Click the "SAVE" button at the top of the window. From dd6e69151169adb4cf6718e4549adcadeca04c24 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 23:09:30 -0600 Subject: [PATCH 38/48] Fixed Alexa references in Google Home --- docs/plugins/googlehome-plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 8d287d8be71..2b8556a9f47 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -97,7 +97,7 @@ If you add support for another language, please consider [making a pull request] 1. For each item in the list, replace the items on the RIGHT side of the list with equivalent words and phrases in your language. - What ever you do, **DO NOT** change the values on the left side of the list. Nightscout will be looking for these exact values. Only change the items on the right side of the list. 1. Click the "SAVE" button. -1. You should be good to go! Feel free to try it out using the "Test" tab near the top of the window, or start asking your Alexa-enabled device some questions. See [Interacting with Virtual Assistants](interacting-with-virtual-assistants.md) for details on what you can do with Alexa. +1. You should be good to go! Feel free to try it out by click the "See how it works in Google Assistant" link in the right navigation pane, or start asking your Google-Home-enabled device some questions. See [Interacting with Virtual Assistants](interacting-with-virtual-assistants.md) for details on what you can do with Google Home. ## Adding Google Home support to a plugin From 6032aab7a82cf9777f19e0772d53299afa4ff418 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Wed, 11 Sep 2019 23:59:27 -0600 Subject: [PATCH 39/48] Added a couple steps for improved user experience --- docs/plugins/googlehome-plugin.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 2b8556a9f47..00a7a721b82 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -42,6 +42,10 @@ To add Google Home support for your Nightscout site, here's what you need to do: 1. In the navigation pane on the left, click on "Fulfillment". 1. Enable the toggle for "Webhook" and then fill in the URL field with your Nightscout URL: `https://YOUR-NIGHTSCOUT-SITE/api/v1/googlehome` 1. Scroll down to the bottom of the page and click the "SAVE" button. +1. Click on "Integrations" in the navigation pane. +1. Click on "INTEGRATION SETTINGS" for "Google Assistant". +1. Under "Implicit invocation", add every intent listed. +1. Click "CLOSE". That's it! Now try asking Google "Hey Google, ask *your agent's name* how am I doing?" From 87261afad4be8b0d32a712e07b5bce3861768e82 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Thu, 12 Sep 2019 00:00:34 -0600 Subject: [PATCH 40/48] One more forgotten step --- docs/plugins/googlehome-plugin.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 00a7a721b82..8474cee5ba8 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -45,6 +45,7 @@ To add Google Home support for your Nightscout site, here's what you need to do: 1. Click on "Integrations" in the navigation pane. 1. Click on "INTEGRATION SETTINGS" for "Google Assistant". 1. Under "Implicit invocation", add every intent listed. +1. Turn on the toggle for "Auto-preview changes". 1. Click "CLOSE". That's it! Now try asking Google "Hey Google, ask *your agent's name* how am I doing?" From 450fbc2572c9aa762e582aa4e9864b4c22046d0e Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 16 Sep 2019 14:33:50 -0600 Subject: [PATCH 41/48] Updated pump reservoir handler to handle undefined values --- lib/language.js | 26 ++++++++++++++++++++++++++ lib/plugins/pump.js | 13 +++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/language.js b/lib/language.js index f1560e122ef..93bfb7eab2b 100644 --- a/lib/language.js +++ b/lib/language.js @@ -13274,6 +13274,32 @@ function init() { , zh_cn: '快速上升' , zh_tw: 'rapidly rising' }, + 'virtAsstUnknown': { + bg: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , cs: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , de: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , dk: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , el: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , en: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , es: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , fi: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , fr: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , he: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , hr: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , it: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , ko: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , nb: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , pl: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , pt: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , ro: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , nl: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , ru: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , sk: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , sv: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , tr: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , zh_cn: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , zh_tw: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + }, 'virtAsstStatus': { bg: '%1 and %2 as of %3.' , cs: '%1 %2 čas %3.' diff --git a/lib/plugins/pump.js b/lib/plugins/pump.js index a2d95a68c9d..8eee2477bb7 100644 --- a/lib/plugins/pump.js +++ b/lib/plugins/pump.js @@ -136,12 +136,17 @@ function init (ctx) { }; function virtAsstReservoirHandler (next, slots, sbx) { + var reservoir = _.get(sbx, 'properties.pump.pump.reservoir'); + if (reservoir) { var response = translate('virtAsstReservoir', { params: [ - sbx.properties.pump.pump.reservoir + reservoir ] - }); - next('Remaining insulin', response); + }); + next('Remaining insulin', response); + } else { + next('Remaining insulin', translate('virtAsstUnknown')); + } } function virtAsstBatteryHandler (next, slots, sbx) { @@ -155,7 +160,7 @@ function init (ctx) { }); next('Pump battery', response); } else { - next(); + next('Pump battery', translate('virtAsstUnknown')); } } From bf57dfec782aa084d4f424a2fa0e11368297b4ba Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 16 Sep 2019 15:12:59 -0600 Subject: [PATCH 42/48] Updated titles and unknown-value responses --- lib/plugins/ar2.js | 2 +- lib/plugins/basalprofile.js | 2 +- lib/plugins/iob.js | 2 -- lib/plugins/loop.js | 14 +++++++++----- lib/plugins/openaps.js | 20 +++++++++++++------- lib/plugins/pump.js | 11 +++++------ lib/plugins/rawbg.js | 8 ++++++-- lib/plugins/upbat.js | 8 ++++++-- 8 files changed, 41 insertions(+), 26 deletions(-) diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js index 78b0d10e0ba..9f4b8af33b6 100644 --- a/lib/plugins/ar2.js +++ b/lib/plugins/ar2.js @@ -166,7 +166,7 @@ function init (ctx) { var response = 'You are expected to be between ' + min + ' and ' + max + ' over the ' + moment(maxForecastMills).from(moment(sbx.time)); next('AR2 Forecast', response); } else { - next('AR2 Forecast', 'AR2 plugin does not seem to be enabled'); + next('AR2 Forecast', translate('virtAsstUnknown')); } } diff --git a/lib/plugins/basalprofile.js b/lib/plugins/basalprofile.js index e229ff0fac4..e30e1238c92 100644 --- a/lib/plugins/basalprofile.js +++ b/lib/plugins/basalprofile.js @@ -102,7 +102,7 @@ function init (ctx) { function basalMessage(slots, sbx) { var basalValue = sbx.data.profile.getTempBasal(sbx.time); - var response = 'Unable to determine current basal'; + var response = translate('virtAsstUnknown'); var preamble = ''; if (basalValue.treatment) { preamble = (slots && slots.pwd && slots.pwd.value) ? translate('virtAsstPreamble3person', { diff --git a/lib/plugins/iob.js b/lib/plugins/iob.js index 567968cd5e2..614cc56981b 100644 --- a/lib/plugins/iob.js +++ b/lib/plugins/iob.js @@ -247,11 +247,9 @@ function init(ctx) { var message = translate('virtAsstIobIntent', { params: [ - //preamble, getIob(sbx) ] }); - //preamble + + ' insulin on board'; callback('Current IOB', message); } diff --git a/lib/plugins/loop.js b/lib/plugins/loop.js index 7b30eafb644..ad7d06e5a51 100644 --- a/lib/plugins/loop.js +++ b/lib/plugins/loop.js @@ -441,7 +441,7 @@ function init (ctx) { var startPrediction = moment(sbx.properties.loop.lastLoop.predicted.startDate); var endPrediction = startPrediction.clone().add(maxForecastIndex * 5, 'minutes'); if (endPrediction.valueOf() < sbx.time) { - next('Loop Forecast', 'Unable to forecast with the data that is available'); + next('Loop Forecast', translate('virtAsstUnknown')); } else { for (var i = 1, len = forecast.slice(0, maxForecastIndex).length; i < len; i++) { if (forecast[i] > max) { @@ -461,14 +461,18 @@ function init (ctx) { next('Loop Forecast', response); } } else { - next('Loop forecast', 'Loop plugin does not seem to be enabled'); + next('Loop Forecast', translate('virtAsstUnknown')); } } function virtAsstLastLoopHandler (next, slots, sbx) { - console.log(JSON.stringify(sbx.properties.loop.lastLoop)); - var response = 'The last successful loop was ' + moment(sbx.properties.loop.lastOkMoment).from(moment(sbx.time)); - next('Last loop', response); + if (sbx.properties.loop.lastLoop) { + console.log(JSON.stringify(sbx.properties.loop.lastLoop)); + var response = 'The last successful loop was ' + moment(sbx.properties.loop.lastOkMoment).from(moment(sbx.time)); + next('Last Loop', response); + } else { + next('Last Loop', translate('virtAsstUnknown')); + } } loop.virtAsst = { diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 0865b3352fe..293aadf00d4 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -518,17 +518,23 @@ function init (ctx) { ] }); next('Loop Forecast', response); + } else { + next('Loop Forecast', translate('virtAsstUnknown')); } } function virtAsstLastLoopHandler (next, slots, sbx) { - console.log(JSON.stringify(sbx.properties.openaps.lastLoopMoment)); - var response = translate('virtAsstLastLoop', { - params: [ - moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time)) - ] - }); - next('Last loop', response); + if (sbx.properties.openaps.lastLoopMoment) { + console.log(JSON.stringify(sbx.properties.openaps.lastLoopMoment)); + var response = translate('virtAsstLastLoop', { + params: [ + moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time)) + ] + }); + next('Last Loop', response); + } else { + next('Last Loop', translate('virtAsstUnknown')); + } } openaps.virtAsst = { diff --git a/lib/plugins/pump.js b/lib/plugins/pump.js index 8eee2477bb7..840afa8aeae 100644 --- a/lib/plugins/pump.js +++ b/lib/plugins/pump.js @@ -136,16 +136,15 @@ function init (ctx) { }; function virtAsstReservoirHandler (next, slots, sbx) { - var reservoir = _.get(sbx, 'properties.pump.pump.reservoir'); - if (reservoir) { + if (sbx.properties.pump.pump.reservoir) { var response = translate('virtAsstReservoir', { params: [ reservoir ] }); - next('Remaining insulin', response); + next('Remaining Insulin', response); } else { - next('Remaining insulin', translate('virtAsstUnknown')); + next('Remaining Insulin', translate('virtAsstUnknown')); } } @@ -158,9 +157,9 @@ function init (ctx) { battery.unit ] }); - next('Pump battery', response); + next('Pump Battery', response); } else { - next('Pump battery', translate('virtAsstUnknown')); + next('Pump Battery', translate('virtAsstUnknown')); } } diff --git a/lib/plugins/rawbg.js b/lib/plugins/rawbg.js index 91ebdb849dd..997cf7c55a3 100644 --- a/lib/plugins/rawbg.js +++ b/lib/plugins/rawbg.js @@ -107,8 +107,12 @@ function init (ctx) { }; function virtAsstRawBGHandler (next, slots, sbx) { - var response = 'Your raw bg is ' + sbx.properties.rawbg.mgdl; - next('Current Raw BG', response); + if (sbx.properties.rawbg.mgdl) { + var response = 'Your raw bg is ' + sbx.properties.rawbg.mgdl; + next('Current Raw BG', response); + } else { + next('Current Raw BG', translate('virtAsstUnknown')); + } } rawbg.virtAsst = { diff --git a/lib/plugins/upbat.js b/lib/plugins/upbat.js index 509d9347f89..1bd8795ef7c 100644 --- a/lib/plugins/upbat.js +++ b/lib/plugins/upbat.js @@ -222,8 +222,12 @@ function init() { }; function virtAsstUploaderBatteryHandler (next, slots, sbx) { - var response = 'Your uploader battery is at ' + sbx.properties.upbat.display; - next('Uploader battery', response); + if (sbx.properties.upbat.display) { + var response = 'Your uploader battery is at ' + sbx.properties.upbat.display; + next('Uploader Battery', response); + } else { + next('Uploader Battery', translate('virtAsstUnknown')); + } } upbat.virtAsst = { From ddd8f63cbd060dd8d6784956faa24bafcdd507c8 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 16 Sep 2019 15:47:06 -0600 Subject: [PATCH 43/48] Modified forecast responses to use translate() --- lib/language.js | 92 +++++++++++++++++++++++++++++++++++++++++++++ lib/plugins/ar2.js | 13 ++++++- lib/plugins/loop.js | 19 +++++++--- 3 files changed, 118 insertions(+), 6 deletions(-) diff --git a/lib/language.js b/lib/language.js index 93bfb7eab2b..9227f4ae33d 100644 --- a/lib/language.js +++ b/lib/language.js @@ -667,6 +667,81 @@ function init() { ,tr: 'Son 3 ay' ,zh_cn: '过去3个月' } + , 'between': { + cs: 'between' + ,de: 'between' + ,es: 'between' + ,fr: 'between' + ,el: 'between' + ,pt: 'between' + ,sv: 'between' + ,ro: 'between' + ,bg: 'between' + ,hr: 'between' + ,it: 'between' + ,ja: 'between' + ,dk: 'between' + ,fi: 'between' + ,nb: 'between' + ,he: 'between' + ,pl: 'between' + ,ru: 'between' + ,sk: 'between' + ,nl: 'between' + ,ko: 'between' + ,tr: 'between' + ,zh_cn: 'between' + } + , 'around': { + cs: 'around' + ,de: 'around' + ,es: 'around' + ,fr: 'around' + ,el: 'around' + ,pt: 'around' + ,sv: 'around' + ,ro: 'around' + ,bg: 'around' + ,hr: 'around' + ,it: 'around' + ,ja: 'around' + ,dk: 'around' + ,fi: 'around' + ,nb: 'around' + ,he: 'around' + ,pl: 'around' + ,ru: 'around' + ,sk: 'around' + ,nl: 'around' + ,ko: 'around' + ,tr: 'around' + ,zh_cn: 'around' + } + , 'and': { + cs: 'and' + ,de: 'and' + ,es: 'and' + ,fr: 'and' + ,el: 'and' + ,pt: 'and' + ,sv: 'and' + ,ro: 'and' + ,bg: 'and' + ,hr: 'and' + ,it: 'and' + ,ja: 'and' + ,dk: 'and' + ,fi: 'and' + ,nb: 'and' + ,he: 'and' + ,pl: 'and' + ,ru: 'and' + ,sk: 'and' + ,nl: 'and' + ,ko: 'and' + ,tr: 'and' + ,zh_cn: 'and' + } ,'From' : { cs: 'Od' ,de: 'Von' @@ -13636,6 +13711,23 @@ function init() { , ru: 'по прогнозу алгоритма ЗЦ ожидается %1 за последующие %2' , tr: 'Döngü tahminine göre sonraki %2 ye göre %1 olması bekleniyor' }, + 'virtAsstAR2Forecast': { + bg: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , cs: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , en: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , hr: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , de: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , dk: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , ko: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , nl: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , zh_cn: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , sv: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , fi: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , ro: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , pl: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , ru: 'According to the AR2 forecast you are expected to be %1 over the next %2' + , tr: 'According to the AR2 forecast you are expected to be %1 over the next %2' + }, 'virtAsstForecastUnavailable': { bg: 'Unable to forecast with the data that is available' , cs: 'S dostupnými daty přepověď není možná' diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js index 9f4b8af33b6..cab989c8150 100644 --- a/lib/plugins/ar2.js +++ b/lib/plugins/ar2.js @@ -163,7 +163,18 @@ function init (ctx) { maxForecastMills = forecast[i].mills; } } - var response = 'You are expected to be between ' + min + ' and ' + max + ' over the ' + moment(maxForecastMills).from(moment(sbx.time)); + var value = ''; + if (min === max) { + value = translate('around') + ' ' + max; + } else { + value = translate('between') + ' ' + min + ' ' + translate('and') + ' ' + max; + } + var response = translate('virtAsstAR2Forecast', { + params: [ + value + , moment(maxForecastMills).from(moment(sbx.time)) + ] + }); next('AR2 Forecast', response); } else { next('AR2 Forecast', translate('virtAsstUnknown')); diff --git a/lib/plugins/loop.js b/lib/plugins/loop.js index ad7d06e5a51..2f627409c45 100644 --- a/lib/plugins/loop.js +++ b/lib/plugins/loop.js @@ -441,7 +441,7 @@ function init (ctx) { var startPrediction = moment(sbx.properties.loop.lastLoop.predicted.startDate); var endPrediction = startPrediction.clone().add(maxForecastIndex * 5, 'minutes'); if (endPrediction.valueOf() < sbx.time) { - next('Loop Forecast', translate('virtAsstUnknown')); + next('Loop Forecast', translate('virtAsstForecastUnavailable')); } else { for (var i = 1, len = forecast.slice(0, maxForecastIndex).length; i < len; i++) { if (forecast[i] > max) { @@ -453,11 +453,16 @@ function init (ctx) { } var value = ''; if (min === max) { - value = 'around ' + max; + value = translate('around') + ' ' + max; } else { - value = 'between ' + min + ' and ' + max; + value = translate('between') + ' ' + min + ' ' + translate('and') + ' ' + max; } - var response = 'According to the loop forecast you are expected to be ' + value + ' over the next ' + moment(endPrediction).from(moment(sbx.time)); + var response = translate('virtAsstLoopForecast', { + params: [ + value + , moment(endPrediction).from(moment(sbx.time)) + ] + }); next('Loop Forecast', response); } } else { @@ -468,7 +473,11 @@ function init (ctx) { function virtAsstLastLoopHandler (next, slots, sbx) { if (sbx.properties.loop.lastLoop) { console.log(JSON.stringify(sbx.properties.loop.lastLoop)); - var response = 'The last successful loop was ' + moment(sbx.properties.loop.lastOkMoment).from(moment(sbx.time)); + var response = translate('virtAsstLastLoop', { + params: [ + moment(sbx.properties.loop.lastOkMoment).from(moment(sbx.time)) + ] + }); next('Last Loop', response); } else { next('Last Loop', translate('virtAsstUnknown')); From d3346fe3ddceb9d56d938ae3ac088f7fbbc6105e Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 16 Sep 2019 15:56:26 -0600 Subject: [PATCH 44/48] Updated tests --- tests/ar2.test.js | 2 +- tests/loop.test.js | 2 +- tests/openaps.test.js | 2 +- tests/pump.test.js | 8 ++++---- tests/upbat.test.js | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/ar2.test.js b/tests/ar2.test.js index 8fee3ec1c63..01f4f3d41a1 100644 --- a/tests/ar2.test.js +++ b/tests/ar2.test.js @@ -158,7 +158,7 @@ describe('ar2', function ( ) { ar2.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { title.should.equal('AR2 Forecast'); - response.should.equal('You are expected to be between 109 and 120 over the in 30 minutes'); + response.should.equal('According to the AR2 forecast you are expected to be between 109 and 120 over the next in 30 minutes'); done(); }, [], sbx); }); diff --git a/tests/loop.test.js b/tests/loop.test.js index 8506de4555b..71bc0860bda 100644 --- a/tests/loop.test.js +++ b/tests/loop.test.js @@ -262,7 +262,7 @@ describe('loop', function ( ) { response.should.equal('According to the loop forecast you are expected to be between 147 and 149 over the next in 25 minutes'); loop.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { - title.should.equal('Last loop'); + title.should.equal('Last Loop'); response.should.equal('The last successful loop was a few seconds ago'); done(); }, [], sbx); diff --git a/tests/openaps.test.js b/tests/openaps.test.js index 9bfc5161969..5c76deeaaf3 100644 --- a/tests/openaps.test.js +++ b/tests/openaps.test.js @@ -389,7 +389,7 @@ describe('openaps', function ( ) { response.should.equal('The OpenAPS Eventual BG is 125'); openaps.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { - title.should.equal('Last loop'); + title.should.equal('Last Loop'); response.should.equal('The last successful loop was 2 minutes ago'); done(); }, [], sbx); diff --git a/tests/pump.test.js b/tests/pump.test.js index 483d5a49316..374ba03f06c 100644 --- a/tests/pump.test.js +++ b/tests/pump.test.js @@ -269,19 +269,19 @@ describe('pump', function ( ) { pump.virtAsst.intentHandlers.length.should.equal(4); pump.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { - title.should.equal('Remaining insulin'); + title.should.equal('Remaining Insulin'); response.should.equal('You have 86.4 units remaining'); pump.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { - title.should.equal('Pump battery'); + title.should.equal('Pump Battery'); response.should.equal('Your pump battery is at 1.52 volts'); pump.virtAsst.intentHandlers[2].intentHandler(function next(title, response) { - title.should.equal('Remaining insulin'); + title.should.equal('Remaining Insulin'); response.should.equal('You have 86.4 units remaining'); pump.virtAsst.intentHandlers[3].intentHandler(function next(title, response) { - title.should.equal('Pump battery'); + title.should.equal('Pump Battery'); response.should.equal('Your pump battery is at 1.52 volts'); done(); }, [], sbx); diff --git a/tests/upbat.test.js b/tests/upbat.test.js index cac1439160c..42d18bb0854 100644 --- a/tests/upbat.test.js +++ b/tests/upbat.test.js @@ -109,11 +109,11 @@ describe('Uploader Battery', function ( ) { upbat.virtAsst.intentHandlers.length.should.equal(2); upbat.virtAsst.intentHandlers[0].intentHandler(function next(title, response) { - title.should.equal('Uploader battery'); + title.should.equal('Uploader Battery'); response.should.equal('Your uploader battery is at 20%'); upbat.virtAsst.intentHandlers[1].intentHandler(function next(title, response) { - title.should.equal('Uploader battery'); + title.should.equal('Uploader Battery'); response.should.equal('Your uploader battery is at 20%'); done(); From 6dee062f1840f83af8845010d856c8b60766518d Mon Sep 17 00:00:00 2001 From: inventor96 Date: Mon, 16 Sep 2019 16:20:30 -0600 Subject: [PATCH 45/48] Improved training phrases --- docs/plugins/alexa-templates/en-us.json | 6 ++++++ docs/plugins/google-home-templates/en-us.zip | Bin 12265 -> 13230 bytes 2 files changed, 6 insertions(+) diff --git a/docs/plugins/alexa-templates/en-us.json b/docs/plugins/alexa-templates/en-us.json index bb1ff0932c5..cf90a710b88 100644 --- a/docs/plugins/alexa-templates/en-us.json +++ b/docs/plugins/alexa-templates/en-us.json @@ -42,6 +42,12 @@ } ], "samples": [ + "how much {metric} does {pwd} have left", + "what's {metric}", + "what's my {metric}", + "how much {metric} is left", + "what's {pwd} {metric}", + "how much {metric}", "how is {metric}", "how is my {metric}", "how is {pwd} {metric}", diff --git a/docs/plugins/google-home-templates/en-us.zip b/docs/plugins/google-home-templates/en-us.zip index 71dc40256bf9958fba2cef7d4c1cd35f4d25e718..6a8498b0b19e0c1822efaf4652f737cf282b350d 100644 GIT binary patch literal 13230 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 literal 12265 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 Date: Wed, 16 Oct 2019 15:34:54 -0700 Subject: [PATCH 46/48] Wording improvements --- docs/plugins/googlehome-plugin.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 8474cee5ba8..6cb50738ffd 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -25,8 +25,8 @@ To add Google Home support for your Nightscout site, here's what you need to do: 1. Click any of the "development experience" options (it really doesn't matter). 1. Click on the "Develop" tab at the top of the sreen 1. Click on "Invocation" in the left navigation pane. -1. Set the display name (e.g. "Nightscout") and set your Google Assistant voice. - - Unfortunately, the name needs to be two words, and has to be unique across all of Google, even though you won't be publishing for everyone on Google to use. So you'll have to be creative in the name since "Night Scout" is already taken. +1. Set the display name (e.g. "Night Scout") of your Action and set your Google Assistant voice. + - Unfortunately, the Action name needs to be two words, and is required to be unique across all of Google, even though you won't be publishing this for everyone on Google to use. So you'll have to be creative with the name since "Night Scout" is already taken. 1. Click "Save" in the upper right corner. 1. Navigate to "Actions" in the left nagivation pane, then click on the "Add your first action" button. 1. Make sure you're on "Cutom intent" and then click "Build" to open DialogFlow in a new tab. @@ -48,7 +48,7 @@ To add Google Home support for your Nightscout site, here's what you need to do: 1. Turn on the toggle for "Auto-preview changes". 1. Click "CLOSE". -That's it! Now try asking Google "Hey Google, ask *your agent's name* how am I doing?" +That's it! Now try asking Google "Hey Google, ask *your Action's name* how am I doing?" ### What questions can you ask it? From 0fc121c734e4eeb8a91cbd213d1184e6a0b82fc0 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sat, 19 Oct 2019 13:07:08 -0700 Subject: [PATCH 47/48] Google Home setup instruction corrections --- docs/plugins/googlehome-plugin.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 6cb50738ffd..c5dff113ab1 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -10,7 +10,7 @@ To add Google Home support for your Nightscout site, here's what you need to do: ## Activate the Nightscout Google Home Plugin -1. Your Nightscout site needs to be new enough that it supports the `googlehome` plugin. It needs to be [version VERSION_NUMBER (VERSION_NAME)](https://github.com/nightscout/cgm-remote-monitor/releases/tag/VERSION_NUMBER) or later. See [updating my version](https://github.com/nightscout/cgm-remote-monitor#updating-my-version) if you need a newer version. +1. Your Nightscout site needs to be new enough that it supports the `googlehome` plugin. It needs to be [version 0.13 (VERSION_NAME)](https://github.com/nightscout/cgm-remote-monitor/releases/tag/0.13) or later. See [updating my version](https://github.com/nightscout/cgm-remote-monitor#updating-my-version) if you need a newer version. 1. Add `googlehome` to the list of plugins in your `ENABLE` setting. ([Environment variables](https://github.com/nightscout/cgm-remote-monitor#environment) are set in the configuration section for your monitor. Typically Azure, Heroku, etc.) ## Create Your DialogFlow Agent @@ -22,8 +22,8 @@ To add Google Home support for your Nightscout site, here's what you need to do: 1. Click on the "New Project" button. 1. If prompted, agree to the Terms of Service. 1. Give your project a name (e.g. "Nightscout") and then click "Create project". -1. Click any of the "development experience" options (it really doesn't matter). -1. Click on the "Develop" tab at the top of the sreen +1. For the "development experience", select "Conversational" at the bottom of the list. +1. Click on the "Develop" tab at the top of the sreen. 1. Click on "Invocation" in the left navigation pane. 1. Set the display name (e.g. "Night Scout") of your Action and set your Google Assistant voice. - Unfortunately, the Action name needs to be two words, and is required to be unique across all of Google, even though you won't be publishing this for everyone on Google to use. So you'll have to be creative with the name since "Night Scout" is already taken. From 3cb3f47c50f8636fd7a5a628f33f542370eb53b3 Mon Sep 17 00:00:00 2001 From: inventor96 Date: Sun, 20 Oct 2019 01:30:35 -0700 Subject: [PATCH 48/48] Corrected how metric selection is found --- lib/api/alexa/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index 6669a894823..f5a55c214de 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -135,7 +135,16 @@ function configure (app, wares, ctx, env) { } function handleIntent(intentName, slots, next) { - var handler = ctx.alexa.getIntentHandler(intentName, slots.metric.value); + if (slots.metric.resolutions.resolutionsPerAuthority[0].status.code != "ER_SUCCESS_MATCH"){ + next('Unknown Intent', 'I\'m sorry. I don\'t know what you\'re asking for.'); + } + + var metricValues = slots.metric.resolutions.resolutionsPerAuthority[0].values; + if (metricValues.length == 0){ + next('Unknown Intent', 'I\'m sorry. I don\'t know what you\'re asking for.'); + } + + var handler = ctx.alexa.getIntentHandler(intentName, metricValues[0].value.name); if (handler){ var sbx = initializeSandbox(); handler(next, slots, sbx);