diff --git a/Resources/Python/record_control_example_client.py b/Resources/Python/record_control_example_client.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b4c0f899366ac26378629073787faf58c076883
--- /dev/null
+++ b/Resources/Python/record_control_example_client.py
@@ -0,0 +1,69 @@
+"""
+    A zmq client to test remote control of open-ephys GUI
+"""
+
+import zmq
+import os
+import time
+
+
+def run_client():
+
+    # Basic start/stop commands
+    start_cmd = 'StartRecord'
+    stop_cmd = 'StopRecord'
+
+    # Example settings
+    rec_dir = os.path.join(os.getcwd(), 'Output_RecordControl')
+    print "Saving data to:", rec_dir
+
+    # Some commands
+    commands = [start_cmd + ' RecDir=%s' % rec_dir,
+                start_cmd + ' PrependText=Session01 AppendText=Condition01',
+                start_cmd + ' PrependText=Session01 AppendText=Condition02',
+                start_cmd + ' PrependText=Session02 AppendText=Condition01',
+                start_cmd,
+                start_cmd + ' CreateNewDir=1']
+
+    # Connect network handler
+    ip = '127.0.0.1'
+    port = 5556
+    timeout = 1.
+
+    url = "tcp://%s:%d" % (ip, port)
+
+    with zmq.Context() as context:
+        with context.socket(zmq.REQ) as socket:
+            socket.RCVTIMEO = int(timeout * 1000)  # timeout in milliseconds
+            socket.connect(url)
+
+            # Finally, start data acquisition
+            socket.send('StartAcquisition')
+            answer = socket.recv()
+            print answer
+            time.sleep(5)
+
+            for start_cmd in commands:
+
+                for cmd in [start_cmd, stop_cmd]:
+                    socket.send(cmd)
+                    answer = socket.recv()
+                    print answer
+
+                    if 'StartRecord' in cmd:
+                        # Record data for 5 seconds
+                        time.sleep(5)
+                    else:
+                        # Stop for 1 second
+                        time.sleep(1)
+
+            # Finally, stop data acquisition; it might be a good idea to 
+            # wait a little bit until all data have been written to hard drive
+            time.sleep(0.5)
+            socket.send('StopAcquisition')
+            answer = socket.recv()
+            print answer
+
+
+if __name__ == '__main__':
+    run_client()
diff --git a/Source/CoreServices.cpp b/Source/CoreServices.cpp
index 1f4412f6fb2104eb4be746327661ce4ed7f6a8da..7e4d1325382fb7e70a9340cb01c51bd299f8d3d1 100644
--- a/Source/CoreServices.cpp
+++ b/Source/CoreServices.cpp
@@ -52,6 +52,16 @@ void setRecordingStatus(bool enable)
     getControlPanel()->setRecordState(enable);
 }
 
+bool getAcquisitionStatus()
+{
+	return getControlPanel()->getAcquisitionState();
+}
+
+void setAcquisitionStatus(bool enable)
+{
+    getControlPanel()->setAcquisitionState(enable);
+}
+
 void sendStatusMessage(const String& text)
 {
     getBroadcaster()->sendActionMessage(text);
@@ -77,6 +87,26 @@ int64 getSoftwareTimestamp()
 	return getMessageCenter()->getTimestamp(true);
 }
 
+void setRecordingDirectory(String dir)
+{
+    getControlPanel()->setRecordingDirectory(dir);
+}
+
+void createNewRecordingDir()
+{
+   getControlPanel()->labelTextChanged(NULL);
+}
+
+void setPrependTextToRecordingDir(String text)
+{
+    getControlPanel()->setPrependText(text);
+}
+
+void setAppendTextToRecordingDir(String text)
+{
+    getControlPanel()->setAppendText(text);
+}
+
 namespace RecordNode
 {
 void createNewrecordingDir()
@@ -105,4 +135,4 @@ int addSpikeElectrode(SpikeRecordInfo* elec)
 }
 };
 
-};
\ No newline at end of file
+};
diff --git a/Source/CoreServices.h b/Source/CoreServices.h
index f319882333879d7a6316640a00b07209595c33fe..8e47876300a0039328318ce369db3de948bbd19e 100644
--- a/Source/CoreServices.h
+++ b/Source/CoreServices.h
@@ -42,6 +42,12 @@ bool getRecordingStatus();
 /** Activated or deactivates recording */
 void setRecordingStatus(bool enable);
 
+/** Returns true if the GUI is acquiring data */
+bool getAcquisitionStatus();
+
+/** Activates or deactivates data acquisition */
+void setAcquisitionStatus(bool enable);
+
 /** Sends a string to the message bar */
 void sendStatusMessage(const String& text);
 
@@ -59,6 +65,18 @@ int64 getGlobalTimestamp();
 /** Gets the software timestamp based on a high resolution timer aligned to the start of each processing block */
 int64 getSoftwareTimestamp();
 
+/** Set new recording directory */
+void setRecordingDirectory(String dir);
+
+/** Create new recording directory */
+void createNewRecordingDir();
+
+/** Manually set the text to be prepended to the recording directory */
+void setPrependTextToRecordingDir(String text);
+
+/** Manually set the text to be appended to the recording directory */
+void setAppendTextToRecordingDir(String text);
+
 namespace RecordNode
 {
 /** Forces creation of new directory on recording */
diff --git a/Source/Processors/NetworkEvents/NetworkEvents.cpp b/Source/Processors/NetworkEvents/NetworkEvents.cpp
index 3b8fefc97ac0ff9043c6c22ef2431eaec4c19c25..3f444cdca27cc21d465f565bf4c50a609692f073 100644
--- a/Source/Processors/NetworkEvents/NetworkEvents.cpp
+++ b/Source/Processors/NetworkEvents/NetworkEvents.cpp
@@ -405,7 +405,31 @@ String NetworkEvents::handleSpecialMessages(StringTS msg)
     }
 
     */
-    return String("NotHandled");
+
+	/** Start/stop data acquisition */
+	String s = msg.getString();
+
+	const MessageManagerLock mmLock;
+	if (s.compareIgnoreCase("StartAcquisition") == 0)
+	{
+		if (!CoreServices::getAcquisitionStatus())
+	    {
+	        CoreServices::setAcquisitionStatus(true);
+	    }
+		return String("StartedAcquisition");
+	}
+	else if (s.compareIgnoreCase("StopAcquisition") == 0)
+	{
+		if (CoreServices::getAcquisitionStatus())
+	    {
+	        CoreServices::setAcquisitionStatus(false);
+	    }
+		return String("StoppedAcquisition");
+	}
+	else
+	{
+	    return String("NotHandled");
+	}
 }
 
 void NetworkEvents::process(AudioSampleBuffer& buffer,
@@ -565,4 +589,4 @@ void NetworkEvents::createZmqContext()
     if (zmqcontext == nullptr)
         zmqcontext = zmq_ctx_new(); //<-- this is only available in version 3+
 #endif
-}
\ No newline at end of file
+}
diff --git a/Source/Processors/RecordControl/RecordControl.cpp b/Source/Processors/RecordControl/RecordControl.cpp
index f32f9cb18d251be8a8cd5e897fea3cb4c1724a65..65a08a02c5e7c43ae60d8cfae57882c8c73d2d4a 100644
--- a/Source/Processors/RecordControl/RecordControl.cpp
+++ b/Source/Processors/RecordControl/RecordControl.cpp
@@ -110,8 +110,124 @@ void RecordControl::handleEvent(int eventType, MidiMessage& event, int)
         {
             CoreServices::setRecordingStatus(!CoreServices::getRecordingStatus());
         }
+    }
+	else if (eventType == MESSAGE)
+	{
+		handleNetworkEvent(event);
+	}
+
+}
+
+void RecordControl::handleNetworkEvent(MidiMessage& event)
+{
+	/** Extract network message from midi event */
+	const uint8* dataptr = event.getRawData();
+	int bufferSize = event.getRawDataSize();
+    int len = bufferSize - 6; // 6 for initial event prefix
+	String msg = String((const char*)(dataptr + 6), len);
+
+	/** Command is first substring */
+    StringArray inputs = StringArray::fromTokens(msg, " ");
+    String cmd = String(inputs[0]);
 
+    const MessageManagerLock mmLock;
 
+    if (String("StartRecord").compareIgnoreCase(cmd) == 0)
+    {
+		if (!CoreServices::getRecordingStatus())
+		{
+			/** First set optional parameters (name/value pairs)*/
+		    if (msg.contains("="))
+		    {
+				String s = msg.substring(cmd.length());
+				StringPairArray dict = parseNetworkMessage(s);
+
+				StringArray keys = dict.getAllKeys();
+		        for (int i=0; i<keys.size(); i++)
+		        {
+					String key = keys[i];
+					String value = dict[key];
+
+		            if (key.compareIgnoreCase("CreateNewDir") == 0)
+		            {
+		                if (value.compareIgnoreCase("1") == 0)
+		                {
+		                    CoreServices::createNewRecordingDir();
+		                }
+		            }
+		            else if (key.compareIgnoreCase("RecDir") == 0)
+		            {
+		                CoreServices::setRecordingDirectory(value);
+		            }
+		            else if (key.compareIgnoreCase("PrependText") == 0)
+		            {
+		                CoreServices::setPrependTextToRecordingDir(value);
+		            }
+		            else if (key.compareIgnoreCase("AppendText") == 0)
+		            {
+	                	CoreServices::setAppendTextToRecordingDir(value);
+		            }
+		        }
+		    }
+
+			/** Start recording */
+		    CoreServices::setRecordingStatus(true);
+		}
     }
+    else if (String("StopRecord").compareIgnoreCase(cmd) == 0)
+    {
+        if (CoreServices::getRecordingStatus())
+        {
+            CoreServices::setRecordingStatus(false);
+        }
+    }
+}
+
+StringPairArray RecordControl::parseNetworkMessage(String msg)
+{
+    StringArray splitted;
+	splitted.addTokens(msg, "=", "");
+
+	StringPairArray dict = StringPairArray();
+	String key = "";
+	String value = "";
+	for (int i=0; i<splitted.size()-1; i++)
+	{
+		String s1 = splitted[i];
+		String s2 = splitted[i+1];
+
+		/** Get key */
+		if (!key.isEmpty())
+		{
+			if (s1.contains(" "))
+			{
+				int i1 = s1.lastIndexOf(" ");
+				key = s1.substring(i1+1);
+			}
+			else
+			{
+				key = s1;
+			}
+		}
+		else
+		{
+			key = s1.trim();
+		}
+
+		/** Get value */
+		if (i < splitted.size() - 2)
+		{
+			int i1 = s2.lastIndexOf(" ");
+			value = s2.substring(0, i1);
+		}
+		else
+		{
+			value = s2;
+		}
+
+		dict.set(key, value);
+	}
+
+	return dict;
+}
 
-}
\ No newline at end of file
diff --git a/Source/Processors/RecordControl/RecordControl.h b/Source/Processors/RecordControl/RecordControl.h
index b813d8cee5ecb8f82f59e7ff7e031cf3ffece4c7..b43470dcc4f4ca8b1b651471be0de88803401c31 100644
--- a/Source/Processors/RecordControl/RecordControl.h
+++ b/Source/Processors/RecordControl/RecordControl.h
@@ -26,8 +26,8 @@
 
 #include "../../../JuceLibraryCode/JuceHeader.h"
 #include "../GenericProcessor/GenericProcessor.h"
+#include "../NetworkEvents/NetworkEvents.h"
 #include "RecordControlEditor.h"
-#include "../RecordNode/RecordNode.h"
 
 /**
 
@@ -47,6 +47,11 @@ public:
     void setParameter(int, float);
     void updateTriggerChannel(int newChannel);
     void handleEvent(int eventType, MidiMessage& event, int);
+	void handleNetworkEvent(MidiMessage& event);
+
+	//* Split network message into name/value pairs (name1=val1 name2=val2 etc) */
+	StringPairArray parseNetworkMessage(String msg);
+
     bool enable();
 
     bool isUtility()
@@ -67,4 +72,4 @@ private:
 
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/Source/UI/ControlPanel.cpp b/Source/UI/ControlPanel.cpp
index 56a776cdf15e7f920875d5b55b1721560c3dbca9..4cc8b1e1178131270e7c39f0fe061bf880e44124 100755
--- a/Source/UI/ControlPanel.cpp
+++ b/Source/UI/ControlPanel.cpp
@@ -489,6 +489,33 @@ void ControlPanel::setRecordState(bool t)
 
 }
 
+bool ControlPanel::getRecordingState()
+{
+
+	return recordButton->getToggleState();
+
+}
+
+void ControlPanel::setRecordingDirectory(String path)
+{
+    File newFile(path);
+    filenameComponent->setCurrentFile(newFile, true, sendNotificationSync);
+
+    graph->getRecordNode()->newDirectoryNeeded = true;
+    masterClock->resetRecordTime();
+}
+
+bool ControlPanel::getAcquisitionState()
+{
+	return playButton->getToggleState();
+}
+
+void ControlPanel::setAcquisitionState(bool state)
+{
+	playButton->setToggleState(state, sendNotification);
+}
+
+
 void ControlPanel::updateChildComponents()
 {
 
@@ -972,6 +999,16 @@ String ControlPanel::getTextToPrepend()
     }
 }
 
+void ControlPanel::setPrependText(String t)
+{
+    prependText->setText(t, sendNotificationSync);
+}
+
+void ControlPanel::setAppendText(String t)
+{
+    appendText->setText(t, sendNotificationSync);
+}
+
 void ControlPanel::setDateText(String t)
 {
     dateText->setText(t, dontSendNotification);
@@ -1048,4 +1085,4 @@ StringArray ControlPanel::getRecentlyUsedFilenames()
 void ControlPanel::setRecentlyUsedFilenames(const StringArray& filenames)
 {
     filenameComponent->setRecentlyUsedFilenames(filenames);
-}
\ No newline at end of file
+}
diff --git a/Source/UI/ControlPanel.h b/Source/UI/ControlPanel.h
index 22ecafaeb5b546e6f043ec0fd68cf01172c4035b..69581084126022e71c85e48faedd161bcb27cf5d 100755
--- a/Source/UI/ControlPanel.h
+++ b/Source/UI/ControlPanel.h
@@ -301,6 +301,19 @@ public:
 
     /** Used to manually turn recording on and off.*/
     void setRecordState(bool isRecording);
+
+    /** Return current recording state.*/
+    bool getRecordingState();
+
+    /** Set recording directory and update FilenameComponent */
+    void setRecordingDirectory(String path);
+
+    /** Return current acquisition state.*/
+    bool getAcquisitionState();
+
+    /** Used to manually turn recording on and off.*/
+    void setAcquisitionState(bool state);
+
     /** Returns a boolean that indicates whether or not the FilenameComponet
         is visible. */
     bool isOpen()
@@ -317,6 +330,12 @@ public:
     /** Used by RecordNode to set the filename. */
     String getTextToAppend();
 
+    /** Manually set the text to be prepended to the recording directory */
+    void setPrependText(String text);
+
+    /** Manually set the text to be appended to the recording directory */
+    void setAppendText(String text);
+
     /** Set date text. */
     void setDateText(String);