Browse Source

Merge branch 'neurons_review'

Conflicts:
	brain.yml
	neurons/__init__.py
	test.py
nico 8 years ago
parent
commit
347ae39454

+ 1 - 1
Docs/neuron_list.md

@@ -5,12 +5,12 @@ A neuron is a module you can use in your synapses. See the [complete neuron docu
 | Name                                               | Description                                                                             |
 |----------------------------------------------------|-----------------------------------------------------------------------------------------|
 | [ansible_task](../neurons/ansible_task/)           | Run an ansible playbook                                                                 |
-| [command](../neurons/command/)                     | Run a shell command                                                                     |
 | [gmail_checker](../neurons/gmail_checker/)         | Get the number of unread email and their subjects from a gmail account                  |
 | [kill_switch](../neurons/kill_switch/)             | Stop Jarvis process                                                                     |
 | [push_message](../neurons/push_message/)           | Send a push message to a remote device like Android/iOS/Windows Phone or Chrome browser |
 | [say](../neurons/say/)                             | Make Jarvis talk by using TTS                                                           |
 | [script](../neurons/script/)                       | Run an executable script                                                                |
+| [shell](../neurons/command/)                       | Run a shell command                                                                     |
 | [sleep](../neurons/sleep/)                         | Make Jarvis sleep for a while before continuing                                         |
 | [systemdate](../neurons/systemdate/)               | Give the local system date and time                                                     |
 | [tasker_autoremote](../neurons/tasker_autoremote/) | Send a message to Android tasker app                                                    |

+ 4 - 3
core/NeuronModule.py

@@ -93,7 +93,7 @@ class NeuronModule(object):
             logger.debug("message is dict")
             tts_message = self._get_message_from_dict(message)
 
-        if message is not None:
+        if tts_message is not None:
             # get an instance of the target TTS
             tts_instance = self._get_tts_instance(self.tts)
             tts_args = None
@@ -148,8 +148,9 @@ class NeuronModule(object):
                                                         % real_file_template_path)
             return returned_message
 
-        else:
-            raise NoTemplateException("You must specify a say_template or a file_template")
+        # we don't force the usage of a template. The user can choose to do nothing with returned value
+        # else:
+        #     raise NoTemplateException("You must specify a say_template or a file_template")
 
     @staticmethod
     def _get_content_of_file(real_file_template_path):

+ 1 - 1
neurons/__init__.py

@@ -1,5 +1,5 @@
 from ansible_playbook import Ansible_playbook
-from command import Command
+from shell import Shell
 from kill_switch import Kill_switch
 from say import Say
 from script import Script

+ 0 - 1
neurons/command/__init__.py

@@ -1 +0,0 @@
-from command import Command

+ 0 - 12
neurons/command/command.py

@@ -1,12 +0,0 @@
-import subprocess
-
-from core.NeuronModule import NeuronModule
-
-
-class Command(NeuronModule):
-    def __init__(self, command, **kwargs):
-        super(Command, self).__init__(**kwargs)
-        p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
-        (output, err) = p.communicate()
-
-

+ 1 - 5
neurons/gmail_checker/gmail_checker.py

@@ -3,16 +3,12 @@ import logging
 
 from gmail import Gmail
 from email.header import decode_header
-from core.NeuronModule import NeuronModule
+from core.NeuronModule import NeuronModule, MissingParameterException
 
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
 
 
-class MissingParameterException(Exception):
-    pass
-
-
 class Gmail_checker(NeuronModule):
     def __init__(self, **kwargs):
         super(Gmail_checker, self).__init__(**kwargs)

+ 1 - 0
neurons/openweathermap/README.md

@@ -93,3 +93,4 @@ You also can define the "location" args directly in neuron argument list.
 
 ## Notes
 
+> **Note:** You need to create a free account on [openweathermap.org](http://openweathermap.org/) to get your API key.

+ 105 - 0
neurons/shell/Readme.md

@@ -0,0 +1,105 @@
+# shell
+
+## Synopsis
+
+Run a shell command on the local system where Kalliope is installed.
+
+
+## Options
+
+| parameter | required | default | choices  | comment                                                                     |
+|-----------|----------|---------|----------|-----------------------------------------------------------------------------|
+| cmd       | yes      |         |          | The shell command to run                                                    |
+| async     | no       | False   |          | If True, Kalliope will not wait for the end of the execution of the command |
+
+
+## Return Values
+
+Values are only returned by the neuron if the async mode is set to `False`.
+
+| Name       | Description                                                                                           | Type   | sample                        |
+|------------|-------------------------------------------------------------------------------------------------------|--------|-------------------------------|
+| output     | The shell output of the command if any. The command "date" will retun "Sun Oct 16 15:50:45 CEST 2016" | string | Sun Oct 16 15:50:45 CEST 2016 |
+| returncode | The returned code of the command. Return 0 if the command was succesfuly exectued, else 1             | int    | 0                             |
+
+
+## Synapses example
+
+Simple that will create a file locally
+```
+  - name: "create a local file"
+    neurons:
+      - shell:
+          cmd: "touch ~/test.txt"
+    signals:
+      - order: "touch"
+```
+
+We want to launch our favorite web radio. This command, which it call mplayer, will block the entire Kalliope process if we 
+wait for the result unless the mplayer process is killed. So we add async parameter. 
+``` 
+  - name: "run web radio"
+    neurons:
+      - shell:
+          cmd: "mplayer http://192.99.17.12:6410/"
+          async: True
+      - say:
+          message: "web radio lanched"
+    signals:
+      - order: "run web radio"
+```
+If the parameter `async` is set to True, the neuron will not return any values.
+
+
+Then, we can kill the player process with another synapse
+```
+  - name: "stop web radio"
+    neurons:
+      - shell:
+          cmd: "pkill mplayer"
+      - say:
+          message: "web radio stopped"
+    signals:
+      - order: "stop web radio"
+```
+
+Make Kalliope add two number and speak out loud the result. Here you should hear "4".
+```
+  - name: "get the result of the addition: 1 + 3"
+    neurons:
+      - shell:
+          cmd: "echo $(expr \"1\" + \"3\")"
+          say_template: "{{ output }}"
+    signals:
+      - order: "addition"
+```
+
+Let's use a file template. We try to remove the file `~/test.txt` and make Kalliope gice us the result depending of the 
+returned error code.
+If the file is present on the system, you will hear "The command has succeeded" and so the file has been deleted. 
+If you run it a second time, the command will fail as the file is not anymore present and so you should hear 
+"The command has failed". See the template example bellow.
+```
+  - name: "remove a file"
+    neurons:
+      - shell:
+          cmd: "rm ~/test.txt"
+          file_template: remove_file.j2
+    signals:
+      - order: "rm file"
+```
+
+## Templates example 
+
+Template `remove_file.j2` used in the remove file example remove_file.j2
+```
+{% if returncode == 0 %}
+    The command succeeded
+{% else %}
+    The command failled
+{% endif %}
+```
+
+## Notes
+
+> **Note:** If the parameter `async` is set to True, the neuron will not return any values.

+ 1 - 0
neurons/shell/__init__.py

@@ -0,0 +1 @@
+from shell import Shell

+ 54 - 0
neurons/shell/shell.py

@@ -0,0 +1,54 @@
+import logging
+import subprocess
+import threading
+from core.NeuronModule import NeuronModule, MissingParameterException
+
+logging.basicConfig()
+logger = logging.getLogger("kalliope")
+
+
+class AsyncShell(threading.Thread):
+    def __init__(self, cmd):
+        self.stdout = None
+        self.stderr = None
+        self.cmd = cmd
+        threading.Thread.__init__(self)
+
+    def run(self):
+        p = subprocess.Popen(self.cmd,
+                             shell=True,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE)
+
+        self.stdout, self.stderr = p.communicate()
+
+
+class Shell(NeuronModule):
+    def __init__(self, **kwargs):
+        super(Shell, self).__init__(**kwargs)
+
+        # get the command
+        cmd = kwargs.get('cmd', None)
+        # get if the user select a blocking command or not
+        async = kwargs.get('async', False)
+
+        if cmd is None:
+            raise MissingParameterException("cmd parameter required")
+
+        # run the command
+        if not async:
+            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+            (output, err) = p.communicate()
+            message = {
+                "output": output,
+                "returncode": p.returncode
+            }
+            self.say(message)
+
+        else:
+            async_shell = AsyncShell(cmd=cmd)
+            async_shell.start()
+
+
+
+

+ 5 - 0
templates/remove_file.j2

@@ -0,0 +1,5 @@
+{% if returncode == 0 %}
+    The command has succeeded
+{% else %}
+    The command has failed
+{% endif %}