announceNest : function (device, command, controllers, values, config) { var runCommand = require(__dirname + '/../lib/runCommand'), translate = require(__dirname + '/../lib/translate'), notify = require(__dirname + '/../lib/notify'), message = '', tempMessage = '', i = 0, subDevice, deviceId, rawMacro, macro; if(values.protect) { for(subDevice in values.protect) { if(values.protect[subDevice].smoke !== 'ok') { tempMessage = translate.translate('{{i18n_SMOKE_DETECTED}}', 'nest', controllers.config.language).replace('{{LABEL}}', values.protect[subDevice].label); if(message) { message = message + ' '; } message = message + tempMessage; } if(values.protect[subDevice].co !== 'ok') { tempMessage = translate.translate('{{i18n_CO_DETECTED}}', 'nest', controllers.config.language).replace('{{LABEL}}', values.protect[subDevice].label); if(message) { message = message + ' '; } message = message + tempMessage; } } if(message) { notify.notify(message, controllers, device); // If you have a macro assigned to this specific Mode, we'll act upon // it. if(config.macro) { rawMacro = config.macro.split(';'); for(macro in rawMacro) { runCommand.macroCommands(rawMacro[macro]); } } } } }
hallLightHome : function (deviceId, command, controllers, values, config) { var deviceState = require(__dirname + '/../lib/deviceState'), runCommand = require(__dirname + '/../lib/runCommand'), now = new Date().getTime(), delay = (config.delay || 15) * 1000, rawMacro = (config.macros || '').split(';'), macro, currentDeviceState, currDevice, subdevice, state, isIn = function (command, collection, prefix) { var found = false, current; for (current in collection) { if (command === prefix + collection[current] + '-on') { found = true; break; } } return found; }; if (isIn(command, config.presence, 'subdevice-state-presence-')) { this.lastEvents.presence = now; } else if (isIn(command, config.contact, 'subdevice-state-contact-')) { this.lastEvents.open = now; } if ((now > delay + this.lastEvents.acted) && (now < delay + this.lastEvents.presence) && (now < delay + this.lastEvents.open)) { if (config.macros) { for (macro in rawMacro) { if (rawMacro.hasOwnProperty(macro)) { runCommand.macroCommands(rawMacro[macro]); } } } for (currDevice in controllers) { if (controllers.hasOwnProperty(currDevice)) { state = deviceState.getDeviceState(currDevice); if (controllers[currDevice].config) { switch (controllers[currDevice].config.typeClass) { case 'smartthings' : case 'wemo' : case 'raspberryRemote' : currentDeviceState = deviceState.getDeviceState(currDevice); break; default : currentDeviceState = null; } if ((currentDeviceState.value) && (currentDeviceState.value.devices)) { for (subdevice in currentDeviceState.value.devices) { if (config.action.indexOf(currentDeviceState.value.devices[subdevice].label) !== -1) { this.lastEvents.acted = now; runCommand.runCommand(currDevice, 'subdevice-' + currentDeviceState.value.devices[subdevice].label + '-on', currDevice); } } } } } } } }
setDevice : function (rawText, controllers, device, macros, language) { var translate = require(__dirname + '/../../lib/translate'), runCommand = require(__dirname + '/../../lib/runCommand'), gertyLanguage = require(__dirname + '/language'), genericDevices = gertyLanguage.getGenericDevices(controllers), subDevices = gertyLanguage.getSubDevices(controllers), genericTerms = gertyLanguage.getGenericTerms(language), verbs = gertyLanguage.getVerbs(language), inquiry = gertyLanguage.getInquiry(language), implied = translate.translate('{{i18n_AND}}', 'gerty', language), commands = [{ action : null, implied : false }], questions = [{ action : null, implied : false }], devices = [{ device : null, typeClass : null, subDevice : null }], rawMacro = [], macro = '', text = [], keyword = '', acted = false, i = 0, j = 0, k = 0, x = 0; text = rawText.split(' '); if (macros) { // Loop through all configured macros anywhere in the inputted text. for (keyword in macros) { if (rawText.indexOf(keyword.toUpperCase()) !== -1) { rawMacro = macros[keyword].split(';'); for (macro in rawMacro) { if (rawMacro.hasOwnProperty(macro)) { runCommand.macroCommands(rawMacro[macro]); } } acted = true; } } } for (i = 0; i < text.length; i += 1) { // If you have a series of commands, you don't want to have to repeat // the same word. So we'll use "AND" to assume the same action. if ((commands.length > 1) && (text[i] === implied.toUpperCase())) { commands[j].action = commands[(j - 1)].action; commands[j].implied = true; } // Loop through looking for action words. Once we have one, store it // so we can act on it once we find a suitable device. for (keyword in verbs) { if (verbs.hasOwnProperty(keyword)) { // Look ahead for "Channel Up" to not confuse with just "Up". if (text[i] + ' ' + text[(i + 1)] === verbs[keyword].toUpperCase()) { commands[j].action = verbs[keyword]; i += 1; break; } else if (text[i] === verbs[keyword].toUpperCase()) { commands[j].action = verbs[keyword]; break; } // When we have a pair of action + command, we can start looking for // our next command. if ((commands[j].action) && (devices[j].device)) { j += 1; commands[j] = { action : null, implied : false }; devices[j] = { device : null, typeClass : null, subDevice : null }; } } } // Loop through looking for inquiry words. Once we have one, store it // so we can act on it once we find a suitable device. for (keyword in inquiry) { if (inquiry.hasOwnProperty(keyword)) { if (text[i] === inquiry[keyword].toUpperCase()) { questions[x].action = inquiry[keyword]; break; } // When we have a pair of action + command, we can start looking for // our next command. if ((questions[x].action) && (devices[j].device)) { x += 1; questions[x] = { action : null, implied : false }; devices[j] = { device : null, typeClass : null, subDevice : null }; } } } for (keyword in genericTerms) { // Check for generic names "TV", "Stereo", "Playstation", etc. if (genericTerms[keyword].toUpperCase() === text[i]) { if (controllers[genericDevices[genericTerms[keyword].toUpperCase()]]) { devices[j].device = genericDevices[genericTerms[keyword].toUpperCase()]; devices[j].typeClass = controllers[genericDevices[genericTerms[keyword].toUpperCase()]].config.typeClass; // When we have a pair of action + command, we can start looking // for our next command. if ((commands[j].action) && (devices[j].device)) { j += 1; commands[j] = { action : null, implied : false }; devices[j] = { device : null, typeClass : null, subDevice : null }; } } } } // Look through any registered subdevices that may need to be acted // upon. for (keyword in controllers) { if (keyword !== 'config') { if ((subDevices) && (subDevices[keyword]) && (subDevices[keyword].subDevices)) { for (k = 0; k < subDevices[keyword].subDevices.length; k += 1) { // Look ahead for device names that may be multiple words. if (text[i] + ' ' + text[(i + 1)] + ' ' + text[(i + 2)] === subDevices[keyword].subDevices[k].toUpperCase()) { devices[j].device = keyword; devices[j].typeClass = controllers[keyword].config.typeClass; devices[j].subDevice = subDevices[keyword].subDevices[k]; i += 2; break; } else if (text[i] + ' ' + text[(i + 1)] === subDevices[keyword].subDevices[k].toUpperCase()) { devices[j].device = keyword; devices[j].typeClass = controllers[keyword].config.typeClass; devices[j].subDevice = subDevices[keyword].subDevices[k]; i += 1; break; } else if (text[i] === subDevices[keyword].subDevices[k].toUpperCase()) { devices[j].device = keyword; devices[j].typeClass = controllers[keyword].config.typeClass; devices[j].subDevice = subDevices[keyword].subDevices[k]; } // When we have a pair of action + command, we can start looking for // our next command. if ((commands[j].action) && (devices[j].device)) { j += 1; commands[j] = { action : null, implied : false }; devices[j] = { device : null, typeClass : null, subDevice : null }; } } } } } // Look through each device and compare with the "title" used in the // navigation. for (keyword in controllers) { if (keyword !== 'config') { // Look ahead for device names that may be multiple words. if (text[i] + ' ' + text[(i + 1)] + ' ' + text[(i + 2)] === controllers[keyword].config.title.toUpperCase()) { commands[j].device = keyword; commands[j].typeClass = controllers[keyword].config.typeClass; i += 2; break; } else if (text[i] + ' ' + text[(i + 1)] === controllers[keyword].config.title.toUpperCase()) { commands[j].device = keyword; commands[j].typeClass = controllers[keyword].config.typeClass; i += 1; break; } else if (text[i] === controllers[keyword].config.title.toUpperCase()) { commands[j].device = keyword; commands[j].typeClass = controllers[keyword].config.typeClass; } // When we have a pair of action + command, we can start looking for // our next command. if ((commands[j].action) && (commands[j].device)) { j += 1; commands[j] = { action : null, device : null, typeClass: null, subDevice : null }; } } } } // If we have a question that's not related to any device. // "What time is it?" // "What is the date?" // "Do I need a coat?" // "How are you doing?" if ((!devices[0].device) && (!commands[0].action) && (questions[0].action)) { // Register questions } else if ((devices[0].device) && ((commands[0].action) || (questions[0].action))) { // Figure out how to coordinate "questions" with "commands" // If we have more commands than devices, there's probably some // ambiguity with a conjunction, such as: // "Turn off the hall light and office light" // Which "and" should imply that both devices be "off". However, a // structure such as: // "Turn off the hall light and turn on the office light" // This would produce an extra element in the "commands" list, which is // what we'll try and filter here. if (commands.length > devices.length) { for (i = 0; i < commands.length; i += 1) { if (commands[i].implied === true) { commands.splice(i, 1); } } } // We should have a perfect matching between devices and commands. If // we do not, then we clearly misunderstand part (or all) of a message, // so it's probably best to not act on it rather than act incorrectly // on it. if (commands.length === devices.length) { for (i = 0; i < commands.length; i += 1) { if ((devices[i].device) && (commands[i].action)) { // Only at this point should we assume a command will actually be // acted upon. acted = true; if (devices[i].subDevice) { if (devices[i].typeClass === 'nest') { devices[i].subDevice = devices[i].subDevice + '-' + commands[i].action.toLowerCase(); commands[i].action = 'mode'; } commands[i].action = 'subdevice-' + commands[i].action.toLowerCase() + '-' + devices[i].subDevice; } switch (this.findDeviceType(devices[i].typeClass)) { case 'tv' : case 'entertainment' : case 'stereo' : switch (commands[i].action.toUpperCase()) { case 'OFF' : commands[i].action = 'PowerOff'; break; case 'ON' : commands[i].action = 'PowerOn'; break; } break; case 'security' : switch (commands[i].action.toUpperCase()) { case 'ARM' : commands[i].action = 'Alarm_On'; break; case 'DISARM' : commands[i].action = 'Alarm_Off'; break; } break; } runCommand.runCommand(devices[i].device, commands[i].action); } } } } return acted; },
setDevice = function(rawText, controllers, device, macros, language) { var genericDevices = getGenericDevices(controllers), subDevices = getSubDevices(controllers), genericTerms = getGenericTerms(language), verbs = getVerbs(language), commands = { 0 : {} }, rawMacro = [], macro = '', text = [], keyword = '', acted = false, i = 0, j = 0, k = 0; text = rawText.split(' '); if(macros) { // Loop through all configured macros anywhere in the inputted text. for(keyword in macros) { if(rawText.indexOf(keyword.toUpperCase()) !== -1) { rawMacro = macros[keyword].split(';'); for(macro in rawMacro) { runCommand.macroCommands(rawMacro[macro]); } acted = true; } } } for(i = 0; i < text.length; i += 1) { // Loop through looking for action words. Once we have one, store it // so we can act on it once we find a suitable device. for(keyword in verbs) { // Look ahead for "Channel Up" to not confuse with just "Up". if(text[i] + ' ' + text[(i + 1)] === verbs[keyword].toUpperCase()) { commands[j].action = verbs[keyword]; i += 1; break; } else if(text[i] === verbs[keyword].toUpperCase()) { commands[j].action = verbs[keyword]; break; } // When we have a pair of action + command, we can start looking for // our next command. if((commands[j].action) && (commands[j].device)) { j += 1; commands[j] = { action : null, device : null, subdevice : null }; } } for(keyword in genericTerms) { // Check for generic names "TV", "Stereo", "Playstation", etc. if(genericTerms[keyword] === text[i]) { commands[j].device = genericDevices[genericTerms[keyword]]; // When we have a pair of action + command, we can start looking // for our next command. if((commands[j].action) && (commands[j].device)) { j += 1; commands[j] = { action : null, device : null, subdevice : null }; } } } // Look through any registered subdevices that may need to be acted // upon. for(keyword in controllers) { if(keyword !== 'config') { if((subDevices) && (subDevices[keyword]) && (subDevices[keyword].subDevices)) { for(k = 0; k < subDevices[keyword].subDevices.length; k += 1) { // Look ahead for device names that may be multiple words. if(text[i] + ' ' + text[(i + 1)] + ' ' + text[(i + 2)] === subDevices[keyword].subDevices[k].toUpperCase()) { commands[j].device = keyword; commands[j].subDevice = subDevices[keyword].subDevices[k]; i += 2; break; } else if(text[i] + ' ' + text[(i + 1)] === subDevices[keyword].subDevices[k].toUpperCase()) { commands[j].device = keyword; commands[j].subDevice = subDevices[keyword].subDevices[k]; i += 1; break; } else if(text[i] === subDevices[keyword].subDevices[k].toUpperCase()) { commands[j].device = keyword; commands[j].subDevice = subDevices[keyword].subDevices[k]; } // When we have a pair of action + command, we can start looking for // our next command. if((commands[j].action) && (commands[j].device)) { j += 1; commands[j] = { action : null, device : null, subdevice : null }; } } } } } // Look through each device and compare with the "title" used in the // navigation. for(keyword in controllers) { if(keyword !== 'config') { // Look ahead for device names that may be multiple words. if(text[i] + ' ' + text[(i + 1)] + ' ' + text[(i + 2)] === controllers[keyword].config.title.toUpperCase()) { commands[j].device = keyword; i += 2; break; } else if(text[i] + ' ' + text[(i + 1)] === controllers[keyword].config.title.toUpperCase()) { commands[j].device = keyword; i += 1; break; } else if(text[i] === controllers[keyword].config.title.toUpperCase()) { commands[j].device = keyword; } // When we have a pair of action + command, we can start looking for // our next command. if((commands[j].action) && (commands[j].device)) { j += 1; commands[j] = { action : null, device : null, subdevice : null }; } } } } if((commands[0].device) && (commands[0].action)) { acted = true; for(keyword in commands) { if((commands[keyword].device) && (commands[keyword].action)) { if(commands[keyword].subDevice) { commands[keyword].action = 'subdevice-' + commands[keyword].action.toLowerCase() + '-' + commands[keyword].subDevice; } runCommand.runCommand(commands[keyword].device, commands[keyword].action, 'single'); } } } return acted; };