esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
412 stars 26 forks source link

WireGuard Support for ESP32 #1444

Closed davey closed 1 year ago

davey commented 2 years ago

Describe the problem you have/What new integration you would like

Please help me adding support for WireGuard to ESPHome on ESP32 boards. WireGuard is an extremely simple yet fast and modern VP.

There already seems to be an Arduino library in Platformio for the ESP32.

Please describe your use case for this integration and alternatives you've tried:

I need to have a bidirectional, secure channel between multiple ESPHome/ESP32s at multiple locations and some remote backend server. From these backend servers I want to be able to push e.g. OTA updates centrally to many different NATed locations (where a site2site VPN is not an option). Also I'd like to reach all those different locations from one central HomeAssistant instance. On the ESP side, only traffic to a specific remote subnet (the backend) needs be routed through Wireguard, all remaining network traffic should use the default gateway.

AFAIK there are no VPN alternatives available for ESPhome yet.

Additional context

Basically this is all about being able to directly reach (on IP level) multiple ESPHome boards at different locations/networks behind their NAT routers from some central place / VPN server / backend.

my-bam commented 1 year ago
wireguard:
  address: 10.0.0.1
  private_key: private_key=
  peer_key: public_key=
  peer_endpoint: wg.server.example

Hi. I get an error: src/esphome/components/wireguard/wireguard.cpp:4:10: fatal error: arpa/inet.h: No such file or directory 4 | #include <arpa/inet.h> | ^~~~~~~~~~~~~ compilation terminated. How do I fix it?

What is you config? ESP32 or ESP8266 or .. ?

ESP8266 (board: d1_mini)

esphome:
  name: wireguard-ext-component
external_components:
  - source: github://pr#4256
    components: [ wireguard ]  

esp8266:
  board: d1_mini

# Enable logging
logger:

ota:
  password: "72b5472823f0b6dbd3a2f56002d6c920"

wifi:
  ssid: "..."
  password: "..."
  use_address: ... 

wireguard:
  address: 10.0.0.1
  private_key: private_key=
  peer_key: public_key=
  peer_endpoint: wg.server.example
time:
  - platform: sntp
lhoracek commented 1 year ago

@my-bam Unfortunately, this is for ESP32 only for now.

timsmithlx commented 1 year ago

So ihave managed to get a wireguard link, i can see the ESPHOME Device in integrations and turn on and off a switch remotely

What i cant get is the ESPHOME dashboard to show the device as online or be able to update "wirelessly"

Followed Carlos method... any tips?

originalbase commented 1 year ago

OK, got it to work with Home Assistant & OTA! 😄

We were missing an IP route from the Home Assistant network to the Wireguard network (i.e. packets sent from HASS to the ESPHome node IP were being forwarded to the router, which dropped them). So neither HASS nor OTA could reach the nodes. I've arranged these instructions to make it work:

1. Set up the official [Wireguard addon](https://github.com/hassio-addons/addon-wireguard) with the standard configuration, verify you can connect to HASS from your phone on data.

2. Add the following to your Home Assistant's configuration.yaml. It creates a "command" sensor to periodically fetch the Wireguard addon's internal IP, and also configure the correct IP route.
sensor:
  - platform: command_line
    name: Wireguard addon internal IP # Creates the IP route to support ESPHome devices on Wireguard
    command: host_result=$(host a0d7b954-wireguard); addon_ip=${host_result##* }; ip route replace 172.27.66.0/24 via $addon_ip; echo $addon_ip
3. Restart HASS, the new text sensor will take a couple minutes to settle into an IP like 172.30.33.2.

4. Then note: To add the ESPHome nodes to Home Assistant you need to do it manually by going to `Config->Integrations->Add->ESPHome` and typing the node's specific wireguard IP. Make sure that you have the `api:` line in the yaml for each node. And for the ESPHome dashboard, remember to enable `status_use_ping` so the nodes are properly detected.

A bit tacky but at least we know it can work! Thanks @davey, @mrkeuz and @ciniml for making this possible! 🎉 Finally we can properly have remote ESPHome nodes :D

I created an automation that is triggered by HA start and WG addon start. It fires a 'shell_command', which does exactly what your command line sensor does.

And it worked brilliantly for a while (HassOS on RPi 4). A remote microcontroller connected though a wireguard tunnel and completely servicable via OTA... amazing.

Sadly, setting a route - as mentioned above - now throws an error: ip: RTNETLINK answers: Operation not permitted

Presumably, a recent update rendered this method useless.

Does somebody else face the same problem?

Is the issue related to docker capabilities (NET_ADMIN)? Is there another simple and persistent solution to make wireguard clients accessible for home assistant?

I don't see the woods for all the trees. Help me find the elephant in the room.

vuzdorf commented 1 year ago

Wireguard works on esp32 thanks to @lhoracek! Home Assistant can show sensor data after it was manually added, BUT in my case OTA isn't working, and I don't know what to do. As I'm running HA in VirtualBox from default image - it's very restricted on what can be done. After connecting device via WG, ESPhome and the device are in different subnets, as it's impossible to send mDNS through the subnet barrier - ESPHome can not resolve device's IP by name. Modifying /etc/hosts - doesn't work, it is possible to ping and traceroute WG device by IP, but even nslookup shows nothing. Installing DNSmasq plugin and configuring hosts there - doesn't work - after adding DNSmasq to resolv.conf - nslookup shows the device, but ESPHome still can't resolve the IP from name. Changing address to IP in /config/esphome/.esphome/[devicename].yaml.json - only makes device online in ESPHome dashboard for a while - an attempt to flash the device seems overwriting this file. What else can be done? Is there any possibility to enforce ESPHome use wireguard IP instead of devicename.local hostname?

lhoracek commented 1 year ago

One workaround should be to use use_address in you wifi config to tell esphome where to look for you device, otherwise it tries mDns and that is most likely no-go with VPN configs.

originalbase commented 1 year ago

@lhoracek Providing the ip of the wg client (and using ping for discovery) is part of the solution. The other part is routing the traffic from Home Assistant to the wireguard container.

A few days ago the shell command shown above by @CarlosGS was executable (manually via termimal (addon) or automatically via sensor or shell_command triggered by an automation) did the trick.

Initially everything worked fine. Trying to set a route now the same way throws an error (ip: RTNETLINK answers: Operation not permitted).

I am not able to identify the recent change, that causes this new restriction.

lhoracek commented 1 year ago

Yep that is a different issue then. I have my local network routed s it can reach the VPN hosts as well. Using the Mikrotik Wireguard support in RouterOS since version 7. Having it running side-by-side in containers it requires you to setup networking in the container host correctly that depending on you running HA in host network mode or not. In my case the Home Assistant is running very far (on premise - at home) from Wireguard host (in cloud VPS)

originalbase commented 1 year ago

I use Home Assistant OS and therefore I'm not able to modify the docker network settings without corrupting the concept of a self organising system (definitely hacky, potentially tacky).

I my opinion it's worth to spend a bit of time to investigate for the tiny missing link, that causes the perfectly integrated solution to fail recently.

Using a dedicated vpn server and the routing capabilities on the local gateway is a proper solution but lacks the (energy) efficiency and might be oversized for most of the szenarios (here: a handful of microcontrollers).

Another idea is, to implement a respective configuration setting / a routing table on this addon (or addons and physical interfaces in general).

Before considering all of that and intended not to blur the view on my specific issue with more warm air:

Can anyone identify the recent change that is responsible for the lack of permission to set a route in the Home Assistant container?

@CarlosGS Does the sensor still work for you?

CarlosGS commented 1 year ago

Yes, the sensor in https://github.com/esphome/feature-requests/issues/1444#issuecomment-974915276 still works for me. Using Home Assistant Operating System on both a Raspberry 4 and also on a VirtualBox instance. Sorry not sure of what could be happening in your installation :S

originalbase commented 1 year ago

Fine, back to the drawing board. Thanks for the immediate replys.

vuzdorf commented 1 year ago

Set up a supervised version of HA on a virtualboxed debian, configured Wireguard on OS level (not plugin), now getting an unpredictable number of invalid handshakes before connection is finally established: image What it could be? Connecting to the same wg by a phone works perfect from the first shot.

vuzdorf commented 1 year ago

One workaround should be to use use_address in you wifi config to tell esphome where to look for you device, otherwise it tries mDns and that is most likely no-go with VPN configs.

YEAH!!! It works, finally! @lhoracek Thank You!

Tested setup:

Wg Plugin config:

 peers:
  - addresses:
      - 172.27.66.2/32
    allowed_ips: []
    client_allowed_ips: []
    name: esp
    public_key: _device_public_key=_
server:
  addresses:
    - 172.27.66.1
  host: _your_domain.com_
  peers.allowed_ips:
    - 0.0.0.0/0

ESPHome config - Use ping for status - enabled yaml:

esphome:
  name: _wgtest100500_
external_components:
  - source: github://pr#4256
    components: [ wireguard ]

esp32:
  board: esp32dev
  framework:
    type: arduino

wireguard:
  address: 172.27.66.2
  private_key: _device_private_key=_
  peer_key: _server_public_key=_
  peer_endpoint: _your_domain.com_

time:
  - platform: sntp
    id: mytime

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  use_address: 172.27.66.2

@CarlosGS sensor also need to be configured! I don't understand how this magic works, but executing "ip route replace..." from terminal returns - ip: RTNETLINK answers: Operation not permitted, but being configured as a sensor - creates a route to WG device. configuration.yaml:

sensor:
  - platform: command_line
    name: Wireguard addon internal IP # Creates the IP route to support ESPHome devices on Wireguard
    command: host_result=$(host _wireguard_host_); addon_ip=${host_result##* }; ip route replace 172.27.66.0/24 via $addon_ip; echo $addon_ip

Firewall rule & Port forwarding configured to HA virtual host on mikrotik for port 51820 Sensors are available, Wireless logs, online status and OTA available in ESPHome!

mrivero33 commented 1 year ago

What about ESP8266, it´s posible??

ZenonBombalina commented 1 year ago

Great job Gents. Maybe you will be able to help: After configuration esp was started correctly, handshake was successful, everything was working as charm, however (without any further flashing, or changing anything) after some time I start to get in logs message like that:

D][sntp:078]: Synchronized time: 2023-03-08 21:01:23
[D][wireguard:038]: Starting...
[D][wireguard:040]: Initializing WG interface...
E (24824) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (24824) task_wdt:  - loopTask (CPU 1)
E (24824) task_wdt: Tasks currently running:
E (24824) task_wdt: CPU 0: IDLE
E (24824) task_wdt: CPU 1: IDLE
E (24824) task_wdt: Aborting.

abort() was called at PC 0x400f68dc on core 0

Backtrace:0x40083771:0x3ffbea3c |<-CORRUPTED

ELF file SHA256: 0000000000000000

Rebooting...

Any ideas what I can adjust? Many thanks in advance.

distancerunner commented 1 year ago

Hello everyone, first of all, thanks a lot for your work, it's awesome! I have an addition to the solution from @CarlosGS . Details are in this issue (ciniml/WireGuard-ESP32-Arduino#13). The correct configuration should be like this to avoid reboots every ~10 min:

time:
  - platform: sntp
    on_time_sync:
        then:
        - lambda: |
            static const char* TAG = "wireguard";
            ESP_LOGD(TAG, "Starting...");
            if( !wg.is_initialized() ) {
                        ESP_LOGD(TAG, "Initializing WG interface...");
                        if( !wg.begin(
                                local_ip,
                                private_key,
                                endpoint_address,
                                public_key,
                                endpoint_port) ) {
                            ESP_LOGD(TAG, "Failed to initialize WG interface.");
                        }
                    }

I hope this information will be useful and save someone a few nights of debugging :)

My ESP32 client with ESPHome yaml also connects to my VPN. In this VPN is my mqtt-broker. But the problem is mqtt on my ESP32 client. Mqtt starts before the VPN initialisation and keeps trying to connect. My VPN needs to be at first, and mqtt needs to wait till finished vpn-connection. Did someone know, how to time this?

RoboMagus commented 1 year ago

I'd love to see this component supported not only on the Arduino framework, but ESP-idf also. A quick look at the initial library mentioned does not actually show me any real Arduino dependencies.

Keep my hopes up? 😅

droscy commented 1 year ago

Starting from @lhoracek's work (esphome/esphome#4256) I added support for esp-idf framework using my customized version of @trombik's wireguard implementation (see trombik/esp_wireguard#42, as soon as he merges my commits I'll update the library link to point to his repo).

To @lhoracek I submitted lhoracek/esphome#1 and lhoracek/esphome#2:

I have no real knowledge of what is happening on lower levels of esp32 network stack and @trombik tagged his code as "esp-idf only" but I can compile it even with Arduino framework: my device correctly links to the other peer and I can interact through wireguard tunnel from Home Assistant. So I ask @lhoracek (and anyone else here) to please test both my PRs.

I also appreciated the comment of @lightingman117 here https://github.com/esphome/esphome/pull/4256#issuecomment-1438590958 on trying to be consistent to wireguard naming so I changed the yaml schema of wireguard, this is the template to test it:

external_components:
  - source:
      type: git
      url: https://github.com/droscy/esphome
      ref: feature/wireguard_esp_idf/1  # new lib for esp-idf, lhoracek's lib for Arduino
      #ref: feature/wireguard_esp_idf/2  # new lib both for esp-idf and Arduino
    components: [ wireguard ]

time:
  # don't forget to setup a time source
  - platform: sntp
    id: src_time

wireguard:
  address: x.y.z.w
  private_key: !secret wg_privkey
  peer_endpoint: wg.server.example
  peer_public_key: !secret wg_peer_pubkey

  # optional netmask (this is the default if omitted)
  netmask: 255.255.255.255

  # optional custom port (this is the wireguard default)
  peer_port: 51820

  # optional pre-shared key
  peer_preshared_key: !secret wg_peer_shrdkey

  # optional keepalive in seconds (disabled by default)
  # available only with new lib, so only on esp-idf for
  # first PR and on both frameworks for second PR
  peer_persistent_keepalive: 0

If you give an id to the wireguard component you can manually create a binary sensor to check if the peer is online (this is far away from an integrated sensor but can be a starting point):

wireguard:
  id: vpn
  [...]

binary_sensor:
  - platform: template
    name: 'Wireguard status'
    device_class: connectivity
    lambda: |-
      return id(vpn).is_peer_up();
droscy commented 1 year ago

I have added the method to get the latest handshake timestamp.

Waiting for native ESPHome sensors this is the configuration you can use:

# the branch wireguard/dev will receive my most
# updated code, so use it to test my developments
external_components:
  - source:
      type: git
      url: https://github.com/droscy/esphome
      ref: wireguard/dev
    components: [ wireguard ]

# a time source is required, do not use homeassistant
# as a source if Home Assistant is on the remote peer
time:
  - platform: sntp
    id: src_time

# configure wireguard as described in the previous post adding an id
wireguard:
  id: vpn
  [...]

# create a template binary sensor to check if the remote peer is online
binary_sensor:
  - platform: template
    name: 'WireGuard Status'
    device_class: connectivity
    lambda: |-
      return id(vpn).is_peer_up();

# create a template sensor to retrive the timestamp of the latest handshake
sensor:
  - platform: template
    name: 'WireGuard Latest Handshake'
    device_class: timestamp
    lambda: |-
      static time_t latest_handshake;
      latest_handshake = id(vpn).get_latest_handshake();
      return (latest_handshake > 0) ? latest_handshake : NAN;
snechiporenko commented 1 year ago

How can Home Assistant access ESPHome that is not on the local network? I want to set up the standard integration using the Native API Component, but I'm not sure what IP to use. Also, is it possible to make ESPHome visible from the smart home server? Thank you!

droscy commented 1 year ago

How can Home Assistant access ESPHome that is not on the local network? I want to set up the standard integration using the Native API Component, but I'm not sure what IP to use.

@snechiporenko have you already set up wireguard in Home Assistant server?

If yes, from Home Assistant "Integrations" page you need to manually add the remote esphome device using its wireguard IP.

In config file of esphome you wrote something like:

wireguard:
  address: x.y.z.w
  [...]

the address x.y.z.w is the IP you have to use in Home Assistant to reach the remote device. If it is not working maybe there is a misconfiguration either in wireguard (from Home Assistant side) or in firewalls or in routing.

If you haven't setup wireguard yet, you need to install and configure it. See WireGuard Quick Start for a manual installation in the system or have a look at this add-on for Home Assistant.

droscy commented 1 year ago

Hello, I have good news (I hope) for anybody here:

Here the complete example for your configuration:

# Configure wireguard external source (my branch wireguard/main
# will receive my most stable code)
external_components:
  - source:
      type: git
      url: https://github.com/droscy/esphome
      ref: wireguard/main
    components:
      - wireguard
      - wireguard_status
      - wireguard_handshake

# Setup a time source.
# Do not use 'homeassistant' platform if Home Assistant is on the remote
# peer because the time synchronization is a prerequisite to establish
# the vpn link.
time:
  - platform: sntp

# Setup WireGuard
wireguard:
  address: x.y.z.w
  private_key: private_key=
  peer_endpoint: wg.server.example
  peer_public_key: public_key=

  # optional netmask (this is the default if omitted)
  netmask: 255.255.255.255

  # optional custom port (this is the wireguard default)
  peer_port: 51820

  # optional pre-shared key
  peer_preshared_key: shared_key=

  # optional keepalive in seconds (disabled by default, suggested 25
  # seconds if the board is behind NATs)
  peer_persistent_keepalive: 25

  # optional list of allowed ip/mask (any host is allowed if omitted)
  peer_allowed_ips:
    - x.y.z.0/24
    - l.m.n.o/32  # the /32 can be omitted for single host
    - [...]

  # if remote peer is unreachable reboot the board (default to 15min,
  # set to 0s to disable)
  reboot_timeout: 15min

# Configure the sensors
binary_sensor:
  - platform: wireguard_status
    name: 'WireGuard Status'

    # optional (default to 10s)
    update_interval: 10s

sensor:
  - platform: wireguard_handshake
    name: 'WireGuard Latest Handshake'

    # optional (default to 60s)
    update_interval: 60s

Feedback are of course welcome.

snechiporenko commented 1 year ago

I have problem of sharing VPN and new component voice assistant The component attempts to establish a reverse UDP connection (from the device to the server). In this case, the connection address is specified as 172.30.32.1, and it is available for connection from the desktop client. The error that can be seen in response to an attempt to send data is "[E][voice_assistant:228]: Error: stt-stream-failed - Speech to text failed", which indicates that the voice data was not transmitted. Perhaps a problem with establishing a UDP connection?

droscy commented 1 year ago

@snechiporenko are you using the latest wireguard code as described in my previous post?

Maybe you hit the same issue described here https://github.com/esphome/esphome/pull/4256#issuecomment-1556167145: voice assistant has a setup priority set to AFTER_CONNECTION and older wireguard code has LATE that is causing wireguard to be initialized at the end of the boot process.

snechiporenko commented 1 year ago

I have checked on the latest version of the code from the "wireguard/main" branch, but it didn't succeed. I think the issue is not related to the connection establishment because, for the UDP protocol, there is no connection setup; there is only initialisation

  this->socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  if (socket_ == nullptr) {
    ESP_LOGW(TAG, "Could not create socket.");
    this->mark_failed();
    return;
  }
  int enable = 1;
  int err = socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
  if (err != 0) {
    ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err);
    // we can still continue
  }
  err = socket_->setblocking(false);
  if (err != 0) {
    ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err);
    this->mark_failed();
    return;
  }

and packet transmission

  this->mic_->add_data_callback([this](const std::vector<uint8_t> &data) {
    if (!this->running_) {
      return;
    }
    this->socket_->sendto(data.data(), data.size(), 0, (struct sockaddr *) &this->dest_addr_, sizeof(this->dest_addr_));
  });

The actual packet transmission occurs when the user presses a button and speaks into the microphone. This operation takes place after establishing a VPN connection.

Perhaps @jesserockz can suggest what the problem might be?

droscy commented 1 year ago

Could you please provide your testing yaml file? I'll try to help debugging.

snechiporenko commented 1 year ago

Could you please provide your testing yaml file? I'll try to help debugging.

It must be work without hardware microphone. Thank you for help.

esphome:
  name: t-watch
  friendly_name: t-watch

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  level: VERBOSE

external_components:
  - source:
      type: git
      url: https://github.com/droscy/esphome
      ref: wireguard/main
    components:
      - wireguard

wireguard:
  id: vpn
  address: 172.27.66.4
  private_key: c...4=
  peer_public_key: 2...s=
  peer_endpoint: ....net.ua

time:
  - platform: sntp
    id: mytime

binary_sensor:
  - platform: template
    name: 'Wireguard status'
    device_class: connectivity
    lambda: |-
      return id(vpn).is_peer_up();
  - platform: gpio
    id: button
    pin: 
      number: GPIO39
      inverted: true
    on_press:
      - voice_assistant.start:
    on_release:
      - voice_assistant.stop:

sensor:
  - platform: template
    name: 'WireGuard Latest Handshake'
    device_class: timestamp
    lambda: |-
      static time_t latest_handshake;
      latest_handshake = id(vpn).get_latest_handshake();
      return (latest_handshake > 0) ? latest_handshake : NAN;

# Enable Home Assistant API
api:
  encryption:
    key: "AnOHOHsQ71cz7heIkSd6wmM3dzJrfp49x/pZ9+GGnq4="

ota:
  password: "64a7e4abbe2a3ff1c8d5cad52b6112db"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  use_address: 172.27.66.4

captive_portal:

web_server:
  port: 80

i2s_audio:
  - id: i2s_in
    i2s_lrclk_pin: GPIO25
    i2s_bclk_pin: GPIO32

microphone:
  - platform: i2s_audio
    id: mic_i2s
    i2s_audio_id: i2s_in
    i2s_din_pin: GPIO33
    adc_type: external
    pdm: false
    on_data:
      - logger.log:
          format: "Received %d bytes"
          args: ['x.size()']

voice_assistant:
  microphone: mic_i2s
droscy commented 1 year ago

Hi @snechiporenko I did some tests using the following configuration.

button:
  - platform: template
    id: voice_start
    name: 'Press to start'
    on_press:
      - voice_assistant.start:
  - platform: template
    id: voice_stop
    name: 'Press to stop'
    on_press:
      - voice_assistant.stop:

i2s_audio:
  - id: i2s_in
    i2s_lrclk_pin: GPIO25
    i2s_bclk_pin: GPIO32

microphone:
  - platform: i2s_audio
    id: mic_i2s
    i2s_audio_id: i2s_in
    i2s_din_pin: GPIO33
    adc_type: external
    pdm: false
    on_data:
      - logger.log:
          format: "Received %d bytes"
          args: ['x.size()']

voice_assistant:
  microphone: mic_i2s

The connection from Home Assistant to the esp device has been correctly established through wireguard (network 172.16.34.0/24)

[16:54:25][D][wireguard:057]: WireGuard remote peer is online (latest handshake 2023-05-26 16:50:32 CEST)
[...]
[16:54:51][D][api:102]: Accepted 172.16.34.10
[16:54:51][V][api.connection:941]: Hello from client: 'Home Assistant 2023.5.0 (172.16.34.10)' | API Version 1.7
[16:54:51][D][api.connection:959]: Home Assistant 2023.5.0 (172.16.34.10): Connected successfully
[...]
[16:54:55][D][wireguard:057]: WireGuard remote peer is online (latest handshake 2023-05-26 16:54:28 CEST)

When I press the Start button I see

[16:54:57][D][button:010]: 'Press to start' Pressed.
[16:54:57][D][voice_assistant:105]: Requesting start...
[16:54:57][D][voice_assistant:085]: Starting...
[16:54:57][D][main:320]: Received 512 bytes
[16:54:57][D][main:320]: Received 512 bytes
[16:54:57][D][main:320]: Received 512 bytes
[16:54:57][D][main:320]: Received 512 bytes
[16:54:57][D][main:320]: Received 512 bytes
[...]

So it seems that the transmission is running but in the logs of the firewall I have many of this message

May 26 16:54:57 host DROP-ESP-DEVICES: IN=eth0 OUT= SRC=192.168.34.105 DST=172.16.34.10 PROTO=UDP SPT=55808 DPT=41183

Except that the packet has been dropped, the source address is the esp IP of the local network not the IP of the vpn. Maybe this is the problem: the voice_assistant does not use the vpn interface to send packets out. I don't know if there is a way to force the component to use a different interface or to force wireguard to define its interface as the default. I'll check this second option.

droscy commented 1 year ago

Hi all, the wireguard code has been merged to official PR waiting for approval, you can test it with

external_components:
  - source: github://pr#4256
    components:
      - wireguard
      - wireguard_status
      - wireguard_handshake

The full preview of the documentation is here from PR https://github.com/esphome/esphome-docs/pull/2948

nagyrobi commented 1 year ago

The documentation should point out in a note box what extra steps need to be taken in Home Assistant in order to make it work nicely.

droscy commented 1 year ago

Hi @nagyrobi, which extra steps are you referring to?

The description of how to setup WireGuard to Home Assistant side, I think, is out of scope. Also because there are many different configuration methods (border router, system wide, HA integration, etc) for different platforms and operating systems.

I can add a section pointing out that WireGuard needs to be installed and ready to accept connections in the remote peer, being it Home Assistant OS or any other OS. I considered this and obvious note, but better more information then less.

If you think I'm missing something, please, write what you'd like to be added (or open a PR in my repo) and we will review and merge.

nagyrobi commented 1 year ago

It's not out of scope, because otherwise it will generate a lot of support questions (=work for the devs) on how to set up the HA side.

The users need a documentation which provides complete information, end-to-end to set it up and make it turnkey working.

I think you should at least put a note with a link showing an example on how to configure it the simplest way with Home Assistant, perhaps noting that there are many other ways to do it.

tefracky commented 1 year ago

@nagyrobi Take a look here: https://community.home-assistant.io/t/home-assistant-community-add-on-wireguard/134662 Why should it be necessary to copy and paste well working instructions? A linkt to the official support thread should be enough.

nagyrobi commented 1 year ago

I may be wrong, but I don't see this linked anywhere in the doc.

tefracky commented 1 year ago

That's right, but you mentioned to write a whole new instruction. To my opinion, it is enough to link these to websites:

https://community.home-assistant.io/t/home-assistant-community-add-on-wireguard/134662 https://github.com/hassio-addons/addon-wireguard

nagyrobi commented 1 year ago

Yes, please add them in a note box stating that WireGuard in ESPHome needs a separate connection leg such as te links above.

droscy commented 1 year ago

Ok, I'll add a section with links to most common installation methods. Stay tuned ;-)

Tratos-1 commented 1 year ago

Hi, great work. Unfortunately I can't make it work. I followed the instruction and getting an error below. Do you have any idea what is wrong? Thanks in advance.

[D][sntp:078]: Synchronized time: 2023-06-07 22:28:03
[D][wireguard:178]: starting WireGuard connection...
[D][esp-idf:000]: E (12678) esp_wireguard: netif_add: failed
[D][esp-idf:000]: E (12689) esp_wireguard: esp_wireguard_netif_create: ESP_FAIL
[W][wireguard:193]: cannot start WireGuard connection, error code -1
[D][wireguard:078]: WireGuard remote peer is offline (latest handshake timestamp not available)

Full yaml file:

esphome:
  name: weatherstation
  friendly_name: Weather Station

esp32:
  board: esp32dev
  framework:
    type: arduino

logger:

wifi:
  ssid: XXXXXX
  password: XXXXXX

external_components:
  - source: github://pr#4256
    components:
      - wireguard
      - wireguard_status
      - wireguard_handshake

time:
  - platform: sntp
    id: ntp

wireguard:
  address: 192.168.6.6
  private_key: private_key=XXXXXX=
  peer_endpoint: XXX.XXX.XXX.XXX
  peer_public_key: public_key=XXXXXX=

  # Optional netmask (this is the default if omitted)
  netmask: 255.255.255.255

  # Optional pre-shared key
  peer_preshared_key: shared_key=

  # Optional list of ip/mask (any host is allowed if omitted)
  peer_allowed_ips:
    - 192.168.6.0/24

  # Optional keepalive (disabled by default)
  peer_persistent_keepalive: 25s
droscy commented 1 year ago

Hello @Tratos-1 the error reports a failure creating the network interface to be used by wireguard. I've just opened the issue droscy/esphome#6, let's continue there.

droscy commented 1 year ago

Doc updated:

I hope it is not too messy. @nagyrobi, @tefracky, @CarlosGS could you review please?

https://deploy-preview-2948--esphome.netlify.app/components/wireguard.html

tefracky commented 1 year ago

I am not a native English speaker, so I didn't take care on spelling/grammer. Overall, I think the documentation is sufficient and I very like your explenation about the allowed IP-ranges! I also think, the part about the Wireguard installation as warning is sufficient. However, to my personal opinion, I would place this warning as one of the first paragraphs, maybe directly befor the time component warning (which is also very helpful). Unfortunately, I cannot test the whole setup, since my company has a WiFi captive portal side for the guest WiFi and I don't know how to handle it in ESPHome. I know, it is out of topic, but maybe someone has an idea or link for solving this problem.

CarlosGS commented 1 year ago

Looking great, thanks @droscy! Agreed with @tefracky (btw I can't think of a solution for guest captive portal) To complete the documentation and make it fully self-contained, I'm only missing this which is needed at the moment. Maybe add it in the "Remote peer setup" section:

In order to route outbound traffic into the VPN, you can add this to your Home Assistant configuration file:

command_line:
  - sensor:
      name: Wireguard addon internal IP
      command: "host_result=$(host a0d7b954-wireguard); addon_ip=${host_result##* }; ip route replace 172.27.66.0/24 via $addon_ip; echo $addon_ip"
droscy commented 1 year ago

Code updated, these are the changes:

Note due to braking changes from esphome/esphome#4926 and probably until next stable esphome release, you must use esphome from dev branch to compile wireguard.

I would place this warning as one of the first paragraphs, maybe directly befor the time component warning (which is also very helpful).

@tefracky I've just moved it there, please check if the introduction is sill well readble.

To complete the documentation and make it fully self-contained, I'm only missing this which is needed at the moment. [...] command: "host_result=$(host a0d7b954-wireguard); addon_ip=${host_result##* }; ip route replace 172.27.66.0/24 via $addon_ip; echo $addon_ip"

@CarlosGS I still think that everything not directly related to ESPHome is out of scope, even if a strict bond exists with Home Assistant. However, leaving my thoughs apart, before adding that snippet to the doc I need to understand when and why that command is needed.

In my wireguard setup I've never used that command and everything works correctly, wireguard software creates the static routes by iteself. And my Home Assistant is not running as root, thus the ip route command will fail because it must be excuted by root.

So, these are my questions:

CarlosGS commented 1 year ago

In my wireguard setup I've never used that command and everything works correctly, wireguard software creates the static routes by iteself. And my Home Assistant is not running as root, thus the ip route command will fail because it must be excuted by root. In which situation or configuration is that command required?

Good point. I thought it was always needed, because in all installations I'm using Home Assistant OS.

a0d7b954-wireguard is a hostname, but is it "static" (I mean valid everywhere) or it depends by... what? If I run host a0d7b954-wireguard in my setup, of course, it will fails Host a0d7b954-wireguard not found because I don't have such host

That is the hash of the addon URL, in this case https://github.com/hassio-addons/addon-wireguard (see here). I think then, this command is only necessary for installation methods: OS and Supervised. Or are you using supervised? :thinking:

172.27.66.0/24 this, I suppose, is the vpn network configured "server-side" Is there a documentation for such command that I can read?

I didn't document the command further, since it is customized to the default parameters of the official Addon. With the broad different setups, I'm now also doubtful if we should complicate the ESPHome documentation with this. Here's another option for the text, modifications in bold:

Remote peer setup

There are many different ways for installing and configuring WireGuard® on servers, home servers or general host. It depends on the platform and on the operating system in use.

You can start reading the official documentation to have an overview of what it is and on how to install it system wide for common operating systems. Read the thread at Home Assistant Community Add-on: WireGuard if you intend to install it through Home Assistant. Note that securely setting up a VPN requires some networking experience, you'll need to open router ports and possibly use custom commands to redirect traffic.

Once everything is configured you should be able to add the device to Home Assistant. See next section.

remcom commented 1 year ago

Cool addition when its getting merged. Currently i'm runnign into the following issue:

src/esphome/components/wireguard/wireguard.cpp:10:10: fatal error: esphome/core/time.h: No such file or directory
 #include "esphome/core/time.h"
          ^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
*** [/data/esp-office/.pioenvs/esp-office/src/esphome/components/wireguard/wireguard.cpp.o] Error 1

What am i missing in my config:

esphome:
  name: esp-office
  friendly_name: esp-office

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxx"

ota:
  password: "xxxxxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp-Office Fallback Hotspot"
    password: "xxxxxxxx"

# captive_portal:

# web_server:
#   port: 80

external_components:
  - source: github://pr#4256
    components:
      - wireguard
      - wireguard_status
      - wireguard_handshake

time:
  - platform: sntp
    id: ntp

wireguard:
  id: vpn
  address: xxxxxx
  private_key: xxxxx
  peer_public_key: xxxxx
  peer_endpoint: xxxxxx

binary_sensor:
  - platform: template
    name: 'Wireguard status'
    device_class: connectivity
    lambda: |-
      return id(vpn).is_peer_up();

sensor:
  - platform: template
    name: 'WireGuard Latest Handshake'
    device_class: timestamp
    lambda: |-
      static time_t latest_handshake;
      latest_handshake = id(vpn).get_latest_handshake();
      return (latest_handshake > 0) ? latest_handshake : NAN;
droscy commented 1 year ago

Hello @RemCom, due to breaking changes from https://github.com/esphome/esphome/pull/4926 (and probably until next stable esphome release), you must use esphome dev to compile wireguard component. If using docker [...] ghcr.io/esphome/esphome:dev, if using python virtualenv pip install -e /folder/to/github/clone.

You should also use sensor components instead of templates:

sensor:
  - platform: wireguard_handshake
    name: 'Wireguard Latest Handshake'

binary_sensor:
  - platform: wireguard_status
    name: 'Wireguard Status'

For other parameter please see the ongoing documentation https://deploy-preview-2948--esphome.netlify.app/components/wireguard

droscy commented 1 year ago

I think then, this command is only necessary for installation methods: OS and Supervised. Or are you using supervised?

No @CarlosGS, I'm not. I'm using core installation in virtualenv and wireguard is configured in the server with official package.

With the broad different setups, I'm now also doubtful if we should complicate the ESPHome documentation with this. Here's another option for the text, modifications in bold:

I agree. I'll add your changes in next commit.

droscy commented 1 year ago

Code updated moving all the sensors inside wireguard component.

This is a breaking change, to use the new code you need the following configuration:

external_components:
  - source: github://pr#4256
    components: [wireguard]  # only wireguard, not the others

wireguard:
  # configure as usual

# new conf here
binary_sensor:
  - platform: wireguard
    status:
      name: 'WireGuard Status'

# new conf here
sensor:
  - platform: wireguard
    latest_handshake:
      name: 'WireGuard Latest Handshake'

Doc updated as well.

mrivero33 commented 1 year ago

Hi, i get this error

src/esphome/components/wireguard/wireguard.cpp:10:10: fatal error: esphome/core/time.h: No such file or directory

include "esphome/core/time.h"

^~~~~ compilation terminated.


[/data/remoto02/.pioenvs/remoto02/src/esphome/components/wireguard/wireguard.cpp.o] Error 1

El vie, 16 jun 2023 a las 1:40, Simone Rossetto @.***>) escribió:

Code updated moving all the sensors inside wireguard component.

This is a breaking change, to use the new code you need the following configuration:

external_components:

  • source: github://pr#4256 components: [wireguard] # only wireguard, not the others wireguard:

    configure as usual

    new conf herebinary_sensor:

  • platform: wireguard status: name: 'WireGuard Status'

    new conf heresensor:

  • platform: wireguard latest_handshake: name: 'WireGuard Latest Handshake'

Doc https://deploy-preview-2948--esphome.netlify.app/components/wireguard.html updated as well.

— Reply to this email directly, view it on GitHub https://github.com/esphome/feature-requests/issues/1444#issuecomment-1594088315, or unsubscribe https://github.com/notifications/unsubscribe-auth/AH7HAVPCWS4H2KIXDRVDAY3XLPPTVANCNFSM5FE3PAVA . You are receiving this because you commented.Message ID: @.***>

droscy commented 1 year ago

Hello @mrivero33, due to breaking changes from https://github.com/esphome/esphome/pull/4926 (and probably until next stable esphome release), you must use esphome dev to compile wireguard component.