Bladeren bron

update command neuron. Rename it "shell". Use parameter and can get the returned value

nico 10 jaren geleden
bovenliggende
commit
9fae93a8d9
10 gewijzigde bestanden met toevoegingen van 214 en 26 verwijderingen
  1. 1 1
      Docs/neuron_list.md
  2. 44 9
      brain.yml
  3. 1 1
      neurons/__init__.py
  4. 0 1
      neurons/command/__init__.py
  5. 0 12
      neurons/command/command.py
  6. 105 0
      neurons/shell/Readme.md
  7. 1 0
      neurons/shell/__init__.py
  8. 54 0
      neurons/shell/shell.py
  9. 5 0
      templates/remove_file.j2
  10. 3 2
      test.py

+ 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                                                    |

+ 44 - 9
brain.yml

@@ -65,7 +65,8 @@
 
   - name: "Close rolling shutter"
     neurons:
-      - command: "curl http://192.168.0.22:5000/fermeture -d \"password=monpass\" -X POST"
+      - shell:
+          cmd: "curl http://192.168.0.22:5000/fermeture -d \"password=monpass\" -X POST"
       - say:
           message: "Fermeture en cours, monsieur"
     signals:
@@ -73,7 +74,8 @@
 
   - name: "Open rolling shutter"
     neurons:
-      - command: "curl http://192.168.0.22:5000/ouverture -d \"password=monpass\" -X POST"
+      - shell:
+          cmd: "curl http://192.168.0.22:5000/ouverture -d \"password=monpass\" -X POST"
       - say:
           message: "Ouverture en cours, monsieur"
     signals:
@@ -81,8 +83,10 @@
 
   - name: "Start steam"
     neurons:
-      - command: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"kodi\",\"state\":\"stop\"}' http://192.168.0.17:8000/app"
-      - command: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"steam\",\"state\":\"start\"}' http://192.168.0.17:8000/app"
+      - shell:
+          cmd: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"kodi\",\"state\":\"stop\"}' http://192.168.0.17:8000/app"
+      - shell:
+          cmd: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"steam\",\"state\":\"start\"}' http://192.168.0.17:8000/app"
       - say:
           message: "Lancement en cours, monsieur"
     signals:
@@ -90,8 +94,10 @@
 
   - name: "Start Kodi"
     neurons:
-      - command: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"steam\",\"state\":\"stop\"}' http://192.168.0.17:8000/app"
-      - command: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"kodi\",\"state\":\"start\"}' http://192.168.0.17:8000/app"
+      - shell:
+          cmd: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"steam\",\"state\":\"stop\"}' http://192.168.0.17:8000/app"
+      - shell:
+          cmd: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"kodi\",\"state\":\"start\"}' http://192.168.0.17:8000/app"
       - say:
           message: "Lancement en cours, monsieur"
     signals:
@@ -99,16 +105,18 @@
 
   - name: "Start music"
     neurons:
-      - command: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"music\",\"state\":\"start\"}' http://192.168.0.17:8000/app"
+      - shell:
+          cmd: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"music\",\"state\":\"start\"}' http://192.168.0.17:8000/app"
       - say:
-          message: "Musique lance, monsieur"
+          message: "Musique lancé, monsieur"
     signals:
       - order: "mais nous de la musique"
       - order: "musique rock"
 
   - name: "Stop music"
     neurons:
-      - command: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"music\",\"state\":\"stop\"}' http://192.168.0.17:8000/app"
+      - shell:
+          cmd: "curl -i --user admin:secret -H \"Content-Type: application/json\" -X POST -d '{\"app_name\":\"music\",\"state\":\"stop\"}' http://192.168.0.17:8000/app"
       - say:
           message: "musique stoppé, monsieur"
     signals:
@@ -162,3 +170,30 @@
           message: "lost"
     signals:
       - order: "où est mon téléphone"
+
+  - name: "test command"
+    neurons:
+      - shell:
+          cmd: "mplayer http://192.99.17.12:6410/"
+          async: True
+      - say:
+          message: "lancé"
+    signals:
+      - order: "test commande"
+
+  - name: "test stop"
+    neurons:
+      - shell:
+          cmd: "pkill mplayer"
+      - say:
+          message: "stopé"
+    signals:
+      - order: "test stop"
+
+  - name: "remove a file"
+    neurons:
+      - shell:
+          cmd: "rm ~/test.txt"
+          file_template: remove_file.j2
+    signals:
+      - order: "rm file"

+ 1 - 1
neurons/__init__.py

@@ -1,5 +1,5 @@
 from ansible_tasks import Ansible_tasks
-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()
-
-

+ 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 %}

+ 3 - 2
test.py

@@ -12,8 +12,9 @@ logger = logging.getLogger("kalliope")
 logger.setLevel(logging.DEBUG)
 
 
-
-order = "test heure"
+# order = "musique rock"
+# order = "stop la musique"
+order = "rm file"
 oa = OrderAnalyser(order)
 oa.start()