Car presence detection - possible Logic fail

This is my first attempt at using ESPHome, what I am attempting to do is use a generic ESP32 to determine presence of a vehicle in my driveway and if it is departing or arriving.

Currently the logic I am working on is that the device would be powered from the car, so only being powered when the car is. On boot the device defaults to ‘departing’ mode and attempts to connect to my home wifi and if successful it will connect to home assistant API.

If it fails to connect I want it to wait 5 minutes (to avoid false arrivall indication) and then set the indication to arriving. Which I will then be able to use to trigger automations in home assistant and if the car is running for a while is reverts to departing again.

My proof of concept is currently only ever returning the departing indication, never arriving. I’ve tried playing with the timing and removing the device from wifi range for extended periods but no change. I am guessing I have a problem with my logic?

Any assistance would be appreciated.

esphome:
  name: car-presence

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "somekey"
  reboot_timeout: 10800s

ota:
  password: "somepassword"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: True
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "somessid"
    password: "somepassword"

captive_portal:

globals:
  - id: api_connection
    type: bool
    restore_value: no
    initial_value: 'true'

interval:
  - interval: 5s
    then:
      - if:
          condition:
            # check last connection state
            - lambda: 'return { (id(api_connection) = false) };'
          then:
            - if:
                condition:
                  api.connected:
                then:
                  # just connected now
                  - delay: 5s
                  - lambda: "id(api_connection) = true;"
                else: 
                  - logger.log: "api disconnected, api_connection remains false"

          else:
            - if:
                condition:
                  not:
                    api.connected:
                then:
                  # disconnected
                  - delay: 300s
                  - lambda: "id(api_connection) = false;"
                else:
                  - logger.log: "api connected, api_connection remains true"

binary_sensor:
  - platform: template
    name: "Arriving"
    lambda: |-
      if (id(api_connection) = false) {
        // Car away from house for more than 5 minutes.
        return true;
      } else {
        // Car away from house for less than 5 Minutes.
        return false;
      }
  - platform: template
    name: "Departing"
    lambda: |-
      if (id(api_connection) = true) {
        // Car has been away from house for less than 5 minutes.
        return true;
      } else {
        // Car away from house for more than 5 minutes.
        return false;
      }

Maybe something to do with the wifi connection timer - causing the device to go into AP mode? Thus by the time you get home it’s not actually trying to connect, or rebooting.

Not sure how you would solve this. maybe start by removing the fallback ap: settings, and fiddling with reboot_timeout:

I did a similar thing but with a different approach, I installed ESPresense on the ESP32 and left it in my Garage, than I put a 2€ beacon in my car.
When my car is in the garage ESPresense track it as in the garage.
When I leave state change from garage to not_home
When I return state change from not_home to garage

1 Like

I am already using ESPresence for room and people detection with BLE beacons, my main issue is the car is parked on the driveway so I don’t want it triggering unintentionally (if my Mqtt server or network went down) so I’m looking for that directionality to make it fail safe.

Ok, working the problem. I have removed the captive portal and AP fall back. I have moved the logic around a bit and added logging output to follow what is happening on the serial interface.

It does appear to get to the part of the code I want, and the log shows
“api not connected” followed by “api_connection has been set to false”
but I do not see any output to tell me that the arriving or departing sensors have changed.

So I guess I am missing something to tell the sensors to update??
Most sensor calls seem to be related to external changes, so I am unsure how I might implement this.

I tried using a lambda: - lambda: “id(arriving).publish_state(true);” But this didn’t change the value of the sensor.

Cheers for the feedback so far.

Code below:

esphome:
  name: car-presence

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "key"
  reboot_timeout: 180min 

ota:
  password: "pass"

wifi:
  networks:
    - ssid: ssid
      password: pass
  fast_connect: True
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  #ap:
  #  ssid: "ssid"
  #  password: "pass"
  #  ap_timeout: 30min

#captive_portal:

globals:
  - id: api_connection
    type: bool
    restore_value: no
    initial_value: 'true'

interval:
  - interval: 300s
    then:
      - logger.log: "Checking status"
      - if:
          condition:
            # check last connection state
            - lambda: 'return { (id(api_connection) = false) };'
          then:
            - logger.log: "api_connection is currently set to false"
            - if:
                condition:
                  api.connected:
                then:
                  # just connected now
                  - delay: 120s
                  - lambda: "id(api_connection) = true;"
                  - lambda: "id(arriving).publish_state(true);"
                  - logger.log:
                    level: DEBUG
                    format: 'The state of arriving is %d'
                    args: ['id(arriving).state']
                  - logger.log: "api_connection has been set to true"
                else: 
                  - logger.log: "api disconnected, api_connection remains false"

          else:
            - if:
                condition:
                  not:
                    api.connected:
                then:
                  # disconnected
                  - logger.log: "api not connected"
                  - lambda: "id(api_connection) = false;"
                  - logger.log: "api_connection has been set to false"
                else:
                  - logger.log: "api connected, api_connection remains true"

binary_sensor:
  - platform: template
    id: arriving
    name: "Arriving"
    lambda: |-
      if (id(api_connection) = false) {
        return true;
      } else {
        return false;
      }
    
  - platform: template
    id: departing
    name: "Departing"
    lambda: |-
      if (id(api_connection) = true) {
        return true;
      } else {
        return false;
      }


Ultimately I have ended up just using the ESP as a bluetooth beacon for now, for the workflow Apple carplay triggers the driving focus mode when the car is started (which is reported to home assistant through the companion app) and having a condition that that has been triggered for 5 minutes to prevent it opening the garage when departing the house. A little bit disappointing as I was hoping to have the ESP alone trigger the automation, I will have to do some more research to see if my original aim is achievable through other methods.

Would love to know if you get this figured out. I’m trying to setup vehicle presence using ESPhome that way maybe I can also use the same node as a bluetooth proxy.