Quickstart

Running Server

Let’s first figure out how to start the external node server.

A minimal server running script looks something like this:

import mh_en_exec as mh

from nodes.foo_node import FooNode

try:
  mh.exec([FooNode])
except KeyboardInterrupt:
  pass

So what did that code do?

  1. First we imported the Machine Heads External Node module mh_en_exec as mh.

  2. Next we imported custom node class called FooNode. For now, let’s skip the details of creating the class, but if you want details see “Creating node class

  3. Then we use exec() function to execute server and wait until ends. As an argument we send list of the node classes.

  4. Also we trying to catch KeyboardInterrupt exception in order to be able stop external nodes execution by pressing Ctrl+C.

Now using this code we can run the external node server.

Creating node class

Next, let’s see how to create your own node.

First of all, need to decide the type of the node.
Machine Heads have two type of nodes: action node and data node.
The difference is that an action node provides some operation when executed, while a data node provides data that can be used on an action node
In terms of node structure, an action node has built-in “in_action” input port and “out_on_success” and “out_on_failure” output ports, and a data node has no built-in ports.

Creating data node

First, let’s create simple data node.

In order to do so, need to create class that will be inherited from NodeBase. It will be something like this.

# import NodeBase class
from mh_en_exec.nodes import NodeBase

# create new node class
class SimpleDataNode(NodeBase):
  # set a display name
  NODE_NAME = 'Simple Data'

Next, need to add ports. For this SimpleDataNode class, let’s create one string output port and name it as text.
To do so need to import StringNodeOutput

# import string output port
from mh_en_exec.nodes.ports import StringNodeOutput

And add new class variable called text, an instance of the StringNodeOutput class

  # output port variable
  text = StringNodeOutput()

And, finally let’s override perform function to be able return some value on the node execution.

  # node execution function
  def perform(self):
    return ('Hello World',)

In this case SimpleDataNode will give ‘Hello World’ string value through the text output port when executed.

Final class code will be like this:

# import NodeBase class
from mh_en_exec.nodes import NodeBase
# import string output port
from mh_en_exec.nodes.ports import StringNodeOutput

# create new node class
class SimpleDataNode(NodeBase):
  # set a display name
  NODE_NAME = 'Simple Data'

  # output port variable
  text = StringNodeOutput()

  # node execution function
  def perform(self):
    return ('Hello World',)

On “Machine Heads” node will be look like this:

Simple Data Node Image

Creating data node with view

In the previous example, we made the port value hardcoded, but it is possible to make the port value set from the “Machine Heads” user interface. To do so, you need to use a port view.

Let’s try adding a port view for the text port of our previous example class SimpleDataNode. To do this, need to add a new variable named text_view, an instance of the NodeStringView, and link it to our text variable. To link, need to pass the name of the variable to which we want to link as the first argument of the NodeStringView constructor.

But first, need to import NodeStringView class.

# import string port view
from mh_en_exec.nodes.views import NodeStringView

And only after that need to add our text_view variable.

# output port variable
text = StringNodeOutput()

# output port view
text_view = NodeStringView('text')

After that, node will look like this:

Simple Data Node With View

Final code will be like this:

# import NodeBase class
from mh_en_exec.nodes import NodeBase
# import string output port
from mh_en_exec.nodes.ports import StringNodeOutput
# import string port view
from mh_en_exec.nodes.views import NodeStringView


# create new node class
class SimpleDataNode(NodeBase):
  # set a display name
  NODE_NAME = 'Simple Data'

  # output port variable
  text = StringNodeOutput()

  # output port view
  text_view = NodeStringView('text')

Note

The perform function has been removed since it is no longer necessary to return the port value through python code.
If the function perform is not in the node class, then when the node is executed, the value of the ports will be returned as is.

Creating action node

Next, let’s create simple action node.

This time we will try to make the node add up the value of the input ports.
The formula for the operation will be as follows: a + b = c

As the last time, we start by creating a class, but this time we need to inherit ActionNodeBase class.

# import ActionNodeBase class
from mh_en_exec.nodes import ActionNodeBase

# create new node class
class SimpleActionNode(ActionNodeBase):
  # set a display name
  NODE_NAME = 'Simple Action'

Next, create ports. To do so, first, import IntegerNodeInput and IntegerNodeOutput

# import integer input port
from mh_en_exec.nodes.ports import IntegerNodeInput
# import integer output port
from mh_en_exec.nodes.ports import IntegerNodeOutput

and create input and output ports.

  # input port variables
  a = IntegerNodeInput()
  b = IntegerNodeInput()

  # output port variable
  c = IntegerNodeOutput()

And as always need to override perform function to make some operations, but this time we will receive input port values as arguments of the perform function and return values will be not just tuple of output values, but also result of node execution.

  # node execution function
  def perform(self, a, b):
    return True, (a + b,)

So final code will be like this:

# import ActionNodeBase class
from mh_en_exec.nodes import ActionNodeBase
# import integer input port
from mh_en_exec.nodes.ports import IntegerNodeInput
# import integer output port
from mh_en_exec.nodes.ports import IntegerNodeOutput

# create new node class
class SimpleActionNode(ActionNodeBase):
  # set a display name
  NODE_NAME = 'Simple Action'

  # input port variables
  a = IntegerNodeInput()
  b = IntegerNodeInput()

  # output port variable
  c = IntegerNodeOutput()

  # node execution function
  def perform(self, a, b):
    return True, (a + b,)

On “Machine Heads” this action node will be look like this:

Simple Action Node Image