- C 39.7%
- Python 38.3%
- Shell 11.5%
- CMake 10.5%
| .devcontainer | ||
| .vscode | ||
| main | ||
| .clangd | ||
| .gitattributes | ||
| .gitignore | ||
| ArbeitsplanV1.odt | ||
| ArbeitsplanV1.pdf | ||
| CMakeLists.txt | ||
| pytest_hello_world.py | ||
| README.md | ||
| sdkconfig | ||
| sdkconfig.ci | ||
Development Setup
This project is developed with ESP-IDF inside a VS Code dev container. The container brings the complete toolchain, so nothing ESP-IDF-related has to be installed on your machine.
The container cannot access USB devices directly. Flashing and the serial monitor therefore go through a small RFC2217 serial bridge (esp_rfc2217_server) that runs on the host and forwards the board's serial port over the network into the container.
┌──────────── Host ─────────────┐ ┌──────── Dev container ────────┐
│ USB ── esp_rfc2217_server │ ◄────► │ idf.py flash monitor │
│ (port 4000) │ TCP │ (ESPPORT=rfc2217://<ip>:4000) │
└───────────────────────────────┘ └───────────────────────────────┘
1. Hardware
- Waveshare ESP32-S3-A7670E-4G board
- USB-C cable with data lines (charge-only cables are a common cause of "no device found")
2. Prerequisites
2.1 Operating system and software
| Linux | Windows 10/11 | |
|---|---|---|
| Docker | Docker Engine (rootless or rootful) | Docker Desktop with WSL2 backend |
Shell for initializeCommand |
bash (preinstalled) | WSL2 with a Linux distro (provides bash) |
| Git | sudo apt install git |
Git for Windows, or git inside WSL |
| VS Code | .deb from code.visualstudio.com |
Installer from code.visualstudio.com |
| Python (for esptool on host) | preinstalled | python.org installer or winget install Python.Python.3.12 |
WSL2 is required on Windows. The dev container runs bash .devcontainer/write-host-ip.sh on the host before it starts. Without bash on the PATH, the container will not start.
Linux: do not use the Flatpak version of VS Code (e.g. from the Linux Mint Software Manager). It is sandboxed and usually cannot reach the Docker socket. Check with flatpak list | grep -i code.
2.2 VS Code extension
Install the Dev Containers extension (ms-vscode-remote.remote-containers) on the host. All other extensions (ESP-IDF, C/C++, Claude Code) are installed automatically inside the container.
2.3 esptool on the host (for the RFC2217 server)
esp_rfc2217_server is part of esptool and must be installed on the host, not in the container.
Linux
The esptool package from apt (sudo apt install esptool / Software Manager) does not ship the RFC2217 server. Plain pip install is blocked on Ubuntu/Mint ("externally-managed-environment"). Use pipx:
sudo apt remove esptool # only if the apt version is installed
sudo apt install pipx
pipx install esptool
pipx ensurepath # then open a new terminal
Windows
py -m pip install esptool
If esp_rfc2217_server is not found afterwards, the Python Scripts folder is not on the PATH. py -m pip show -f esptool shows where it was installed.
Depending on the esptool version, the command is called
esp_rfc2217_server(v5) oresp_rfc2217_server.py(v4).
2.4 Serial port permissions (Linux)
The RFC2217 server runs as your user and needs access to the board's serial port, which belongs to the dialout group. Check whether you are already a member:
groups | grep -w dialout
If nothing is printed, add yourself and log out and back in:
sudo usermod -aG dialout $USER
2.5 Docker setup (Linux)
Rootless Docker: start the daemon at login
systemctl --user enable --now docker
Encrypted home: move Docker's data directory
Rootless Docker stores images in ~/.local/share/docker by default. Overlayfs does not work on top of ecryptfs, and pulling the ESP-IDF image fails with failed to mount ... overlay ... invalid argument (dmesg shows overlayfs: upper fs missing required features).
Check whether you are affected:
findmnt -T ~/.local/share/docker -o TARGET,FSTYPE # "ecryptfs" = affected
Fix: move Docker's data to the (unencrypted) system partition.
systemctl --user stop docker
sudo mkdir -p /var/lib/docker-rootless-$USER
sudo chown $USER:$USER /var/lib/docker-rootless-$USER
mkdir -p ~/.config/docker
cat > ~/.config/docker/daemon.json <<EOF
{
"data-root": "/var/lib/docker-rootless-$USER"
}
EOF
systemctl --user start docker
docker info | grep "Docker Root Dir" # should show the new path
Optionally remove the old data afterwards: rootlesskit rm -rf ~/.local/share/docker.
Note: images, containers and Docker volumes are then stored unencrypted. The project folder itself stays in your home folder.
2.6 Docker setup (Windows)
Docker Desktop's integration with your WSL distro is not enabled by default. Without it, the docker command inside WSL cannot reach Docker Desktop, and the dev container fails to start with:
failed to connect to the docker API at unix:///var/run/docker.sock
Enable it in Docker Desktop:
- Settings → General: make sure Use the WSL 2 based engine is checked.
- Settings → Resources → WSL Integration: switch on your distro (e.g. Ubuntu).
- Click Apply & restart.
Check in a WSL terminal:
docker version # the "Server" section should show Docker Desktop
If the distro does not appear in the list or docker version still fails, check whether Docker was additionally installed inside WSL via apt. That installation conflicts with Docker Desktop's integration and should be removed:
sudo apt remove docker-ce docker-ce-cli containerd.io
Then run wsl --shutdown in PowerShell, restart Docker Desktop and open a new WSL terminal.
3. First-time setup
3.1 Clone the repository
Linux
git clone https://git.steinbeis.schule/alvesja/RemoteControlledOffgridCamera.git
cd RemoteControlledOffgridCamera
code .
Windows
Clone inside WSL (e.g. into ~/projects in your WSL distro), not onto C:\. Builds on the Windows filesystem are very slow because every file access crosses into the Docker VM.
# in a WSL terminal
mkdir -p ~/projects && cd ~/projects
git clone https://git.steinbeis.schule/alvesja/RemoteControlledOffgridCamera.git
cd RemoteControlledOffgridCamera
code .
3.2 Open the project in the container
- In VS Code press F1 and run Dev Containers: Reopen in Container.
- The first start downloads the ESP-IDF image (several GB) and installs the VS Code server and extensions. This takes a few minutes; later starts are fast.
- Open a terminal in VS Code (Terminal → New Terminal). It runs inside the container.
Check that everything is in place:
idf.py --version
echo $ESPPORT # should show rfc2217://<your host IP>:4000?ign_set_control
3.3 Useful VS Code commands
| Command (F1) | When |
|---|---|
| Dev Containers: Reopen in Container | Open the project in the container |
| Dev Containers: Rebuild Container | After changes to .devcontainer/ |
| Dev Containers: Reopen Folder Locally | Leave the container |
| Dev Containers: Show Container Log | Container fails to start |
4. Build and flash
4.1 Find the board's serial port (host)
The board exposes two USB devices: the ESP32-S3 (via a CH343 USB-UART chip) and the A7670E LTE modem. Make sure to use the ESP32-S3.
Linux
ls -l /dev/serial/by-id/
usb-1a86_USB_Single_Serial_...→ ESP32-S3 (usually/dev/ttyACM0)usb-SIMCom_Wireless_Solution_...→ LTE modem (/dev/ttyUSB0–3), not the ESP32
Windows
Device Manager → Ports (COM & LPT) → the CH343 / "USB-SERIAL" entry, e.g. COM5.
4.2 Start the RFC2217 server (host)
Run in a normal terminal on the host and leave it running:
# Linux (by-id path stays valid even if ttyACM numbering changes)
esp_rfc2217_server -v -p 4000 /dev/serial/by-id/usb-1a86_USB_Single_Serial_*-if00
# Windows
esp_rfc2217_server -v -p 4000 COM5
4.3 Build and flash (container terminal)
idf.py set-target esp32s3 # only once after cloning / after a fullclean
idf.py build
idf.py flash monitor
Exit the monitor with Ctrl+].
Do not pass -p to idf.py. The port is set automatically via the ESPPORT environment variable, and idf.py refuses to run if -p and ESPPORT differ.
Only the terminal commands work for flashing and monitoring. The flash/monitor buttons of the ESP-IDF extension do not use
ESPPORTand currently fail in this setup.
5. Caveats and troubleshooting
The RFC2217 server accepts only one client at a time
If a monitor is still open in another terminal, new connections are queued and esptool fails with:
Remote does not seem to support RFC2217 or BINARY mode
Close all other monitor terminals (or run pkill -f esp_idf_monitor; pkill -f esptool in the container), restart the server, and try again. On Linux, ss -tnp | grep 4000 shows open connections.
Restart the server after standby or replugging the board
The server keeps the serial device open and cannot recover when the USB device disappears. After standby, replugging, or a hanging server: stop it with Ctrl+C and start it again.
Network changes
The host IP is detected when the container opens (.devcontainer/write-host-ip.sh writes it to .devcontainer/.host-ip). After switching networks, either reopen the container or run on the host:
bash .devcontainer/write-host-ip.sh
and open a new terminal in the container. Without any network connection there is no host IP, and flashing via the bridge does not work. Any network (even a phone hotspot) is enough.
Why not host.docker.internal on Linux?
With rootless Docker, host.docker.internal points to the user-space network stack, not the real host ([Errno 113] No route to host). The script therefore uses the host's real IPv4 address on Linux and host.docker.internal only on Windows/macOS, where Docker Desktop provides it.
The server is reachable from the local network
esp_rfc2217_server listens on all network interfaces. While it runs, other devices on the same network can connect to the board's serial port. Stop it when you are not flashing, especially on shared networks.