Cynics at Large Indigo: Cynical Network

Cynical Network Plugin

Download Cynical Network (Release Notes)

This plugin allows Indigo to make and receive network connections over the Internet. You may write text with actions. You may define events that trigger when a particular text pattern is seen in a received line, using regular expressions. You may enable and disable these events dynamically so as to shape a conversation - all without writing any Python or AppleScript code.

This plugin is primarily aimed at line-oriented text conversations. Binary data can be sent using dynamic field values. There is no support for UDP. (If you don't know what that is, don't worry about it.)

If you want a worked example, here is how to control a TiVO using Cynical Network.


For each network connection you want to use, create either a TCP Out device if you want to originate it, or a TCP In device if you want to wait for an incoming connection. Choose your port numbers well. For TCP Out devices, you can either use an explicit Connect action to connect it, or you can check the Auto-connect configuration checkbox to ask Indigo to keep the connection up all the time. For TCP In devices, the connection will happen when some program out there asks for it.

Use Device State Change event triggers on these network devices to respond to the situation. Watch for connected to respond to the start of a connection, and for disconnected for the end - which may come because the other end has broken off the connection or the network has failed.

Use Send Text actions to send whole or partial text lines to a connected device. Use Recognized Input and Unrecognized Input triggers to respond to incoming text. Enable and disable individual triggers, using ordinary Indigo actions, to tailor the response to the state of your conversation. End connections with the Disconnect action. A device will automatically disconnect if you disable it.


The TCP Out and TCP In devices support TCP (stream) connections to or from some Internet service somewhere (which may be on your own computer). They differ only in how a connection is established; once connected, they behave exactly the same:

TCP Out Device

A TCP Out device is a way to make a TCP connection to some server out there. By default, it remains idle until a Connect action for it is executed, at which point it attempts to make the connection.

If the Auto-connect checkbox is enabled, this is automatically done whenever the connection is idle. In other words, an autoconnect device will continuously attempt to establish and maintain its connection. Note that applying the Disconnect action to an autoconnecting device will terminate the present connection but immediately attempt to establish a new one. The only way to stop an auto-connecting device from trying to re-establish its connection is to disable it.

TCP In Device

A TCP In device is Indigo's way of listening for some other program out there making a connection to Indigo. When a request for a connection is received, Indigo establishes the connection and handles it as described above. Only one connection can ever be active for each TCP In device; additional incoming requests are queued (within reason) and accepted when the present connection terminates.

Device States

Use a device state change trigger for the connected state to catch the start of a new connection, regardless of how it got started. Use a trigger for the disconnected state to catch the end of a connection.

The disconnected state is momentary; after a brief hesitation, the state will automatically move on - usually to idle or connecting. This state exists just so you can have a device state change trigger that fires whenever a connection ends, regardless of the circumstances.


Connect Action

Tells a TCP Out device to try and establish its connection. This does nothing (and produces an error message in the Indigo log) if the connection is not idle.

A persistent connection automatically performs a Connect whenever it is becoming idle.

Connect cannot be used on TCP In devices; they are connecting automatically in response to incoming connection requests as long as they are enabled.

Disconnect Action

Immediately disconnects a connected TCP Out or TCP In device. The device state becomes momentarily disconnected. The device then follows its normal progression:

Disabling a device automatically disconnects it. If you want to finish an existing connection but then not allow subsequent ones, disable the device in a device state change trigger for the disconnected state.

Send Text Action

Send some text to a connected device. A full line is sent by automatically appending the device's line ending characters - see Line Endings. The partial checkbox defeats this completion and sends a partial line instead.

The text value may contain Python escape sequence codes which allows you to include unprintable characters in the string. This will also allow you to send unusual line ending characters if needed. If needed, this allows you to send arbitrary binary data using \x escape codes. Be aware that backslash characters "\" will need to be escaped by doubling them.

This action will fail (with an error message in the Indigo log) if the device state is not currently connected.


Incoming text lines on a connected device trigger events you can use to take action. Recognized Input events can be configured with regular expressions to match particular input lines. They are only eligible for matching when they are enabled; you can conduct an entire network conversation by selectively enabling and disabling these event triggers based on the situation.

If you need to deal with arbitrary input, use Unrecognized Input events and read the actual line received from the Indigo variable configured for the device. This is also useful for handling unexpected error cases.

Normally, Cynical Network only processes event triggers when a full line (as defined by the device's line ending setting) has been received. Partial line input is kept indefinitely, waiting for the line ending to arrive; but you can't see or act upon it until that happens. If you must handle partial line input, you can use the None line ending, but you must be prepared for data to arrive in arbitrary chunks of characters, subject to the vagaries of network traffic.

Recognized Input Event

A Recognized Input event applies to a particular TCP device. It specifies a regular expression pattern. Whenever that device receives a complete line that matches this regular expression, the event triggers and Indigo performs its actions. If you specified a variable in the device configuration, it will contain the (whole) line that triggered the event.

You can have any number of Recognized Input events for the same device, but they should all have distinct patterns that don't overlap. If an incoming text line matches multiple enabled pattern events, the system will pick a single one at random and trigger it; the others will not fire for that line.

The last line matched variable, if specified, will be set to the value of the first matching group (string within "()" characters) in the pattern. If the pattern contains no parentheses, it will be assigned the whole line (without the line ending).

Unrecognized Input Event

An Unrecognized Input event fires whenever a given network device receives a complete text line that does not match any enabled Recognized Input triggers for that device. It acts as a catch-all to consume unexpected input. If you have no enabled Recognized Input triggers, each incoming line will be delivered this way. If you have multiple enabled triggers of this type for a device, they will all fire in some unspecified order. If you specified a variable in the device configuration, it will contain the line that triggered the event.

Line Endings

Cynical Network handles data one line at a time. The line ending configuration setting determines how lines are recognized. You can set this separately for each connection device.

Newline\x0ACommon in UNIX systems and their protocols.
CRNL\x0D\x0AUsed in "classic" Internet protocols and on Windows.
Carriage Return\x0DUsed in some embedded systems.
Null\x00Lines are separated by zero (null) bytes.
NonenothingUse no lines at all.

The none line ending means that we're not really processing lines at all. The send text action does not append anything to outgoing text; and anything arriving from the remote partner is immediately treated as a line and delivered accordingly, even if it is just a single character at a time. Use this if you have to work with a protocol that is not line oriented. Happily, this is rare in practice.

Note that Cynical Network will add the designated line ending bytes automatically to outgoing text, unless you use the Partial option on the Send Text action. You can put suitable ending characters into your text explicitly using Python character escape codes; just make sure you don't do both or you'll end up inadvertently sending an extra (empty) line.

Binary Data

Handling binary data in an otherwise line-oriented protocol is not hard. If the binary data is constant, use Python escape sequence codes in your output text. Incoming lines treat binary data as ordinary characters, and you can match them likewise.

If you need to send variable binary data, take a look at the Python struct module. Combined with a dynamic formula for the Send Text memssage, this allows you to pack arbitrary values into bytes.

If the protocol does not use recognizable line endings (it is completely binary), then choose the None line ending to avoid sprinkling unexpected characters into your output. This also disables scanning for full lines on input, and any bytes arriving from the peer are delivered immediately, using the standard event mechanism, as a line. It is up to you to assemble these bytes into whatever groups make sense in your case. Beware that the network sometimes splits seemingly contiguous bytes into multiple chunks, so assuming that an entire data packet will arrive intact is unwise. You must use whatever termination bytes or length fields are defined for your protocol.

If this all turns out to be too hard for you, it may be time to write your own plugin. Happily, this turns out to be fairly rare.

Release Notes

About This Area 29 Oct 2019 20:37