Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speech plugin #3325

Merged
merged 5 commits into from
Jul 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,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](lib/plugins/alexa-plugin.md)

##### `speech` (Speech)
Speech synthesis plugin. When enabled, speaks out the blood glucose values, IOB and alarms.

##### `cors` (CORS)
Enabled [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) so other websites can make request to your Nightscout site, uses these extended settings:
* `CORS_ALLOW_ORIGIN` (`*`) - The list of sites that are allow to make requests
Expand Down
7 changes: 7 additions & 0 deletions lib/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,13 @@ client.load = function load(serverSettings, callback) {
playAlarm(audio);
$(this).addClass('playing');
});

var speechPlugin = client.plugins('speech');

if (speechPlugin) {
speechPlugin.say(alarmMessage);
}

}

container.addClass('alarming').addClass(file === urgentAlarmSound ? 'urgent' : 'warning');
Expand Down
63 changes: 39 additions & 24 deletions lib/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,37 @@ var _ = require('lodash');

function init() {
var lang;

language.speechCode;

function language() {
return language;
}

language.languages = [
{ code: 'bg', language: 'Български' }
, { code: 'cs', language: 'Čeština' }
, { code: 'de', language: 'Deutsch' }
, { code: 'dk', language: 'Dansk' }
, { code: 'el', language: 'Ελληνικά' }
, { code: 'en', language: 'English' }
, { code: 'es', language: 'Español' }
, { code: 'fi', language: 'Suomi' }
, { code: 'fr', language: 'Français' }
, { code: 'he', language: 'עברית' }
, { code: 'hr', language: 'Hrvatski' }
, { code: 'it', language: 'Italiano' }
, { code: 'ko', language: '한국어' }
, { code: 'nb', language: 'Norsk (Bokmål)' }
, { code: 'nl', language: 'Nederlands' }
, { code: 'pl', language: 'Polski' }
, { code: 'pt', language: 'Português (Brasil)' }
, { code: 'ro', language: 'Română' }
, { code: 'ru', language: 'Русский' }
, { code: 'sk', language: 'Slovenčina' }
, { code: 'sv', language: 'Svenska' }
  , { code: 'zh_cn', language: '中文(简体)' }
  , { code: 'zh_tw', language: '中文(繁體)' }
{ code: 'bg', language: 'Български', speechCode: 'bg-BG' }
, { code: 'cs', language: 'Čeština', speechCode: 'cs-CZ' }
, { code: 'de', language: 'Deutsch', speechCode: 'de-DE' }
, { code: 'dk', language: 'Dansk', speechCode: 'dk-DK' }
, { code: 'el', language: 'Ελληνικά', speechCode: 'el-GR'}
, { code: 'en', language: 'English', speechCode: 'en-US' }
, { code: 'es', language: 'Español', speechCode: 'es-ES' }
, { code: 'fi', language: 'Suomi', speechCode: 'fi-FI' }
, { code: 'fr', language: 'Français', speechCode: 'fr-FR' }
, { code: 'he', language: 'עברית', speechCode: 'he-IL' }
, { code: 'hr', language: 'Hrvatski', speechCode: 'hr-HR' }
, { code: 'it', language: 'Italiano', speechCode: 'it-IT' }
, { code: 'ko', language: '한국어', speechCode: 'ko-KR' }
, { code: 'nb', language: 'Norsk (Bokmål)', speechCode: 'no-NO' }
, { code: 'nl', language: 'Nederlands', speechCode: 'nl-NL' }
, { code: 'pl', language: 'Polski', speechCode: 'pl-PL' }
, { code: 'pt', language: 'Português (Brasil)', speechCode: 'pt-BR' }
, { code: 'ro', language: 'Română', speechCode: 'ro-RO' }
, { code: 'ru', language: 'Русский', speechCode: 'ru-RU' }
, { code: 'sk', language: 'Slovenčina', speechCode: 'sk-SK' }
, { code: 'sv', language: 'Svenska', speechCode: 'sv-SE' }
  , { code: 'zh_cn', language: '中文(简体)', speechCode: 'cmn-Hans-CN' }
  , { code: 'zh_tw', language: '中文(繁體)', speechCode: 'cmn-Hant-TW' }
];

var translations = {
Expand Down Expand Up @@ -11446,6 +11448,14 @@ function init() {
'Eating Soon': {
fi: 'Ruokailu pian'
}
,
'Last entry {0} minutes ago': {
fi: 'Edellinen verensokeri {0} minuuttia sitten'
}
,
'change': {
fi: 'muutos'
}

};

Expand Down Expand Up @@ -11487,7 +11497,7 @@ function init() {
}
return translated;
};

language.DOMtranslate = function DOMtranslate($) {
// do translation of static text on load
$('.translate').each(function () {
Expand All @@ -11502,6 +11512,11 @@ function init() {

language.set = function set(newlang) {
lang = newlang;

language.languages.forEach(function (l) {
if (l.code == lang && l.speechCode) language.speechCode = l.speechCode;
});

return language();
};

Expand Down
1 change: 1 addition & 0 deletions lib/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function init (ctx) {
, require('./basalprofile')(ctx)
, require('./boluscalc')(ctx) // fake plugin to show/hide
, require('./profile')(ctx) // fake plugin to hold extended settings
, require('./speech')(ctx)
];

var serverDefaultPlugins = [
Expand Down
80 changes: 80 additions & 0 deletions lib/plugins/speech.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use strict';

var levels = require('../levels');
var times = require('../times');

var lastEntryValue;
var lastTime;
var lastMinutes;


function init(ctx) {
var translate = ctx.language.translate;
var speechLangCode = ctx.language.speechCode;

var speech = {
name: 'speech',
label: 'Speech',
pluginType: 'pill-status',
pillFlip: true
};


speech.say = function say(sayIt) {
console.log('saying ' + sayIt + ' using lang code' + speechLangCode);
var msg = new SpeechSynthesisUtterance(sayIt);
if (speechLangCode) msg.lang = speechLangCode;
window.speechSynthesis.speak(msg);
}

speech.updateVisualisation = function updateVisualisation(sbx) {

if (sbx.data.inRetroMode) return;

var timeNow = sbx.time;
var entry = sbx.lastSGVEntry();

if (timeNow && entry && entry.mills) {

var timeSince = timeNow - entry.mills;
var timeMinutes = Math.round(timeSince / 60000);

if (lastEntryValue != entry.mgdl) {

var delta = entry.mgdl - lastEntryValue;
lastEntryValue = entry.mgdl;

var sayIt = sbx.roundBGToDisplayFormat(sbx.scaleMgdl(entry.mgdl));
if (!isNaN(delta)) {

sayIt += ', ' + translate('change') + ' ' + sbx.roundBGToDisplayFormat(sbx.scaleMgdl(delta))
}

var iob = sbx.properties.iob;
if (iob) {
var iobString = sbx.roundInsulinForDisplayFormat(iob.display);

if (iobString) {
sayIt += ", IOB " + iobString;
}
}
speech.say(sayIt);

} else {

if (timeMinutes > 5 && timeMinutes != lastMinutes) {
lastMinutes = timeMinutes;

var lastEntryString = translate('Last entry {0} minutes ago');
var sayIt = lastEntryString.replace('{0}', timeMinutes);
speech.say(sayIt);
}
}
}
};

return speech;

}

module.exports = init;