Repository: evcc-io/evcc (go)

Issue:
Vehicles identification via RFID should overrule id via status api
**Describe the bug**
2 Cars configured with 2 LP's and both cars configured to both LP's then you can run into following issue:
If you connect 2 Cars to 2 Wallboxes nearly at the same time or if you restart EVCC during both Cars are connected.
The identification isn't working EVCC don't know which Car is connected to which LP.
But as I got RFID identification it should and it is identifying them correctly for a very short time.

**To Reproduce**
Steps to reproduce the behavior:
If you connect 2 Cars to 2 Wallboxes nearly at the same time or if you restart EVCC during both Cars are connected.

**Expected behavior**
if you use RFID tokens it should stop trying to identify the Car by which is connected.

**EVCC details:**
Show output of <code>evcc -v</code>:
```
evcc version 0.64 (d2e3c47)

```

<details><summary>Show output of <code>evcc dump -c configfile</code>:</summary><br><pre>
config
======

grid: grid
----------
Power:          11331W
Current L1..L3: 16.4A 16.4A 16.9A

loadpoint 1
===========

charger: Einfahrt
-----------------
Power:          10670W
Energy:         996.1kWh
Current L1..L3: 15.7A 15.7A 15.6A
Charge status:  C
Enabled:        true
Duration:       5m38s
Identifier:     xxxxx

vehicle 0
---------
.SoC:          38%
Charge status: C
Capacity:      88kWh
Range:         148km
Identifier:    xxxxx

vehicle 1
---------
SoC:            100%
Charge status:  B
Capacity:       11kWh
Range:          48km
Finish time:    not available
Climate active: false
Outside temp:   17.1°C
Target temp:    20.0°C
Identifier:     yyyyy

loadpoint 2
===========

charger: Garage
---------------
Power:          0W
Energy:         115.3kWh
Current L1..L3: 0A 0A 0A
Charge status:  B
Enabled:        true
Duration:       22s
Identifier:     yyyyy

vehicle 0
---------
SoC:            100%
Charge status:  B
Capacity:       11kWh
Range:          48km
Finish time:    not available
Climate active: false
Outside temp:   17.1°C
Target temp:    20.0°C
Identifier:     yyyyy

vehicle 1
---------
SoC:           38%
Charge status: C
Capacity:      88kWh
Range:         148km
Identifier:    xxxxx
</pre></details>

<details><summary>Show evcc configuration file <code>evcc.yaml</code>:</summary><br><pre>

interval: 10s # control cycle interval
uri: 0.0.0.0:7070 # uri for ui

# log settings
log: error
levels:
  core: debug
  lp-1: debug
  lp-2: debug

# meter definitions
# name can be freely chosen and is used as reference when assigning meters to site and loadpoints
# for examples see https://github.com/andig/evcc-config#meters
meters:
- name: grid
  type: custom
  power: # power reading
    type: mqtt # use mqtt plugin
    topic: mbmd/sdm1-1/Power # mqtt topic
    timeout: 10s # don't use older values
  Currents:
    - type: mqtt # use mqtt plugin
      topic: mbmd/sdm1-1/Current/L1 # mqtt topic
      timeout: 10s # don't use older values
    - type: mqtt # use mqtt plugin
      topic: mbmd/sdm1-1/Current/L2 # mqtt topic
      timeout: 10s # don't use older values
    - type: mqtt # use mqtt plugin
      topic: mbmd/sdm1-1/Current/L3 # mqtt topic
      timeout: 10s # don't use older values

#- name: pv
#  type: ...
#- name: battery
#  type: ...
#- name: charge
#  type: ...

# charger definitions
# name can be freely chosen and is used as reference when assigning charger to vehicle
# for examples see https://github.com/andig/evcc-config#chargers
chargers:
- name: Garage
  type: evsewifi
  uri: http://10.20.1.16
- name: Einfahrt
  type: evsewifi
  uri: http://10.20.1.13

# vehicle definitions
# name can be freely chosen and is used as reference when assigning vehicle to loadpoint
# for examples see https://github.com/andig/evcc-config#vehicles
vehicles:
- name: Cubra
  type: seat
  identifier: yyyyy # RFID token
  title: Cubra Leon
  capacity: 11 # kWh
  user: abc
  password: xxxxx
  vin: xxxxx
  cache: 5m
- type: ford
  name: Mustang
  identifier: xxxxx # RFID token
  title: Mustang Mach-E # display name for UI
  capacity: 88 # kWh
  user: abc
  password: "xxxxx"
  vin: xxxxx # optional
  cache: 5m

# site describes the EVU connection, PV and home battery
site:
  title: Home
  meters:
    grid: grid # grid meter
#    pv: pv # pv meter
#    battery: battery # battery meter
  prioritySoC: 60 # give home battery priority up to this soc (0 to disable)


# loadpoint describes the charger, charge meter and connected vehicle
loadpoints:
- title: Einfahrt
  charger: Einfahrt
  vehicles:
    - Mustang
    - Cubra
  OnIdentify: # set defaults when vehicle is identified
    - xxxxx: # Mustang
        mode: "now" # mode
        targetSoC: 80 # charge to 100%
#        MaxCurrent: 10
#        MinCurrent: 6
    - yyyyy: # Cubra
        mode: "now" # mode
        targetSoC: 100 # charge to 100%
#        MaxCurrent: 16
#        MinCurrent: 6
  mode: "off"
  soc:
    # polling defines usage of the vehicle APIs
    # Modifying the default settings it NOT recommended. It MAY deplete your vehicle's battery
    # or lead to vehicle manufacturer banning you from API use. USE AT YOUR OWN RISK.
    poll:
      # poll mode defines under which condition the vehicle API is called:
      #   charging: update vehicle ONLY when charging (this is the recommended default)
      #   connected: update vehicle when connected (not only charging), interval defines how often
      #   always: always update vehicle regardless of connection state, interval defines how often
      mode: charging
      # poll interval defines how often the vehicle API may be polled if NOT charging
      interval: 60m
    min: 0 # immediately charge to 0% regardless of mode unless "off" (disabled)
    target: 0 # use onDisconnect targetSoC
    estimate: true # set true to interpolate between api updates
  onDisconnect: # set defaults when vehicle disconnects
    mode: "off" # switch back to pv mode
    targetSoC: 100 # charge to 100%
  phases: 3 # ev phases (default 3)
  enable: # pv mode enable behavior
    delay: 1m # threshold must be exceeded for this long
    threshold: 0 # minimum export power (W). If zero, export must exceed minimum charge power to enable
  disable: # pv mode disable behavior
    delay: 10m # threshold must be exceeded for this long
    threshold: 200 # maximum import power (W)
  guardduration: 5m # switch charger contactor not more often than this (default 10m)
  mincurrent: 6 # minimum charge current (default 6A)
  maxcurrent: 16 # maximum charge current (default 16A)
- title: Garage
  charger: Garage
  vehicles:
    - Cubra
    - Mustang
  OnIdentify: # set defaults when vehicle is identified
    - xxxxx: # Mustang
        mode: "now" # mode
        targetSoC: 80 # charge to 100%
#        MaxCurrent: 10
#        MinCurrent: 6
    - yyyyy: # Cubra
        mode: "now" # mode
        targetSoC: 100 # charge to 100%
#        MaxCurrent: 16
#        MinCurrent: 6
  mode: "off"
  soc:
    # polling defines usage of the vehicle APIs
    # Modifying the default settings it NOT recommended. It MAY deplete your vehicle's battery
    # or lead to vehicle manufacturer banning you from API use. USE AT YOUR OWN RISK.
    poll:
      # poll mode defines under which condition the vehicle API is called:
      #   charging: update vehicle ONLY when charging (this is the recommended default)
      #   connected: update vehicle when connected (not only charging), interval defines how often
      #   always: always update vehicle regardless of connection state, interval defines how often
      mode: charging
      # poll interval defines how often the vehicle API may be polled if NOT charging
      interval: 60m
    min: 0 # immediately charge to 0% regardless of mode unless "off" (disabled)
    target: 0 # use onDisconnect targetSoC
    estimate: true # set true to interpolate between api updates
  onDisconnect: # set defaults when vehicle disconnects
    mode: "off" # switch back to pv mode
    targetSoC: 100 # charge to 100%
  phases: 3 # ev phases (default 3)
  enable: # pv mode enable behavior
    delay: 1m # threshold must be exceeded for this long
    threshold: 0 # minimum export power (W). If zero, export must exceed minimum charge power to enable
  disable: # pv mode disable behavior
    delay: 10m # threshold must be exceeded for this long
    threshold: 200 # maximum import power (W)
  guardduration: 5m # switch charger contactor not more often than this (default 10m)
  mincurrent: 6 # minimum charge current (default 6A)
  maxcurrent: 16 # maximum charge current (default 16A)

# mqtt message broker
mqtt:
  broker: 10.20.1.10:1883
  topic: evcc # root topic for publishing, set empty to disable
  user: evcc
  password: xxxxx

# influx database
influx:
  url: http://10.20.1.10:8086
  database: evcc
  user: evcc
  password: xxxxx

# push messages
messaging:
  events:
    start: # charge start event
      title: Charge started
      msg: Started charging in "${mode}" mode
    stop: # charge stop event
      title: Charge finished
      msg: Finished charging ${chargedEnergy:%.1fk}kWh in ${chargeDuration}.
    connect: # vehicle connect event
      title: Car connected
      msg: "Car connected at ${pvPower:%.1fk}kW PV"
    disconnect: # vehicle connected event
      title: Car disconnected
      msg: Car disconnected after ${connectedDuration}
  services:
  # - type: pushover
  #   app: # app id
  #   recipients:
  #   - # list of recipient ids
  # - type: telegram
  #   token: # bot id
  #   chats:
  #   - # list of chat ids
  # - type: email
  #   uri: smtp://<user>:<password>@<host>:<port>/?fromAddress=<from>&toAddresses=<to>


</pre></details>

<details><summary>Show evcc log output with <code>--log debug</code>:</summary><br><pre>
[main  ] INFO 2021/09/26 18:26:56 evcc 0.64 (d2e3c47)
[main  ] INFO 2021/09/26 18:26:56 using config file /etc/evcc.yaml
[main  ] INFO 2021/09/26 18:26:56 listening at 0.0.0.0:7070
[mqtt  ] INFO 2021/09/26 18:26:56 connecting evcc-1147694172 at 10.201.1.10:1883
[mqtt  ] DEBUG 2021/09/26 18:26:56 10.201.1.10:1883 connected
[cache ] DEBUG 2021/09/26 18:26:58 title: Einfahrt
[cache ] DEBUG 2021/09/26 18:26:58 minCurrent: 6
[cache ] DEBUG 2021/09/26 18:26:58 maxCurrent: 16
[cache ] DEBUG 2021/09/26 18:26:58 phases: 3
[cache ] DEBUG 2021/09/26 18:26:58 activePhases: 3
[cache ] DEBUG 2021/09/26 18:26:58 hasVehicle: true
[cache ] DEBUG 2021/09/26 18:26:58 mode: off
[cache ] DEBUG 2021/09/26 18:26:58 targetSoC: 100
[cache ] DEBUG 2021/09/26 18:26:58 minSoC: 0
[cache ] DEBUG 2021/09/26 18:26:58 title: Garage
[cache ] DEBUG 2021/09/26 18:26:58 minCurrent: 6
[cache ] DEBUG 2021/09/26 18:26:58 maxCurrent: 16
[cache ] DEBUG 2021/09/26 18:26:58 phases: 3
[cache ] DEBUG 2021/09/26 18:26:58 activePhases: 3
[cache ] DEBUG 2021/09/26 18:26:58 hasVehicle: true
[cache ] DEBUG 2021/09/26 18:26:58 mode: off
[cache ] DEBUG 2021/09/26 18:26:58 targetSoC: 100
[cache ] DEBUG 2021/09/26 18:26:58 minSoC: 0
[lp-2  ] DEBUG 2021/09/26 18:26:59 max charge current: 6A
[site  ] INFO 2021/09/26 18:26:59 site config:
[site  ] INFO 2021/09/26 18:26:59   meters:    grid ✓ pv ✗ battery ✗
[cache ] DEBUG 2021/09/26 18:26:59 siteTitle: Home
[cache ] DEBUG 2021/09/26 18:26:59 chargeCurrent: 6
[site  ] INFO 2021/09/26 18:26:59     grid:    power ✓ energy ✗ currents ✓
[cache ] DEBUG 2021/09/26 18:26:59 gridConfigured: true
[cache ] DEBUG 2021/09/26 18:26:59 pvConfigured: false
[cache ] DEBUG 2021/09/26 18:26:59 batteryConfigured: false
[lp-1  ] INFO 2021/09/26 18:26:59 loadpoint 1:
[lp-1  ] INFO 2021/09/26 18:26:59   mode:      off
[lp-1  ] INFO 2021/09/26 18:26:59   charger:   power ✓ energy ✓ currents ✓ timer ✓
[lp-1  ] INFO 2021/09/26 18:26:59   meters:    charge ✓
[lp-1  ] INFO 2021/09/26 18:26:59     charge:  power ✓ energy ✓ currents ✓
[lp-1  ] INFO 2021/09/26 18:26:59   vehicles:  ✓
[lp-1  ] INFO 2021/09/26 18:26:59     car 0:   range ✓ finish ✗ status ✓ climate ✗
[lp-1  ] INFO 2021/09/26 18:26:59     car 1:   range ✓ finish ✓ status ✓ climate ✓
[lp-2  ] INFO 2021/09/26 18:26:59 loadpoint 2:
[lp-2  ] INFO 2021/09/26 18:26:59   mode:      off
[lp-2  ] INFO 2021/09/26 18:26:59   charger:   power ✓ energy ✓ currents ✓ timer ✓
[lp-2  ] INFO 2021/09/26 18:26:59   meters:    charge ✓
[lp-2  ] INFO 2021/09/26 18:26:59     charge:  power ✓ energy ✓ currents ✓
[lp-2  ] INFO 2021/09/26 18:26:59   vehicles:  ✓
[lp-2  ] INFO 2021/09/26 18:26:59     car 0:   range ✓ finish ✓ status ✓ climate ✓
[lp-2  ] INFO 2021/09/26 18:26:59     car 1:   range ✓ finish ✗ status ✓ climate ✗
[cache ] DEBUG 2021/09/26 18:26:59 chargeConfigured: true
[cache ] DEBUG 2021/09/26 18:26:59 chargeConfigured: true
[site  ] DEBUG 2021/09/26 18:26:59 ----
[site  ] DEBUG 2021/09/26 18:26:59 grid power: 572W
[site  ] DEBUG 2021/09/26 18:26:59 grid currents: [0.844 0.485 1.31]A
[site  ] DEBUG 2021/09/26 18:26:59 site power: 572W
[cache ] DEBUG 2021/09/26 18:26:59 gridPower: 571.676
[cache ] DEBUG 2021/09/26 18:26:59 gridCurrents: [0.844 0.485 1.309]
[cache ] DEBUG 2021/09/26 18:26:59 mode: off
[lp-1  ] DEBUG 2021/09/26 18:26:59 charge power: 0W
[cache ] DEBUG 2021/09/26 18:26:59 chargePower: 0
[lp-1  ] DEBUG 2021/09/26 18:26:59 charge currents: [0 0 0]A
[cache ] DEBUG 2021/09/26 18:26:59 chargeCurrents: [0 0 0]
[cache ] DEBUG 2021/09/26 18:26:59 chargeCurrent: 0
[cache ] DEBUG 2021/09/26 18:26:59 chargedEnergy: 0
[cache ] DEBUG 2021/09/26 18:26:59 chargeDuration: 9s
[lp-1  ] DEBUG 2021/09/26 18:26:59 charger status: B
[cache ] DEBUG 2021/09/26 18:26:59 connectedDuration: 0s
[cache ] DEBUG 2021/09/26 18:26:59 chargeCurrent: 0
[cache ] DEBUG 2021/09/26 18:26:59 connected: true
[cache ] DEBUG 2021/09/26 18:26:59 charging: false
[cache ] DEBUG 2021/09/26 18:26:59 enabled: false
[lp-1  ] DEBUG 2021/09/26 18:26:59 charger vehicle id: yyyyy
[lp-1  ] INFO 2021/09/26 18:26:59 vehicle updated: unknown -> Mustang Mach-E
[cache ] DEBUG 2021/09/26 18:26:59 vehicleIdentity: yyyyy
[lp-1  ] DEBUG 2021/09/26 18:26:59 running vehicle action: {now 80}
[lp-1  ] INFO 2021/09/26 18:26:59 set charge mode: now
[cache ] DEBUG 2021/09/26 18:26:59 vehiclePresent: true
[cache ] DEBUG 2021/09/26 18:26:59 vehicleTitle: Mustang Mach-E
[cache ] DEBUG 2021/09/26 18:26:59 vehicleCapacity: 88
[lp-1  ] INFO 2021/09/26 18:26:59 set target soc: 80
[cache ] DEBUG 2021/09/26 18:26:59 mode: now
[cache ] DEBUG 2021/09/26 18:26:59 targetSoC: 80
[ford  ] DEBUG 2021/09/26 18:27:00 vehicle status is outdated (age 35m15.527285314s > 5m0s), requesting refresh
[lp-1  ] ERROR 2021/09/26 18:27:01 vehicle status: must retry
[lp-1  ] DEBUG 2021/09/26 18:27:01 vehicle status: B (Cubra Leon)
[lp-1  ] INFO 2021/09/26 18:27:01 vehicle updated: Mustang Mach-E -> Cubra Leon
[lp-1  ] DEBUG 2021/09/26 18:27:01 vehicle soc: 100%
[cache ] DEBUG 2021/09/26 18:27:01 vehiclePresent: true
[cache ] DEBUG 2021/09/26 18:27:01 vehicleTitle: Cubra Leon
[cache ] DEBUG 2021/09/26 18:27:01 vehicleCapacity: 11
[cache ] DEBUG 2021/09/26 18:27:01 vehicleSoc: 100
[lp-1  ] DEBUG 2021/09/26 18:27:01 vehicle range: 48km
[cache ] DEBUG 2021/09/26 18:27:01 chargeRemainingDuration: -1ns
[cache ] DEBUG 2021/09/26 18:27:01 range: 48
[lp-1  ] DEBUG 2021/09/26 18:27:01 targetSoC reached: 100.0 > 80
[lp-1  ] DEBUG 2021/09/26 18:27:01 climater active: false, target temp: 20.0°C, outside temp: 17.1°C
[site  ] DEBUG 2021/09/26 18:27:01 ----
[site  ] DEBUG 2021/09/26 18:27:01 grid power: 546W
[site  ] DEBUG 2021/09/26 18:27:01 grid currents: [0.754 0.486 1.31]A
[site  ] DEBUG 2021/09/26 18:27:01 site power: 546W
[cache ] DEBUG 2021/09/26 18:27:01 gridPower: 545.945
[cache ] DEBUG 2021/09/26 18:27:01 gridCurrents: [0.754 0.486 1.311]
[cache ] DEBUG 2021/09/26 18:27:01 climater: off
[cache ] DEBUG 2021/09/26 18:27:01 mode: now
[lp-1  ] DEBUG 2021/09/26 18:27:01 charge power: 0W
[cache ] DEBUG 2021/09/26 18:27:01 chargePower: 0
[lp-1  ] DEBUG 2021/09/26 18:27:01 charge currents: [0 0 0]A
[cache ] DEBUG 2021/09/26 18:27:01 chargeCurrents: [0 0 0]
[cache ] DEBUG 2021/09/26 18:27:01 chargeCurrent: 0
[cache ] DEBUG 2021/09/26 18:27:01 chargedEnergy: 0
[cache ] DEBUG 2021/09/26 18:27:01 chargeDuration: 9s
[lp-1  ] DEBUG 2021/09/26 18:27:01 charger status: B
[cache ] DEBUG 2021/09/26 18:27:01 connected: true
[cache ] DEBUG 2021/09/26 18:27:01 charging: false
[cache ] DEBUG 2021/09/26 18:27:01 enabled: false
[lp-1  ] ERROR 2021/09/26 18:27:01 vehicle status: must retry
[lp-1  ] DEBUG 2021/09/26 18:27:01 vehicle status: B (Cubra Leon)
[lp-1  ] DEBUG 2021/09/26 18:27:01 targetSoC reached: 100.0 > 80
[lp-1  ] DEBUG 2021/09/26 18:27:01 climater active: false, target temp: 20.0°C, outside temp: 17.1°C
[cache ] DEBUG 2021/09/26 18:27:01 climater: off
[site  ] DEBUG 2021/09/26 18:27:09 ----
[site  ] DEBUG 2021/09/26 18:27:09 grid power: 617W
[site  ] DEBUG 2021/09/26 18:27:09 grid currents: [0.946 0.484 1.3]A
[cache ] DEBUG 2021/09/26 18:27:09 gridPower: 617.172
[cache ] DEBUG 2021/09/26 18:27:09 gridCurrents: [0.946 0.484 1.304]
[site  ] DEBUG 2021/09/26 18:27:09 site power: 617W
[cache ] DEBUG 2021/09/26 18:27:09 mode: off
[lp-2  ] DEBUG 2021/09/26 18:27:09 charge power: 0W
[cache ] DEBUG 2021/09/26 18:27:09 chargePower: 0
[lp-2  ] DEBUG 2021/09/26 18:27:09 charge currents: [0 0 0]A
[cache ] DEBUG 2021/09/26 18:27:09 chargeCurrents: [0 0 0]
[cache ] DEBUG 2021/09/26 18:27:09 chargeCurrent: 6
[cache ] DEBUG 2021/09/26 18:27:09 chargedEnergy: 0
[cache ] DEBUG 2021/09/26 18:27:09 chargeDuration: 21s
[lp-2  ] DEBUG 2021/09/26 18:27:10 charger status: B
[cache ] DEBUG 2021/09/26 18:27:10 connectedDuration: 0s
[cache ] DEBUG 2021/09/26 18:27:10 chargeCurrent: 6
[cache ] DEBUG 2021/09/26 18:27:10 connected: true
[cache ] DEBUG 2021/09/26 18:27:10 charging: false
[cache ] DEBUG 2021/09/26 18:27:10 enabled: true
[lp-2  ] DEBUG 2021/09/26 18:27:10 charger vehicle id: xxxxx
[lp-2  ] INFO 2021/09/26 18:27:10 vehicle updated: unknown -> Cubra Leon
[lp-2  ] DEBUG 2021/09/26 18:27:10 running vehicle action: {now 100}
[lp-2  ] INFO 2021/09/26 18:27:10 set charge mode: now
[cache ] DEBUG 2021/09/26 18:27:10 vehicleIdentity: xxxxx
[cache ] DEBUG 2021/09/26 18:27:10 vehiclePresent: true
[cache ] DEBUG 2021/09/26 18:27:10 vehicleTitle: Cubra Leon
[cache ] DEBUG 2021/09/26 18:27:10 vehicleCapacity: 11
[cache ] DEBUG 2021/09/26 18:27:10 mode: now
[lp-2  ] INFO 2021/09/26 18:27:10 set target soc: 100
[lp-2  ] DEBUG 2021/09/26 18:27:10 vehicle status: B (Cubra Leon)
[lp-2  ] ERROR 2021/09/26 18:27:10 vehicle status: must retry
[lp-2  ] DEBUG 2021/09/26 18:27:10 vehicle soc: 100%
[cache ] DEBUG 2021/09/26 18:27:10 vehicleSoc: 100
[cache ] DEBUG 2021/09/26 18:27:10 chargeRemainingDuration: -1ns
[lp-2  ] DEBUG 2021/09/26 18:27:10 vehicle range: 48km
[cache ] DEBUG 2021/09/26 18:27:10 range: 48
[lp-2  ] DEBUG 2021/09/26 18:27:10 charger disable
[site  ] DEBUG 2021/09/26 18:27:11 ----
[site  ] DEBUG 2021/09/26 18:27:11 grid power: 578W
[cache ] DEBUG 2021/09/26 18:27:11 chargeCurrent: 0
[cache ] DEBUG 2021/09/26 18:27:11 gridPower: 577.594
[site  ] DEBUG 2021/09/26 18:27:11 grid currents: [0.881 0.484 1.3]A
[site  ] DEBUG 2021/09/26 18:27:11 site power: 578W
[cache ] DEBUG 2021/09/26 18:27:11 gridCurrents: [0.881 0.484 1.304]
[cache ] DEBUG 2021/09/26 18:27:11 mode: now
[lp-2  ] DEBUG 2021/09/26 18:27:11 charge power: 0W
[cache ] DEBUG 2021/09/26 18:27:11 chargePower: 0
[lp-2  ] DEBUG 2021/09/26 18:27:11 charge currents: [0 0 0]A
[cache ] DEBUG 2021/09/26 18:27:11 chargeCurrents: [0 0 0]
[cache ] DEBUG 2021/09/26 18:27:11 chargeCurrent: 0
[cache ] DEBUG 2021/09/26 18:27:11 chargedEnergy: 0
[cache ] DEBUG 2021/09/26 18:27:11 chargeDuration: 21s
[lp-2  ] DEBUG 2021/09/26 18:27:11 charger status: B
[cache ] DEBUG 2021/09/26 18:27:11 connected: true
[cache ] DEBUG 2021/09/26 18:27:11 charging: false
[cache ] DEBUG 2021/09/26 18:27:11 enabled: false
[lp-2  ] DEBUG 2021/09/26 18:27:11 vehicle status: B (Cubra Leon)
[lp-2  ] ERROR 2021/09/26 18:27:11 vehicle status: must retry
[lp-2  ] WARN 2021/09/26 18:27:11 charger out of sync: expected disabled, got enabled
[lp-2  ] DEBUG 2021/09/26 18:27:11 max charge current: 16A
[lp-2  ] DEBUG 2021/09/26 18:27:11 charger enable
[cache ] DEBUG 2021/09/26 18:27:11 chargeCurrent: 0
[cache ] DEBUG 2021/09/26 18:27:11 chargeCurrent: 16
[site  ] DEBUG 2021/09/26 18:27:19 ----
[site  ] DEBUG 2021/09/26 18:27:19 grid power: 652W
[site  ] DEBUG 2021/09/26 18:27:19 grid currents: [2.54 0.479 1.3]A
[site  ] DEBUG 2021/09/26 18:27:19 site power: 652W
[cache ] DEBUG 2021/09/26 18:27:19 gridPower: 651.77
[cache ] DEBUG 2021/09/26 18:27:19 gridCurrents: [2.536 0.479 1.302]
[cache ] DEBUG 2021/09/26 18:27:19 mode: now
[lp-1  ] DEBUG 2021/09/26 18:27:19 charge power: 0W
[cache ] DEBUG 2021/09/26 18:27:19 chargePower: 0
[lp-1  ] DEBUG 2021/09/26 18:27:19 charge currents: [0 0 0]A
[cache ] DEBUG 2021/09/26 18:27:19 chargeCurrents: [0 0 0]
[cache ] DEBUG 2021/09/26 18:27:19 chargeCurrent: 0
[cache ] DEBUG 2021/09/26 18:27:19 chargedEnergy: 0
[cache ] DEBUG 2021/09/26 18:27:19 chargeDuration: 9s
[lp-1  ] DEBUG 2021/09/26 18:27:19 charger status: B
[cache ] DEBUG 2021/09/26 18:27:19 connected: true
[cache ] DEBUG 2021/09/26 18:27:19 charging: false
[cache ] DEBUG 2021/09/26 18:27:19 enabled: false
[lp-1  ] ERROR 2021/09/26 18:27:19 vehicle status: must retry
[lp-1  ] INFO 2021/09/26 18:27:19 vehicle updated: Cubra Leon -> unknown
[cache ] DEBUG 2021/09/26 18:27:19 vehiclePresent: false
[cache ] DEBUG 2021/09/26 18:27:19 vehicleTitle: 
[cache ] DEBUG 2021/09/26 18:27:19 vehicleCapacity: 0
[cache ] DEBUG 2021/09/26 18:27:19 vehicleOdometer: 0
[lp-1  ] DEBUG 2021/09/26 18:27:19 max charge current: 16A
[lp-1  ] DEBUG 2021/09/26 18:27:19 charger enable
[cache ] DEBUG 2021/09/26 18:27:19 chargeCurrent: 0
[cache ] DEBUG 2021/09/26 18:27:19 chargeCurrent: 16
[site  ] DEBUG 2021/09/26 18:27:29 ----
[site  ] DEBUG 2021/09/26 18:27:29 grid power: 550W
[site  ] DEBUG 2021/09/26 18:27:29 grid currents: [1.56 0.787 1.38]A
[site  ] DEBUG 2021/09/26 18:27:29 site power: 550W
[cache ] DEBUG 2021/09/26 18:27:29 gridPower: 550.329
[cache ] DEBUG 2021/09/26 18:27:29 gridCurrents: [1.559 0.787 1.38]
[cache ] DEBUG 2021/09/26 18:27:29 mode: now
[lp-2  ] DEBUG 2021/09/26 18:27:29 charge power: 10W
[cache ] DEBUG 2021/09/26 18:27:29 chargePower: 10
[lp-2  ] DEBUG 2021/09/26 18:27:29 charge currents: [0.472 0 0]A
[cache ] DEBUG 2021/09/26 18:27:29 chargeCurrents: [0.472092 0 0]
[cache ] DEBUG 2021/09/26 18:27:29 chargeCurrent: 16
[cache ] DEBUG 2021/09/26 18:27:29 chargedEnergy: 0
[cache ] DEBUG 2021/09/26 18:27:29 chargeDuration: 9s
[lp-2  ] DEBUG 2021/09/26 18:27:30 charger status: C
[lp-2  ] DEBUG 2021/09/26 18:27:30 charge start energy: 115kWh
[lp-2  ] INFO 2021/09/26 18:27:30 start charging ->
[cache ] DEBUG 2021/09/26 18:27:30 chargeCurrent: 16
[cache ] DEBUG 2021/09/26 18:27:30 connected: true
[cache ] DEBUG 2021/09/26 18:27:30 charging: true
[cache ] DEBUG 2021/09/26 18:27:30 enabled: true
[lp-2  ] DEBUG 2021/09/26 18:27:30 vehicle status: B (Cubra Leon)
[lp-2  ] DEBUG 2021/09/26 18:27:30 vehicle status: B (Mustang Mach-E)
[lp-2  ] DEBUG 2021/09/26 18:27:30 vehicle status: >1 matches, giving up
[lp-2  ] INFO 2021/09/26 18:27:30 vehicle updated: Cubra Leon -> unknown
[cache ] DEBUG 2021/09/26 18:27:30 vehiclePresent: false
[cache ] DEBUG 2021/09/26 18:27:30 vehicleTitle: 
[cache ] DEBUG 2021/09/26 18:27:30 vehicleCapacity: 0
[cache ] DEBUG 2021/09/26 18:27:30 vehicleOdometer: 0
[site  ] DEBUG 2021/09/26 18:27:39 ----
[site  ] DEBUG 2021/09/26 18:27:39 grid power: 2247W
[site  ] DEBUG 2021/09/26 18:27:39 grid currents: [3.64 2.96 3.64]A
[site  ] DEBUG 2021/09/26 18:27:39 site power: 2247W
[cache ] DEBUG 2021/09/26 18:27:39 gridPower: 2247.225
[cache ] DEBUG 2021/09/26 18:27:39 gridCurrents: [3.644 2.959 3.643]
[cache ] DEBUG 2021/09/26 18:27:39 mode: now
[lp-1  ] DEBUG 2021/09/26 18:27:39 charge power: 1860W
[cache ] DEBUG 2021/09/26 18:27:39 chargePower: 1860
[lp-1  ] DEBUG 2021/09/26 18:27:39 charge currents: [2.89 2.87 2.86]A
[cache ] DEBUG 2021/09/26 18:27:39 chargeCurrents: [2.894532 2.872127 2.857533]
[cache ] DEBUG 2021/09/26 18:27:39 chargeCurrent: 16
[cache ] DEBUG 2021/09/26 18:27:39 chargedEnergy: 0
[cache ] DEBUG 2021/09/26 18:27:39 chargeDuration: 13s
[lp-1  ] DEBUG 2021/09/26 18:27:39 charger status: C
[lp-1  ] DEBUG 2021/09/26 18:27:39 charge start energy: 995kWh
[lp-1  ] INFO 2021/09/26 18:27:39 start charging ->
[cache ] DEBUG 2021/09/26 18:27:39 chargeCurrent: 16
[cache ] DEBUG 2021/09/26 18:27:39 connected: true
[cache ] DEBUG 2021/09/26 18:27:39 charging: true
[cache ] DEBUG 2021/09/26 18:27:39 enabled: true
[lp-1  ] DEBUG 2021/09/26 18:27:39 vehicle status: B (Mustang Mach-E)
[lp-1  ] DEBUG 2021/09/26 18:27:39 vehicle status: B (Cubra Leon)
[lp-1  ] DEBUG 2021/09/26 18:27:39 vehicle status: >1 matches, giving up
[site  ] DEBUG 2021/09/26 18:27:49 ----
[site  ] DEBUG 2021/09/26 18:27:49 grid power: 5900W
[site  ] DEBUG 2021/09/26 18:27:49 grid currents: [8.8 8.17 8.86]A
[site  ] DEBUG 2021/09/26 18:27:49 site power: 5900W
[cache ] DEBUG 2021/09/26 18:27:49 gridPower: 5899.51
[cache ] DEBUG 2021/09/26 18:27:49 gridCurrents: [8.798 8.167 8.856]
[cache ] DEBUG 2021/09/26 18:27:49 mode: now
[lp-2  ] DEBUG 2021/09/26 18:27:49 charge power: 0W
[cache ] DEBUG 2021/09/26 18:27:49 chargePower: 0
[lp-2  ] DEBUG 2021/09/26 18:27:49 charge currents: [0 0 0]A
[cache ] DEBUG 2021/09/26 18:27:49 chargeCurrents: [0 0 0]
[cache ] DEBUG 2021/09/26 18:27:49 chargeCurrent: 16
[cache ] DEBUG 2021/09/26 18:27:50 chargedEnergy: 0
[cache ] DEBUG 2021/09/26 18:27:50 chargeDuration: 22s
[lp-2  ] DEBUG 2021/09/26 18:27:50 charger status: B
[lp-2  ] DEBUG 2021/09/26 18:27:51 final charge energy: 0kWh
[lp-2  ] INFO 2021/09/26 18:27:51 stop charging <-
[cache ] DEBUG 2021/09/26 18:27:51 chargeCurrent: 16
[cache ] DEBUG 2021/09/26 18:27:51 connected: true
[cache ] DEBUG 2021/09/26 18:27:51 charging: false
[cache ] DEBUG 2021/09/26 18:27:51 enabled: true
[lp-2  ] DEBUG 2021/09/26 18:27:51 vehicle status: B (Cubra Leon)
[lp-2  ] DEBUG 2021/09/26 18:27:51 vehicle status: B (Mustang Mach-E)
[lp-2  ] DEBUG 2021/09/26 18:27:51 vehicle status: >1 matches, giving up

</pre></details>

**If using Docker:**
Show output of <code>docker run andig/evcc -v</code>:
```
evcc version 0.64 (d2e3c47)

```

<details><summary>Show evcc log output with <code>docker logs <container id></code>:</summary><br><pre>


</pre></details>


Pull request description:
Improve vehicle identification experience
- allow multiple identifiers per vehicle to support RFID and MAC ~~and VIN~~ across multiple chargers
- ~~add `VIN` as default identifier~~
- move `onIdentify` action config from loadpoint to vehicle
- add `minSoC` to action config
- replace `onDisconnect` with simpler `resetOnDisconnect`

Fix #1636, fix https://github.com/evcc-io/evcc/issues/1891, fix https://github.com/evcc-io/evcc/issues/1893

/cc @chris591 @xerion @bicaluv 

Patch:
diff --git a/api/api.go b/api/api.go
index b03d2964..fe7f8818 100644
--- a/api/api.go
+++ b/api/api.go
@@ -40,6 +40,15 @@ func (c ChargeStatus) String() string {
 	return string(c)
 }
 
+// ActionConfig defines an action to take on event
+type ActionConfig struct {
+	Mode       ChargeMode `mapstructure:"mode"`       // Charge mode
+	MinCurrent float64    `mapstructure:"minCurrent"` // Minimum Current
+	MaxCurrent float64    `mapstructure:"maxCurrent"` // Maximum Current
+	MinSoC     int        `mapstructure:"minSoC"`     // Minimum SoC
+	TargetSoC  int        `mapstructure:"targetSoC"`  // Target SoC
+}
+
 // Meter is able to provide current power in W
 type Meter interface {
 	CurrentPower() (float64, error)
@@ -111,9 +120,10 @@ type Authorizer interface {
 // Vehicle represents the EV and it's battery
 type Vehicle interface {
 	Battery
-	Identifier
 	Title() string
 	Capacity() int64
+	Identifiers() []string
+	OnIdentified() ActionConfig
 }
 
 // VehicleFinishTimer provides estimated charge cycle finish time
diff --git a/cmd/dumper.go b/cmd/dumper.go
index 9bfc7499..72340180 100644
--- a/cmd/dumper.go
+++ b/cmd/dumper.go
@@ -179,6 +179,7 @@ func (d *dumper) Dump(name string, v interface{}) {
 
 	if v, ok := v.(api.Vehicle); ok {
 		fmt.Fprintf(w, "Capacity:\t%dkWh\n", v.Capacity())
+		fmt.Fprintf(w, "Identifiers:\t%v\n", v.Identifiers())
 	}
 
 	w.Flush()
diff --git a/core/loadpoint.go b/core/loadpoint.go
index 2679c99f..db3114ca 100644
--- a/core/loadpoint.go
+++ b/core/loadpoint.go
@@ -16,6 +16,7 @@ import (
 	"github.com/evcc-io/evcc/provider"
 	"github.com/evcc-io/evcc/push"
 	"github.com/evcc-io/evcc/util"
+	"github.com/thoas/go-funk"
 
 	evbus "github.com/asaskevich/EventBus"
 	"github.com/avast/retry-go/v3"
@@ -65,12 +66,6 @@ type ThresholdConfig struct {
 	Threshold float64
 }
 
-// ActionConfig defines an action to take on event
-type ActionConfig struct {
-	Mode      api.ChargeMode `mapstructure:"mode"`      // Charge mode to apply when car disconnected
-	TargetSoC int            `mapstructure:"targetSoC"` // Target SoC to apply when car disconnected
-}
-
 // LoadPoint is responsible for controlling charge depending on
 // SoC needs and power availability.
 type LoadPoint struct {
@@ -93,10 +88,12 @@ type LoadPoint struct {
 	Meters      struct {
 		ChargeMeterRef string `mapstructure:"charge"` // Charge meter reference
 	}
-	SoC             SoCConfig
-	OnDisconnect    ActionConfig            `mapstructure:"onDisconnect"`
-	OnIdentify      map[string]ActionConfig `mapstructure:"onIdentify"`
-	Enable, Disable ThresholdConfig
+	SoC               SoCConfig
+	OnDisconnect_     interface{} `mapstructure:"onDisconnect"`
+	OnIdentify_       interface{} `mapstructure:"onIdentify"`
+	Enable, Disable   ThresholdConfig
+	ResetOnDisconnect bool `mapstructure:"resetOnDisconnect"`
+	onDisconnect      api.ActionConfig
 
 	MinCurrent    float64       // PV mode: start current	Min+PV mode: min current
 	MaxCurrent    float64       // Max allowed current. Physically ensured by the charger
@@ -157,6 +154,14 @@ func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[strin
 		lp.SoC.Poll.Mode = pollConnected
 	}
 
+	if lp.OnIdentify_ != nil {
+		lp.log.WARN.Printf("loadpoint.onIdentify is deprecated and will be removed in a future release. Use vehicle.onIdentify instead.")
+	}
+
+	if lp.OnDisconnect_ != nil {
+		lp.log.WARN.Printf("loadpoint.onDisconnect is deprecated and will be removed in a future release. Use loadpoint.resetOnDisconnect instead.")
+	}
+
 	// set vehicle polling interval
 	if lp.SoC.Poll.Interval < pollInterval {
 		if lp.SoC.Poll.Interval == 0 {
@@ -167,7 +172,7 @@ func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[strin
 	}
 
 	if lp.SoC.Target == 0 {
-		lp.SoC.Target = lp.OnDisconnect.TargetSoC // use disconnect value as default soc
+		lp.SoC.Target = lp.onDisconnect.TargetSoC // use disconnect value as default soc
 		if lp.SoC.Target == 0 {
 			lp.SoC.Target = 100
 		}
@@ -181,6 +186,9 @@ func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[strin
 		lp.log.WARN.Println("maxCurrent must be larger than minCurrent")
 	}
 
+	// store defaults
+	lp.collectDefaults()
+
 	if lp.Meters.ChargeMeterRef != "" {
 		lp.chargeMeter = cp.Meter(lp.Meters.ChargeMeterRef)
 	}
@@ -242,6 +250,17 @@ func NewLoadPoint(log *util.Logger) *LoadPoint {
 	return lp
 }
 
+// collectDefaults collects default values for use on disconnect
+func (lp *LoadPoint) collectDefaults() {
+	lp.onDisconnect = api.ActionConfig{
+		Mode:       lp.GetMode(),
+		MinCurrent: lp.GetMinCurrent(),
+		MaxCurrent: lp.GetMaxCurrent(),
+		MinSoC:     lp.GetMinSoC(),
+		TargetSoC:  lp.GetTargetSoC(),
+	}
+}
+
 // requestUpdate requests site to update this loadpoint
 func (lp *LoadPoint) requestUpdate() {
 	select {
@@ -367,7 +386,9 @@ func (lp *LoadPoint) evVehicleDisconnectHandler() {
 	}
 
 	// set default mode on disconnect
-	lp.applyAction(lp.OnDisconnect)
+	if lp.ResetOnDisconnect {
+		lp.applyAction(lp.onDisconnect)
+	}
 
 	// soc update reset
 	lp.socUpdated = time.Time{}
@@ -399,12 +420,29 @@ func (lp *LoadPoint) evChargeCurrentWrappedMeterHandler(current float64) {
 }
 
 // applyAction executes the action
-func (lp *LoadPoint) applyAction(action ActionConfig) {
-	if action.Mode != "" && lp.GetMode() != api.ModeEmpty {
+func (lp *LoadPoint) applyAction(action api.ActionConfig) {
+	if action.Mode != api.ModeEmpty {
 		lp.SetMode(action.Mode)
 	}
+	if action.MinCurrent > 0 {
+		lp.SetMinCurrent(action.MinCurrent)
+	}
+	if action.MaxCurrent > 0 {
+		lp.SetMaxCurrent(action.MaxCurrent)
+	}
+	if action.MinSoC != 0 {
+		// TODO deduplicate with SetMinSoC
+		lp.Lock()
+		lp.SoC.Min = action.MinSoC
+		lp.publish("minSoC", action.MinSoC)
+		lp.Unlock()
+	}
 	if action.TargetSoC != 0 {
-		_ = lp.SetTargetSoC(action.TargetSoC)
+		// TODO deduplicate with SetTargetSoC
+		lp.Lock()
+		lp.SoC.Target = action.TargetSoC
+		lp.publish("targetSoC", action.TargetSoC)
+		lp.Unlock()
 	}
 }
 
@@ -647,11 +685,6 @@ func (lp *LoadPoint) identifyVehicle() {
 		if vehicle := lp.selectVehicleByID(id); vehicle != nil {
 			lp.setActiveVehicle(vehicle)
 		}
-
-		if action, ok := lp.OnIdentify[id]; ok {
-			lp.log.DEBUG.Println("running vehicle action:", action)
-			lp.applyAction(action)
-		}
 	}
 }
 
@@ -659,14 +692,14 @@ func (lp *LoadPoint) identifyVehicle() {
 func (lp *LoadPoint) selectVehicleByID(id string) api.Vehicle {
 	// find exact match
 	for _, vehicle := range lp.vehicles {
-		if vid, err := vehicle.Identify(); err == nil && vid == id {
+		if funk.ContainsString(vehicle.Identifiers(), id) {
 			return vehicle
 		}
 	}
 
 	// find placeholder match
 	for _, vehicle := range lp.vehicles {
-		if vid, err := vehicle.Identify(); err == nil && vid != "" {
+		for _, vid := range vehicle.Identifiers() {
 			re, err := regexp.Compile(strings.ReplaceAll(vid, "*", ".*?"))
 			if err != nil {
 				lp.log.ERROR.Printf("vehicle id: %v", err)
@@ -706,6 +739,8 @@ func (lp *LoadPoint) setActiveVehicle(vehicle api.Vehicle) {
 		lp.publish("vehiclePresent", true)
 		lp.publish("vehicleTitle", lp.vehicle.Title())
 		lp.publish("vehicleCapacity", lp.vehicle.Capacity())
+
+		lp.applyAction(vehicle.OnIdentified())
 	} else {
 		lp.socEstimator = nil
 
@@ -726,7 +761,8 @@ func (lp *LoadPoint) startVehicleDetection() {
 
 // vehicleUnidentified checks if loadpoint has multiple vehicles associated and starts discovery period
 func (lp *LoadPoint) vehicleUnidentified() bool {
-	res := len(lp.vehicles) > 1 && lp.clock.Since(lp.vehicleConnected) < vehicleDetectDuration
+	res := len(lp.vehicles) > 1 && lp.vehicle == nil &&
+		lp.clock.Since(lp.vehicleConnected) < vehicleDetectDuration
 
 	// request vehicle api refresh while waiting to identify
 	if res {
diff --git a/core/loadpoint_api.go b/core/loadpoint_api.go
index 960773f0..de46bc2d 100644
--- a/core/loadpoint_api.go
+++ b/core/loadpoint_api.go
@@ -57,13 +57,13 @@ func (lp *LoadPoint) GetTargetSoC() int {
 
 // SetTargetSoC sets loadpoint charge target soc
 func (lp *LoadPoint) SetTargetSoC(soc int) error {
+	lp.Lock()
+	defer lp.Unlock()
+
 	if lp.vehicle == nil {
 		return api.ErrNotAvailable
 	}
 
-	lp.Lock()
-	defer lp.Unlock()
-
 	lp.log.INFO.Println("set target soc:", soc)
 
 	// apply immediately
@@ -85,13 +85,13 @@ func (lp *LoadPoint) GetMinSoC() int {
 
 // SetMinSoC sets loadpoint charge minimum soc
 func (lp *LoadPoint) SetMinSoC(soc int) error {
+	lp.Lock()
+	defer lp.Unlock()
+
 	if lp.vehicle == nil {
 		return api.ErrNotAvailable
 	}
 
-	lp.Lock()
-	defer lp.Unlock()
-
 	lp.log.INFO.Println("set min soc:", soc)
 
 	// apply immediately
@@ -108,7 +108,6 @@ func (lp *LoadPoint) SetMinSoC(soc int) error {
 func (lp *LoadPoint) GetPhases() int {
 	lp.Lock()
 	defer lp.Unlock()
-
 	return lp.Phases
 }
 
@@ -178,6 +177,8 @@ func (lp *LoadPoint) SetMinCurrent(current float64) {
 	lp.Lock()
 	defer lp.Unlock()
 
+	lp.log.INFO.Println("set min current:", current)
+
 	if current != lp.MinCurrent {
 		lp.MinCurrent = current
 		lp.publish("minCurrent", lp.MinCurrent)
@@ -196,6 +197,8 @@ func (lp *LoadPoint) SetMaxCurrent(current float64) {
 	lp.Lock()
 	defer lp.Unlock()
 
+	lp.log.INFO.Println("set max current:", current)
+
 	if current != lp.MaxCurrent {
 		lp.MaxCurrent = current
 		lp.publish("maxCurrent", lp.MaxCurrent)
diff --git a/evcc.dist.yaml b/evcc.dist.yaml
index bfac9d3f..8166e64a 100644
--- a/evcc.dist.yaml
+++ b/evcc.dist.yaml
@@ -44,14 +44,16 @@ chargers:
 # name can be freely chosen and is used as reference when assigning vehicle to loadpoint
 # for examples see https://github.com/evcc-io/config#vehicles
 vehicles:
-- name: renault
+- name: car1
   type: renault
   title: Zoe
   capacity: 60 # kWh
   user: # user
   password: # password
   vin: WREN...
-  cache: 5m
+  onIdentify: # set defaults when vehicle is identified
+    minSoC: 20 # charge to at least 20% independent of charge mode
+    targetSoC: 90 # limit charge to 90%
 
 # site describes the EVU connection, PV and home battery
 site:
@@ -75,6 +77,7 @@ loadpoints:
   # - ID.3
   # - e-Up
   mode: pv
+  resetOnDisconnect: true # set defaults when vehicle disconnects
   soc:
     # polling defines usage of the vehicle APIs
     # Modifying the default settings it NOT recommended. It MAY deplete your vehicle's battery
@@ -90,13 +93,6 @@ loadpoints:
     min: 0 # immediately charge to 0% regardless of mode unless "off" (disabled)
     target: 100 # always charge to 100%
     estimate: false # set true to interpolate between api updates
-  onDisconnect: # set defaults when vehicle disconnects
-    mode: pv # switch back to pv mode
-    targetSoC: 100 # charge to 100%
-  onIdentify: # set defaults when vehicle is identified
-  - e-Up:
-      mode: pv # switch back to pv mode
-      targetSoC: 100 # charge to 100%
   phases: 3 # ev phases (default 3)
   enable: # pv mode enable behavior
     delay: 1m # threshold must be exceeded for this long
diff --git a/go.mod b/go.mod
index b474227f..a4c72b7f 100644
--- a/go.mod
+++ b/go.mod
@@ -59,7 +59,7 @@ require (
 	github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da
 	github.com/olekukonko/tablewriter v0.0.5
 	github.com/onsi/ginkgo v1.16.4 // indirect
-	github.com/philippseith/signalr v0.5.0
+	github.com/philippseith/signalr v0.5.1-0.20211118093900-e50db63c7d31
 	github.com/prometheus/client_golang v1.11.0
 	github.com/prometheus/common v0.29.0 // indirect
 	github.com/prometheus/procfs v0.7.1 // indirect
diff --git a/go.sum b/go.sum
index fb32e5e3..7413cef5 100644
--- a/go.sum
+++ b/go.sum
@@ -540,8 +540,8 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv
 github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
 github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/peterbourgon/ff v1.2.0/go.mod h1:ljiF7yxtUvZaxUDyUqQa0+uiEOgwVboj+Q2S2+0nq40=
-github.com/philippseith/signalr v0.5.0 h1:/fm4xZZi4+RmnLeaH4Yro5IonTgGIt3wi2zOXb8TknI=
-github.com/philippseith/signalr v0.5.0/go.mod h1:lvHqx1JLduRcRHqWiDX6u/LHtSsfb08g+e+QP/B2gTA=
+github.com/philippseith/signalr v0.5.1-0.20211118093900-e50db63c7d31 h1:Zsy7b533DquoHODY0w59Vxylz37TLEcymgKdbALYCpM=
+github.com/philippseith/signalr v0.5.1-0.20211118093900-e50db63c7d31/go.mod h1:lvHqx1JLduRcRHqWiDX6u/LHtSsfb08g+e+QP/B2gTA=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
diff --git a/mock/mock_api.go b/mock/mock_api.go
index 833ca77e..60e518c1 100644
--- a/mock/mock_api.go
+++ b/mock/mock_api.go
@@ -318,19 +318,32 @@ func (mr *MockVehicleMockRecorder) Capacity() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Capacity", reflect.TypeOf((*MockVehicle)(nil).Capacity))
 }
 
-// Identify mocks base method.
-func (m *MockVehicle) Identify() (string, error) {
+// Identifiers mocks base method.
+func (m *MockVehicle) Identifiers() []string {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Identify")
-	ret0, _ := ret[0].(string)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
+	ret := m.ctrl.Call(m, "Identifiers")
+	ret0, _ := ret[0].([]string)
+	return ret0
 }
 
-// Identify indicates an expected call of Identify.
-func (mr *MockVehicleMockRecorder) Identify() *gomock.Call {
+// Identifiers indicates an expected call of Identifiers.
+func (mr *MockVehicleMockRecorder) Identifiers() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Identifiers", reflect.TypeOf((*MockVehicle)(nil).Identifiers))
+}
+
+// OnIdentified mocks base method.
+func (m *MockVehicle) OnIdentified() api.ActionConfig {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "OnIdentified")
+	ret0, _ := ret[0].(api.ActionConfig)
+	return ret0
+}
+
+// OnIdentified indicates an expected call of OnIdentified.
+func (mr *MockVehicleMockRecorder) OnIdentified() *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Identify", reflect.TypeOf((*MockVehicle)(nil).Identify))
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnIdentified", reflect.TypeOf((*MockVehicle)(nil).OnIdentified))
 }
 
 // SoC mocks base method.
diff --git a/vehicle/embed.go b/vehicle/embed.go
new file mode 100644
index 00000000..bfc878eb
--- /dev/null
+++ b/vehicle/embed.go
@@ -0,0 +1,30 @@
+package vehicle
+
+import "github.com/evcc-io/evcc/api"
+
+type embed struct {
+	Title_       string           `mapstructure:"title"`
+	Capacity_    int64            `mapstructure:"capacity"`
+	Identifiers_ []string         `mapstructure:"identifiers"`
+	OnIdentify   api.ActionConfig `mapstructure:"onIdentify"`
+}
+
+// Title implements the api.Vehicle interface
+func (v *embed) Title() string {
+	return v.Title_
+}
+
+// Capacity implements the api.Vehicle interface
+func (v *embed) Capacity() int64 {
+	return v.Capacity_
+}
+
+// Identifiers implements the api.Identifier interface
+func (v *embed) Identifiers() []string {
+	return v.Identifiers_
+}
+
+// OnIdentified returns the identify action
+func (v *embed) OnIdentified() api.ActionConfig {
+	return v.OnIdentify
+}
diff --git a/vehicle/vehicle.go b/vehicle/vehicle.go
index 84a1c48c..c8d559bb 100644
--- a/vehicle/vehicle.go
+++ b/vehicle/vehicle.go
@@ -9,27 +9,6 @@ import (
 	"github.com/evcc-io/evcc/util"
 )
 
-type embed struct {
-	Title_      string `mapstructure:"title"`
-	Capacity_   int64  `mapstructure:"capacity"`
-	Identifier_ string `mapstructure:"identifier"`
-}
-
-// Title implements the api.Vehicle interface
-func (v *embed) Title() string {
-	return v.Title_
-}
-
-// Capacity implements the api.Vehicle interface
-func (v *embed) Capacity() int64 {
-	return v.Capacity_
-}
-
-// Identify implements the api.Identifier interface
-func (v *embed) Identify() (string, error) {
-	return v.Identifier_, nil
-}
-
 //go:generate go run ../cmd/tools/decorate.go -f decorateVehicle -b api.Vehicle -t "api.ChargeState,Status,func() (api.ChargeStatus, error)" -t "api.VehicleRange,Range,func() (int64, error)" -t "api.VehicleOdometer,Odometer,func() (float64, error)"
 
 // Vehicle is an api.Vehicle implementation with configurable getters and setters.
diff --git a/vehicle/wrapper/wrapper.go b/vehicle/wrapper/wrapper.go
index e41187b7..3ea04e08 100644
--- a/vehicle/wrapper/wrapper.go
+++ b/vehicle/wrapper/wrapper.go
@@ -30,11 +30,18 @@ func (v *Wrapper) Capacity() int64 {
 	return 0
 }
 
-// Identify implements the api.Identifier interface
-func (v *Wrapper) Identify() (string, error) {
-	return "", v.err
+// Identifiers implements the api.Vehicle interface
+func (v *Wrapper) Identifiers() []string {
+	return nil
 }
 
+// OnIdentified returns the identify action
+func (v *Wrapper) OnIdentified() api.ActionConfig {
+	return api.ActionConfig{}
+}
+
+var _ api.Battery = (*Wrapper)(nil)
+
 // SoC implements the api.Battery interface
 func (v *Wrapper) SoC() (float64, error) {
 	return 0, v.err


Test patch:
diff --git a/core/loadpoint_test.go b/core/loadpoint_test.go
index b9defdc4..bc088a89 100644
--- a/core/loadpoint_test.go
+++ b/core/loadpoint_test.go
@@ -456,16 +456,15 @@ func TestSetModeAndSocAtDisconnect(t *testing.T) {
 		MinCurrent:  minA,
 		MaxCurrent:  maxA,
 		status:      api.StatusC,
-		OnDisconnect: struct {
-			Mode      api.ChargeMode `mapstructure:"mode"`      // Charge mode to apply when car disconnected
-			TargetSoC int            `mapstructure:"targetSoC"` // Target SoC to apply when car disconnected
-		}{
-			Mode:      api.ModeOff,
-			TargetSoC: 70,
+		Mode:        api.ModeOff,
+		SoC: SoCConfig{
+			Target: 70,
 		},
+		ResetOnDisconnect: true,
 	}
 
 	attachListeners(t, lp)
+	lp.collectDefaults()
 
 	lp.enabled = true
 	lp.chargeCurrent = float64(minA)
@@ -764,35 +763,35 @@ func TestVehicleDetectByID(t *testing.T) {
 	}
 	tc := []testcase{
 		{"1/_/_->0", "1", "", "", nil, func(tc testcase) {
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			v2.EXPECT().Identify().Return(tc.i2, nil)
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			v2.EXPECT().Identify().Return(tc.i2, nil)
+			v1.EXPECT().Identifiers().Return(nil)
+			v2.EXPECT().Identifiers().Return(nil)
+			v1.EXPECT().Identifiers().Return(nil)
+			v2.EXPECT().Identifiers().Return(nil)
 		}},
 		{"1/1/2->1", "1", "1", "2", v1, func(tc testcase) {
-			v1.EXPECT().Identify().Return(tc.i1, nil)
+			v1.EXPECT().Identifiers().Return([]string{tc.i1})
 		}},
 		{"2/1/2->2", "2", "1", "2", v2, func(tc testcase) {
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			v2.EXPECT().Identify().Return(tc.i2, nil)
+			v1.EXPECT().Identifiers().Return([]string{tc.i1})
+			v2.EXPECT().Identifiers().Return([]string{tc.i2})
 		}},
 		{"11/1*/2->1", "11", "1*", "2", v1, func(tc testcase) {
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			v2.EXPECT().Identify().Return(tc.i2, nil)
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			// v2.EXPECT().Identify().Return(tc.i2, nil)
+			v1.EXPECT().Identifiers().Return([]string{tc.i1})
+			v2.EXPECT().Identifiers().Return([]string{tc.i2})
+			v1.EXPECT().Identifiers().Return([]string{tc.i1})
+			// v2.EXPECT().Identifiers().Return([]string{tc.i2})
 		}},
 		{"22/1*/2*->2", "22", "1*", "2*", v2, func(tc testcase) {
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			v2.EXPECT().Identify().Return(tc.i2, nil)
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			v2.EXPECT().Identify().Return(tc.i2, nil)
+			v1.EXPECT().Identifiers().Return([]string{tc.i1})
+			v2.EXPECT().Identifiers().Return([]string{tc.i2})
+			v1.EXPECT().Identifiers().Return([]string{tc.i1})
+			v2.EXPECT().Identifiers().Return([]string{tc.i2})
 		}},
 		{"2/_/*->2", "2", "", "*", v2, func(tc testcase) {
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			v2.EXPECT().Identify().Return(tc.i2, nil)
-			v1.EXPECT().Identify().Return(tc.i1, nil)
-			v2.EXPECT().Identify().Return(tc.i2, nil)
+			v1.EXPECT().Identifiers().Return(nil)
+			v2.EXPECT().Identifiers().Return([]string{tc.i2})
+			v1.EXPECT().Identifiers().Return(nil)
+			v2.EXPECT().Identifiers().Return([]string{tc.i2})
 		}},
 	}
 
diff --git a/meter/config_test.go b/meter/config_test.go
index 3e7f33a9..1ba9c0d6 100644
--- a/meter/config_test.go
+++ b/meter/config_test.go
@@ -18,6 +18,7 @@ func TestMeters(t *testing.T) {
 		"connect: no route to host",
 		"connect: connection refused",
 		"i/o timeout",
+		"connect: network is unreachable",
 		"no ping response for 192.0.2.2", // SMA
 		"network is unreachable",
 		"[1ESY1161052714 1ESY1161229249 1EMH0008842285 1ESY1161978584 1EMH0004864048 1ESY1161979033 7ELS8135823805]", // Discovergy