-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mast_Experiment_Commander_Threshold_Test_B.koi
1 lines (1 loc) · 69.3 KB
/
Mast_Experiment_Commander_Threshold_Test_B.koi
1
{"nodes":[{"nid":0,"version":"0.0.2","uid":1,"category":"function","type":"Start","x":11,"y":20,"headerStyle":{"background":"#15ad60"},"fields":{"in":[],"out":[{"name":"start"}]},"python":"def start():\n return {'Start':True,'Settings':{'Verbose':True,'UIMode':False},'Status':{},'Threads':[],'Data':[]}\n","python_import":"","python_exec":"start","settings":[],"icon":"./static/media/start.c59e7ea6.svg","data":{},"kwargs":{},"description":"This is the starting node that starts the program. It initializes settings and the data for the rest of the program. ","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[]","stringPins":"{\"in\":[],\"out\":[{\"name\":\"start\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"showImports":false},{"nid":1,"version":"0.0.2","uid":10,"category":"function","type":"Stop","x":1180,"y":68,"headerStyle":{"background":"#ad1562"},"fields":{"in":[{"name":"start"}],"out":[]},"python":"@on_start\ndef stop(*args,**kwargs):\n print('Exiting...')\n sys.exit()\n ","python_import":"import sys","python_exec":"stop","settings":[],"icon":"./static/media/stop.a2171794.svg","data":{},"kwargs":{},"description":"This node ends the existing node experiment. It will not stop processes that have started in parallel using split nodes.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"showImports":false},{"nid":3,"version":"0.0.2","uid":5,"category":"logical","type":"Arduino Communication Class","x":211,"y":20,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"########################################################################################################################\n# arcom.py\n#\n# Contains all the low level utility functions used to talk to and interact with the PythonSlave Arduino sketch.\n########################################################################################################################\n\n# These are the opcodes we use when talking to the Arduino. They define the\n# command we want to execute. There is a 1 to 1 correspondence between these\n# opcodes and the ones defined on the Arduino.\nclass OpCodes:\n SetPin = 0\n GetPin = 1\n SetPinMode = 2\n\n# Initializing a class for the arudino communication\nclass arcom:\n def __init__(self, arduino_com):\n self.__author__ = 'Christopher Broussard & Edited by Dr. Dave & Supraja Kalva'\n self.arduino_com = arduino_com\n self.DEBUG_LEVEL = 0\n \n # Define some constants that correspond to values used on the Arduino itself.\n self.INPUT = 0\n self.OUTPUT = 1\n self.HIGH = 1\n self.LOW = 0\n\n def set_pinmode(self, pin, pinmode):\n \"\"\"\n Sets the pinmode for the designated pin.\n \n @param arduino_com: Serial port object connected to the Arduino.\n @type arduino_com: serial.Serial\n @param pin: The pin to set.\n @type pin: int\n @param pinmode: The pin mode.\n @type pinmode: int\n \"\"\"\n \n # Send the pinmode.\n self.arduino_com.write(\"{0} {1} {2}\\n\".format(OpCodes.SetPinMode, pin, pinmode).encode('ascii'))\n \n # Wait for the echo string.\n self.wait_for_response()\n\n\n def set_pin(self, pin, pin_value):\n \"\"\"\n Sets the pin value for the designated pin.\n \n @param arduino_com: Serial port object connected to the Arduino.\n @type arduino_com: serial.Serial\n @param pin: The pin to set.\n @type pin: int\n @param pin_value: The pin value.\n @type pin_value: int\n \"\"\"\n \n # Send the pin value.\n self.arduino_com.write(\"{0} {1} {2}\\n\".format(OpCodes.SetPin, pin, pin_value).encode('ascii'))\n \n # Wait for the echo string.\n self.wait_for_response()\n \n \n def get_pin(self, pin):\n \"\"\"\n Gets the pin value for the designated pin.\n \n @param arduino_com: Serial port object connected to the Arduino.\n @type arduino_com: serial.Serial\n @param pin: The pin to set.\n @type pin: int\n @return: The current value of the pin.\n @rtype: int\n \"\"\"\n \n # Request the pin value.\n self.arduino_com.write(\"{0} {1}\\n\".format(OpCodes.GetPin, pin).encode('ascii'))\n \n # Wait for the echo string, which will contain the pin value.\n return int(self.wait_for_response())\n \n \n def wait_for_response(self):\n \"\"\"\n Wait for a response from the Arduino and returns it as a string\n with the newline character stripped off.\n \n @param arduino_com: Serial port object connected to the Arduino.\n @type arduino_com: serial.Serial\n @return: Response from the Arduino\n @rtype: str\n \"\"\"\n \n while self.arduino_com.inWaiting() == 0:\n pass\n \n echo = self.arduino_com.readline().strip().decode(\"ascii\")\n \n if self.DEBUG_LEVEL > 0:\n print('Echo String: ' + echo)\n \n return echo","python_import":"","python_exec":"","settings":[],"icon":"./static/media/blankNode.38260d5b.svg","data":{},"kwargs":{},"description":"This node contains all the necessary code that will be used to communicate with the Arduino.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"showImports":false,"headerStyle":{"background":"#1562ad"}},{"nid":4,"version":"0.0.2","uid":5,"category":"logical","type":"Connection to Arduino","x":412,"y":25,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as soon as the node starts.\n@on_start\ndef arduinoConnect|||(*args,**kwargs):\n \n # This is the port and baud rate that will be used to talk to the Arduino.\n # On Windows setups, the serial port will look something like 'COM3'.\n # On Mac/OS setups, the serial port will look something like \n #'/dev/tty.usbmodem14401'. \n \n SERIAL_PORT = '/dev/tty.usbmodem14401'\n BAUD_RATE = 57600\n arduino_com = serial.Serial(SERIAL_PORT, BAUD_RATE)\n print(\"Arudino connecting...\")\n \n # Give the Arduino a couple of seconds to process\n # the connection. For some computers, there seems\n # to be a lag from the time we connect via serial\n # to when the Arduino actually responds to serial\n # input.\n time.sleep(2)\n \n # Clear anything that's on the serial port connection. We don't care\n # about any communication at this point.\n arduino_com.flush()\n print('Flushed Serial port entries...')\n print('Initializing Arcom...')\n \n # Set the Arduino information as the settings in the program.\n kwargs['Settings']['Arduino'] = arcom(arduino_com)\n # Return the kwargs\n return kwargs","python_import":"# These are the imports for this node\nimport serial\nimport time","python_exec":"arduinoConnect|||","settings":[],"icon":"./static/media/blankNode.38260d5b.svg","data":{},"kwargs":{},"description":"This node contains the code that will be used to connect to the Ardunio.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"showImports":true,"headerStyle":{"background":"#1562ad"}},{"uid":4,"category":"hardware","version":"0.0.2","nid":5,"type":"Main Experimental Loop","x":673,"y":53,"fields":{"in":[{"name":"start"},{"name":"habPattern"}],"out":[{"name":"pass"}]},"python":"# This function starts as soon as the node executes\n@on_start\ndef mainExpLoop|||(*args,**kwargs):\n \n # Getting ready to set-up the solenoids\n print('Getting Ready...')\n \n # -------------------------------------------------------------------------\n \n # PIN(s) Information: \n \n # These are the Arduino pin designations for the solenoids. The order in\n # the array corresponds to the physical solenoid index. So, element 0\n # of this array is solenoid 1, while element 7 is solenoid 8.\n SOLENOID_PINS = [22, 24, 26, 28, 30, 32, 34, 36]\n \n # Nose poke pin.\n NOSEPOKE_PIN = 2\n \n # -------------------------------------------------------------------------\n \n # StremeCoder Correction we are using a class instance but also \n # overriding the class. This only takes effect in this node. \n arcom = kwargs['Settings']['Arduino']\n\n # Setting the solenoid pins to outputs.\n print(\"Setting Solenoids...\")\n for pin in SOLENOID_PINS:\n arcom.set_pinmode(pin, arcom.OUTPUT)\n \n # Setting the solenoid pin for the nosepoke as the input\n print(\"Setting NosePoke Pin Solenoid...\")\n arcom.set_pinmode(NOSEPOKE_PIN, arcom.INPUT)\n \n # -------------------------------------------------------------------------\n \n # Do the program start delay.\n START_DELAY = {startDelay}\n print(\"Start Delay Started...\")\n time.sleep(START_DELAY)\n print(\"Start Delay Completed...\")\n \n # -------------------------------------------------------------------------\n \n # Set up the dataframe to collect the data from the trials\n print(\"Setting up the dataframe...\")\n df = pd.DataFrame([], columns = [\"Event\",\"Timestamp\"])\n kwargs['Data'] = df\n \n # -------------------------------------------------------------------------\n \n # Declare and Initialize the variable for the sound object to play sound\n wave_obj = sa.WaveObject.from_wave_file(\"Mikes Behavior Brown noise.wav\")\n # Play the background sound for the animals...\n play_obj = wave_obj.play()\n \n # Run the trials and collect the data\n data = {habPattern}\n \n # Stop playing the background sound.\\\n play_obj.stop()\n \n # Pass the data to the next node\n kwargs['Data'] = data.get('Data')\n \n # -------------------------------------------------------------------------\n \n # This is used to collect more data (run more of the same trials.)\n # somedata = {function1}['Data']\n # moredata = {function2}['Data']\n # andmoredata = {function3}['Data']\n \n # Close the connection to the Arduino.\n arcom.arduino_com.close()\n \n return kwargs","python_import":"# These are the imports for this node\nimport serial\nimport time\nimport pandas as pd\nimport simpleaudio as sa","python_exec":"mainExpLoop|||","settings":[{"key":"startDelay","label":"Start Delay (in seconds); Ex: 100"}],"icon":"./static/media/splitNode.d0a69cc1.svg","data":{"startDelay":"600"},"kwargs":{},"description":"This node includes everything that will be needed to run the main experimental loop.","showExecution":true,"showFunction":false,"executionClass":"uk-active","descriptionClass":"","importsClass":"","functionClass":"","showDescription":false,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"startDelay\",\"label\":\"Start Delay (in seconds); Ex: 100\"}]","stringPins":"{\"in\":[{\"name\":\"start\"},{\"name\":\"habPattern\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"showImports":false,"headerStyle":{"background":"#1562ad"}},{"nid":7,"version":"0.0.2","uid":5,"category":"logical","type":"[H1] Solenoid>NosePoke>ITI","x":477,"y":112,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"180","solenoidpin":"22","solenoidpinname":"\"MO1\""},"kwargs":{},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"showImports":false,"headerStyle":{"background":""}},{"nid":10,"version":"0.0.2","uid":5,"category":"logical","type":"Save Data as CSV","x":937,"y":59,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function runs as soon as this node starts. \n@on_start\ndef saveData|||(*args,**kwargs):\n \n # Start saving the file...\n print(\"Saving Data as a file...\")\n \n # Get the data from the trials\n df = kwargs['Data']\n \n # Convert data to a csv & \n # Save it in the same file location as this koi file\n df.to_csv(\"MastExperiment\" + {date} + \".csv\") # FILE OUTPUT\n \n # Let the user know the file has been save successfully.\n print(\"File Saved Successfully!\")\n \n return kwargs","python_import":"# These are the imports for this node\nimport pandas as pd","python_exec":"saveData|||","settings":[{"key":"date","label":"Date (Ex:01_06_21"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"date":"\"04_01_21\"","file_name":"\"MastExperiment_01_06_21\""},"kwargs":{},"description":"This node saves the data collected from the trials as a csv/Excel file.\n\n- The date variable is used as a file name in our experimental lab for the output csv file. This feature can be modified accordingly so that the user known it is the filename variable in your node.\n - Make this modification by editing the user dialog:\n \n ```[{\"key\":\"file_name\",\"label\":\"File Name (Ex: \\\"Mast_Experiment_01_06_21\\\" )\"}]```\n\n - Make this modification in the function section under the \"# Convert data to a csv & Save it in the same file location as this koi file\"\n \n ```df.to_csv(\"\" + {file_name} + \".csv\")```\n\n\n\n\n\n","headerStyle":{"background":"#adac15"},"showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"date\",\"label\":\"Date (Ex:01_06_21\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"showImports":false},{"nid":31,"uid":"custom","category":"logical","type":"[H2] Solenoid>NosePoke>ITI","x":475,"y":191,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"180","solenoidpin":"24","solenoidpinname":"\"MO2\""},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"headerStyle":{"background":""},"version":"0.0.2"},{"nid":32,"uid":"custom","category":"logical","type":"[H3] Solenoid>NosePoke>ITI","x":475,"y":269,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"180","solenoidpin":"26","solenoidpinname":"\"MO3\""},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"headerStyle":{"background":""},"version":"0.0.2"},{"nid":33,"uid":"custom","category":"logical","type":"[H4] Solenoid>NosePoke>ITI","x":476,"y":348,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"180","solenoidpin":"24","solenoidpinname":"\"MO4\""},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"headerStyle":{"background":""},"version":"0.0.2"},{"nid":34,"uid":"custom","category":"logical","type":"[O1] Solenoid>NosePoke>ITI","x":475,"y":426,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"180","solenoidpin":"32","solenoidpinname":"\"AA 5-7\""},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"version":"0.0.2"},{"nid":35,"uid":"custom","category":"logical","type":"[H5] Solenoid>NosePoke>ITI","x":476,"y":509,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"180","solenoidpin":"30","solenoidpinname":"\"MO5\""},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"version":"0.0.2"},{"nid":36,"uid":"custom","category":"logical","type":"[O2] Solenoid>NosePoke>ITI","x":474,"y":590,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"180","solenoidpin":"34","solenoidpinname":"\"AA -6\""},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"version":"0.0.2"},{"nid":37,"uid":"custom","category":"logical","type":"[H6] Solenoid>NosePoke>ITI","x":472,"y":675,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"180","solenoidpin":"22","solenoidpinname":"\"MO6\""},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"version":"0.0.2"},{"nid":38,"uid":"custom","category":"logical","type":"[O3] Solenoid>NosePoke>ITI","x":472,"y":763,"fields":{"in":[{"name":"start"}],"out":[{"name":"pass"}]},"python":"# This function starts as this node executes. \n@on_start\ndef solenoidFire|||(*args,**kwargs):\n # Getting the information from the Arduino\n arcom = kwargs['Settings']['Arduino']\n \n # Declaring and initializing the user entered information\n SOLENOID_PIN = {solenoidpin}\n SOLENOID_PIN_NAME = {solenoidpinname}\n TRIAL_DURATION = {trialDuration}\n ITI = {iti}\n \n # The nosepoke solenoid pin was declared in the main experimental loop\n NOSEPOKE_PIN = 2\n \n # Letting the user know the trial is running...\n print(\"Running trial for solenoid\", SOLENOID_PIN_NAME)\n \n # Log to terminal that we turned on the distractor valve \n print(\"Distractor On!\") \n # Log to terminal that we turned on the LED light\n print(\"LED On!\")\n # Log to terminal that we opened the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.HIGH)\n print(\"Valve On!\")\n \n \n # Log in the data that we've opened the solenoid.\n dataDict = {{(\"ODOR_ON_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}}\n \n # Check the nose pokes while the valve is open\n print(\"Now Within the Trial\")\n t0 = time.time()\n last_nosepoke_state = 0\n count = 1\n while time.time() - t0 < TRIAL_DURATION:\n # Get the current nose poke value.\n nosepoke_value = arcom.get_pin(NOSEPOKE_PIN)\n # Get the time we checked the nose port.\n nosepoke_time = get_timestamp()\n # If the last nosepoke state was 'unpoked' and the current one\n # is 'poked', count that as a single nose poke.\n if last_nosepoke_state == 0 and nosepoke_value == 1:\n # save poke data (when a mice enters the nose poke)\n dataDict.update({{(\"POKE_ENTER_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeEnter \", nosepoke_time)\n elif last_nosepoke_state == 1 and nosepoke_value == 0:\n # save poke data (when a mice exits the nose poke)\n dataDict.update({{(\"POKE_EXIT_\"+ str(count)):nosepoke_time}})\n print(\"NosePokeExit \", nosepoke_time) \n count = count + 1\n \n # Store the nose poke value so we can compare it to later\n # poke values.\n last_nosepoke_state = nosepoke_value\n \n # Log to terminal that we closed the solenoid valve\n arcom.set_pin(SOLENOID_PIN, arcom.LOW)\n print(\"Valve Off!\")\n # Log to terminal that we turned off the LED light\n print(\"LED Off!\")\n # Log to terminal that we turned the DISTRACTOR valve off.\n print(\"Distractor Off!\")\n \n # Log in the data that we've closed the solenoid.\n dataDict.update({{(\"ODOR_OFF_\" + str(SOLENOID_PIN) + \":\" + SOLENOID_PIN_NAME):get_timestamp()}})\n \n # Save the information to the dataframe\n df2 = pd.DataFrame(list(dataDict.items()),columns = [\"Event\",\"Timestamp\"])\n # Log to terminal the trial data\n print(df2)\n # Concat the previous dataframe with this dataframe\n result = pd.concat([kwargs['Data'], df2], ignore_index=True)\n kwargs['Data'] = result\n \n # Log to terminal that we entered ITI\n print (\"Entering ITI..\")\n # Wait the ITI\n time.sleep(ITI)\n # Log to terminal that we finished ITI\n print (\"Finished ITI... Next Trial...\")\n \n return kwargs\n\n\n# This function has the code in regards to getting the timestamp. \ndef get_timestamp():\n \"\"\"\n Gets the current time and converts it into a log format compatible with the commercial\n olfactometer output, which looks like \"Hour:Minute:Seconds\".\n\n :rtype : str\n :return: The time string \"Hour:Minute:Seconds\". Example: 12:34:9.23423\n \"\"\"\n\n # Get the current time in seconds since the epoch.\n t = time.time()\n\n # Convert the seconds into a time structure.\n time_struct = time.localtime(t)\n\n # The time structure doesn't maintain the fractional seconds data, so get that\n # ourselves.\n seconds_fraction = str(t).split('.')[1] [:-3]\n\n #sec_frac = seconds_fraction - 3\n\n # Format everything into a string and return it.\n return time.strftime(\"%H:%M:%S\", time_struct) + \".\" + seconds_fraction\n #%Y-%m-%d %H:%M: %S.%f\n #%H:%M:%S","python_import":"# These are the imports for this node\nimport time\nimport pandas as pd","python_exec":"solenoidFire|||","settings":[{"key":"trialDuration","label":"Trial Duration [in seconds]: {Ex: 100} "},{"key":"iti","label":"Inter Trial Interval [in seconds]: {Ex: 100}"},{"key":"solenoidpin","label":"Solenoid Pin Number: {Ex: 22}"},{"key":"solenoidpinname","label":"Solenoid Pin Name: {Ex: \"Mineral Oil 1\"}"}],"icon":"./static/media/blankNode.38260d5b.svg","data":{"trialDuration":"120","iti":"0","solenoidpin":"36","solenoidpinname":"\"AA 5 10-6\""},"description":"This node contains the code to turn on/off the solenoid valve, run the nose poke trial, and also run the inter-trial interval, in preparation for the next solenoid to go off.\n- Note: We hardwired the led light and the distractor solenoid valve so that they turn on/off at the same time when the solenoid valve goes on/off.","showExecution":false,"showFunction":false,"executionClass":"","descriptionClass":"uk-active","importsClass":"","functionClass":"","showDescription":true,"toggleMarkdown":false,"toggleUserDialog":false,"stringDialog":"[{\"key\":\"trialDuration\",\"label\":\"Trial Duration [in seconds]: {Ex: 100} \"},{\"key\":\"iti\",\"label\":\"Inter Trial Interval [in seconds]: {Ex: 100}\"},{\"key\":\"solenoidpin\",\"label\":\"Solenoid Pin Number: {Ex: 22}\"},{\"key\":\"solenoidpinname\",\"label\":\"Solenoid Pin Name: {Ex: \\\"Mineral Oil 1\\\"}\"}]","stringPins":"{\"in\":[{\"name\":\"start\"}],\"out\":[{\"name\":\"pass\"}]}","togglePins":false,"pintracker":false,"dialogtracker":false,"descriptiontracker":false,"version":"0.0.2"}],"connections":[{"from_node":0,"from":"start","to_node":3,"to":"start"},{"from_node":10,"from":"pass","to_node":1,"to":"start"},{"from_node":3,"from":"pass","to_node":4,"to":"start"},{"from_node":4,"from":"pass","to_node":5,"to":"start"},{"from_node":5,"from":"pass","to_node":10,"to":"start"},{"from_node":7,"from":"pass","to_node":5,"to":"habPattern"},{"from_node":31,"from":"pass","to_node":7,"to":"start"},{"from_node":32,"from":"pass","to_node":31,"to":"start"},{"from_node":33,"from":"pass","to_node":32,"to":"start"},{"from_node":34,"from":"pass","to_node":33,"to":"start"},{"from_node":35,"from":"pass","to_node":34,"to":"start"},{"from_node":36,"from":"pass","to_node":35,"to":"start"},{"from_node":37,"from":"pass","to_node":36,"to":"start"},{"from_node":38,"from":"pass","to_node":37,"to":"start"}],"title":"Mast_Experiment_Commander_Threshold_Test_B","showPopup":false,"current":-1,"count":38,"servers":{},"serverselection":null}