Caravan Connectivity: Keeping the Data Flowing With ESPHome & WireGuard

This post is an overview of how I set up an ESP32 board in my touring caravan to monitor a Victron SmartSolar MPPT and SmartBMV battery monitor, together with a few other sensors and controls via Home Assistant, using ESPHome.

One thing to note from the outset—there is no Home Assistant installation in the caravan. The ESPHome node communicates directly with my main HA instance, whether we are pitched up deep in the countryside or parked up on the driveway at home.

Connection Basics

The API-based connection between my ESP32 and Home Assistant (HA) is direct when we are at home over our standard house Wi-Fi. However, when we are away, the magic happens over a WireGuard VPN tunnel established directly between the ESP32 board and my home router.

Note: it does not use the WireGuard add-on available in Home Assistant—and as I found out later, that distinction saved my sanity.

Victron Communication: Ditching the Wires

The Victron MPPT and Smart BMV monitor communicate with my ESP32 over Bluetooth Low Energy (BLE). Initially, I went the traditional route and had a physical, wired connection between the MPPT and ESP32 using the VE.Direct port. For some reason, the MPPT would regularly stop sending data after a random period of time. The only fix was a complete power cycle of the unit, which quickly became a complete pain in the backside.

After hours of troubleshooting to no avail, I cut the cord and moved over to BLE, and it has proven to be absolutely rock-solid. As a massive bonus, using Bluetooth means my single ESP32 can wirelessly pull data from multiple Victron devices at once.

Because native Victron BLE support isn't baked directly into the core of ESPHome, I used a custom external component created by Fabian-Schmidt on GitHub -  https://github.com/Fabian-Schmidt/esphome-victron_ble. This allows the ESP32's Bluetooth radio to decode the encrypted advertisement packets that the Victron devices constantly broadcast into the ether.

For security, Victron encrypts its broadcast data, so I had to provide the ESP32 with the unique hardware MAC address and a 32-character hexadecimal encryption key (the "bindkey") for each device. These can be found in the official VictronConnect mobile app by digging into the device settings under the "Product Info" section. With these keys in place, the ESP32 silently listens and decrypts the data streams without ever needing to establish a formal, clunky Bluetooth pairing connection.

With the decrypted data stream flowing, I split the information into individual, readable sensors for Home Assistant. For my SmartBMV Battery Monitor, I track real-time battery health metrics like time remaining, voltage, current, consumed amp-hours, and state of charge. I even added a clamp filter to the voltage sensor to ignore any rogue, out-of-range spikes. For my SmartSolar MPPT, I pull in the output voltage, current, daily solar yield, live PV power, and the charger's current state (Bulk, Absorption, or Float).

Note: Since I set up this install, a Victron BLE integration has been added to Home Assistant. You may (or may not) be able to achieve connection to Victron devices using this integration and just using the ESP32 as a Bluetooth proxy (not tested). However, doing so would require communication back to HA for any automations to work so I still prefer this more direct approach.

Other Bits & Pieces (and Saving the Wine)

Because an ESP32 has plenty of GPIO pins going spare, I couldn't resist adding a few extra bits to the "Wobblebox" setup:

  • Climate Monitoring: A basic DHT22 sensor is wired up to keep an eye on caravan temperature and humidity.

  • Shore Power Sensing: An opto-isolated mains voltage sensor is hooked up to let HA and the ESP32 know the exact moment we are plugged into grid power.

  • Relay Controls: I have a couple of relays wired up. One is currently a spare, but the other controls the "Fridge Transformer" switch.

  • Power: The ESP32 is powered via a 12v-5v regulated 'buck converter'

The reason for controlling the mains voltage to the fridge is born out of pure frustration. The power supply unit (PSU) for my DIY compressor fridge should automatically switch between mains and battery power. However, if the compressor happened to be running at the exact moment the mains switchover occurred, it would throw the compressor control circuit into an error state, killing the cooling entirely.

On a couple of past occasions, on sites with less-than-stable hook-ups (or careless neighbours overloading a breaker), we would either wake up to find the fridge had stopped overnight or—even worse—arrive back from a day out to find the wine wasn’t chilled to perfection!

Pics of the bits installed under one of the front bench seats:

Automations: Intelligence on the Edge

I decided that things in the caravan should still function perfectly even if the 4G connection dropped and the board couldn't talk to Home Assistant. To achieve this, the crucial automations are baked directly into my ESPHome YAML configuration.

1. The Shore Power Interlock

If the opto-isolated sensor detects that shore power has been lost, the ESP32 instantly triggers the fridge relay to cut the mains transformer supply and does not blindly reconnect it when mains power returns. This prevents the dreaded compressor switchover lock-up, keeping our food fresh and our drinks cold on battery/solar power.

2. Smart Network Switching

To keep the network traffic clean, the ESP32 dynamically enables or disables the WireGuard VPN based on which Wi-Fi network it connects to. Using a Wi-Fi info text sensor, the board watches the active SSID. If it connects to my home Wi-Fi, it logs the change and disables WireGuard. If it connects to the caravan's 4G router, it automatically fires up the WireGuard tunnel to bridge the gap back home.

The WireGuard Process: Lessons Learned

Technically, routing the ESP32 back to HA should be possible using the official Home Assistant WireGuard add-on. Indeed, I spent days trying to make it work during initial bench testing.

The issue? While I could get data to pass via MQTT over the VPN, the native Home Assistant API connection completely refused to play ball when the board was remote. This was incredibly limiting. If I wanted to tweak the ESPHome configuration while away in the caravan, the ESPHome dashboard couldn't see or connect to the board, either for sensor data or to flash it over-the-air (OTA). For some unknown reason, the HA WireGuard add-on was preventing the necessary routing when the board was off-site.

The breakthrough came during a routine firmware upgrade. I noticed that DrayTek had added native WireGuard VPN support to our home router (a Vigor 2865). Instead of routing the ESP32 into the Home Assistant container, I configured the ESP32's WireGuard component connect to the DrayTek router instead.

The default Draytek configuration sets up WireGuard clients on the IP range as the main network so I could actually use the same IP for the ESP board whether it was directly connecting or via the VPN. This meant I could knock out bunch of code in the ESPHome configuration to handle the IP address change when the device was remote. I do wonder if I made that change on the HA Wireguard App configuration, whether my other issues may have disappeared. However, the benefit of not having to forward the WireGuard port to my HA instance won the day so I didn't bother exploring further.

Using the router Wireguard allowed The Home Assistant API to connect immediately, the ESPHome dashboard could see the node for remote updates, and the local web server remained fully accessible on its static IP via the caravan's local 4G router if I ever need to check it locally.

To ensure everything stays fresh and any memory leaks from the heavy BLE tracking are swept away, I also threw in a little nightly automation. Every morning at 1:00 AM, the SNTP time component triggers a quick sensor restart. Note - BLE used to have issues with memory leaks, I no longer know if that is the case!

More Automations 

I've also implemented a few native Home Assistant automations to perform certain actions and send alerts under certain conditions:

  • Alert - Battery under 12.5 volts.
  • Alert - Shore power lost.
  • Alert - Shore power reconnected.
  • Alert - Internal temp over 35°C - (mainly a 'open it up warning' for when it's sat on the drive)
  • The fridge mains power switch on the dashboard below is actually a toggle helper. There is an automation that triggers when that is turned on and waits until the 'Charger Switch Load' value is below 2 amps before it actually switches the fridge over to mains hook-up (meaning that we don't have to sit around waiting for the compressor to stop running in order to prevent the error state mentioned elsewhere).

Conclusion

With ESPHome handling the local logic and the router managing the VPN, our Wobblebox is now fully integrated into our smart home. Whether we are parked on the drive or in the middle of a field, I can track my solar yields, monitor battery health, and—crucially—rest easy knowing the fridge is running exactly as it should. I now also have a handy HA dashboard tab for monitoring and controlling bits of the caravan and a backup if we end up in a signal blackspot while we are away.

Below is the complete, sanitized ESPHome and commented configuration file I used to get everything running.

The Complete ESPHome Configuration

# ==============================================================================
# CORE ESPHOME CONFIGURATION
# Defines the device name and runs a rule on boot to ensure WireGuard starts off.
# ==============================================================================
esphome:
  name: caravan
  friendly_name: "Caravan"
  min_version: 2024.6.0 
  on_boot: 
    then:
      wireguard.disable # Prevents VPN loops on boot before Wi-Fi stabilizes

# ==============================================================================
# EXTERNAL COMPONENTS
# Pulls in the custom Victron BLE code from GitHub to decode BLE broadcast packets.
# ==============================================================================
external_components:
  - source: github://Fabian-Schmidt/esphome-victron_ble   

esp32:
  board: nodemcu-32s
  framework:
    type: esp-idf
  
# Enable logging to serial and web interface
logger:

# ==============================================================================
# HOME ASSISTANT API & OTA
# Configures the native API connection back to HA and enables wireless updates.
# ==============================================================================
api:
  encryption:
    key: "YOUR_SECRET_HA_API_ENCRYPTION_KEY____________________=" # Secured placeholder
  reboot_timeout: 0s # Stops the ESP32 from rebooting constantly if HA goes offline
      
ota:
  - platform: esphome

# ==============================================================================
# WI-FI NETWORKS
# Dual-network profiles with static local IPs for home and caravan 4G routers.
# ==============================================================================
wifi:
  use_address: 192.168.69.190
  networks:
    - ssid: !secret wifi_ssid       # Home Wi-Fi Network Name
      password: !secret wifi_password
      manual_ip:
        static_ip: 192.168.69.190
        gateway: 192.168.69.1
        subnet: 255.255.255.0
        dns1: 8.8.8.8
        dns2: 8.8.4.4
    - ssid: !secret wifi_wobble     # Caravan 4G Mobile Router Network Name
      password: !secret wifi_password
      manual_ip:
        static_ip: 192.168.1.190
        gateway: 192.168.1.1
        subnet: 255.255.255.0
        dns1: 8.8.8.8
        dns2: 8.8.4.4

# Simple web interface accessible on the local caravan network via a browser
web_server:
 port: 80  

# ==============================================================================
# TIME & SCHEDULING
# Synchronises time via NTP and triggers a safe nightly restart at 1:00 AM.
# ==============================================================================
time:
  - platform: sntp
    id: sntp_time
    servers:
     - 0.pool.ntp.org
     - 1.pool.ntp.org
     - 2.pool.ntp.org
    on_time:
      - seconds: 0
        minutes: 0
        hours: 1
        then:
          - switch.turn_on: restartsensor

# ==============================================================================
# WIREGUARD VPN
# Establishes the secure tunnel back to the home DrayTek router when off-site.
# ==============================================================================
wireguard:
  id: wg0
  address: 192.168.69.190
  private_key: YOUR_SECRET_WIREGUARD_PRIVATE_KEY____________=       # Secured placeholder
  peer_endpoint: YOUR_HOME_VPN_ENDPOINT_ADDRESS                      # Secured placeholder
  peer_port: 51820
  peer_public_key: YOUR_ROUTER_WIREGUARD_PUBLIC_KEY___________=     # Secured placeholder
  peer_preshared_key: YOUR_ROUTER_WIREGUARD_PRESHARED_KEY________=  # Secured placeholder
  peer_allowed_ips: 192.168.69.0/24
  peer_persistent_keepalive: 25s

# ==============================================================================
# VICTRON BLE TRACKING DEFINITIONS
# Registers the Bluetooth tracker and decrypts data streams using bindkeys.
# ==============================================================================
esp32_ble_tracker:

victron_ble:
  - id: SmartBMV
    mac_address: "XX:XX:XX:XX:XX:XX"    # Secured placeholder
    bindkey: "your_secret_bmv_bindkey_here________________"

  - id: SmartSolarMTTP
    mac_address: "YY:YY:YY:YY:YY:YY"    # Secured placeholder
    bindkey: "your_secret_mppt_bindkey_here_______________"     

# ==============================================================================
# SENSORS (VICTRON DATA & CLIMATE)
# Translates decrypted BLE data and GPIO states into Home Assistant sensors.
# ==============================================================================
sensor:
  # --- SmartBMV Battery Monitor Metrics ---
  - platform: victron_ble
    victron_ble_id: SmartBMV
    name: "Time remaining"
    type: TIME_TO_GO
            
  - platform: victron_ble
    victron_ble_id: SmartBMV
    name: "Battery Voltage"
    type: BATTERY_VOLTAGE
    filters:
    - clamp: # Drops rogue voltage spikes outside realistic ranges
        min_value: 10
        max_value: 20
        ignore_out_of_range: true

  - platform: victron_ble
    victron_ble_id: SmartBMV
    name: "Battery Current"
    type: BATTERY_CURRENT

  - platform: victron_ble
    victron_ble_id: SmartBMV
    name: "Consumed Ah"
    type: CONSUMED_AH

  - platform: victron_ble
    victron_ble_id: SmartBMV
    name: "State of charge"
    type: STATE_OF_CHARGE

  # --- SmartSolar MPPT Solar Controller Metrics ---
  - platform: victron_ble
    victron_ble_id: SmartSolarMTTP
    name: "MPPT Output Voltage"
    type: BATTERY_VOLTAGE

  - platform: victron_ble
    victron_ble_id: SmartSolarMTTP
    name: "MPPT Output Current"
    type: BATTERY_CURRENT

  - platform: victron_ble
    victron_ble_id: SmartSolarMTTP
    name: "MPPT Yield Today"
    type: YIELD_TODAY

  - platform: victron_ble
    victron_ble_id: SmartSolarMTTP
    name: "MPPT PV Power"
    type: PV_POWER

  - platform: victron_ble
    victron_ble_id: SmartSolarMTTP
    name: "MPPT Load Current"
    type: LOAD_CURRENT

  # --- Caravan Environmental Monitoring ---
  - platform: dht
    model: DHT22
    pin: GPIO32
    temperature:
      name: "Caravan Temperature"
    humidity:
      name: "Caravan Humidity"
      device_class: "humidity"
      state_class: "measurement"
      accuracy_decimals: 0

# ==============================================================================
# TEXT SENSORS & NETWORK INTERLOCK
# Evaluates the current SSID to intelligently toggle WireGuard on or off.
# ==============================================================================
text_sensor:
  - platform: wifi_info
    ssid: 
      name: "WiFI SSID"
      id: activessid
      on_value: 
        then:
          - if:
              condition:
                lambda: 'return x == "ASHLEIGH";' # Home Wi-Fi Network Name
              then:
                - logger.log: "SSID is ASHLEIGH, disabling WireGuard."
                - wireguard.disable
              else: 
                - if: 
                    condition:
                      lambda: 'return x == "WOBBLEBOX-WIFI";' # Caravan 4G Network Name
                    then:
                      - logger.log: "SSID is WOBBLEBOX-WIFI, enabling WireGuard."
                      - wireguard.enable
                    else: 
                      - logger.log: "SSID is neither ASHLEIGH nor WOBBLEBOX-WIFI, no WireGuard action taken."

  # Exposes whether the solar controller is in Bulk, Absorption, or Float mode
  - platform: victron_ble
    victron_ble_id: SmartSolarMTTP
    name: "MPPT State"
    type: DEVICE_STATE

# ==============================================================================
# BINARY SENSORS (VPN STATUS & MAIN POWER DETECTION)
# Monitors connections and handles the safety interlock automation for the fridge.
# ==============================================================================
binary_sensor:
  - platform: wireguard
    status:
      name: 'WireGuard Status'

  - platform: gpio
    pin: 
      number: GPIO15
      inverted: True # Set to match the opto-isolated sensor's output pull
    name: Shore Power
    on_release: # Instantly triggers the moment mains grid power fails
      then:
        - switch.turn_off: fridgemains # Cuts the fridge mains transformer to protect the compressor

# ==============================================================================
# SWITCHES (RELAYS & REBOOT CONTROLS)
# Physical relay triggers and the internal restart switch.
# ==============================================================================
switch:
  - platform: restart
    name: "Restart Sensor"
    id: restartsensor      

  - platform: gpio
    name: Fridge Transformer
    pin: GPIO25 
    id: fridgemains
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF # Safe failure state

  - platform: gpio
    name: Relay
    pin: GPIO26
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF # Reserved spare relay

Comments

You should also read:

IRONING WITH SIMPLIFY 3D

Ironing is now included with Simplify 3D Version 5 which may well render this post irrelevant. However, it may still be of use…

Mini ESPHome Motion & Light Sensor - D1 Mini

I use a lot of ESPHome based motion and light sensors in my Home Assistant setup. If there is a readily available 5 volt supply, I will use them in place of Zigbee sensors. I just find them more dependable.