Skip to content

Commit 43df47f

Browse files
committed
added new node and simple workflow
- added compilation and upload - added a node to write arduino code - added a simple workflow to write and upload code
1 parent 0552516 commit 43df47f

File tree

6 files changed

+146
-9
lines changed

6 files changed

+146
-9
lines changed

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,33 @@
44

55
### Core Features (Roadmap)
66

7+
<p align="center">
8+
<img src="docs/image1.png" alt="workflow screen">
9+
</p>
10+
11+
712
Here are the initial goals for the project:
813

914
- [x] **Self-contained Installer Node:** Automatically downloads and manages `arduino-cli` locally. No manual setup required from the user, ensuring a smooth "all-in-one" experience.
10-
- [ ] **Dynamic Upload Node:** Visually build logic with nodes, which will then generate, compile, and upload a custom sketch to your connected Arduino board.
15+
- [x] **Dynamic Upload Node:** Visually build logic with nodes, which will then generate, compile, and upload a custom sketch to your connected Arduino board.
1116
- [ ] **Real-time Communication:** Implement a standard sketch and corresponding nodes to send live data (e.g., servo angles, LED colors) from ComfyUI to a running Arduino without re-uploading.
12-
- [ ] **Example Workflows:** Provide simple, functional examples to help users get started quickly.
17+
- [x] **Example Workflows:** Provide simple, functional examples to help users get started quickly.
1318

14-
### Future Vision
19+
### other features
1520

1621
Ideas for the long-term development of the project:
1722

1823
- [ ] **Arduino Library Management:** A node to automatically install required libraries for your sketch using `arduino-cli`.
1924
- [ ] **High-Level Hardware Nodes:** Easy-to-use nodes for common components (servos, sensors, NeoPixel LEDs, etc.) that abstract away the low-level code.
20-
- [ ] **In-Workflow C++ Editor:** A dedicated node to write or paste raw Arduino (C++) code directly within ComfyUI.
25+
- [x] **In-Workflow C++ Editor:** A dedicated node to write or paste raw Arduino (C++) code directly within ComfyUI.
2126
- [ ] **Full Sketch Export:** An option to export the generated C++ code and a list of its dependencies, allowing it to be used outside of ComfyUI.
2227

2328
### Installation
2429

2530
1. Navigate to your `ComfyUI/custom_nodes/` directory.
2631
2. Clone this repository: `git clone https://github.com/Juste-Leo2/ComfyUI-Arduino.git`
27-
3. Restart ComfyUI. The necessary dependencies, including `arduino-cli`, should be installed automatically on the first run.
32+
3. install dependencies: `pip install -r requirements.txt`
33+
4. Restart ComfyUI. The necessary dependencies, including `arduino-cli`, should be installed automatically on the first run.
2834

2935
### Contributing
3036

__init__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
# __init__.py
22

3-
from .nodes import ArduinoTargetNode # <-- NOM MIS À JOUR
3+
from .nodes import ArduinoTargetNode, ArduinoCodeNode, ArduinoCompileUploadNode
44

55
# --- Mappings for ComfyUI ---
66

77
NODE_CLASS_MAPPINGS = {
8-
"ArduinoTarget": ArduinoTargetNode, # <-- NOM MIS À JOUR
8+
"ArduinoTarget": ArduinoTargetNode,
9+
"ArduinoCode": ArduinoCodeNode,
10+
"ArduinoCompileUpload": ArduinoCompileUploadNode,
911
}
1012

1113
NODE_DISPLAY_NAME_MAPPINGS = {
12-
"ArduinoTarget": "Define Arduino Target", # <-- NOM MIS À JOUR
14+
"ArduinoTarget": "Define Arduino Target",
15+
"ArduinoCode": "Arduino Code",
16+
"ArduinoCompileUpload": "Compile & Upload to Arduino",
1317
}
1418

1519
print("...Custom Nodes: ComfyUI-Arduino loaded.")

docs/image1.png

101 KB
Loading

nodes.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
from .src.arduino_installer import setup_arduino_cli
55
from .src.arduino_board_finder import get_available_boards, get_fqbn_by_name
6+
from .src.arduino_actions import compile_and_upload_sketch # <-- NOUVEL IMPORT
67
import serial.tools.list_ports
78

89
def list_physical_ports():
@@ -61,4 +62,67 @@ def define_target(self, board_name, port_str):
6162
return ("ERROR", "ERROR", error)
6263

6364
status_message = f"✅ Target defined: {board_name} ({fqbn}) on {port}"
64-
return (port, fqbn, status_message)
65+
return (port, fqbn, status_message)
66+
67+
# --------------------------------------------------------------------
68+
# -- NODE: ARDUINO CODE INPUT ----------------------------------------
69+
# --------------------------------------------------------------------
70+
class ArduinoCodeNode:
71+
@classmethod
72+
def INPUT_TYPES(s):
73+
default_code = "void setup() {\n // put your setup code here, to run once:\n\n}\n\nvoid loop() {\n // put your main code here, to run repeatedly:\n\n}"
74+
return {
75+
"required": {
76+
"code": ("STRING", {"multiline": True, "default": default_code}),
77+
}
78+
}
79+
80+
RETURN_TYPES = ("STRING",)
81+
RETURN_NAMES = ("code",)
82+
FUNCTION = "get_code"
83+
CATEGORY = "Arduino"
84+
85+
def get_code(self, code):
86+
return (code,)
87+
88+
# --------------------------------------------------------------------
89+
# -- NODE: COMPILE & UPLOAD SKETCH -----------------------------------
90+
# --------------------------------------------------------------------
91+
class ArduinoCompileUploadNode:
92+
@classmethod
93+
def INPUT_TYPES(s):
94+
return {
95+
"required": {
96+
"port": ("STRING", {"forceInput": True}),
97+
"fqbn": ("STRING", {"forceInput": True}),
98+
"code": ("STRING", {"forceInput": True}),
99+
}
100+
}
101+
102+
RETURN_TYPES = ("STRING",)
103+
RETURN_NAMES = ("status",)
104+
FUNCTION = "compile_and_upload"
105+
CATEGORY = "Arduino"
106+
107+
def compile_and_upload(self, port, fqbn, code):
108+
# Step 1: Node-level validation
109+
if SETUP_ERROR is not None:
110+
return (f"❌ ERROR: Setup failed: {SETUP_ERROR}",)
111+
if port == "ERROR" or fqbn == "ERROR":
112+
return ("❌ ERROR: Invalid target. Check 'Define Arduino Target' node.",)
113+
114+
print(f"--- Arduino: Starting compile & upload for {fqbn} on {port} ---")
115+
116+
# Step 2: Call the backend logic function
117+
success, message = compile_and_upload_sketch(
118+
cli_path=ARDUINO_CLI_PATH,
119+
config_path=ARDUINO_CONFIG_PATH,
120+
port=port,
121+
fqbn=fqbn,
122+
code=code
123+
)
124+
125+
print(f"--- Arduino: Process finished. ---")
126+
127+
# Step 3: Return the result from the logic function
128+
return (message,)

src/arduino_actions.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# src/arduino_actions.py
2+
3+
import os
4+
import shutil
5+
import tempfile
6+
from .cli_utils import run_cli_command
7+
8+
def compile_and_upload_sketch(cli_path: str, config_path: str, port: str, fqbn: str, code: str) -> tuple[bool, str]:
9+
"""
10+
Handles the entire process of compiling and uploading an Arduino sketch.
11+
12+
Args:
13+
cli_path: Path to the arduino-cli executable.
14+
config_path: Path to the arduino-cli.yaml config file.
15+
port: The COM port to upload to (e.g., "COM3").
16+
fqbn: The Fully Qualified Board Name (e.g., "arduino:avr:uno").
17+
code: A string containing the Arduino C++ code.
18+
19+
Returns:
20+
A tuple containing:
21+
- bool: True if successful, False otherwise.
22+
- str: A status message detailing the outcome.
23+
"""
24+
# Arduino CLI requires the .ino file to be in a folder with the same name.
25+
# We create a temporary directory for this.
26+
temp_dir = tempfile.mkdtemp()
27+
sketch_name = os.path.basename(temp_dir)
28+
sketch_path = os.path.join(temp_dir, f"{sketch_name}.ino")
29+
30+
try:
31+
# 1. Write the code to the temporary .ino file
32+
with open(sketch_path, 'w', encoding='utf-8') as f:
33+
f.write(code)
34+
print(f" - Temporary sketch created at {sketch_path}")
35+
36+
# 2. Compile the sketch
37+
print(f" - Compiling for board {fqbn}...")
38+
compile_args = ["compile", "--fqbn", fqbn, temp_dir]
39+
success, result = run_cli_command(cli_path, config_path, compile_args)
40+
if not success:
41+
error_msg = f"❌ Compilation failed: {result}"
42+
print(f" - {error_msg}")
43+
return False, error_msg
44+
print(" - ✅ Compilation successful.")
45+
46+
# 3. Upload the sketch
47+
print(f" - Uploading to port {port}...")
48+
upload_args = ["upload", "-p", port, "--fqbn", fqbn, temp_dir]
49+
success, result = run_cli_command(cli_path, config_path, upload_args)
50+
if not success:
51+
error_msg = f"❌ Upload failed: {result}"
52+
print(f" - {error_msg}")
53+
return False, error_msg
54+
55+
status_message = f"✅✅✅ Upload to {fqbn} on {port} successful!"
56+
print(f" - {status_message}")
57+
return True, status_message
58+
59+
finally:
60+
# 4. Clean up the temporary directory, regardless of outcome
61+
print(f" - Cleaning up temporary sketch directory: {temp_dir}")
62+
shutil.rmtree(temp_dir)

workflow/simple_test_arduino.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"id":"01e2f77f-e4dc-45d5-8489-8923142e53bb","revision":0,"last_node_id":8,"last_link_id":8,"nodes":[{"id":6,"type":"ArduinoCompileUpload","pos":[1288.7777099609375,476.75299072265625],"size":[220.41665649414062,66],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"port","name":"port","type":"STRING","link":4},{"localized_name":"fqbn","name":"fqbn","type":"STRING","link":5},{"localized_name":"code","name":"code","type":"STRING","link":6}],"outputs":[{"localized_name":"status","name":"status","type":"STRING","links":[7]}],"properties":{"Node name for S&R":"ArduinoCompileUpload"},"widgets_values":[]},{"id":7,"type":"PreviewAny","pos":[1579.9434814453125,475.4234619140625],"size":[515.86572265625,269.7618713378906],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"source","name":"source","type":"*","link":7}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.52","Node name for S&R":"PreviewAny"},"widgets_values":[]},{"id":5,"type":"ArduinoCode","pos":[813.4561157226562,671.795654296875],"size":[400,200],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"code","name":"code","type":"STRING","widget":{"name":"code"},"link":null}],"outputs":[{"localized_name":"code","name":"code","type":"STRING","links":[6]}],"properties":{"Node name for S&R":"ArduinoCode"},"widgets_values":["void setup() {\n // put your setup code here, to run once:\n pinMode(7, OUTPUT);\n\n}\n\nvoid loop() {\n // put your main code here, to run repeatedly:\n digitalWrite(7, HIGH);\n}"]},{"id":1,"type":"ArduinoTarget","pos":[877.5122680664062,371.6294250488281],"size":[270,122],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"board_name","name":"board_name","type":"COMBO","widget":{"name":"board_name"},"link":null},{"localized_name":"port_str","name":"port_str","type":"COMBO","widget":{"name":"port_str"},"link":null}],"outputs":[{"localized_name":"port","name":"port","type":"STRING","links":[4]},{"localized_name":"fqbn","name":"fqbn","type":"STRING","links":[5]},{"localized_name":"status","name":"status","type":"STRING","links":[]}],"properties":{"Node name for S&R":"ArduinoTarget"},"widgets_values":["Arduino Uno","COM3 - Silicon Labs CP210x USB to UART Bridge (COM3)"]}],"links":[[4,1,0,6,0,"STRING"],[5,1,1,6,1,"STRING"],[6,5,0,6,2,"STRING"],[7,6,0,7,0,"*"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.3310000000000028,"offset":[-581.8514898039264,-169.2931295445007]}},"version":0.4}

0 commit comments

Comments
 (0)