# Docker-based ESP32 Development Environment

In the [previous article,](https://ariesgun.xyz/managing-dev-projects-with-docker-dev-environments) I discussed the benefits of using Docker containers for building and managing development environments. In this post, I would like to describe how I use the Docker Dev Environment to create a development environment for building ESP32 applications. Additionally, it is also possible to flash the application directly to an ESP board from within the container.

Luckily for us, Espressif has provided a Docker image (`espressif/idf`) for building applications and libraries with specific versions of ESP-IDF. It appears that the image is regularly, making it reasonably safe to employ it for our setup.

## Setup

* For this setup, you are using a host system running Windows OS with WSL2 enabled. The WSL2 will be used so that we can access the ESP development board from within the container.
    

* Docker Desktop installed
    
* The IDE used here is VSCode with the **Dev Containers** installed. It lets you use a [Docker container](https://docker.com/) as a full-featured development environment.
    

## Constructing `compose-dev.yaml`

To use the Docker Dev Environment, we need to create the `compose-dev.yaml` file. It is quite simple with a few additions.

```yaml
services:
  build-env:
    image: espressif/idf
    command: sleep infinity
    devices:
      - '/dev:/dev'
    init: true
    volumes:
      - ..:/workspaces
```

I added `devices: '/dev:/dev'` to map `/dev` directory from the WSL2 environment to the Docker container. This is useful for the next step when we want to communicate with the ESP board from inside the container.

Open Docker Desktop and go to Dev Environments. Simply click on the Create button and create the new environment. The container will stay running and you will see the following results.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693081274492/65c11d4f-dc91-4ae2-83e7-323d08a13387.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693081250394/823e79d4-c69b-4295-8398-04bae6c102bb.png align="center")

## Flashing and Monitoring ESP32

The ESP-IDF Programming Guide [page](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html) outlines a method to communicate with the development boards from within the container. The idea is to use the remote serial port protocol (RFC2217). So I tried to follow the method described in the document, but it was not successful for me. Luckily there is another way to achieve this.

An alternative way for accessing the ESP development board from inside the container is using WSL2. By default, WSL2 does not support USB devices. Fortunately, there is a project officially supported by Microsoft that enables WSL2 to be able to access connected USB devices on Windows OS via a USB/IP mechanism. The project is called `usbipd-win`.

### Setting up `usbipd-win`

1. Firstly we need to install `usbipd-win`. We just need to follow the installation instructions described on its Github repository [page](https://github.com/dorssel/usbipd-win). It is pretty straightforward.
    
2. Open the WSL2 terminal and execute `uname -a`. If it reports a kernel version of 5.10.60.1 or later, then you don't need to do anything. Otherwise, follow the instructions on installing USB/IP client tools on WSL2 [here](https://github.com/dorssel/usbipd-win).
    
3. Run Powershell as Administrator and execute the following command.
    
    ```powershell
    ### Powershell
    PS C:\Windows\system32> usbipd wsl list
    BUSID  VID:PID    DEVICE                                                        STATE
    2-1    303a:1001  USB Serial Device (COM3), USB JTAG/serial debug unit          Not attached
    2-2    046d:c534  USB Input Device                                              Not attached
    2-3    0bda:4853  Realtek Bluetooth Adapter                                     Not attached
    3-1    04f2:b758  Integrated Camera, Integrated IR Camera, Camera DFU Device    Not attached
    ```
    
    Find the USB device of your ESP development board connected. In this example, it is assigned BUSID 2-1
    
4. Attach the USB device to WSL2 by running this command.
    
    ```powershell
    ### Powershell
    PS C:\Windows\system32> usbipd wsl attach --busid 2-1
    usbipd: info: Using default WSL distribution 'Ubuntu-22.04'; specify the '--distribution' option to select a different one.
    ```
    
5. Go back to the WSL2 terminal and run `lsusb` to see that the ESP32 development can be accessed from WSL2 now via `/dev/ttyACM0` (or `/dev/ttyUSB0`).
    
    ```bash
    ### WSL2
    > lsusb
    Bus 001 Device 014: ID 303a:1001 Espressif USB JTAG/serial debug unit
    
    > ls -al /dev/tty*
    ...
    crw------- 1 root root 166,  0 Aug 26 17:27 /dev/ttyACM0
    ...
    ```
    
6. Now we need to change the permission so that the device can be accessed by non-root users.
    
    ```bash
    ### WSL2
    > sudo chmod 666 /dev/ttyACM0
    ```
    

If you remember, we added an extra field in the `compose-dev.yaml` file. With this option, we map the `/dev` directory of WSL2 into the Docker container. Hence, it is possible to access your development board from inside the container.

```yaml
...
    devices:
      - '/dev:/dev'
...
```

### Automating `usbipd`

Attaching USB devices using `usbipd` requires manual steps that need to be executed whenever we plug or re-plug our ESP development board. It can be quite annoying over time. Luckily, there is a convenient GUI that can automate all these steps. This project was created by [Andrew Leech](https://gitlab.com/alelec/wsl-usb-gui). You can just download the package from [here](https://gitlab.com/alelec/wsl-usb-gui/-/releases) and install it.

The GUI is quite self-explanatory. You just need to find your ESP development board and click on 'Auto-Attach'. With this feature enabled, your ESP development board will be attached automatically.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693085038991/c4cdbc8b-a603-4384-9a05-da19a0f01d05.png align="center")

### udev

On WSL2, we have to configure the attached USB device so that non-root users can access it. We can use the `chmod` command to configure it manually, but then we have to do it every time the USB device is re-attached. To avoid all the hassles, we can create a `udev` rule.

Create a new file called `99-usbftdi.rules` on `/etc/udev/rules.d/` and add the following information to the file. The `{idVendor}` and `{idProduct}` values can be obtained from `lsusb`

```bash
> lsusb
Bus 001 Device 014: ID 303a:1001 Espressif USB JTAG/serial debug unit

> cat /etc/udev/rules.d/99-usbftdi.rules
SUBSYSTEM=='usb', ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666"

# Then reload udevadm and restart the udev service
> udevadm control --reload
> sudo service udev restart
```

Now, every time the development board is plugged in, it will be automatically attached to your WSL2 environment and can be readily accessed from the container.

## Final Result

Upon the successful creation of the development environment, the container can be opened in VSCode. The VSCode extensions, such as CMake and C++, will also be automatically installed.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693086126894/669b6c3a-9aea-49af-8f32-f23fca24ddf9.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693143611446/d7c9bf25-121e-41f6-a229-86a3f3b034e9.png align="center")

If everything is correctly configured, it is possible to build the application inside the container

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693142933595/47b3b7ff-7f13-4bc2-ba16-38f276be0a93.png align="center")

Since the container can access the USB device via WSL2, we are also able to directly flash the image to the ESP development board.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693143700276/58d76f71-1d12-44a7-a609-6fb563eef995.png align="center")

---

In this article, we discuss creating a Docker container using the Docker Dev Environment for building ESP32 applications and flashing them directly to an ESP board from within the Docker container. This streamlined workflow simplifies the development process and ensures a consistent development environment across different systems.

You can see the full setup on my Github repository.

%[https://github.com/ariesgun/esp32-docker-dev]
