ESP32 Sensor connected via Wireguard does not work

I would like to use sensors or other devices in another network than my Home Assistant server is. I try to do a proove of concept with an M5Stack Atom Lite ESP32 module.

My setup has a hassIO installation on a NUC and also as an addon the Wiregurad server. Home Assistant my own public IPv4 and is accessible via HTTPS.

I created an yaml with a NTP, LED and a button section and also the Wireguard client. And it connects now to another WLAN and also connects with Wireguard to my VPN.

Not working is the connection to ESPhome and to Home Assistant. So as I see it, the Home Assistant Integrations need the Home Assistant server to connect to the ESP and itā€™s not the ESP that connects to HA and ESPhome. I also added the ā€œuse_addressā€ parameter as mentioned here: WireGuard Component ā€” ESPHome
But this did also not help.

As I see it, there is no routing to from the Home Assistant / hassIO to the Wireguard network the device / Wireguard clients are in. And in the in the other direction, there is NAT, so I only see the IP of home assistant as source on for example my NAS. And on Home Assistant (in AddGuard) I see as source the IP of the Wireguard Docker container. So many issues to overcome, if you like to connect to the Wireguard client.

I did not yet try a MQTT sensor on the ESP that then connects to HomeAssistants MQTT broker. Probably that works, but there will be no management of the ESPhome device or OTA update possible.

Did anyone have a remote location with sensors connectiong via VPN up- and running ?

Please post your YAML (obviously without the keys)

Hello Nick
I donā€™t know what this helps to post the ESPhome XML, but here it is.
Most probably a change in the Wireguard addon config is the way forward (donā€™t use NAT)

substitutions:
  device_name: "m5stack-atom-lite-1"
  device_friendly_name: "M5Stack Atom Lite 1"
  device_description: "M5Stack Atom Lite 1"
  time_timezone: "Europe/Zurich"
  
esphome:
  name: ${device_name}
  friendly_name: $device_friendly_name
  comment: "${device_description}"
  name_add_mac_suffix: false

esp32:
  board: m5stack-atom
  framework:
    type: arduino

wifi:
  networks:
  #use_address: "172.27.66.6"
    - ssid: !secret wifi_ssid2
      password: !secret wifi_password2
   
 
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${device_name}
    password: !secret wifi_fallback_password
 
captive_portal:
 
# Enable logging
logger:
#  level: VERY_VERBOSE

# Enable Home Assistant API
api:
  encryption:
    key: !secret home_assistant_key
 
ota:
   password: !secret ota_password 

light:
  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    pin: 27
    num_leds: 1
    rmt_channel: 0
    chipset: SK6812
    name: "Status LED"
    id: status_led
    default_transition_length: 0.1s
    effects:
      - random:
      - flicker:
      - addressable_rainbow:

binary_sensor:
  - platform: gpio
    pin:
      number: 39
      inverted: True
    name: Button
    filters:
      - delayed_off: 10ms
    on_press:
      then:
        - light.toggle: status_led

time:
  - platform: sntp
    id: sntp_time

wireguard:
  address: 172.27.66.6
  private_key: !secret wg_privkey
  peer_public_key: !secret wg_pubkey
  peer_endpoint: !secret wg_host
  peer_port: !secret wg_port
  peer_persistent_keepalive: 25s
  

The setup of wireguard are quite complex. I was wondering about your netmask and other such stuff. I was also wondering if you had followed all the instructions.

So perhaps tell us more about what you have done, and how your network is set up.

Router:
Wireguard interface ip : 10.10.10.1/24
Peer:
allowed address: 10.10.10.10/32 / 192.168.1.0/24

ESP32:

substitutions:
  name: "wireguard-test"
  friendly_name: "wireguard-test"
  id_prefix: "wireguard_test"
esphome:
  name: ${name}
esp32:
  board: esp-wrover-kit
  framework:
    type: arduino
wifi:
  ssid: "***********"
  password: "***********"
  fast_connect: true
  use_address: 10.10.10.10
time:
  - platform: sntp
    timezone: Europe/Warsaw
    id: net_time
wireguard:
  require_connection_to_proceed: true
  address: 10.10.10.10
  private_key: ***************************
  peer_endpoint: public_ip - public_ip
  peer_public_key: ************************
  peer_port: 999999
  netmask: 0.0.0.0
  peer_allowed_ips:
    - 192.168.1.0/24 - local lan
  peer_persistent_keepalive: 10s
mqtt:
  broker: local_lan_ip
  username: ****
  password: ****
  discovery: false
ota:
api:
logger:
  baud_rate: 0
  level: INFO
web_server:
  port: 80
binary_sensor:
  - platform: wireguard
    status:
      name: 'WireGuard Status'  

MQTT - work
OTA - work
API - dont work

edit:
sorry for my mistake but
require_connection_to_proceed: false should be true

require_connection_to_proceed: true

Is it possible to run api and mqtt on same esphome device?

I just saw the warning
Warning

If you enable MQTT and you do not use the ā€œnative APIā€ for Home Assistant, you must remove the api: line from your ESPHome configuration, otherwise the ESP will reboot every 15 minutes because no client connected to the native API.
Ok that answers that

I have API and MQTT enabled, but in MQTT i have discovery set to false and there is no problem.
If you have discovery set to true and API enabled, entities are duplicated

How did you add the esp device to HA?

MQTT custom sensor in configuration.yaml

No I mean api wise.

I wrote earlier, you donā€™t read carefully :slight_smile:

MQTT - work
OTA - work
API - dont work in wireguard config.

API problem solved.
change default port 6053 to other.

api: 
  port: 9999

I did not know that MQTT implementation is so simple.

I got MQTT working, but not API and OTA. This works in my home LAN, but not outside. But this is a difficult issue, because the default Wireguard AddOn uses NAT and this eliminates the access from the LAN to a Wireguard client. NAT must be changed to a propper routing.

I disabled reboot on API not connected. I added a few options and took some inspiration from @bodychmarcin . So I have now a functional demo and can now get to serious applications.

substitutions:
  device_name: "m5stack-atom-lite-1"
  device_friendly_name: "M5Stack Atom Lite 1"
  device_description: "M5Stack Atom Lite 1"
  time_timezone: "Europe/Zurich"
  
esphome:
  name: ${device_name}
  friendly_name: $device_friendly_name
  comment: "${device_description}"
  name_add_mac_suffix: false

esp32:
  board: m5stack-atom
  framework:
    type: arduino

wifi:
  networks:
    - ssid: !secret wifi_ssid5
      password: !secret wifi_password5
    - ssid: !secret wifi_ssid4
      password: !secret wifi_password4
    - ssid: !secret wifi_ssid3
      password: !secret wifi_password3
    - ssid: !secret wifi_ssid2
      password: !secret wifi_password2
    - ssid: !secret wifi_ssid
      password: !secret wifi_password
  #fast_connect: true
  #use_address: "172.27.66.6"
 
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${device_name}
    password: !secret wifi_fallback_password
 
captive_portal:
 
# Enable logging
logger:
#  level: VERY_VERBOSE

# Enable Home Assistant API
api:
  encryption:
    key: !secret home_assistant_key
  reboot_timeout: 0s

ota:
   password: !secret ota_password 

light:
  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    pin: 27
    num_leds: 1
    rmt_channel: 0
    chipset: SK6812
    name: "Status LED"
    id: status_led
    default_transition_length: 0.1s
    effects:
      - random:
      - random:
          name: Random slow
          transition_length: 15s
          update_interval: 20s
      - flicker:
      - addressable_rainbow:
      - addressable_rainbow:
          name: Rainbow slow
          speed: 1
          width: 100
      - strobe:
          name: Blink
      - strobe:
          name: Flash
          colors:
            - state: true
              brightness: 100%
              duration: 50ms
            - state: false
              duration: 950ms
      - pulse:
      - pulse:
          name: "Slow Pulse"
          update_interval: 5s
      - lambda:
          name: My Custom Effect
          update_interval: 1s
          lambda: |-
            static int state = 0;
            auto call = id(status_led).turn_on();
            // Transition of 1000ms = 1s
            call.set_transition_length(1000);
            if (state == 0) {
              call.set_rgb(1.0, 1.0, 1.0);
            } else if (state == 1) {
              call.set_rgb(1.0, 0.0, 1.0);
            } else if (state == 2) {
              call.set_rgb(0.0, 0.0, 1.0);
            } else {
              call.set_rgb(1.0, 0.0, 0.0);
            }
            call.perform();
            state += 1;
            if (state == 4)
              state = 0;

binary_sensor:
  - platform: gpio
    pin:
      number: 39
      inverted: True
    name: Button
    filters:
      - delayed_off: 10ms
    on_press:
      then:
        - light.toggle: status_led
  - platform: wireguard
    status:
      name: 'WireGuard Status'

time:
  - platform: sntp
    id: sntp_time

mqtt:
  broker: 192.168.1.88
  username: !secret mqtt_user
  password: !secret mqtt_password
  #discovery: false

web_server:
  port: 80
  include_internal: true
  ota: False

wireguard:
  address: 172.27.66.6
  private_key: !secret wg_privkey
  peer_public_key: !secret wg_pubkey
  peer_endpoint: !secret wg_host
  peer_port: !secret wg_port
  peer_persistent_keepalive: 30s
  require_connection_to_proceed: true
  netmask: 0.0.0.0
  #peer_allowed_ips:
  #  - 192.168.1.0/24

I would like to be abled to do remote OTA and to use the API instead of MQTT. Is here an expert on Wireguard server configuration including hassio docker and routing setup ?

1 Like

Did you manage to realize your idea? does the API work via wireguard?

No, see last post just above yours. I still need help configuring the Wireguard Server AddOn differently (without NAT but with routing), probably from @frenck . But as I understand docker and Nnetworking, this can be tricky to route from an ā€œinternalā€ VPN network like Wireguard has, to the ā€œoutsideā€ and especially from my local LAN (and Home Assistant itself) to a VPN connected client.

1 Like

Hi, I have exactly the same problem. Iā€™m trying to solve it, as soon as I found a way to route from Wireguard to Hassio, I immediately report

Hello,
I had the same problem, ESP32 connected with wireguard VPN addon in HAOS.
Only MQTT work
I found that the problem is that ESPHOME is behind SSL Proxy
(additional settings for SSL proxy didnĀ“t work for me)

I solve it with second HA instance (on different machine which is not behind the proxy)
connected to my main HA instance via HACS custom component.
MQTT work
API work
bluetooth proxy on ESP also work so I am able to use BLE sensors on remote site as bonus

I know :slight_smile: , the easier way is to set up SSL proxy, but I donĀ“t know how to do it

Hi - maybe too late, maybe notā€¦

I have the same issue - esphome/wireguard was not visible from HA

I had to enter the following line to config.yaml of HA:

command_line:

  • sensor:

name: Wireguard addon internal IP

command: ā€œhost_result=$(host a0d7b954-wireguard); addon_ip=${host_result##* }; ip route replace 172.244.66.0/24 via $addon_ip src 192.168.2.4ā€

172.244.66.0 - ip of wg / server is 172.244.66.1

192.168.2.4 - ip of HA host

it fixing the routing from wg subnet to local one, to enable esp device be visible in HA

hopping it helps!

1 Like

Hello glitch69. I have the same problem but not very expert. I wold appreciate if you can show me where did you calculate the a0d7b954. ? is an addres of what ?. thanks in advance

I added this to my commandline part:

  - sensor:
      name: Wireguard addon internal IP
      command: ā€œhost_result=$(host a0d7b954-wireguard); addon_ip=${host_result##* }; ip route replace 172.244.66.0/24 via $addon_ip src 192.168.111.88ā€

And I get this error:

Command failed (with return code 1): ā€œhost_result=$(host a0d7b954-wireguard); addon_ip=${host_result##* }; ip route replace 172.244.66.0/24 via $addon_ip src 192.168.111.88ā€

Probably it would my sense you check the exact syntax and/or paste your example as preformated text like I did above.

Thanks