diff --git a/lib/language.js b/lib/language.js index 65dd59d3962..dbae7657a72 100644 --- a/lib/language.js +++ b/lib/language.js @@ -12078,7 +12078,7 @@ function init() { 'alexaIobIntent': { bg: 'Máte %1 jednotek aktivního inzulínu' , cs: 'You have %1 insulin on board' - , de: 'Du hast noch %1 Insulin wirkend' + , de: 'Du hast %1 Insulin wirkend' , dk: 'Du har %1 insulin i kroppen' , el: 'You have %1 insulin on board' , en: 'You have %1 insulin on board' @@ -12137,7 +12137,7 @@ function init() { , fr: 'Your' , he: 'Your' , hr: 'Your' - , it: 'Tuo' + , it: 'La tua' , ko: 'Your' , nb: 'Your' , pl: 'twój' @@ -12150,6 +12150,31 @@ function init() { , zh_cn: '你的' , zh_tw: 'Your' }, + 'alexaPreambleHaving': { + bg: 'You have' + , cs: 'You have' + , de: 'Du hast' + , dk: 'You have' + , el: 'You have' + , en: 'You have' + , es: 'You have' + , fi: 'You have' + , fr: 'You have' + , he: 'You have' + , hr: 'You have' + , it: 'Tu hai' + , ko: 'You have' + , nb: 'You have' + , pl: 'You have' + , pt: 'You have' + , nl: 'You have' + , ro: 'You have' + , ru: 'You have' + , sk: 'You have' + , sv: 'You have' + , zh_cn: 'You have' + , zh_tw: 'You have' + }, 'alexaPreamble3person': { bg: '%1 has a ' , cs: '%1 má ' @@ -12175,7 +12200,32 @@ function init() { , zh_cn: '%1 有一个 ' , zh_tw: '%1 has a ' }, - 'alexaNoInsulin': { + 'alexaPreamble3person': { + bg: '%1 has a ' + , cs: '%1 má ' + , de: '%1 hat eine' + , dk: '%1 har en ' + , el: '%1 has a ' + , en: '%1 has a ' + , es: '%1 tiene un ' + , fi: '%1 on ' + , fr: '%1 has a ' + , he: '%1 has a ' + , hr: '%1 has a ' + , it: '%1 ha un ' + , ko: '%1 has a ' + , nb: '%1 has a ' + , nl: '%1 heeft een ' + , pl: '%1 ma ' + , pt: '%1 has a ' + , ro: '%1 are ' + , ru: '%1 имеет ' + , sk: '%1 has a ' + , sv: '%1 has a ' + , zh_cn: '%1 有一个 ' + , zh_tw: '%1 has a ' + }, + 'alexaNo': { bg: 'no' , cs: 'žádný' , de: 'kein' @@ -12206,6 +12256,7 @@ function init() { , en: 'Your uploader battery is at %1' , de: 'Der Akku deines Uploader Handys ist bei %1' , dk: 'Din uploaders batteri er %1' + , it: 'La batteria del tuo dispositivo è %1' , nl: 'De batterij van je mobiel is bij %l' ,zh_cn: '你的手机电池电量是 %1 ' , sv: 'Din uppladdares batteri är %1' @@ -12220,6 +12271,7 @@ function init() { , en: 'You have %1 units remaining' , de: 'Du hast %1 Einheiten übrig' , dk: 'Du har %1 enheder tilbage' + , it: 'Ci sono ancora %1 unità rimanenti' , nl: 'Je hebt nog %l eenheden in je reservoir' ,zh_cn: '你剩余%1 U的胰岛素' , sv: 'Du har %1 enheter kvar' @@ -12234,6 +12286,7 @@ function init() { , en: 'Your pump battery is at %1 %2' , de: 'Der Batteriestand deiner Pumpe ist bei %1 %2' , dk: 'Din pumpes batteri er %1 %2' + , it: 'La batteria del microinfusore è al %1 %2' , nl: 'Je pomp batterij is bij %1 %2' ,zh_cn: '你的泵电池电量是%1 %2' , sv: 'Din pumps batteri är %1 %2' @@ -12248,6 +12301,7 @@ function init() { , en: 'The last successful loop was %1' , de: 'Der letzte erfolgreiche Loop war %1' , dk: 'Seneste successfulde loop var %1' + , it: 'L ultimo loop riuscito di %1' , nl: 'De meest recente goede loop was %1' ,zh_cn: '最后一次成功闭环的是在%1' , sv: 'Senaste lyckade loop var %1' @@ -12262,6 +12316,7 @@ function init() { , en: 'Loop plugin does not seem to be enabled' , de: 'Das Loop Plugin scheint nicht aktiviert zu sein' , dk: 'Loop plugin lader ikke til at være slået til' + , it: 'Non è attivato il plugin di Loop' , nl: 'De Loop plugin is niet geactiveerd' ,zh_cn: 'Loop插件看起来没有被启用' , sv: 'Loop plugin verkar inte vara aktiverad' @@ -12276,6 +12331,7 @@ function init() { , en: 'According to the loop forecast you are expected to be %1 over the next %2' , de: 'Entsprechend der Loop Vorhersage landest du bei %1 während der nächsten %2' , dk: 'Ifølge Loops forudsigelse forventes du at blive %1 i den næste %2' + , it: 'In base alla predizione di Loop la tua glicemia sarà di %1 nei prossimi %2' , nl: 'Volgens de Loop voorspelling is je waarde %1 over de volgnede %2' ,zh_cn: '根据loop的预测,在接下来的%2你的血糖将会是%1' , sv: 'Enligt Loops förutsägelse förväntas du bli %1 inom %2' @@ -12290,6 +12346,7 @@ function init() { , en: 'Unable to forecast with the data that is available' , de: 'Mit den verfügbaren Daten ist eine Loop Vorhersage nicht möglich' , dk: 'Det er ikke muligt at forudsige md de tilgængelige data' + , it: 'Non è possibile avere una predizione con i dati disponibili' , nl: 'Niet mogelijk om een voorspelling te doen met de data die beschikbaar is' ,zh_cn: '血糖数据不可用,无法预测未来走势' , sv: 'Förutsägelse ej möjlig med tillgänlig data' @@ -12298,11 +12355,27 @@ function init() { , pl: 'Prognoza pętli nie jest możliwa, z dostępnymi danymi.' , ru: 'прогноз при таких данных невозможен' }, + 'alexaLoop': { + bg: 'According to the loop forecast you are expected to be %1 over the next %2' + , cs: 'According to the loop forecast you are expected to be %1 over the next %2' + , en: 'According to the loop forecast you are expected to be %1 over the next %2' + , de: 'Laut Loop Vorhersage liegst du in %2 bei %1' + , dk: 'According to the loop forecast you are expected to be %1 over the next %2' + , it: 'In base alla previsione di Loop la glicemia sarà %1 %2' + , nl: 'According to the loop forecast you are expected to be %1 over the next %2' + ,zh_cn: 'According to the loop forecast you are expected to be %1 over the next %2' + , sv: 'According to the loop forecast you are expected to be %1 over the next %2' + , fi: 'According to the loop forecast you are expected to be %1 over the next %2' + , ro: 'According to the loop forecast you are expected to be %1 over the next %2' + , pl: 'According to the loop forecast you are expected to be %1 over the next %2' + , ru: 'According to the loop forecast you are expected to be %1 over the next %2' + }, 'alexaRawBG': { en: 'Your raw bg is %1' , cs: 'Raw glykémie je %1' , de: 'Dein Rohblutzucker ist %1' , dk: 'Dit raw blodsukker er %1' + , it: 'Il dato grezzo della glicemia è %1' , nl: 'Je raw bloedwaarde is %1' ,zh_cn: '你的血糖是 %1' , sv: 'Ditt raw blodsocker är %1' @@ -12312,11 +12385,20 @@ function init() { , pl: 'Glikemia RAW wynosi %1' , ru: 'ваши необработанные данные RAW $1' }, + 'alexaAr2NoHandler': { + en: 'AR2 plugin does not seem to be enabled', + de: 'AR2 Plugin ist nicht aktiviert' + }, + 'alexaAr2Handler': { + en: 'You are expected to be between %1 and %2 over the %3', + de: 'Der %3 erwartete Blutzucker liegt zwischen %1 und %2' + }, 'alexaOpenAPSForecast': { en: 'The OpenAPS Eventual BG is %1' , cs: 'OpenAPS Eventual BG je %1' , de: 'Der von OpenAPS vorhergesagte Blutzucker ist %1' , dk: 'OpenAPS forventet blodsukker er %1' + , it: 'La glicemia predetta da OpenAPS è %1' , nl: 'OpenAPS uiteindelijke bloedglucose van %1' ,zh_cn: 'OpenAPS 预测最终血糖是 %1' , sv: 'OpenAPS slutgiltigt blodsocker är %1' @@ -12331,6 +12413,21 @@ function init() { , cs: '%1 %2 aktivních sachridů' , de: '%1 %2 Gramm Kohlenhydrate wirkend.' , dk: '%1 %2 gram aktive kulhydrater' + , it: '%1 %2 grammi di carboidrati da digerire' + , nl: '%1 %2 actieve koolhydraten' + ,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' + , pl: '%1 %2 aktywnych węglowodanów' + , ru: '%1 $2 активных углеводов' + }, + 'alexaCOB3erson': { + en: '%1 has %2 carbohydrates on board' + , cs: '%1 %2 aktivních sachridů' + , de: '%1 hat %2 Gramm Kohlenhydrate wirkend.' + , dk: '%1 %2 gram aktive kulhydrater' , nl: '%1 %2 actieve koolhydraten' ,zh_cn: '%1 %2 活性碳水化合物' , sv: '%1 %2 gram aktiva kolhydrater' @@ -12345,6 +12442,7 @@ function init() { ,de: 'Fett [g]' ,dk: 'Fet [g]' ,es: 'Grasas [g]' + ,it: 'Grassi [g]' ,fi: 'Rasva [g]' ,fr: 'Graisses [g]' ,nl: 'Vet [g]' diff --git a/lib/plugins/alexa-plugin.md b/lib/plugins/alexa-plugin.md index dd43fe42ca3..b725b3b41e1 100644 --- a/lib/plugins/alexa-plugin.md +++ b/lib/plugins/alexa-plugin.md @@ -113,12 +113,19 @@ To get up and running with a basic interaction model, which will allow you to as "values": [ { "name": { - "value": "bg" + "value": "bg", + "synonyms": [ + "BZ", + "Blutzucker" //these could be some synonyms to the above value in YOUR language! + ] } }, { "name": { - "value": "blood glucose" + "value": "blood glucose", + "synonyms": [ + //here could be some synonyms to the above value in YOUR language! + ] } }, { @@ -128,7 +135,14 @@ To get up and running with a basic interaction model, which will allow you to as }, { "name": { - "value": "iob" + "value": "iob", + "synonyms": [ + "Insulin an Board", + "Restwirkung", + "Wirkinsulin" + //here could be some synonyms to the above value in YOUR language! + ] + } }, { @@ -143,12 +157,19 @@ To get up and running with a basic interaction model, which will allow you to as }, { "name": { - "value": "basal" + "value": "basal", + "synonyms": [ + "Basalrate" //synonyms in your language + ] } }, { "name": { - "value": "cob" + "value": "cob", + "synonyms": [ + "Kohlenhydraten", + "Kohlenhydrate" //synonyms in your language + ] } }, { @@ -236,6 +257,12 @@ After you enable testing, you can also use the Alexa Simulator in the left colum *Metrics:* +Note: You can add synonyms to the available metric terms: + +- Go to Slot Types -> LIST_OF_METRICS and add your terms in the "synonyms" column. + +Examples: + - "Alexa, ask Nightscout what my bg is" - "Alexa, ask Nightscout what my blood glucose is" - "Alexa, ask Nightscout what my number is" diff --git a/lib/plugins/alexa.js b/lib/plugins/alexa.js index 38ae449c249..aac2dc91a02 100644 --- a/lib/plugins/alexa.js +++ b/lib/plugins/alexa.js @@ -15,12 +15,12 @@ function init(env, ctx) { // 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]) { + 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]]) { @@ -32,6 +32,20 @@ function init(env, ctx) { intentHandlers[intent].handler = handler; } }; + var retrieveMetricSynonym = function (slot) { + //try to get synonym metric names, as those could be translatable: + if (slot['resolutions']) { + var synonyms = slot['resolutions']['resolutionsPerAuthority']; + if (synonyms && synonyms.length > 0 && synonyms[0] //element exists + && synonyms[0].status && synonyms[0].status.code === 'ER_SUCCESS_MATCH') //valid matching + { + var syn = synonyms[0].values[0]; + if (syn && syn.value && syn.value.name) + return syn.value.name; + } + } + return undefined; + }; // This function retrieves a handler based on the intent name and slots requested. alexa.getIntentHandler = function getIntentHandler(intentName, slots) { @@ -39,11 +53,16 @@ function init(env, ctx) { 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) { + var key = slotKeys[i]; + var slot = slots[key]; + var syn = retrieveMetricSynonym(slot); + var metricName = syn ? syn : slot.value; + + if (intentHandlers[intentName][key] && metricName && + intentHandlers[intentName][key][metricName] && + intentHandlers[intentName][key][metricName].handler) { - return intentHandlers[intentName][slotKeys[i]][slots[slotKeys[i]].value].handler; + return intentHandlers[intentName][key][metricName].handler; } } } @@ -57,7 +76,7 @@ function init(env, ctx) { }; - alexa.addToRollup = function(rollupGroup, handler, rollupName) { + alexa.addToRollup = function (rollupGroup, handler, rollupName) { if (!rollup[rollupGroup]) { console.log('Creating the rollup group: ', rollupGroup); rollup[rollupGroup] = []; @@ -66,7 +85,7 @@ function init(env, ctx) { // status = _.orderBy(status, ['priority'], ['asc']) }; - alexa.getRollup = function(rollupGroup, sbx, slots, locale, callback) { + alexa.getRollup = function (rollupGroup, sbx, slots, locale, callback) { var handlers = _.map(rollup[rollupGroup], 'handler'); console.log('Rollup array for ', rollupGroup); console.log(rollup[rollupGroup]); @@ -74,7 +93,7 @@ function init(env, ctx) { _.each(handlers, function (handler) { nHandlers.push(handler.bind(null, slots, sbx)); }); - async.parallelLimit(nHandlers, 10, function(err, results) { + async.parallelLimit(nHandlers, 10, function (err, results) { if (err) { console.error('Error: ', err); } diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js index c440f613e0a..c9ed3287e3e 100644 --- a/lib/plugins/ar2.js +++ b/lib/plugins/ar2.js @@ -15,8 +15,8 @@ var AR = [-0.723, 1.716]; //TODO: move this to css var AR2_COLOR = 'cyan'; -function init (ctx) { - +function init(ctx) { + var translate = ctx.language.translate; var ar2 = { name: 'ar2' , label: 'AR2' @@ -24,7 +24,7 @@ function init (ctx) { }; function buildTitle(prop, sbx) { - var rangeLabel = prop.eventName ? sbx.translate(prop.eventName, { ci: true }).toUpperCase() : sbx.translate('Check BG'); + var rangeLabel = prop.eventName ? sbx.translate(prop.eventName, {ci: true}).toUpperCase() : sbx.translate('Check BG'); var title = sbx.levels.toDisplay(prop.level) + ', ' + rangeLabel; var sgv = sbx.lastScaledSGV(); @@ -34,8 +34,8 @@ function init (ctx) { return title; } - ar2.setProperties = function setProperties (sbx) { - sbx.offerProperty('ar2', function setAR2 ( ) { + ar2.setProperties = function setProperties(sbx) { + sbx.offerProperty('ar2', function setAR2() { var prop = { forecast: ar2.forecast(sbx) @@ -49,7 +49,9 @@ function init (ctx) { } var predicted = prop.forecast && prop.forecast.predicted; - var scaled = predicted && _.map(predicted, function(p) { return sbx.scaleEntry(p) } ); + var scaled = predicted && _.map(predicted, function (p) { + return sbx.scaleEntry(p) + }); if (scaled && scaled.length >= 3) { prop.displayLine = 'BG 15m: ' + scaled[2] + ' ' + sbx.unitsLabel; @@ -59,7 +61,7 @@ function init (ctx) { }); }; - ar2.checkNotifications = function checkNotifications (sbx) { + ar2.checkNotifications = function checkNotifications(sbx) { if (sbx.time - sbx.lastSGVMills() > times.mins(10).msecs) { return; } @@ -79,7 +81,7 @@ function init (ctx) { } }; - ar2.forecast = function forecast (sbx) { + ar2.forecast = function forecast(sbx) { var result = { predicted: [] @@ -110,7 +112,7 @@ function init (ctx) { sbx.pluginBase.addForecastPoints(ar2.forecastCone(sbx), {type: 'ar2', label: 'AR2 Forecast'}); }; - ar2.forecastCone = function forecastCone (sbx) { + ar2.forecastCone = function forecastCone(sbx) { if (!okToForecast(sbx)) { return []; @@ -124,12 +126,12 @@ function init (ctx) { //offset from points so they are at a unique time if (coneFactor > 0) { next.points.push(ar2Point(next - , { offset: 2000, coneFactor: -coneFactor, step: step } + , {offset: 2000, coneFactor: -coneFactor, step: step} )); } next.points.push(ar2Point(next - , { offset: 4000, coneFactor: coneFactor, step: step } + , {offset: 4000, coneFactor: coneFactor, step: step} )); return next; @@ -145,7 +147,7 @@ function init (ctx) { return result.points; }; - function alexaAr2Handler (next, slots, sbx) { + function alexaAr2Handler(next, slots, sbx) { if (sbx.properties.ar2.forecast.predicted) { var forecast = sbx.properties.ar2.forecast.predicted; var max = forecast[0].mgdl; @@ -162,18 +164,25 @@ 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 response = translate('alexaAr2Handler', { + params: [ + min,//min + max,//max + moment(maxForecastMills).from(moment(sbx.time))//time + ] + } + ); next('AR2 Forecast', response); } else { - next('AR2 Forecast', 'AR2 plugin does not seem to be enabled'); + next('AR2 Forecast', translate('alexaAr2NoHandler') ); } } ar2.alexa = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot:'metric' - , slots:['ar2 forecast', 'forecast'] + , routableSlot: 'metric' + , slots: ['ar2 forecast', 'forecast'] , intentHandler: alexaAr2Handler }] }; @@ -185,9 +194,9 @@ function checkForecast(forecast, sbx) { var result = undefined; if (forecast && forecast.avgLoss > URGENT_THRESHOLD) { - result = { level: sbx.levels.URGENT }; + result = {level: sbx.levels.URGENT}; } else if (forecast && forecast.avgLoss > WARN_THRESHOLD) { - result = { level: sbx.levels.WARN }; + result = {level: sbx.levels.WARN}; } if (result) { @@ -198,8 +207,10 @@ function checkForecast(forecast, sbx) { return result; } -function selectEventType (prop, sbx) { - var predicted = prop.forecast && _.map(prop.forecast.predicted, function(p) { return sbx.scaleEntry(p) } ); +function selectEventType(prop, sbx) { + var predicted = prop.forecast && _.map(prop.forecast.predicted, function (p) { + return sbx.scaleEntry(p) + }); var in20mins = predicted && predicted.length >= 4 ? predicted[3] : undefined; @@ -217,7 +228,7 @@ function selectEventType (prop, sbx) { return eventName; } -function pushoverSound (prop, levels) { +function pushoverSound(prop, levels) { var sound; if (prop.level === levels.URGENT) { @@ -231,7 +242,7 @@ function pushoverSound (prop, levels) { return sound; } -function getConeFactor (sbx) { +function getConeFactor(sbx) { var value = Number(sbx.extendedSettings.coneFactor); if (isNaN(value) || value < 0) { value = 2; @@ -251,7 +262,7 @@ function okToForecast(sbx) { return bgnow.mean >= BG_MIN && delta.mean5MinsAgo && _.isNumber(delta.mean5MinsAgo); } -function initAR2 (sbx) { +function initAR2(sbx) { var bgnow = sbx.properties.bgnow; var delta = sbx.properties.delta; var mean5MinsAgo = delta.mean5MinsAgo; @@ -264,7 +275,7 @@ function initAR2 (sbx) { }; } -function incrementAR2 (result) { +function incrementAR2(result) { return { forecastTime: result.forecastTime + times.mins(5).msecs , points: result.points || [] @@ -278,7 +289,7 @@ function pushPoint(result) { next.points.push(ar2Point( next - , { offset: 2000 } + , {offset: 2000} )); return next; @@ -302,15 +313,19 @@ function ar2Point(next, options) { } -function buildDebug (prop, sbx) { +function buildDebug(prop, sbx) { return prop.forecast && { forecast: { avgLoss: prop.forecast.avgLoss - , predicted: _.map(prop.forecast.predicted, function(p) { return sbx.scaleEntry(p) }).join(', ') + , predicted: _.map(prop.forecast.predicted, function (p) { + return sbx.scaleEntry(p) + }).join(', ') } }; } -function log10(val) { return Math.log(val) / Math.LN10; } +function log10(val) { + return Math.log(val) / Math.LN10; +} module.exports = init; diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index 3858e794848..39339739f71 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -17,14 +17,14 @@ function init(ctx) { cob.RECENCY_THRESHOLD = times.mins(30).msecs; cob.setProperties = function setProperties(sbx) { - sbx.offerProperty('cob', function setCOB ( ) { + sbx.offerProperty('cob', function setCOB() { return cob.cobTotal(sbx.data.treatments, sbx.data.devicestatus, sbx.data.profile, sbx.time); }); }; cob.cobTotal = function cobTotal(treatments, devicestatus, profile, time, spec_profile) { - if (!profile || !profile.hasData()) { + if (!profile || !profile.hasData()) { console.warn('For the COB plugin to function you need a treatment profile'); return {}; } @@ -67,7 +67,7 @@ function init(ctx) { }); } - cob.isDeviceStatusAvailable = function isDeviceStatusAvailable (devicestatus) { + cob.isDeviceStatusAvailable = function isDeviceStatusAvailable(devicestatus) { return _.chain(devicestatus) .map(cob.fromDeviceStatus) @@ -76,7 +76,7 @@ function init(ctx) { .length > 0; }; - cob.lastCOBDeviceStatus = function lastCOBDeviceStatus (devicestatus, time) { + cob.lastCOBDeviceStatus = function lastCOBDeviceStatus(devicestatus, time) { var futureMills = time + times.mins(5).msecs; //allow for clocks to be a little off var recentMills = time - cob.RECENCY_THRESHOLD; @@ -92,7 +92,7 @@ function init(ctx) { .value(); }; - cob.COBDeviceStatusesInTimeRange = function COBDeviceStatusesInTimeRange (devicestatus, from, to) { + cob.COBDeviceStatusesInTimeRange = function COBDeviceStatusesInTimeRange(devicestatus, from, to) { return _.chain(devicestatus) .filter(function (cobStatus) { @@ -140,7 +140,7 @@ function init(ctx) { cob: lastCOB , source: 'OpenAPS' , device: devicestatusEntry.device - , mills: lastMoment.valueOf( ) + , mills: lastMoment.valueOf() }; } else if (_.get(devicestatusEntry, 'loop.cob') !== undefined) { cobObj = devicestatusEntry.loop.cob; @@ -148,14 +148,14 @@ function init(ctx) { cob: cobObj.cob , source: 'Loop' , device: devicestatusEntry.device - , mills: moment(cobObj.timestamp).valueOf( ) + , mills: moment(cobObj.timestamp).valueOf() }; } else { return {}; } }; - cob.fromTreatments = function fromTreatments (treatments, devicestatus, profile, time, spec_profile) { + cob.fromTreatments = function fromTreatments(treatments, devicestatus, profile, time, spec_profile) { // TODO: figure out the liverSensRatio that gives the most accurate purple line predictions var liverSensRatio = 8; var totalCOB = 0; @@ -175,7 +175,7 @@ function init(ctx) { var actEnd = iob.calcTotal(treatments, devicestatus, profile, cCalc.decayedBy, spec_profile).activity; var avgActivity = (actStart + actEnd) / 2; // units: g = BG * scalar / BG / U * g / U - var delayedCarbs = ( avgActivity * liverSensRatio / profile.getSensitivity(treatment.mills, spec_profile) ) * profile.getCarbRatio(treatment.mills, spec_profile); + var delayedCarbs = (avgActivity * liverSensRatio / profile.getSensitivity(treatment.mills, spec_profile)) * profile.getCarbRatio(treatment.mills, spec_profile); var delayMinutes = Math.round(delayedCarbs / profile.getCarbAbsorptionRate(treatment.mills, spec_profile) * 60); if (delayMinutes > 0) { cCalc.decayedBy.setMinutes(cCalc.decayedBy.getMinutes() + delayMinutes); @@ -232,7 +232,7 @@ function init(ctx) { if (treatment.carbs) { var carbTime = new Date(treatment.mills); - + var carbs_hr = profile.getCarbAbsorptionRate(treatment.mills, spec_profile); var carbs_min = carbs_hr / 60; @@ -269,11 +269,13 @@ function init(ctx) { var prop = sbx.properties.cob; - if (prop === undefined || prop.cob === undefined) { return; } + if (prop === undefined || prop.cob === undefined) { + return; + } var displayCob = Math.round(prop.cob * 10) / 10; - var info = [ ]; + var info = []; if (prop.treatmentCOB !== undefined && prop.treatmentCOB.cob) { info.push({label: translate('Careportal COB'), value: Math.round(prop.treatmentCOB.cob * 10) / 10}); } @@ -292,21 +294,32 @@ function init(ctx) { }); }; - function alexaCOBHandler (next, slots, sbx) { - var preamble = (slots && slots.pwd && slots.pwd.value) ? slots.pwd.value.replace('\'s', '') + ' has' : 'You have'; - var value = 'no'; + function alexaCOBHandler(next, slots, sbx) { + var preamble = (slots && slots.pwd && slots.pwd.value) ? translate('alexaPreamble3person', { + params: [ + slots.pwd.value + ] + }) : translate('alexaPreambleHaving'); + //var preamble = (slots && slots.pwd && slots.pwd.value) ? slots.pwd.value.replace('\'s', '') + ' has' : 'You have'; + var value = translate('alexaNo'); if (sbx.properties.cob && sbx.properties.cob.cob !== 0) { value = sbx.properties.cob.cob; } - var response = preamble + ' ' + value + ' carbohydrates on board'; + var response = translate('alexaCOB', { + params: [ + preamble, //preamble + Math.round(value * 10) / 10 //cob + ] + }) + preamble + ' ' + value + ' carbohydrates on board'; next('Current COB', response); } cob.alexa = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot:'metric' - , slots:['cob', 'carbs on board', 'carbohydrates on board'] + , routableSlot: 'metric' + , slots: ['cob', 'carbs on board', 'carbohydrates on board'] , intentHandler: alexaCOBHandler }] }; diff --git a/lib/plugins/iob.js b/lib/plugins/iob.js index 5468ff0700d..0329321447d 100644 --- a/lib/plugins/iob.js +++ b/lib/plugins/iob.js @@ -271,7 +271,7 @@ function init(ctx) { ] }); } - return translate('alexaNoInsulin'); + return translate('alexaNo'); } iob.alexa = { diff --git a/lib/plugins/loop.js b/lib/plugins/loop.js index 6082b6bdc00..df03e628604 100644 --- a/lib/plugins/loop.js +++ b/lib/plugins/loop.js @@ -8,6 +8,7 @@ var levels = require('../levels'); // var ALL_STATUS_FIELDS = ['status-symbol', 'status-label', 'iob', 'freq', 'rssi']; Unused variable function init(ctx) { + var translate = ctx.language.translate; var utils = require('../utils')(ctx); var loop = { @@ -415,7 +416,7 @@ function init(ctx) { }; function alexaForecastHandler (next, slots, sbx) { - if (sbx.properties.loop.lastLoop.predicted) { + if (sbx.properties.loop && sbx.properties.loop.lastLoop && sbx.properties.loop.lastLoop.predicted) { var forecast = sbx.properties.loop.lastLoop.predicted.values; var max = forecast[0]; var min = forecast[0]; @@ -440,11 +441,16 @@ function init(ctx) { } else { value = 'between ' + min + ' 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('alexaLoop', { + params: [ + value, + moment(endPrediction).from(moment(sbx.time)) + ] + }); next('Loop Forecast', response); } } else { - next('Loop forecast', 'Loop plugin does not seem to be enabled'); + next('Loop forecast', 'Loop plugin does not seem to be enabled or doesn\' have any recent data.'); } } diff --git a/lib/plugins/rawbg.js b/lib/plugins/rawbg.js index a3853f88e11..cdc57075980 100644 --- a/lib/plugins/rawbg.js +++ b/lib/plugins/rawbg.js @@ -97,7 +97,11 @@ function init (ctx) { }; function alexaRawBGHandler (next, slots, sbx) { - var response = 'Your raw bg is ' + sbx.properties.rawbg.mgdl; + var response = translate('alexaRawBG', { + params: [ + sbx.properties.rawbg.mgdl + ] + }); next('Current Raw BG', response); } diff --git a/lib/plugins/upbat.js b/lib/plugins/upbat.js index eda42a3901f..be45ca4e66c 100644 --- a/lib/plugins/upbat.js +++ b/lib/plugins/upbat.js @@ -4,8 +4,9 @@ var _ = require('lodash'); var times = require('../times'); var levels = require('../levels'); -function init() { +function init(ctx) { + var translate = ctx.language.translate; var upbat = { name: 'upbat' , label: 'Uploader Battery' @@ -222,7 +223,12 @@ function init() { }; function alexaUploaderBatteryHandler (next, slots, sbx) { - var response = 'Your uploader battery is at ' + sbx.properties.upbat.display; + var response = translate('alexaUploadBattery', { + params: [ + //preamble, + sbx.properties.upbat.display + ] + }); next('Uploader battery', response); }