A streamlined Arduino development environment using arduino-cli, Neovim, and tmux. Features LSP support with clangd, automatic port detection, format-on-save, and VS Code compatibility.
./arduino-dev.sh ProjectNameOpens a tmux session with:
- Left pane (70%): Neovim editing your
.inofile - Right pane (30%): Shell for running commands
✅ Auto port detection - Works with any USB port
✅ LSP support - clangd provides autocomplete, go-to-definition, diagnostics
✅ Format on save - Both Neovim and VS Code
✅ Auto-logging - Serial output saves to logs/ProjectName-timestamp.log
✅ VS Code compatible - Same projects work in both editors
✅ tmux integration - Persistent sessions with easy navigation
- Neovim with LSP support
- tmux
- clangd (for LSP)
- arduino-cli (installation guide)
- Clone this repository
- Install Arduino core for your board:
arduino-cli core update-index arduino-cli core install arduino:avr # for AVR boards - Add shell aliases to your
.zshrcor.bashrc:# Arduino CLI setup alias arduino-cli='/Applications/Arduino\ IDE.app/Contents/Resources/app/lib/backend/resources/arduino-cli --config-file ~/.arduinoIDE/arduino-cli.yaml' alias arduino-compile='arduino-cli compile --fqbn arduino:avr:uno' alias arduino-boards='arduino-cli board list' # Auto-detect port helper _arduino_port() { arduino-cli board list | grep 'arduino:avr:uno' | awk '{print $1}' } # Upload with auto-detected port arduino-upload() { local port=$(_arduino_port) if [ -z "$port" ]; then echo "Error: No Arduino Uno found. Please connect your board." return 1 fi arduino-cli upload -p "$port" --fqbn arduino:avr:uno "${1:-.}" } # Monitor with auto-detected port arduino-monitor() { local port=$(_arduino_port) if [ -z "$port" ]; then echo "Error: No Arduino Uno found. Please connect your board." return 1 fi arduino-cli monitor -p "$port" "$@" } # Launch tmux+Neovim session alias arduino='~/Documents/Arduino/arduino-dev.sh' # Short commands for tmux pane ac() { arduino-compile "${1:-.}"; } au() { arduino-upload "${1:-.}"; } af() { arduino-compile "${1:-.}" && arduino-upload "${1:-.}"; } am() { local baud="${1:-9600}" local port=$(_arduino_port) if [ -z "$port" ]; then echo "Error: No Arduino Uno found. Please connect your board." return 1 fi local project=$(basename "$PWD") local logfile="$HOME/Documents/Arduino/logs/${project}-$(date +%Y%m%d-%H%M%S).log" echo "Logging to: $logfile (Port: $port, Baud: $baud)" arduino-cli monitor -p "$port" --config baudrate="$baud" | tee "$logfile" } ab() { arduino-boards; }
- Reload shell:
source ~/.zshrc
./new-arduino-project.sh MyProjectThis creates:
- Project folder with template
.inofile compile_commands.jsonfor clangd LSP.clang-formatfor code formatting.vscode/config for VS Code compatibility
arduino MyProjectIn right pane:
ac # Compile
au # Upload (auto-detects port)
af # Flash (compile + upload)
am # Monitor at 9600 baud with logging
am 115200 # Monitor at 115200 baud
ab # List connected boardsNavigation:
Ctrl-h- Switch to left pane (editor)Ctrl-l- Switch to right pane (terminal)Ctrl-b d- Detach from session
code arduino-projects.code-workspaceTasks (auto-detect port):
Cmd+Shift+B- Compile- Run Task → "Arduino: Upload"
- Run Task → "Arduino: Serial Monitor"
# Compile
arduino-compile ~/Documents/Arduino/MyProject
# Upload (auto-detects any USB port)
arduino-upload ~/Documents/Arduino/MyProject
# Monitor serial output
arduino-monitor --config baudrate=115200
# Check connected boards
arduino-boardsMyProject/
├── MyProject.ino # Arduino sketch
├── compile_commands.json # clangd compilation database
├── .clang-format # Code formatting rules
└── .vscode/
├── tasks.json # Build/upload/monitor tasks
├── c_cpp_properties.json # IntelliSense configuration
└── settings.json # Editor settings
Update the FQBN in:
compile_commands.json.vscode-template/tasks.json- Shell aliases (
_arduino_portfunction)
Example FQBNs:
- Arduino Uno:
arduino:avr:uno - Arduino Mega:
arduino:avr:mega - ESP32:
esp32:esp32:esp32
All upload and monitor commands automatically detect the port using:
arduino-cli board list | grep 'arduino:avr:uno' | awk '{print $1}'This works with any USB port on your computer. No hardcoded ports!
Each project has a .clang-format file:
- Based on Google style
- 2-space indentation
- 100 character line limit
- Format-on-save enabled in both Neovim and VS Code
In Neovim (with clangd):
gd- Go to definitiongr- Find referencesK- Hover documentation<leader>rn- Rename symbol<leader>ca- Code actions- Auto-format on save
In VS Code:
- Full IntelliSense support
- Auto-completion
- Error checking
- Format on save
arduino-dev.sh- Tmux session launchernew-arduino-project.sh- Project creation script.vscode-template/- Template configuration for new projects.clang-format- Formatting rules templatelogs/- Serial monitor output logs
arduino Project1 # Session: arduino-Project1
arduino Project2 # Session: arduino-Project2
# Switch between sessions
tmux attach -t arduino-Project1
tmux attach -t arduino-Project2tmux ls # List sessions
tmux attach -t arduino-Project # Reattach
tmux kill-session -t arduino-Project # Kill sessionab # or arduino-boardsShows all connected Arduino boards with their ports.
am 115200 # In tmux pane
# or
arduino-monitor --config baudrate=115200Board not detected:
ab # Check if board appearsTry different USB ports, unplug/replug board.
Upload fails:
- Close serial monitor (can't upload while monitoring)
- Check board is connected:
ab
LSP errors in Neovim:
- Verify
compile_commands.jsonexists - Restart LSP:
:LspRestart - Check log:
~/.local/state/nvim/lsp.log
Format not working:
- Verify
.clang-formatexists in project - Neovim:
:lua vim.lsp.buf.format() - VS Code: Should format automatically on save
MIT
Contributions welcome! Please open an issue or pull request.