Python

From VoxCommando
Jump to: navigation, search

The IronPython Plugin "PY"

By leveraging the power of IronPython, the "PY" plugin allows us to run Python scripts in VoxCommando. Scripts can interact with VoxCommando, reading and setting variables, triggering events and executing other actions. This allows us to do many new things that VoxCommando was not able to do very well before such as:

  • Math
  • Complex logic
  • Looping (for loop, while loop, etc)
  • and pretty much anything else we can do with Python!

Remember, Python is case sensitive, and depends on proper indentation. Be careful not to mix spaces and tabs in your indentation. This is a common mistake with Python.

IronPython Is Not Quite Python

  • IronPython is based on Python version 2.7. If you grab code that's written for Python 3.x, you might need to make some modifications to make it compatible.
  • IronPython has advantages over regular Python in that we have direct access to various components of VoxCommando.
  • IronPython also gives us access to many of the programming tools available in .Net. For example, in our Arduino Python scripts, we are using .Net's serialport class.
  • Not everything that works correctly in standard Python will work in IronPython, but most things do.

Setting up the Python Libraries

InstallComponents.png
You do not need to install Python to use this plugin. Everything that is required is provided with VoxCommando.

During installation, make sure the Python Libraries checkbox is selected. If you initially unchecked the Python Libraries box upon installing VC, simply run the installation file again, with the box selected.

To use the Python plugin, simply enable the plugin as you would any other plugin in VoxCommando.

Plugin Actions

Currently this plugin allows us to call the following actions from our VoxCommando commands.

PY.ExecString

Executes a single line of Python code. For example, we can use it to handle basic calculations within a VC command macro, or pass VC data to a function we've already defined and loaded as a Python script (using PY.ExecFile), etc. But if we want to do anything fancy, we should probably use PY.ExecFile.

PY.ExecFile

Executes all of the code in the file specified. You can use relative paths, and they will be interpreted relative to the main VoxCommando folder. It is generally a good idea to put all Python scripts into a folder such as ..\VoxCommando\PY.

If you need to pass parameters from VoxCommando to a Python function, you should define the function first using PY.ExecFile, then use PY.ExecString to call the function and pass in parameters. Search the forum for examples (here's one).

Functions only need to be defined once. You may wish to put all your Python functions into a single ExecFile that gets loaded when VoxCommando first starts up (i.e., triggered using a VC.Loaded event). Any function in this file can then be called within individual commands using the PY.ExecString action.

PY.*

List of all actions available in the LCB.

Accessing VoxCommando Methods from Python Code

Through the vc object, Python code can call the following methods available to all plugins:

  • void triggerEvent(string strEventName, List<string> payloads);
  • actionResult callAction(string strActionType, string strParams, List<string> payloads);
  • void doWav(string strWavPath);
    • Evaluates an audio file and tries to recognize speech
  • object getObject(string strObject, string strSubObject);
  • void log(string strLogText);
    • Writes a line of text to the VoxCommando log file (if logging is enabled)
  • bool savePayloadFile(string strPath, Dictionary<string, string> payloadPairs, bool subsetMatching);
  • bool savePayloadListToXML(string strPath, List<xmlPayload> myxmlpayloads);
    • probably too complicated for most users
  • string getLastResult();
    • returns the last result (a string) that was successfully returned by an action
  • void setResultList(List<string> lstResults);

Triggering an Event

Event With No Payloads

For example, if you wanted to trigger an event in VC called "MyEvent.DoIt" you could use the following code:

vc.triggerEvent("MyEvent.DoIt",None)

Note: "None" is the Python equivalent of "Null" and we use it if we don't need payloads.

Event With Payloads

To include payloads in the event:

from System.Collections.Generic import *
vc.triggerEvent("MyEvent.DoIt", List[str](["this is payload1","and this is payload2"]))

Actions

You can execute other VoxCommando actions by using vc.callAction, like this:

vc.callAction("OSD.ShowText","Display me for 5 seconds at the top&&5000&&-10", None)

As with vc.triggerEvent above, the final parameter is None because we are not passing any payloads. In other words:

Primer.png

We can make VoxCommando count to ten.

We can use Python to execute a loop. On each iteration of the loop, we call the "TTS.Speak" action.

for x in range(1, 11):   
    vc.callAction("TTS.Speak","%s"%x, None)    
vc.callAction("TTS.Speak",". There, I counted to ten", None)
  • "%s"%x is a Python method of formatting a string. In this case we are using it to convert an integer to a string

%s will be replaced by the value of x

  • Note that in this case we are not using payloads, so we must send "None" which is the Python way of saying "null"

Generating Payload XML Using a Dictionary in Python

We can generate a payload XML file from a dictionary of key:value pairs.

from System.Collections.Generic import *

myPayloads = {"payload value 1":"payload phrase 1","payload value 2":"payload phrase 2","payload value 3":"payload phrase 3"}
path = "C:/VoxCommando/payloads/payloadtest.xml"

vc.savePayloadFile(path,Dictionary[str,str](myPayloads),False)

CAUTION: The dictionary keys will become the *values* in your payload XML file. The dictionary values will become your payload phrases.

getObject

You can request data from VC by calling vc.getObject(string strObject, string strSubObject)

For example, to print the LastResult variable which was set by a previous action:

print vc.getObject("LastResult","")

strObject

Valid values for strObject are:

  • "lastresult": returns a string
  • "matches": returns a list of strings
  • "displaylanguage": returns a string
  • "payloads": returns a list of strings
  • "fpayloads": returns a list of strings (in this case, friendly payloads)
  • "evalvars" : returns a string where known VC variables in curly brackets have been replaced with their values
    • available only in VoxCommando version 2.2.1.7 or later
#example for evalvars
info = vc.getObject("evalvars","{LastSpoken}")
print info

strSubObject

At the moment, no objects make use of the strSubObject parameter

Returning a Result

To send a result back to VoxCommando you need only set the "result" variable. The value will then be accessible to subsequent actions using {LastResult}

Examples

Example 1.

If we execute the following Python code:

result= 5.0*4/(3+4)

then {LastResult} will be equal to "2.85714285714286".

Example 2.

Verify Internet Status (forum thread)

Example 3.

For Loop (forum thread)

Python Scripting Forum Board

More use scenarios and explanations on issues such as:

can be found on the forum. In particular (though not exclusively), on the Python Scripting board.

Testing Code

Pypluginwindow.png
  • If you open the "PY" plugin settings page, you can enter code directly into the box labelled "Test code:" and then click "Execute" to see what happens. (See the image to the right.)
  • Another way to test code would be to edit a Python file in another program such as "Notepad++" and then test the code by calling the PY.ExecFile action from VoxCommando.

Notepad++ is a good way to edit your Python code and offers many advantages such as code highlighting.



Reinitializing the Python Engine

Sometimes you will need to clear out the various classes and methods that have been loaded into the Python engine. This can be done by:

  • restarting VoxCommando, or,
  • choosing "File >> Reinitialize Python" in the Python plugin window, or
  • within a command macro, using the PY.ReInit action.

Killing Python Threads

  • It is important to note that if you've used threading in your Python, these Python threads will continue to run in the background until they terminate themselves (or VoxCommando is closed).
  • Choosing "File >> Reinitialize Python" will set a variable named "killPy" to true. You can use this to end threaded loops by writing your threaded loops as follows:
while not killPy:
        try:
            ...do your threaded loop stuff here
            ...do your threaded loop stuff here        
        except:
            ...handle errors etc.