Skip to content
This repository has been archived by the owner on Feb 8, 2019. It is now read-only.

How to add commands

eouia edited this page Sep 25, 2017 · 6 revisions

How to add your commands is not difficult. If you have experiences of making command for MMM-TelegramBot, that is ideally same. (See https://github.com/eouia/MMM-TelegramBot/wiki/How-to-add-commands)

Here I assume this is the first time.

1. Simplest 6 lines solution

Your module might already have some functions to execute.

turnOnRadio: function() {
  // your code for turning on Radio
},

In this case, add below function in your module. It has just 6 line codes and it would cause no side-effect to your existing codes.

getCommands: function(commander) {
  commander.add({
    command: 'turn on radio',
    callback: 'turnOnRadio'
  })
},

This makes your voice turn on radio to be added as command in MMM-Assistant.

Or you can just return your commands array instead of using commander object.

getCommands: function(commander) {
  return [
    {
      command: 'turn on radio',
      callback: 'turnOnRadio'
    }
  ]
},

Don't use both methods together at same time. Your command will be registered twice.

All of voice commands should be lowercase and speakable. Voice recognizer couldn't understand clr scrn or hideallmodules

When this command turn on radio is called by the voice of the user, your callback-function named turnOnRadio will be executed. It's really easy, isn't it?

.getCommands() function is used for getting available commands of your module. It might be also used for other Commander modules like voice assistants, web admins, sensors, buttons, or any other modules which want to command other modules if they supports.

How to support MMM-TelegramBot and MMM-Assistant together
getCommands: function(commander) {
  var command = {
    command: '',
    callback: 'turnOnRadio'
  }
  if (commander.constructor.name == 'TelegramBotCommandRegister') {
    command.command = 'radioon'
  }
  if (commander.constructor.name == 'AssistantCommandRegister') {
    command.command = 'turn on radio'
  }
  commander.add(command)
},

This could make the command /radioon for MMM-TelegramBot and turn on radio for MMM-Assistant.

Wait! Some module has already registered the same command with mine, what happens? In that case, unlike the case of MMM-TelegramBot, your command would not be registered.

2. Use Notification

Your module might be controllable by notification already.

notificationReceived: function(notification, payload, sender) {
  if (notification == 'turn off radio') {
    this.turnOffRadio()
  }
},

In this case, even easier than 1.

getCommands: function(commander) {
  commander.add({
    command: 'turn off radio',
  })
},

When callback is omitted, MMM-Assistant send user's command turn off radio to your .notificationReceived() function as 'notification'. (But I think this is not a usual case. You'd better specify callback function name.)

3. Reaction

However, above two methods are not so good because there is no reaction for the user. We can make your command to respond.

getCommands: function(commander) {
  commander.add({
    command: 'turn on radio',
    callback: 'command_turnOnRadio'
  })
},

command_turnOnRadio: function(command, handler) {
  this.turnOnRadio()
  var option = {
    language: 'en-US',
    useAlert: false
  }
  handler.reply("TEXT", "Yes, Sir!", option) 
    or
  handler.response("Yes, Sir!", option)
},

turnOnRadio: function() {
  // your code for turning on Radio
},

When the user tries turn on radio, Yes, Sir! will be responded. The default response function is .response(speakableText, option), but you can use .reply('TEXT', speakableText, option) or .say(...) or even .ask(...) also. However, last 3 methods are implemented for compatibility with MMM-TelegramBot. So, you'd better use .response() for MMM-Assistant.

option could have two parameters. language and useAlert

language : Language for response voice. If omitted, `config.speak.language` would be used by default.
useAlert : Whether show as `alert` or not. If omitted, `config.speak.useAlert` would be used by default.

4. Arguments

Now, we will look the arguments. Each command could get arguments for detailed execution. To define arguments is different with that of MMM-TelegramBot because voice is more complicated.

getCommands: function(commander) {
  commander.add({
    command: 'turn radio',
    callback: 'command_turnRadio'
  })
},

command_turnRadio: function(command, handler) {
  console.log(handler.args)
},

If the user speak turn radio or turn radio blah blah blah, your handler.args carries user inputs like these.

  • turn radio : handler.args == null
  • turn radio blah blah blah : handler.args == 'blah blah blah' You can parse this input by yourself, Or...
getCommands: function(commander) {
  commander.add({
    command: 'turn radio :status',
    callback: 'command_turnRadio',
  })
},

You can use variable to catch arguments. Matched values would be result of RegExp.exec().

  • turn radio : will not be activated
  • turn radio blah blah blah : handler.args.status == 'blah blah blah'

You can define pattern for arguments.

getCommands: function(commander) {
  commander.add({
    command: 'turn radio :status(on|off)',
    callback: 'command_turnRadio',
  })
},

In this case, turn radio or turn radio blah blah will not be activated. turn radio on or turn radio off will. (handler.args.status = 'on' or 'off')

The pattern could be RegExp or RegExp-like-String or just String. () could be used.

4-1. In notification

If you use notificationReceived instead of callback, only handler.args will be carried to .notificationReceived() as payload. handler itself is not carried. In this case, you cannot react because handler is not carried.

5. callback: function(command, handler)

Let's examine callback function.

command is string value of your command. You can control multi commands in one callback function with this parameter.

getCommands: function(commander) {
  commander.add({
    command: 'tv',
    callback: 'command_home',
  })
  commander.add({
    command: 'radio',
    callback: 'command_home',
  })
},

command_home: function(command, handler) {
  if (command == 'tv') { ... }
},

handler object is the magic of this module!

Usually, handler object has this structure. You can use these values for more detailed execution.

AssistantHandler = {
  message: [Object], // See below
  args : [Object], // See upper section 4.
  callbacks : [response(), ask(), reply(), say()],

Details of message object:

message = {
  text : string, // whole text of voice commands.
}

And it has four reaction callback functions.

  • handler.response()
  • handler.reply() // This is same with handler.response(). It is prepared for compatibility with MMM-TelegramBot. If you can, don't use this.
  • handler.say() // This is same with handler.response(). It is prepared for compatibility with MMM-TelegramBot. If you can, don't use this.
  • handler.ask() // This is same with handler.response(). It is prepared for compatibility with MMM-TelegramBot. If you can, don't use this.

You can distinguish handler type by handler.constructor.name.

if (handler.constructor.name == 'TelegramBotMessageHandler') {
  doSomething()
  handler.reply('TEXT', 'This message will be shown in your Telegram.')
}
if (handler.constructor.name == 'AssistantHandler') {
  doSomething()
  handler.response('This message will be spoken by voice on MagicMirror.')
}

6. Pour some sugar on me

You can add a short description of command for convenience. This description will be used by help :commandName.

getCommands: function(commander) {
  commander.add({
    command: 'turn on radio',
    description: "You can turn on radio with this command.",
    callback: 'turnOnRadio'
  })
},

7. Warning

Speech is just response of your voice command. It is not good to use this module as voice output method instead of response of user command.