diff --git a/docs/nodes/IO/IMAGING/OPEN_WEBCAM/OPEN_WEBCAM.md b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/OPEN_WEBCAM.md
new file mode 100644
index 0000000000..5c49b7dfdf
--- /dev/null
+++ b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/OPEN_WEBCAM.md
@@ -0,0 +1,57 @@
+
+[//]: # (Custom component imports)
+
+import DocString from '@site/src/components/DocString';
+import PythonCode from '@site/src/components/PythonCode';
+import AppDisplay from '@site/src/components/AppDisplay';
+import SectionBreak from '@site/src/components/SectionBreak';
+import AppendixSection from '@site/src/components/AppendixSection';
+
+[//]: # (Docstring)
+
+import DocstringSource from '!!raw-loader!./a1-[autogen]/docstring.txt';
+import PythonSource from '!!raw-loader!./a1-[autogen]/python_code.txt';
+
+{DocstringSource}
+{PythonSource}
+
+
+
+
+
+[//]: # (Examples)
+
+## Examples
+
+import Example1 from './examples/EX1/example.md';
+import App1 from '!!raw-loader!./examples/EX1/app.json';
+
+
+
+
+ {App1}
+
+
+
+
+
+
+
+
+[//]: # (Appendix)
+
+import Notes from './appendix/notes.md';
+import Hardware from './appendix/hardware.md';
+import Media from './appendix/media.md';
+
+## Appendix
+
+
+
+
+
+
diff --git a/docs/nodes/IO/IMAGING/OPEN_WEBCAM/a1-[autogen]/docstring.txt b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/a1-[autogen]/docstring.txt
new file mode 100644
index 0000000000..6f4374314e
--- /dev/null
+++ b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/a1-[autogen]/docstring.txt
@@ -0,0 +1,12 @@
+The OPEN_WEBCAM node opens a connection with the selected camera.
+
+ Parameters
+ ----------
+ camera : Camera
+ The camera to use.
+ resolution : select
+ Camera resolution. Choose from a few options.
+
+ Returns
+ -------
+ None
diff --git a/docs/nodes/IO/IMAGING/OPEN_WEBCAM/a1-[autogen]/python_code.txt b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/a1-[autogen]/python_code.txt
new file mode 100644
index 0000000000..fd4be81271
--- /dev/null
+++ b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/a1-[autogen]/python_code.txt
@@ -0,0 +1,20 @@
+import cv2
+from flojoy import CameraDevice, flojoy, DataContainer
+from flojoy.connection_manager import DeviceConnectionManager
+from typing import Optional, Literal
+
+
+@flojoy(deps={"opencv-python-headless": "4.7.0.72"})
+def OPEN_WEBCAM(
+ camera: CameraDevice,
+ default: Optional[DataContainer] = None,
+) -> Optional[DataContainer]:
+
+
+ if not camera:
+ raise ValueError("No camera selected")
+
+ cam = cv2.VideoCapture(camera.get_id())
+ DeviceConnectionManager.register_connection(camera, cam)
+
+ return None
diff --git a/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/hardware.md b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/hardware.md
new file mode 100644
index 0000000000..7f78a555c4
--- /dev/null
+++ b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/hardware.md
@@ -0,0 +1 @@
+This node does not require any peripheral hardware to operate. Please see INSTRUMENTS for nodes that interact with the physical world through connected hardware.
\ No newline at end of file
diff --git a/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/media.md b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/media.md
new file mode 100644
index 0000000000..8bcee9be90
--- /dev/null
+++ b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/media.md
@@ -0,0 +1 @@
+No supporting screenshots, photos, or videos have been added to the media.md file for this node.
\ No newline at end of file
diff --git a/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/notes.md b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/notes.md
new file mode 100644
index 0000000000..04aded2ec9
--- /dev/null
+++ b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/appendix/notes.md
@@ -0,0 +1 @@
+No theory or technical notes have been contributed for this node yet.
\ No newline at end of file
diff --git a/docs/nodes/IO/IMAGING/OPEN_WEBCAM/examples/EX1/app.json b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/examples/EX1/app.json
new file mode 100644
index 0000000000..5db0940404
--- /dev/null
+++ b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/examples/EX1/app.json
@@ -0,0 +1,204 @@
+{
+ "rfInstance": {
+ "nodes": [
+ {
+ "width": 192,
+ "height": 192,
+ "id": "OPEN_WEBCAM-89c7016f-6198-4bee-bb37-0ffa21729da5",
+ "type": "IO",
+ "data": {
+ "id": "OPEN_WEBCAM-89c7016f-6198-4bee-bb37-0ffa21729da5",
+ "label": "OPEN WEBCAM",
+ "func": "OPEN_WEBCAM",
+ "type": "IO",
+ "ctrls": {
+ "camera": {
+ "type": "CameraDevice",
+ "default": null,
+ "desc": null,
+ "overload": null,
+ "functionName": "OPEN_WEBCAM",
+ "param": "camera",
+ "value": ""
+ }
+ },
+ "initCtrls": {},
+ "inputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Any",
+ "multiple": false,
+ "desc": null
+ }
+ ],
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Any",
+ "desc": null
+ }
+ ],
+ "pip_dependencies": [
+ {
+ "name": "opencv-python-headless",
+ "v": "4.7.0.72"
+ }
+ ],
+ "path": "IO/IMAGING/OPEN_WEBCAM/OPEN_WEBCAM.py",
+ "selected": false
+ },
+ "position": {
+ "x": -179.01679378861343,
+ "y": 3.074962043597168
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": -179.01679378861343,
+ "y": 3.074962043597168
+ },
+ "dragging": true
+ },
+ {
+ "width": 192,
+ "height": 192,
+ "id": "WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12c",
+ "type": "IO",
+ "data": {
+ "id": "WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12c",
+ "label": "WEBCAM",
+ "func": "WEBCAM",
+ "type": "IO",
+ "ctrls": {
+ "connection": {
+ "type": "CameraConnection",
+ "default": null,
+ "desc": null,
+ "overload": null,
+ "functionName": "WEBCAM",
+ "param": "connection",
+ "value": ""
+ },
+ "resolution": {
+ "type": "select",
+ "options": [
+ "default",
+ "640x360",
+ "640x480",
+ "1280x720",
+ "1920x1080"
+ ],
+ "default": "default",
+ "desc": "Camera resolution. Choose from a few options.",
+ "overload": null,
+ "functionName": "WEBCAM",
+ "param": "resolution",
+ "value": "default"
+ }
+ },
+ "initCtrls": {},
+ "inputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Any",
+ "multiple": false,
+ "desc": null
+ }
+ ],
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Image",
+ "desc": null
+ }
+ ],
+ "pip_dependencies": [
+ {
+ "name": "opencv-python-headless",
+ "v": "4.7.0.72"
+ }
+ ],
+ "path": "IO/IMAGING/WEBCAM/WEBCAM.py",
+ "selected": false
+ },
+ "position": {
+ "x": 179.0676354144525,
+ "y": 0.6447218141543658
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": 179.0676354144525,
+ "y": 0.6447218141543658
+ },
+ "dragging": true
+ },
+ {
+ "width": 225,
+ "height": 226,
+ "id": "IMAGE-d27c4496-301f-4882-8670-6bb84ebe7e06",
+ "type": "VISUALIZERS",
+ "data": {
+ "id": "IMAGE-d27c4496-301f-4882-8670-6bb84ebe7e06",
+ "label": "IMAGE",
+ "func": "IMAGE",
+ "type": "VISUALIZERS",
+ "ctrls": {},
+ "initCtrls": {},
+ "inputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Image|Grayscale",
+ "multiple": false,
+ "desc": "the DataContainer to be visualized"
+ }
+ ],
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Plotly",
+ "desc": "the DataContainer containing the Plotly Image visualization of the input image"
+ }
+ ],
+ "path": "VISUALIZERS/PLOTLY/IMAGE/IMAGE.py",
+ "selected": false
+ },
+ "position": {
+ "x": 515.9438185125092,
+ "y": -20.240488117947223
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": 515.9438185125092,
+ "y": -20.240488117947223
+ },
+ "dragging": true
+ }
+ ],
+ "edges": [
+ {
+ "source": "WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12c",
+ "sourceHandle": "default",
+ "target": "IMAGE-d27c4496-301f-4882-8670-6bb84ebe7e06",
+ "targetHandle": "default",
+ "id": "reactflow__edge-WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12cdefault-IMAGE-d27c4496-301f-4882-8670-6bb84ebe7e06default"
+ },
+ {
+ "source": "OPEN_WEBCAM-89c7016f-6198-4bee-bb37-0ffa21729da5",
+ "sourceHandle": "default",
+ "target": "WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12c",
+ "targetHandle": "default",
+ "id": "reactflow__edge-OPEN_WEBCAM-89c7016f-6198-4bee-bb37-0ffa21729da5default-WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12cdefault"
+ }
+ ],
+ "viewport": {
+ "x": 255.10425070720453,
+ "y": 317.88940714410813,
+ "zoom": 0.5
+ }
+ }
+}
\ No newline at end of file
diff --git a/docs/nodes/IO/IMAGING/OPEN_WEBCAM/examples/EX1/example.md b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/examples/EX1/example.md
new file mode 100644
index 0000000000..8255654e7e
--- /dev/null
+++ b/docs/nodes/IO/IMAGING/OPEN_WEBCAM/examples/EX1/example.md
@@ -0,0 +1,12 @@
+---
+title: OPEN_WEBCAM
+description: In this example, the OPEN_WEBCAM opens the connection with the connected camera, then uses the `WEBCAM` node takes and returns a picture. The IMSHOW node then displays the image taken by the camera.
+keyword: [Python, Instrument, Web cam, Camera, Python webcam integration, Camera instrument in Python, Capture images and videos, Streamline webcam usage, Python-based camera control, Webcam integration techniques, Python image and video capture, Enhance projects with webcam, Accurate media processing, Webcam usage with Python]
+image: https://raw.githubusercontent.com/flojoy-ai/docs/main/docs/nodes/INSTRUMENTS/WEB_CAM/CAMERA/examples/EX1/output.jpeg
+---
+
+In this example app, the [`CAMERA`](https://github.com/flojoy-io/nodes/blob/main/INSTRUMENTS/WEB_CAM/CAMERA/CAMERA.py) node takes and returns a picture from a camera connected to the computer.
+
+The camera first has to be opened with the [`OPEN_CAMERA`](https://github.com/flojoy-io/nodes/blob/main/INSTRUMENTS/WEB_CAM/CAMERA/CAMERA.py) node, which requires you to select which camera to use.
+
+The [`IMSHOW`](https://github.com/flojoy-io/nodes/blob/main/VISUALIZERS/PLOTLY/TABLE/TABLE.py) node displays the image taken by the camera that was selected.
diff --git a/docs/nodes/IO/IMAGING/WEBCAM/a1-[autogen]/docstring.txt b/docs/nodes/IO/IMAGING/WEBCAM/a1-[autogen]/docstring.txt
index f529c130a9..8844ece47a 100644
--- a/docs/nodes/IO/IMAGING/WEBCAM/a1-[autogen]/docstring.txt
+++ b/docs/nodes/IO/IMAGING/WEBCAM/a1-[autogen]/docstring.txt
@@ -1,11 +1,11 @@
The CAMERA node acquires an image using the selected camera.
- If no camera is detected, an error would be shown.
+ The selected camera must be opened already using the OPEN_WEBCAM node.
Parameters
----------
- camera_ind : int
- Camera index (i.e. camera identifier).
+ connection : Camera
+ The opened camera connection to use.
resolution : select
Camera resolution. Choose from a few options.
diff --git a/docs/nodes/IO/IMAGING/WEBCAM/a1-[autogen]/python_code.txt b/docs/nodes/IO/IMAGING/WEBCAM/a1-[autogen]/python_code.txt
index 857b54e822..1d2c71d19e 100644
--- a/docs/nodes/IO/IMAGING/WEBCAM/a1-[autogen]/python_code.txt
+++ b/docs/nodes/IO/IMAGING/WEBCAM/a1-[autogen]/python_code.txt
@@ -1,41 +1,38 @@
import cv2
-import os
-from flojoy import flojoy, DataContainer
+from flojoy import flojoy, DataContainer, CameraConnection, Image
from typing import Optional, Literal
-from PIL import Image
-import numpy as np
-@flojoy(deps={"opencv-python-headless": "4.7.0.72"})
+@flojoy(deps={"opencv-python-headless": "4.7.0.72"}, inject_connection=True)
def WEBCAM(
+ connection: CameraConnection,
default: Optional[DataContainer] = None,
- camera_ind: int = -1,
resolution: Literal[
"default", "640x360", "640x480", "1280x720", "1920x1080"
] = "default",
-) -> DataContainer:
+) -> Image:
+ cam = connection.get_handle()
try:
- camera = cv2.VideoCapture(camera_ind)
if resolution != "default":
resolution = resolution.split("x")
try:
- camera.set(cv2.CAP_PROP_FRAME_WIDTH, int(resolution[0]))
- camera.set(cv2.CAP_PROP_FRAME_HEIGHT, int(resolution[1]))
+ cam.set(cv2.CAP_PROP_FRAME_WIDTH, int(resolution[0]))
+ cam.set(cv2.CAP_PROP_FRAME_HEIGHT, int(resolution[1]))
except cv2.error as camera_error:
print(f"Invalid resolution ({resolution}). Try a lower value.")
raise camera_error
- if not camera.isOpened():
+ if not cam.isOpened():
raise cv2.error("Failed to open camera")
- result, BGR_img = camera.read()
+ result, BGR_img = cam.read()
if not result:
raise cv2.error("Failed to capture image")
- camera.release()
- del camera
+ # cam.release()
+ # del cam
RGB_img = cv2.cvtColor(BGR_img, cv2.COLOR_BGR2RGB)
@@ -49,8 +46,7 @@ def WEBCAM(
else:
alpha_channel = None
- camera_image = DataContainer(
- type="Image",
+ camera_image = Image(
r=red_channel,
g=green_channel,
b=blue_channel,
diff --git a/docs/nodes/IO/IMAGING/WEBCAM/examples/EX1/app.json b/docs/nodes/IO/IMAGING/WEBCAM/examples/EX1/app.json
index b0da688128..5db0940404 100644
--- a/docs/nodes/IO/IMAGING/WEBCAM/examples/EX1/app.json
+++ b/docs/nodes/IO/IMAGING/WEBCAM/examples/EX1/app.json
@@ -2,26 +2,86 @@
"rfInstance": {
"nodes": [
{
- "width": 150,
- "height": 150,
- "id": "CAMERA-29dc2b2f-b87c-46a3-9ddc-11e685de3206",
- "type": "INSTRUMENTS",
+ "width": 192,
+ "height": 192,
+ "id": "OPEN_WEBCAM-89c7016f-6198-4bee-bb37-0ffa21729da5",
+ "type": "IO",
"data": {
- "id": "CAMERA-29dc2b2f-b87c-46a3-9ddc-11e685de3206",
- "label": "CAMERA",
- "func": "CAMERA",
- "type": "INSTRUMENTS",
+ "id": "OPEN_WEBCAM-89c7016f-6198-4bee-bb37-0ffa21729da5",
+ "label": "OPEN WEBCAM",
+ "func": "OPEN_WEBCAM",
+ "type": "IO",
"ctrls": {
- "camera_ind": {
- "type": "int",
- "default": -1,
- "functionName": "CAMERA",
- "param": "camera_ind",
- "value": -1
+ "camera": {
+ "type": "CameraDevice",
+ "default": null,
+ "desc": null,
+ "overload": null,
+ "functionName": "OPEN_WEBCAM",
+ "param": "camera",
+ "value": ""
+ }
+ },
+ "initCtrls": {},
+ "inputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Any",
+ "multiple": false,
+ "desc": null
+ }
+ ],
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Any",
+ "desc": null
+ }
+ ],
+ "pip_dependencies": [
+ {
+ "name": "opencv-python-headless",
+ "v": "4.7.0.72"
+ }
+ ],
+ "path": "IO/IMAGING/OPEN_WEBCAM/OPEN_WEBCAM.py",
+ "selected": false
+ },
+ "position": {
+ "x": -179.01679378861343,
+ "y": 3.074962043597168
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": -179.01679378861343,
+ "y": 3.074962043597168
+ },
+ "dragging": true
+ },
+ {
+ "width": 192,
+ "height": 192,
+ "id": "WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12c",
+ "type": "IO",
+ "data": {
+ "id": "WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12c",
+ "label": "WEBCAM",
+ "func": "WEBCAM",
+ "type": "IO",
+ "ctrls": {
+ "connection": {
+ "type": "CameraConnection",
+ "default": null,
+ "desc": null,
+ "overload": null,
+ "functionName": "WEBCAM",
+ "param": "connection",
+ "value": ""
},
"resolution": {
"type": "select",
- "default": "default",
"options": [
"default",
"640x360",
@@ -29,24 +89,30 @@
"1280x720",
"1920x1080"
],
- "functionName": "CAMERA",
+ "default": "default",
+ "desc": "Camera resolution. Choose from a few options.",
+ "overload": null,
+ "functionName": "WEBCAM",
"param": "resolution",
"value": "default"
}
},
+ "initCtrls": {},
"inputs": [
{
"name": "default",
"id": "default",
"type": "Any",
- "multiple": false
+ "multiple": false,
+ "desc": null
}
],
"outputs": [
{
"name": "default",
"id": "default",
- "type": "Any"
+ "type": "Image",
+ "desc": null
}
],
"pip_dependencies": [
@@ -55,93 +121,84 @@
"v": "4.7.0.72"
}
],
- "path": "PYTHON/nodes/INSTRUMENTS/WEB_CAM/CAMERA/CAMERA.py",
+ "path": "IO/IMAGING/WEBCAM/WEBCAM.py",
"selected": false
},
"position": {
- "x": 934.4795759482945,
- "y": -38.568710835013746
+ "x": 179.0676354144525,
+ "y": 0.6447218141543658
},
"selected": false,
"positionAbsolute": {
- "x": 934.4795759482945,
- "y": -38.568710835013746
+ "x": 179.0676354144525,
+ "y": 0.6447218141543658
},
"dragging": true
},
{
"width": 225,
"height": 226,
- "id": "IMAGE-cd503f68-87fd-478a-b577-baa959f3df08",
+ "id": "IMAGE-d27c4496-301f-4882-8670-6bb84ebe7e06",
"type": "VISUALIZERS",
"data": {
- "id": "IMAGE-cd503f68-87fd-478a-b577-baa959f3df08",
+ "id": "IMAGE-d27c4496-301f-4882-8670-6bb84ebe7e06",
"label": "IMAGE",
"func": "IMAGE",
"type": "VISUALIZERS",
"ctrls": {},
+ "initCtrls": {},
"inputs": [
{
"name": "default",
"id": "default",
- "type": "Image",
- "multiple": false
+ "type": "Image|Grayscale",
+ "multiple": false,
+ "desc": "the DataContainer to be visualized"
}
],
"outputs": [
{
"name": "default",
"id": "default",
- "type": "Plotly"
+ "type": "Plotly",
+ "desc": "the DataContainer containing the Plotly Image visualization of the input image"
}
],
- "path": "PYTHON/nodes/VISUALIZERS/PLOTLY/IMAGE/IMAGE.py",
+ "path": "VISUALIZERS/PLOTLY/IMAGE/IMAGE.py",
"selected": false
},
"position": {
- "x": 1261.9152508247892,
- "y": -78.58047260527047
+ "x": 515.9438185125092,
+ "y": -20.240488117947223
},
"selected": false,
"positionAbsolute": {
- "x": 1261.9152508247892,
- "y": -78.58047260527047
+ "x": 515.9438185125092,
+ "y": -20.240488117947223
},
"dragging": true
}
],
"edges": [
{
- "source": "CAMERA-29dc2b2f-b87c-46a3-9ddc-11e685de3206",
+ "source": "WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12c",
"sourceHandle": "default",
- "target": "IMAGE-cd503f68-87fd-478a-b577-baa959f3df08",
+ "target": "IMAGE-d27c4496-301f-4882-8670-6bb84ebe7e06",
"targetHandle": "default",
- "id": "reactflow__edge-CAMERA-29dc2b2f-b87c-46a3-9ddc-11e685de3206default-IMAGE-cd503f68-87fd-478a-b577-baa959f3df08default"
+ "id": "reactflow__edge-WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12cdefault-IMAGE-d27c4496-301f-4882-8670-6bb84ebe7e06default"
+ },
+ {
+ "source": "OPEN_WEBCAM-89c7016f-6198-4bee-bb37-0ffa21729da5",
+ "sourceHandle": "default",
+ "target": "WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12c",
+ "targetHandle": "default",
+ "id": "reactflow__edge-OPEN_WEBCAM-89c7016f-6198-4bee-bb37-0ffa21729da5default-WEBCAM-89b91b3a-0682-44db-95d9-b1e26d1dd12cdefault"
}
],
"viewport": {
- "x": -358.59636577932724,
- "y": 99.85117439980638,
- "zoom": 1.0581352782820395
- }
- },
- "ctrlsManifest": [
- {
- "type": "input",
- "name": "Slider",
- "id": "INPUT_PLACEHOLDER",
- "hidden": false,
- "minHeight": 1,
- "minWidth": 2,
- "layout": {
- "x": 0,
- "y": 0,
- "h": 2,
- "w": 2,
- "minH": 1,
- "minW": 2,
- "i": "INPUT_PLACEHOLDER"
- }
+ "x": 255.10425070720453,
+ "y": 317.88940714410813,
+ "zoom": 0.5
}
- ]
+ }
}
\ No newline at end of file
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/a1-[autogen]/docstring.txt b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/a1-[autogen]/docstring.txt
index 862fbadae6..87fc889b00 100644
--- a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/a1-[autogen]/docstring.txt
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/a1-[autogen]/docstring.txt
@@ -1,11 +1,14 @@
-The KEITHLEY2400 node takes an I-V curve measurement with a Keithley 2400 source meter, send voltages, and measures currents.
+The IV_SWEEP node takes an I-V curve measurement with a Keithley 2400 source meter, send voltages, and measures currents.
+
+ Inputs
+ ------
+ default: OrderedPair | Vector
+ The voltages to send to the Keithley 2400 source meter.
Parameters
----------
- comport : str
- Defines the serial communication port for the Keithley2400 source meter.
- baudrate : float
- Specifies the baud rate for the serial communication between the Keithley2400 and the computer.
+ connection: Serial
+ The open connection with the Keithley2400 source meter.
Returns
-------
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/a1-[autogen]/python_code.txt b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/a1-[autogen]/python_code.txt
index 822d972e5c..9f7546ea48 100644
--- a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/a1-[autogen]/python_code.txt
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/a1-[autogen]/python_code.txt
@@ -1,24 +1,26 @@
-from flojoy import flojoy, OrderedPair, Vector, node_initialization, NodeInitContainer
import serial
+import numpy as np
+from flojoy import SerialConnection, flojoy, OrderedPair, Vector
+from typing import cast
-@flojoy(deps={"pyserial": "3.5"})
+@flojoy(deps={"pyserial": "3.5"}, inject_connection=True)
def IV_SWEEP(
- init_container: NodeInitContainer, default: OrderedPair | Vector
+ connection: SerialConnection, default: OrderedPair | Vector
) -> OrderedPair:
# Start serial communication with the instrument
- # ser: serial = serial.Serial()
+ ser = cast(serial.Serial, connection.get_handle())
- ser = init_container.get()
if ser is None:
raise ValueError("Serial communication is not open")
# Keithley 2400 Configuration
ser.write(b"*RST\n") # reinitialisation of the instrument
- ser.write(b":SOUR:FUNC:MODE VOLT\n") # Sourcing tension
- ser.write(b':SENS:FUNC "CURR"\n') # Measuring current
+ ser.write(
+ b":SOUR:FUNC:MODE VOLT\n"
+ ) # Sourcing tension ser.write(b':SENS:FUNC "CURR"\n') # Measuring current
ser.write(
b":SENS:CURR:PROT 1.05\n"
) # Current protection set at 1.05A (Keithley 2400)
@@ -37,11 +39,8 @@ def IV_SWEEP(
ser.write(b":INIT\n") # Start measuring
ser.write(b":FETC?\n") # Retrieve the measured values
- current_str: str = (
- ser.readline().decode("ascii").strip()
- ) # Save answers in a string
- voltage_current_values: str = current_str.split(
- ",") # Split the string
+ current_str = ser.readline().decode("ascii").strip() # Save answers in a string
+ voltage_current_values = current_str.split(",") # Split the string
currents_neg.append(-float(voltage_current_values[1]))
ser.write(b":OUTP OFF\n") # Close output from Instrument
@@ -49,23 +48,4 @@ def IV_SWEEP(
# Close Serial Communication
ser.close()
- return OrderedPair(x=voltages, y=currents_neg)
-
-
-@node_initialization(for_node=IV_SWEEP)
-def init(comport: str = "/dev/ttyUSB0", baudrate: float = 9600):
- ser: serial = serial.Serial()
-
- # Specific parameters
- ser.port = comport # Specify serial port for com
- ser.baudrate = baudrate # Specify Baudrate
-
- # General parameters
- ser.bytesize = serial.EIGHTBITS # Specify Bites number
- ser.parity = serial.PARITY_NONE # Specify Parity
- ser.stopbits = serial.STOPBITS_ONE # Specify Stop bites
- ser.timeout = 1
- # Open Serial Com
- ser.open()
-
- return ser
+ return OrderedPair(x=voltages, y=np.array(currents_neg))
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/examples/EX1/app.json b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/examples/EX1/app.json
index 2617aef0d7..6784b06926 100644
--- a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/examples/EX1/app.json
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/examples/EX1/app.json
@@ -4,32 +4,84 @@
{
"width": 192,
"height": 192,
- "id": "KEITHLEY2400-33053219-7ec1-40d0-9cb9-5d337294a01e",
- "type": "INSTRUMENTS",
+ "id": "OPEN_KEITHLEY_24XX-097d2560-f5b9-468a-9517-32e89dedecc1",
+ "type": "IO",
"data": {
- "id": "KEITHLEY2400-33053219-7ec1-40d0-9cb9-5d337294a01e",
- "label": "KEITHLEY2400",
- "func": "KEITHLEY2400",
- "type": "INSTRUMENTS",
- "ctrls": {},
- "initCtrls": {
- "comport": {
- "type": "str",
- "default": "/dev/ttyUSB0",
+ "id": "OPEN_KEITHLEY_24XX-097d2560-f5b9-468a-9517-32e89dedecc1",
+ "label": "OPEN KEITHLEY 24XX",
+ "func": "OPEN_KEITHLEY_24XX",
+ "type": "IO",
+ "ctrls": {
+ "device": {
+ "type": "SerialDevice",
+ "default": null,
"desc": null,
- "functionName": "KEITHLEY2400",
- "param": "comport",
- "value": "/dev/ttyUSB0"
+ "overload": null,
+ "functionName": "OPEN_KEITHLEY_24XX",
+ "param": "device",
+ "value": ""
},
"baudrate": {
- "type": "float",
+ "type": "int",
"default": 9600,
"desc": null,
- "functionName": "KEITHLEY2400",
+ "overload": null,
+ "functionName": "OPEN_KEITHLEY_24XX",
"param": "baudrate",
"value": 9600
}
},
+ "initCtrls": {},
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Any",
+ "desc": null
+ }
+ ],
+ "pip_dependencies": [
+ {
+ "name": "pyserial",
+ "v": "3.5"
+ }
+ ],
+ "path": "IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/OPEN_KEITHLEY_24XX.py",
+ "selected": false
+ },
+ "position": {
+ "x": -140.35863305434796,
+ "y": 1.9088042829506549
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": -140.35863305434796,
+ "y": 1.9088042829506549
+ },
+ "dragging": true
+ },
+ {
+ "width": 192,
+ "height": 192,
+ "id": "IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7",
+ "type": "IO",
+ "data": {
+ "id": "IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7",
+ "label": "IV SWEEP",
+ "func": "IV_SWEEP",
+ "type": "IO",
+ "ctrls": {
+ "connection": {
+ "type": "SerialConnection",
+ "default": null,
+ "desc": null,
+ "overload": null,
+ "functionName": "IV_SWEEP",
+ "param": "connection",
+ "value": ""
+ }
+ },
+ "initCtrls": {},
"inputs": [
{
"name": "default",
@@ -53,27 +105,27 @@
"v": "3.5"
}
],
- "path": "PYTHON/nodes/INSTRUMENTS/KEITHLEY/KEITHLEY2400/KEITHLEY2400.py",
+ "path": "IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/IV_SWEEP.py",
"selected": false
},
"position": {
- "x": 114.41979939902592,
- "y": -225.9703888733589
+ "x": 511.6912461233678,
+ "y": 5.980216390951398
},
"selected": false,
"positionAbsolute": {
- "x": 114.41979939902592,
- "y": -225.9703888733589
+ "x": 511.6912461233678,
+ "y": 5.980216390951398
},
"dragging": true
},
{
"width": 208,
"height": 96,
- "id": "LINSPACE-a3ec55cd-d572-437a-a823-7a8707fc2099",
+ "id": "LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28",
"type": "GENERATORS",
"data": {
- "id": "LINSPACE-a3ec55cd-d572-437a-a823-7a8707fc2099",
+ "id": "LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28",
"label": "LINSPACE",
"func": "LINSPACE",
"type": "GENERATORS",
@@ -82,6 +134,7 @@
"type": "float",
"default": 10,
"desc": "The start point of the data.",
+ "overload": null,
"functionName": "LINSPACE",
"param": "start",
"value": 10
@@ -90,6 +143,7 @@
"type": "float",
"default": 0,
"desc": "The end point of the data.",
+ "overload": null,
"functionName": "LINSPACE",
"param": "end",
"value": 0
@@ -98,9 +152,10 @@
"type": "int",
"default": 1000,
"desc": "The number of points in the vector.",
+ "overload": null,
"functionName": "LINSPACE",
"param": "step",
- "value": 1000
+ "value": 10
}
},
"initCtrls": {},
@@ -118,32 +173,32 @@
"name": "default",
"id": "default",
"type": "Vector",
- "desc": "v: the vector between start and end with step number of points."
+ "desc": "v: the vector between 'start' and 'end' with a 'step' number of points."
}
],
- "path": "PYTHON/nodes/GENERATORS/SIMULATIONS/LINSPACE/LINSPACE.py",
+ "path": "GENERATORS/SIMULATIONS/LINSPACE/LINSPACE.py",
"selected": false
},
"position": {
- "x": -220.989828306302,
- "y": -177.3419913453396
+ "x": 192.47824090745922,
+ "y": 49.8416165273091
},
"selected": false,
"positionAbsolute": {
- "x": -220.989828306302,
- "y": -177.3419913453396
+ "x": 192.47824090745922,
+ "y": 49.8416165273091
},
"dragging": true
},
{
"width": 225,
"height": 226,
- "id": "LINE-5ea158cf-c235-4bff-bec2-0714507a1bf0",
+ "id": "SCATTER-fee34277-0702-4342-af77-37c9d68701c6",
"type": "VISUALIZERS",
"data": {
- "id": "LINE-5ea158cf-c235-4bff-bec2-0714507a1bf0",
- "label": "LINE",
- "func": "LINE",
+ "id": "SCATTER-fee34277-0702-4342-af77-37c9d68701c6",
+ "label": "SCATTER",
+ "func": "SCATTER",
"type": "VISUALIZERS",
"ctrls": {},
"initCtrls": {},
@@ -161,44 +216,51 @@
"name": "default",
"id": "default",
"type": "Plotly",
- "desc": "the DataContainer containing Plotly Line visualization of the input data"
+ "desc": "the DataContainer containing the Plotly Scatter visualization"
}
],
- "path": "PYTHON/nodes/VISUALIZERS/PLOTLY/LINE/LINE.py",
- "selected": true
+ "path": "VISUALIZERS/PLOTLY/SCATTER/SCATTER.py",
+ "selected": false
},
"position": {
- "x": 448.130869654421,
- "y": -243.92275361997378
+ "x": 822.0611229804773,
+ "y": -8.822814846961876
},
- "selected": true,
+ "selected": false,
"positionAbsolute": {
- "x": 448.130869654421,
- "y": -243.92275361997378
+ "x": 822.0611229804773,
+ "y": -8.822814846961876
},
"dragging": true
}
],
"edges": [
{
- "source": "LINSPACE-a3ec55cd-d572-437a-a823-7a8707fc2099",
+ "source": "OPEN_KEITHLEY_24XX-097d2560-f5b9-468a-9517-32e89dedecc1",
+ "sourceHandle": "default",
+ "target": "LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28",
+ "targetHandle": "default",
+ "id": "reactflow__edge-OPEN_KEITHLEY_24XX-097d2560-f5b9-468a-9517-32e89dedecc1default-LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28default"
+ },
+ {
+ "source": "LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28",
"sourceHandle": "default",
- "target": "KEITHLEY2400-33053219-7ec1-40d0-9cb9-5d337294a01e",
+ "target": "IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7",
"targetHandle": "default",
- "id": "reactflow__edge-LINSPACE-a3ec55cd-d572-437a-a823-7a8707fc2099default-KEITHLEY2400-33053219-7ec1-40d0-9cb9-5d337294a01edefault"
+ "id": "reactflow__edge-LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28default-IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7default"
},
{
- "source": "KEITHLEY2400-33053219-7ec1-40d0-9cb9-5d337294a01e",
+ "source": "IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7",
"sourceHandle": "default",
- "target": "LINE-5ea158cf-c235-4bff-bec2-0714507a1bf0",
+ "target": "SCATTER-fee34277-0702-4342-af77-37c9d68701c6",
"targetHandle": "default",
- "id": "reactflow__edge-KEITHLEY2400-33053219-7ec1-40d0-9cb9-5d337294a01edefault-LINE-5ea158cf-c235-4bff-bec2-0714507a1bf0default"
+ "id": "reactflow__edge-IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7default-SCATTER-fee34277-0702-4342-af77-37c9d68701c6default"
}
],
"viewport": {
- "x": 621.1813795484834,
- "y": 324.9597014372874,
- "zoom": 0.6891413136990774
+ "x": 255.10425070720453,
+ "y": 317.88940714410813,
+ "zoom": 0.5
}
}
}
\ No newline at end of file
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/OPEN_KEITHLEY_24XX.md b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/OPEN_KEITHLEY_24XX.md
new file mode 100644
index 0000000000..ba9d4f78f2
--- /dev/null
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/OPEN_KEITHLEY_24XX.md
@@ -0,0 +1,57 @@
+
+[//]: # (Custom component imports)
+
+import DocString from '@site/src/components/DocString';
+import PythonCode from '@site/src/components/PythonCode';
+import AppDisplay from '@site/src/components/AppDisplay';
+import SectionBreak from '@site/src/components/SectionBreak';
+import AppendixSection from '@site/src/components/AppendixSection';
+
+[//]: # (Docstring)
+
+import DocstringSource from '!!raw-loader!./a1-[autogen]/docstring.txt';
+import PythonSource from '!!raw-loader!./a1-[autogen]/python_code.txt';
+
+{DocstringSource}
+{PythonSource}
+
+
+
+
+
+[//]: # (Examples)
+
+## Examples
+
+import Example1 from './examples/EX1/example.md';
+import App1 from '!!raw-loader!./examples/EX1/app.json';
+
+
+
+
+ {App1}
+
+
+
+
+
+
+
+
+[//]: # (Appendix)
+
+import Notes from './appendix/notes.md';
+import Hardware from './appendix/hardware.md';
+import Media from './appendix/media.md';
+
+## Appendix
+
+
+
+
+
+
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/a1-[autogen]/docstring.txt b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/a1-[autogen]/docstring.txt
new file mode 100644
index 0000000000..09000ede9f
--- /dev/null
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/a1-[autogen]/docstring.txt
@@ -0,0 +1,10 @@
+The OPEN_KEITHLEY_24XX node opens a connection with the Keithley 2400 source meter.
+
+ Parameters
+ ----------
+ device: Serial
+ The connected serial device corresponding to the Keithley 2400 source meter.
+
+ Returns
+ -------
+ None
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/a1-[autogen]/python_code.txt b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/a1-[autogen]/python_code.txt
new file mode 100644
index 0000000000..c32487e867
--- /dev/null
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/a1-[autogen]/python_code.txt
@@ -0,0 +1,24 @@
+import serial
+from typing import Optional
+from flojoy import SerialDevice, flojoy, DataContainer
+from flojoy.connection_manager import DeviceConnectionManager
+
+
+@flojoy(deps={"pyserial": "3.5"})
+def OPEN_KEITHLEY_24XX(
+ device: SerialDevice, baudrate: int = 9600
+) -> Optional[DataContainer]:
+
+
+ ser = serial.Serial(
+ port=device.get_port(),
+ baudrate=baudrate,
+ bytesize=serial.EIGHTBITS,
+ parity=serial.PARITY_NONE,
+ stopbits=serial.STOPBITS_ONE,
+ timeout=1,
+ )
+
+ DeviceConnectionManager.register_connection(device, ser)
+
+ return None
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/hardware.md b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/hardware.md
new file mode 100644
index 0000000000..7f78a555c4
--- /dev/null
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/hardware.md
@@ -0,0 +1 @@
+This node does not require any peripheral hardware to operate. Please see INSTRUMENTS for nodes that interact with the physical world through connected hardware.
\ No newline at end of file
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/media.md b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/media.md
new file mode 100644
index 0000000000..8bcee9be90
--- /dev/null
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/media.md
@@ -0,0 +1 @@
+No supporting screenshots, photos, or videos have been added to the media.md file for this node.
\ No newline at end of file
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/notes.md b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/notes.md
new file mode 100644
index 0000000000..04aded2ec9
--- /dev/null
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/appendix/notes.md
@@ -0,0 +1 @@
+No theory or technical notes have been contributed for this node yet.
\ No newline at end of file
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/examples/EX1/app.json b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/examples/EX1/app.json
new file mode 100644
index 0000000000..6784b06926
--- /dev/null
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/examples/EX1/app.json
@@ -0,0 +1,266 @@
+{
+ "rfInstance": {
+ "nodes": [
+ {
+ "width": 192,
+ "height": 192,
+ "id": "OPEN_KEITHLEY_24XX-097d2560-f5b9-468a-9517-32e89dedecc1",
+ "type": "IO",
+ "data": {
+ "id": "OPEN_KEITHLEY_24XX-097d2560-f5b9-468a-9517-32e89dedecc1",
+ "label": "OPEN KEITHLEY 24XX",
+ "func": "OPEN_KEITHLEY_24XX",
+ "type": "IO",
+ "ctrls": {
+ "device": {
+ "type": "SerialDevice",
+ "default": null,
+ "desc": null,
+ "overload": null,
+ "functionName": "OPEN_KEITHLEY_24XX",
+ "param": "device",
+ "value": ""
+ },
+ "baudrate": {
+ "type": "int",
+ "default": 9600,
+ "desc": null,
+ "overload": null,
+ "functionName": "OPEN_KEITHLEY_24XX",
+ "param": "baudrate",
+ "value": 9600
+ }
+ },
+ "initCtrls": {},
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Any",
+ "desc": null
+ }
+ ],
+ "pip_dependencies": [
+ {
+ "name": "pyserial",
+ "v": "3.5"
+ }
+ ],
+ "path": "IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/OPEN_KEITHLEY_24XX.py",
+ "selected": false
+ },
+ "position": {
+ "x": -140.35863305434796,
+ "y": 1.9088042829506549
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": -140.35863305434796,
+ "y": 1.9088042829506549
+ },
+ "dragging": true
+ },
+ {
+ "width": 192,
+ "height": 192,
+ "id": "IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7",
+ "type": "IO",
+ "data": {
+ "id": "IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7",
+ "label": "IV SWEEP",
+ "func": "IV_SWEEP",
+ "type": "IO",
+ "ctrls": {
+ "connection": {
+ "type": "SerialConnection",
+ "default": null,
+ "desc": null,
+ "overload": null,
+ "functionName": "IV_SWEEP",
+ "param": "connection",
+ "value": ""
+ }
+ },
+ "initCtrls": {},
+ "inputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "OrderedPair|Vector",
+ "multiple": false,
+ "desc": null
+ }
+ ],
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "OrderedPair",
+ "desc": null
+ }
+ ],
+ "pip_dependencies": [
+ {
+ "name": "pyserial",
+ "v": "3.5"
+ }
+ ],
+ "path": "IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/IV_SWEEP.py",
+ "selected": false
+ },
+ "position": {
+ "x": 511.6912461233678,
+ "y": 5.980216390951398
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": 511.6912461233678,
+ "y": 5.980216390951398
+ },
+ "dragging": true
+ },
+ {
+ "width": 208,
+ "height": 96,
+ "id": "LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28",
+ "type": "GENERATORS",
+ "data": {
+ "id": "LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28",
+ "label": "LINSPACE",
+ "func": "LINSPACE",
+ "type": "GENERATORS",
+ "ctrls": {
+ "start": {
+ "type": "float",
+ "default": 10,
+ "desc": "The start point of the data.",
+ "overload": null,
+ "functionName": "LINSPACE",
+ "param": "start",
+ "value": 10
+ },
+ "end": {
+ "type": "float",
+ "default": 0,
+ "desc": "The end point of the data.",
+ "overload": null,
+ "functionName": "LINSPACE",
+ "param": "end",
+ "value": 0
+ },
+ "step": {
+ "type": "int",
+ "default": 1000,
+ "desc": "The number of points in the vector.",
+ "overload": null,
+ "functionName": "LINSPACE",
+ "param": "step",
+ "value": 10
+ }
+ },
+ "initCtrls": {},
+ "inputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Vector|OrderedPair",
+ "multiple": false,
+ "desc": "Optional input in case LINSPACE is used in a loop. Not used."
+ }
+ ],
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Vector",
+ "desc": "v: the vector between 'start' and 'end' with a 'step' number of points."
+ }
+ ],
+ "path": "GENERATORS/SIMULATIONS/LINSPACE/LINSPACE.py",
+ "selected": false
+ },
+ "position": {
+ "x": 192.47824090745922,
+ "y": 49.8416165273091
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": 192.47824090745922,
+ "y": 49.8416165273091
+ },
+ "dragging": true
+ },
+ {
+ "width": 225,
+ "height": 226,
+ "id": "SCATTER-fee34277-0702-4342-af77-37c9d68701c6",
+ "type": "VISUALIZERS",
+ "data": {
+ "id": "SCATTER-fee34277-0702-4342-af77-37c9d68701c6",
+ "label": "SCATTER",
+ "func": "SCATTER",
+ "type": "VISUALIZERS",
+ "ctrls": {},
+ "initCtrls": {},
+ "inputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "OrderedPair|DataFrame|Matrix|Vector",
+ "multiple": false,
+ "desc": "the DataContainer to be visualized"
+ }
+ ],
+ "outputs": [
+ {
+ "name": "default",
+ "id": "default",
+ "type": "Plotly",
+ "desc": "the DataContainer containing the Plotly Scatter visualization"
+ }
+ ],
+ "path": "VISUALIZERS/PLOTLY/SCATTER/SCATTER.py",
+ "selected": false
+ },
+ "position": {
+ "x": 822.0611229804773,
+ "y": -8.822814846961876
+ },
+ "selected": false,
+ "positionAbsolute": {
+ "x": 822.0611229804773,
+ "y": -8.822814846961876
+ },
+ "dragging": true
+ }
+ ],
+ "edges": [
+ {
+ "source": "OPEN_KEITHLEY_24XX-097d2560-f5b9-468a-9517-32e89dedecc1",
+ "sourceHandle": "default",
+ "target": "LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28",
+ "targetHandle": "default",
+ "id": "reactflow__edge-OPEN_KEITHLEY_24XX-097d2560-f5b9-468a-9517-32e89dedecc1default-LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28default"
+ },
+ {
+ "source": "LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28",
+ "sourceHandle": "default",
+ "target": "IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7",
+ "targetHandle": "default",
+ "id": "reactflow__edge-LINSPACE-db9bbe29-66a0-4122-ad24-e3c00b1fba28default-IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7default"
+ },
+ {
+ "source": "IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7",
+ "sourceHandle": "default",
+ "target": "SCATTER-fee34277-0702-4342-af77-37c9d68701c6",
+ "targetHandle": "default",
+ "id": "reactflow__edge-IV_SWEEP-41060d63-89ff-46f2-914b-944a11d24ed7default-SCATTER-fee34277-0702-4342-af77-37c9d68701c6default"
+ }
+ ],
+ "viewport": {
+ "x": 255.10425070720453,
+ "y": 317.88940714410813,
+ "zoom": 0.5
+ }
+ }
+}
\ No newline at end of file
diff --git a/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/examples/EX1/example.md b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/examples/EX1/example.md
new file mode 100644
index 0000000000..00d085c787
--- /dev/null
+++ b/docs/nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/examples/EX1/example.md
@@ -0,0 +1,25 @@
+---
+title: OPEN_KEITHLEY_24XX
+description: In this example, we demonstrate how to record an I"-"V curve using Flojoy, a Keithley 2400 source meter, and a computer.
+keyword: [Python, Instrument, Keithley 2400 control, Python instrument integration, Measurement and analysis, Python"-"based instrument control, Keithley instrument control, Enhance measurements with Python, Python"-"based measurement techniques, Streamline instrument usage, Accurate data analysis,Python integration with Keithley 2400]
+image: https://raw.githubusercontent.com/flojoy-ai/docs/main/docs/nodes/INSTRUMENTS/KEITHLEY/KEITHLEY2/examples/EX1/output.jpeg
+---
+
+In this example, we demonstrate how to record an I-V curve using Flojoy, a Keithley2400 source meter, and a computer. Fist you need to connect the Keithley2400 sourcemeter to the computer with a serial communication cable. Then, connect your device (Solar cell in this example) to the sourcemeter. After that you can prepare your flojoy app:
+
+The [`LINSPACE`](https://github.com/flojoy-io/nodes/blob/main/GENERATORS/SIMULATIONS/LINSPACE/LINSPACE.py) node defines the voltage range sent to the electronic device. The user defines the voltage range by setting these parameters with Numeric Input:
+
+- LINSPACE START: Define your first Voltage.
+- LINSPACE END: Define your last Voltage.
+- LINSPACE STEP: Define the number of voltages between the first and the last one.
+
+The [`KEITHLEY2400`](https://github.com/flojoy-io/nodes/blob/main/INSTRUMENTS/KEITHLEY/KEITHLEY2400/KEITHLEY2400.py) node will communicate with the source meter by serial communication to send voltages and measure currents from the device.
+
+The connection must first be opened using the [`OPEN_KEITHLEY_24XX`](https://github.com/flojoy-io/nodes/blob/main/INSTRUMENTS/KEITHLEY/KEITHLEY2400/KEITHLEY2400.py) node, which has two communication parameters set by the user after connecting the Keithley2400 to their computer:
+
+- DEVICE: Select the serial device that corresponds to the Keithley2400.
+- BAUDRATE: Define the Baud rate of your communication protocol (the default is 9600, the value has to correspond to the Instrument settings).
+
+The [`LINE`](https://github.com/flojoy-io/nodes/blob/main/VISUALIZERS/PLOTLY/LINE/LINE.py) node will display the I-V curve by plotting the currents received from the device as a function of the voltages transmitted to the device.
+
+When the setup is ready, and the parameters above are well defined, the experiment can be started by turning on the source meter and clicking the PLAY button.
diff --git a/docs/nodes/IO/PROTOCOLS/SERIAL/BASIC/SERIAL_SINGLE_MEASUREMENT/a1-[autogen]/python_code.txt b/docs/nodes/IO/PROTOCOLS/SERIAL/BASIC/SERIAL_SINGLE_MEASUREMENT/a1-[autogen]/python_code.txt
index 7bb19b0d24..0b3456111a 100644
--- a/docs/nodes/IO/PROTOCOLS/SERIAL/BASIC/SERIAL_SINGLE_MEASUREMENT/a1-[autogen]/python_code.txt
+++ b/docs/nodes/IO/PROTOCOLS/SERIAL/BASIC/SERIAL_SINGLE_MEASUREMENT/a1-[autogen]/python_code.txt
@@ -1,4 +1,4 @@
-from flojoy import flojoy, OrderedPair
+from flojoy import SerialDevice, flojoy, OrderedPair
from typing import Optional
import serial
import numpy as np
@@ -6,13 +6,13 @@ import numpy as np
@flojoy(deps={"pyserial": "3.5"})
def SERIAL_SINGLE_MEASUREMENT(
+ device: SerialDevice,
default: Optional[OrderedPair] = None,
- comport: str = "/dev/ttyUSB0",
baudrate: int = 9600,
) -> OrderedPair:
- ser = serial.Serial(comport, timeout=1, baudrate=baudrate)
+ ser = serial.Serial(device.port, timeout=1, baudrate=baudrate)
s = ""
while s == "":
s = ser.readline().decode()
diff --git a/docs/nodes/LOADERS/LOCAL_FILE_SYSTEM/LOCAL_FILE/a1-[autogen]/docstring.txt b/docs/nodes/LOADERS/LOCAL_FILE_SYSTEM/LOCAL_FILE/a1-[autogen]/docstring.txt
index 7634cca412..b4e8a6d8dd 100644
--- a/docs/nodes/LOADERS/LOCAL_FILE_SYSTEM/LOCAL_FILE/a1-[autogen]/docstring.txt
+++ b/docs/nodes/LOADERS/LOCAL_FILE_SYSTEM/LOCAL_FILE/a1-[autogen]/docstring.txt
@@ -3,7 +3,9 @@ The LOCAL_FILE node loads a local file of a different type and converts it to a
Parameters
----------
file_path : str
- Path to the file to be loaded.
+ The path to the file to be loaded. This can be either an absolute path or
+ a path relative to the "nodes" directory.
+
default : Optional[TextBlob]
If this input node is connected, the file name will be taken from
the output of the connected node.
@@ -19,4 +21,5 @@ The LOCAL_FILE node loads a local file of a different type and converts it to a
-------
Image | DataFrame
Image for file_type 'image'.
- DataFrame for file_type 'json', 'csv', 'excel', and 'xml'.
+ Grayscale from file_type 'Grayscale'.
+ DataFrame for file_type 'json', 'csv'.
diff --git a/docs/nodes/LOADERS/LOCAL_FILE_SYSTEM/LOCAL_FILE/a1-[autogen]/python_code.txt b/docs/nodes/LOADERS/LOCAL_FILE_SYSTEM/LOCAL_FILE/a1-[autogen]/python_code.txt
index 6c3e713acc..a7ae3a47c7 100644
--- a/docs/nodes/LOADERS/LOCAL_FILE_SYSTEM/LOCAL_FILE/a1-[autogen]/python_code.txt
+++ b/docs/nodes/LOADERS/LOCAL_FILE_SYSTEM/LOCAL_FILE/a1-[autogen]/python_code.txt
@@ -2,36 +2,37 @@ from flojoy import flojoy, Image, DataFrame, Grayscale, TextBlob
from typing import Literal, Optional
import numpy as np
from PIL import Image as PIL_Image
-from os import path
+import os
import pandas as pd
def get_file_path(file_path: str, default_path: str | None = None):
- f_path = path.abspath(file_path) if file_path != "" else default_path
+ f_path = file_path if file_path != "" else default_path
if not f_path:
raise ValueError(
"The file path of the input file is missing. "
"Please provide a input TextBlob or a provide `file_path` with a value!"
)
+ if not os.path.isabs(f_path):
+ path_to_nodes = __file__[: __file__.rfind("nodes") + 5]
+ return os.path.abspath(os.path.join(path_to_nodes, f_path))
return f_path
@flojoy(
deps={
- "xlrd": "2.0.1",
- "lxml": "4.9.2",
- "openpyxl": "3.0.10",
"scikit-image": "0.21.0",
}
)
def LOCAL_FILE(
- file_path: str = None,
+ file_path: str | None = None,
default: Optional[TextBlob] = None,
- file_type: Literal["Image", "Grayscale", "JSON", "CSV", "Excel", "XML"] = "Image",
-) -> Image | DataFrame:
+ file_type: Literal["Image", "Grayscale", "JSON", "CSV"] = "Image",
+) -> Image | DataFrame | Grayscale:
- default_image_path = path.join(
- path.dirname(path.abspath(__file__)),
+
+ default_image_path = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
"assets",
"astronaut.png",
)
@@ -70,11 +71,12 @@ def LOCAL_FILE(
file_path = get_file_path(file_path)
df = pd.read_json(file_path)
return DataFrame(df=df)
- case "XML":
- file_path = get_file_path(file_path)
- df = pd.read_xml(file_path)
- return DataFrame(df=df)
- case "Excel":
- file_path = get_file_path(file_path)
- df = pd.read_excel(file_path)
- return DataFrame(df=df)
+ # TODO: we might add support for following file types later
+ # case "XML":
+ # file_path = get_file_path(file_path)
+ # df = pd.read_xml(file_path)
+ # return DataFrame(df=df)
+ # case "Excel":
+ # file_path = get_file_path(file_path)
+ # df = pd.read_excel(file_path)
+ # return DataFrame(df=df)
diff --git a/nodeSidebar.json b/nodeSidebar.json
index f5a8cd0321..32a78f070c 100644
--- a/nodeSidebar.json
+++ b/nodeSidebar.json
@@ -195,6 +195,7 @@
],
"I/O > SourceMeters": [
"nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/IV_SWEEP/IV_SWEEP",
+ "nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/OPEN_KEITHLEY_24XX/OPEN_KEITHLEY_24XX",
"nodes/IO/INSTRUMENTS/SOURCEMETERS/KEITHLEY/24XX/BASIC/SET_VOLTAGE/SET_VOLTAGE"
],
"NumPy > Linalg": [