SensorsIot / IOTstack

Docker stack for getting started on IOT on the Raspberry PI
GNU General Public License v3.0
1.42k stars 303 forks source link

Integrating ESPHome with My Existing IOTstack Setup #754

Open goderz opened 4 months ago

goderz commented 4 months ago

Hi IOTstack Team,

I've been using IOTstack on my Raspberry Pi and am planning to add ESPHome to my setup for home automation projects. Before I proceed, I wanted to get some insights to ensure a smooth integration.

Here are my main concerns:

Appreciate any guidance you can provide to help me integrate ESPHome effectively.

Also, I'm quite new to Docker, so I'd appreciate any tips on what to consider when adding more containers in the future.

Thanks, Paweł.

Paraphraser commented 4 months ago

Try the following service definition as your starting point:

  esphome:
    container_name: esphome
    image: ghcr.io/esphome/esphome
    restart: unless-stopped
    environment:
      - TZ=${TZ:-Etc/UTC}
      - USERNAME=${ESPHOME_USERNAME:?eg echo ESPHOME_USERNAME=test >>~/IOTstack/.env}
      - PASSWORD=${ESPHOME_PASSWORD:?eg echo ESPHOME_PASSWORD=ChangeMe >>~/IOTstack/.env}
    network_mode: host
    x-ports:
      - "6052:6052"
    x-privileged: true
    volumes:
      - ./volumes/esphome/config:/config

This is based upon ESPHome documentation with adjustments to conform with the norms for IOTstack.

The significant differences are:

  1. Rather than map /etc/localtime into the container (which, although common, is a bit of a hack), IOTstack passes TZ into the container. You can initialise to your own time-zone by doing this:

    $ echo "TZ=$(cat /etc/timezone)" >>~/IOTstack/.env

    This means a single entry in the .env file passes TZ to all the containers which support TZ (in essence, those that have the tzdata package installed).

  2. Rather than provide known defaults for the username and password, this structure of those environment variables forces you to initialise the values yourself (in keeping with best practice):

    $ echo "ESPHOME_USERNAME=goderz" >>~/IOTstack/.env
    $ echo "ESPHOME_PASSWORD=my-super-secure-password" >>~/IOTstack/.env

    If you don't, you get a long-winded (and badly laid-out) error message telling you to run those commands.

  3. The x-ports clause is inactive (any clause starting with x- is treated as a comment). The reason for including it is to document the fact the ESPhome uses port 6052. This helps avoid allocating that port to another service.

  4. I have disabled the privileged flag (by prepending x-). I am always suspicious about any service definition I find on the web which includes this flag. It is rarely needed. What it does is let the container break containerisation. Most containers run as root so using this flag gives the container (and its authors) access to your entire host.

    In many cases, this flag seems to be used as a lazy way of providing access to /dev, completely ignoring the fact that it also provides unrestricted access to the entire host.

    If a container needs access to specific devices, those should be mapped in, either using a devices: clause (providing access to specific devices) or cgroup rules (providing access to a class of devices). For example:

    devices:
      - "/dev/ttyACM0:/dev/ttyACM0"
    device_cgroup_rules:
      - "c 188:* rw"

    I don't use ESPhome so I don't know what it is doing or how it works, so I can't say whether privileged is appropriate. I'll leave it to you to sort out whether it is warranted.

  5. By convention, IOTstack containers have persistent stores at:

    ~/IOTstack/volumes/«containerName»/«path»

    My proposed service definition conforms with this by mapping:

    volumes:
      - ./volumes/esphome/config:/config

Are there any known compatibility issues with ESPHome in the current IOTstack environment?

None that jumped out at me. The above service definition ran first time without incident.

Best practices to avoid port conflicts when adding the ESPHome container?

The network_mode: host clause means the container binds to the host's ports. On startup, the container writes the following message to its log:

2024-02-17 10:47:45,765 INFO Starting dashboard web server on http://0.0.0.0:6052 and configuration dir /config...

That is what caused me to document port 6052 in the x-ports clause. Port 6052 is not mentioned in any other IOTstack service definition so it is unlikely to cause a conflict.

The container may be binding to other ports. I was able to connect a browser to port 6052. Clicking the button to add a new device produced:

Screenshot 2024-02-17 at 11 20 38

That implies that ESPhome really wants to connect over HTTPS but whether that implies a different port is something I don't know. That's something you'll have to figure out.

The Dockerfile only declares port 6052 but the lack of a declaration doesn't stop a process running inside a container from binding to other ports.

In general, I default to containers running in non-host mode unless there's a good reason to run in host mode. Running in non-host mode means you can use a ports: clause for any external port you like and Network Address Translation takes care of the details. You get a lot more flexibility that way.

One good reason to run in host mode is that the container needs to register to receive multicast traffic or snoop on broadcast traffic. Because non-host mode containers connect to an internal (software-emulated) network, traffic to/from that internal network is routed (meaning broadcast packets aren't transported) and Docker doesn't support forwarding multicast traffic to/from internal networks.

If you know that ESPhome needs broadcast/multicast then so be it. But if your reading about ESPhome suggests that it doesn't actually need those capabilities then you can try inverting the arrangement like this:

    x-network_mode: host
    ports:
      - "6052:6052"

Advice on managing ESPHome configurations within Docker?

No. I assume that configurations get written to the internal directory:

/config

which means they will persist to the external directory:

~/IOTstack/volumes/esphome/config

but that is something you should verify. Assuming that's the way it works then backup routines will capture the configurations.

Any specific security considerations with ESPHome?

Other than my reservations about the wisdom (or otherwise) of the privileged flag, none.

Hope this helps.


If you get it running and can write some documentation for other people to follow then I can help you create a pull request to have this added to IOTstack.

Noschvie commented 3 months ago

@goderz any feedback ?

goderz commented 2 months ago

Hey @Noschvie

Unfortunately, I must point out that I haven't attempted to run ESPHome in the end. I'm doing all of this strictly as a hobby, and I had to focus on something entirely different at the moment. I'll probably return to IoT-related projects later this year. I apologize for the lack of response.

Paraphraser commented 2 months ago

@goderz that's cool by me

@Noschvie I assume you commented because you're interested in this too. If yes, have you tried it? Does it work? Should it become a Pull Request for being added to IOTstack? Any hints for what should be in documentation to help people get started?

Noschvie commented 2 months ago

Hello @Paraphraser Phill sorry for the delay. I'm interested, but not a user of ESPHome. Because of an existing integration for HA I think it's not needed to add it to IOTstack.