feat: add Wokwi CLI for visual breadboard simulation
- Install wokwi-cli binary from GitHub releases - Generate wokwi.toml and board-specific diagram.json in arduino-new with a button + LED breadboard layout for each supported board - Add <leader>aw keybinding in nvim to run Wokwi simulation - Diagram templates for: uno, mega, nano, esp32, esp32s3 (+ default) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -105,7 +105,8 @@ echo " arduino-new my-project uno # scaffold a project"
|
||||
echo " adev # launch Arduino workspace"
|
||||
echo " <leader>av # compile in Neovim"
|
||||
echo " <leader>au # upload in Neovim"
|
||||
echo " arduino-sim build/fw.elf # simulate with Renode"
|
||||
echo " wokwi-cli . # simulate with Wokwi (visual)"
|
||||
echo " arduino-sim build/fw.elf # simulate with Renode (GDB)"
|
||||
echo " <leader>ds # attach debugger to Renode"
|
||||
echo " theme # switch colorscheme"
|
||||
echo ""
|
||||
|
||||
@@ -243,6 +243,7 @@ map("n", "<leader>av", "<cmd>ArduinoVerify<cr>", { desc = "Arduino Verify (compi
|
||||
map("n", "<leader>au", "<cmd>ArduinoUpload<cr>", { desc = "Arduino Upload" })
|
||||
map("n", "<leader>as", "<cmd>ArduinoSerial<cr>", { desc = "Arduino Serial Monitor" })
|
||||
map("n", "<leader>ai", "<cmd>ArduinoInfo<cr>", { desc = "Arduino Board Info" })
|
||||
map("n", "<leader>aw", "<cmd>!wokwi-cli .<cr>", { desc = "Arduino Wokwi Simulate" })
|
||||
|
||||
-- Debug (DAP)
|
||||
map("n", "<leader>ds", function() require("dap").continue() end, { desc = "Debug Start/Continue" })
|
||||
|
||||
@@ -102,3 +102,16 @@ SIMSCRIPT
|
||||
chmod +x ~/.local/bin/arduino-sim
|
||||
|
||||
info "Renode simulation helper created (arduino-sim)"
|
||||
|
||||
# ── Wokwi CLI (visual breadboard simulation) ────────────────────
|
||||
if ! command -v wokwi-cli &>/dev/null; then
|
||||
info "Installing Wokwi CLI..."
|
||||
WOKWI_VERSION=$(curl -ks "https://api.github.com/repos/wokwi/wokwi-cli/releases/latest" | jq -r '.tag_name' | sed 's/^v//')
|
||||
curl -ksSLo /tmp/wokwi-cli.tar.gz "https://github.com/wokwi/wokwi-cli/releases/download/v${WOKWI_VERSION}/wokwi-cli-linuxstatic-x64.tar.gz"
|
||||
tar xzf /tmp/wokwi-cli.tar.gz -C /tmp wokwi-cli
|
||||
sudo install -m 755 /tmp/wokwi-cli /usr/local/bin/wokwi-cli
|
||||
rm -f /tmp/wokwi-cli /tmp/wokwi-cli.tar.gz
|
||||
else
|
||||
info "Wokwi CLI already installed"
|
||||
fi
|
||||
info "Wokwi CLI installed (set WOKWI_CLI_TOKEN to enable — get one at https://wokwi.com/dashboard/ci)"
|
||||
|
||||
162
lib/scaffold.sh
162
lib/scaffold.sh
@@ -67,9 +67,38 @@ build/
|
||||
*.bin
|
||||
EOF
|
||||
|
||||
# ── Wokwi simulation config ─────────────────────────────────────
|
||||
# Determine firmware path format based on board family
|
||||
case "$BOARD" in
|
||||
esp32|esp32s3|esp8266)
|
||||
WOKWI_FW="build/$PROJECT.ino.merged.bin"
|
||||
;;
|
||||
*)
|
||||
WOKWI_FW="build/$PROJECT.ino.hex"
|
||||
;;
|
||||
esac
|
||||
|
||||
cat > wokwi.toml <<EOF
|
||||
[wokwi]
|
||||
version = 1
|
||||
firmware = "$WOKWI_FW"
|
||||
elf = "build/$PROJECT.ino.elf"
|
||||
EOF
|
||||
|
||||
# Board-specific diagram with button + LED on breadboard
|
||||
DIAGRAM_TEMPLATE="$TEMPLATE_DIR/diagram-$BOARD.json"
|
||||
if [[ -f "$DIAGRAM_TEMPLATE" ]]; then
|
||||
cp "$DIAGRAM_TEMPLATE" diagram.json
|
||||
else
|
||||
cp "$TEMPLATE_DIR/diagram-default.json" diagram.json
|
||||
fi
|
||||
|
||||
git init -q
|
||||
echo "✓ Created '$PROJECT' for $BOARD ($FQBN)"
|
||||
echo " cd $PROJECT && nvim $PROJECT.ino"
|
||||
echo ""
|
||||
echo " Simulate: arduino-cli compile --fqbn $FQBN --output-dir build ."
|
||||
echo " wokwi-cli ."
|
||||
SCAFFOLD
|
||||
chmod +x ~/.local/bin/arduino-new
|
||||
|
||||
@@ -135,6 +164,139 @@ void loop() {
|
||||
delay(1000);
|
||||
}
|
||||
INO
|
||||
# ── Wokwi diagram templates ──────────────────────────────────────
|
||||
cat >~/.config/archduino/templates/diagram-default.json <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"author": "Archduino",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{ "type": "wokwi-arduino-uno", "id": "mcu", "top": 0, "left": 0 },
|
||||
{ "type": "wokwi-breadboard-half", "id": "bb1", "top": 200, "left": -80 },
|
||||
{ "type": "wokwi-led", "id": "led1", "top": 110, "left": 50, "attrs": { "color": "green" } },
|
||||
{ "type": "wokwi-resistor", "id": "r1", "top": 150, "left": 30, "attrs": { "value": "220" } },
|
||||
{ "type": "wokwi-pushbutton", "id": "btn1", "top": 110, "left": 150, "attrs": { "color": "blue" } }
|
||||
],
|
||||
"connections": [
|
||||
["mcu:2", "led1:A", "green", []],
|
||||
["led1:C", "r1:1", "black", []],
|
||||
["r1:2", "mcu:GND.1", "black", []],
|
||||
["mcu:4", "btn1:1.l", "blue", []],
|
||||
["btn1:2.l", "mcu:GND.2", "black", []]
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
cat >~/.config/archduino/templates/diagram-esp32.json <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"author": "Archduino",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{ "type": "board-esp32-devkit-c-v4", "id": "esp", "top": 0, "left": 0 },
|
||||
{ "type": "wokwi-breadboard-half", "id": "bb1", "top": 200, "left": -80 },
|
||||
{ "type": "wokwi-led", "id": "led1", "top": 110, "left": 50, "attrs": { "color": "green" } },
|
||||
{ "type": "wokwi-resistor", "id": "r1", "top": 150, "left": 30, "attrs": { "value": "220" } },
|
||||
{ "type": "wokwi-pushbutton", "id": "btn1", "top": 110, "left": 150, "attrs": { "color": "blue" } }
|
||||
],
|
||||
"connections": [
|
||||
["esp:2", "led1:A", "green", []],
|
||||
["led1:C", "r1:1", "black", []],
|
||||
["r1:2", "esp:GND.1", "black", []],
|
||||
["esp:4", "btn1:1.l", "blue", []],
|
||||
["btn1:2.l", "esp:GND.2", "black", []]
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
cat >~/.config/archduino/templates/diagram-esp32s3.json <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"author": "Archduino",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{ "type": "board-esp32-s3-devkitc-1", "id": "esp", "top": 0, "left": 0 },
|
||||
{ "type": "wokwi-breadboard-half", "id": "bb1", "top": 200, "left": -80 },
|
||||
{ "type": "wokwi-led", "id": "led1", "top": 110, "left": 50, "attrs": { "color": "green" } },
|
||||
{ "type": "wokwi-resistor", "id": "r1", "top": 150, "left": 30, "attrs": { "value": "220" } },
|
||||
{ "type": "wokwi-pushbutton", "id": "btn1", "top": 110, "left": 150, "attrs": { "color": "blue" } }
|
||||
],
|
||||
"connections": [
|
||||
["esp:2", "led1:A", "green", []],
|
||||
["led1:C", "r1:1", "black", []],
|
||||
["r1:2", "esp:GND.1", "black", []],
|
||||
["esp:4", "btn1:1.l", "blue", []],
|
||||
["btn1:2.l", "esp:GND.2", "black", []]
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
cat >~/.config/archduino/templates/diagram-uno.json <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"author": "Archduino",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{ "type": "wokwi-arduino-uno", "id": "mcu", "top": 0, "left": 0 },
|
||||
{ "type": "wokwi-breadboard-half", "id": "bb1", "top": 200, "left": -80 },
|
||||
{ "type": "wokwi-led", "id": "led1", "top": 110, "left": 50, "attrs": { "color": "green" } },
|
||||
{ "type": "wokwi-resistor", "id": "r1", "top": 150, "left": 30, "attrs": { "value": "220" } },
|
||||
{ "type": "wokwi-pushbutton", "id": "btn1", "top": 110, "left": 150, "attrs": { "color": "blue" } }
|
||||
],
|
||||
"connections": [
|
||||
["mcu:2", "led1:A", "green", []],
|
||||
["led1:C", "r1:1", "black", []],
|
||||
["r1:2", "mcu:GND.1", "black", []],
|
||||
["mcu:4", "btn1:1.l", "blue", []],
|
||||
["btn1:2.l", "mcu:GND.2", "black", []]
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
cat >~/.config/archduino/templates/diagram-mega.json <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"author": "Archduino",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{ "type": "wokwi-arduino-mega", "id": "mcu", "top": 0, "left": 0 },
|
||||
{ "type": "wokwi-breadboard-half", "id": "bb1", "top": 200, "left": -80 },
|
||||
{ "type": "wokwi-led", "id": "led1", "top": 110, "left": 50, "attrs": { "color": "green" } },
|
||||
{ "type": "wokwi-resistor", "id": "r1", "top": 150, "left": 30, "attrs": { "value": "220" } },
|
||||
{ "type": "wokwi-pushbutton", "id": "btn1", "top": 110, "left": 150, "attrs": { "color": "blue" } }
|
||||
],
|
||||
"connections": [
|
||||
["mcu:2", "led1:A", "green", []],
|
||||
["led1:C", "r1:1", "black", []],
|
||||
["r1:2", "mcu:GND.1", "black", []],
|
||||
["mcu:4", "btn1:1.l", "blue", []],
|
||||
["btn1:2.l", "mcu:GND.2", "black", []]
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
cat >~/.config/archduino/templates/diagram-nano.json <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"author": "Archduino",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{ "type": "wokwi-arduino-nano", "id": "mcu", "top": 0, "left": 0 },
|
||||
{ "type": "wokwi-breadboard-half", "id": "bb1", "top": 200, "left": -80 },
|
||||
{ "type": "wokwi-led", "id": "led1", "top": 110, "left": 50, "attrs": { "color": "green" } },
|
||||
{ "type": "wokwi-resistor", "id": "r1", "top": 150, "left": 30, "attrs": { "value": "220" } },
|
||||
{ "type": "wokwi-pushbutton", "id": "btn1", "top": 110, "left": 150, "attrs": { "color": "blue" } }
|
||||
],
|
||||
"connections": [
|
||||
["mcu:D2", "led1:A", "green", []],
|
||||
["led1:C", "r1:1", "black", []],
|
||||
["r1:2", "mcu:GND.1", "black", []],
|
||||
["mcu:D4", "btn1:1.l", "blue", []],
|
||||
["btn1:2.l", "mcu:GND.2", "black", []]
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
# ── Install theme files + theme switcher ─────────────────────────
|
||||
mkdir -p ~/.config/archduino/themes
|
||||
cp "$SCRIPT_DIR/lib/themes/"*.sh ~/.config/archduino/themes/
|
||||
|
||||
Reference in New Issue
Block a user