Hardware suggestions to automate an outlet for electric car charging

Hi guys, I am look for some insights and suggestions, preferably from someone who has experience with this.

I am about to get a PHEV, and wan to use a “normal” outlet for charging (it’s a small battery, and I would rather avoid getting the level 2 charging station for various reasons). But since the car is not overly smart, I want to measure/control the charging from Home Assistant.

Switch needs to:

  • Reliably deliver a continuous 10A+ power (probably only up to 8 hours at a time). I’m in Europe, so ~240V, if that matters.
    • This is obviously necessary, anything with with reported failures operating like this is pretty much out of the question.
  • Be controllable by Home Assistant, of course.
  • Be controllable by manual switch.
    • I want/need a switch on the wall I can flip/press to turn on/off. This switch should be detectable/controllable by HASS (MQTT switch?), but work in case HASS is down.
  • Energy monitoring. Current power draw is sufficient.
  • Preferably be able to operate between -25°C and 35°C.
    • I can place it indoor, if this is not feasible.

What I’ve seen is that I should stay clear of any of the usual suspects (z-wave switches, Sonoff, etc.), and instead use a contactor that is controlled by “something”. Ive seen reports of Sonoff melting here, here, here, here. But there are also many comments out there saying that they are fine. I currently have a Sonoff POW 16A lying around, but because of the reports, I’m a bit hesitant to use for something like this (it seems like it just depends, maybe on batch? But that’s not a risk I would like to take).

I will get an electrician to install this, and (s)he might have ideas. But it would be nice to have some suggestion/idea before.

Any thoughts?

1 Like

I have a friend who uses this HomeMatic switching actuator (HmIP-FSM16) to control the charging of his E-Smart. His electronics know-how is pretty robust, so I personally whould trust his product choice if I were to do something like that myself. So in case you are in the german-speaking area (that’s where HomeMatic products usually are sold), this would probably be a safe solution.

Here’s the documentation for the component itself. To use such devices you’ll also need a hub (CCU2/CCU3/RaspberryMatic).

You could ask https://shelly.cloud/catalogue/ about their Shelly HD, its a dual 32amp wifi relay
Their Shelly 1 and 2 have MQTT support but its not mentioned in the catalog

GE makes a 40A Zwave Plus contactor that works well. It also has energy monitoring.

I use a couple to control pool pump, heater, etc.

Getting a level 2 charger like this one:

https://www.openevse.com/

Seems the most simplest solution.

Thanks for the suggestions!

@danielperna84 I’m in Denmark, so Germany is pretty close by :slight_smile: I’ll keep this one in mind, thanks!

@ady8077 The shelly also looks interesting. Would that be something I would install behind a normal switch, so I could control either with HASS or manual switch? I can’t seem to find much info about it.

@firstof9 That looks like the easiest way. Do you have experience with them? I can’t see if you can actually control them via home assistant, or if you can only monitor, but still have use their app to turn of/off? And would you happen to know if home assistant connects locally, of via internet?

There’s a component for that currently:

Based on their documentation you can use MQTT to control it.

1 Like

Ahhh, I didn’t take a look at their github. I just saw that the HASS component documentation says that it “pulls data”, nothing about controlling. But it seems like it’s covered. Thanks.

I have an OpenEVSE L2 charge (in the USA) and have it working with HA via manually configured MQTT sensors.

image

If you want I can share my MQTT sensor definitions and the Lovelace card.

I have not tried to control functions via MQTT but it is supported. You can start / stop charging or set charge current rates.

The existing OpenEVSE component doesn’t work with current versions of Hass. The problem issue is here: https://github.com/home-assistant/home-assistant/issues/12954 When I looked at the problem, it was beyond my capabilities with my knowledge of Hass at the time.

It doesn’t matter too much to me whether the component works if manual MQTT setup works. But it would be great if you’d share your config; it’s always nice to have a “known functional” setup before buying :slight_smile:

And since you’re an actively user, let me just ask; you can still use the app directly if HASS is down, right? Or control directly on the charger if all wifi is down, correct?

Yes, the OpenEVSE application is standalone and works independently of Home Assistant. It does not require Internet access at all as the WiFi module can create its own hotspot or you can configure it to join an existing one.

I’ll post my configuration when I am back home this evening.

configuration.yaml

# Sensors
sensor:
  # Use OpenEVSE RAPI API to Retrieve the active charging current
  # https://www.home-assistant.io/components/sensor.rest/
  # Example: 
  #  curl curl --digest --user 'user:pass' 'http://openevse.local./r?json=1&rapi=$GU'
  #  $OK 40629846 165327^27
  - platform: rest
    name: "OpenEVSE RAPI $GU"
    resource: 'http://openevse.local/r?json=1&rapi=$GU'
    authentication: digest
    username: !secret OPENEVSE_USERNAME
    password: !secret OPENEVSE_PASSWORD
    headers:
        User-Agent: Home Assistant
        Content-Type: application/json
    json_attributes: [ 'cmd', 'ret' ]
    value_template: '{{ value_json.ret }}'

  # Custom Sensors
  - platform: template
    sensors:
      openevse_session_energy:
        friendly_name: "OpenEVSE Session Energy"
        icon_template: mdi:gauge
        unit_of_measurement: 'kWh'
        value_template: >-
          {%- if states('sensor.openevse_rapi_gu') == 'unknown' -%}
            0.0
          {%- else -%}
            {%- set ret = state_attr('sensor.openevse_rapi_gu', 'ret') -%}
            {%- set rgx = '(?<=^\$OK )[0-9]+' -%}
            {%- if ret|regex_search(rgx) -%}
              {%- set v = ret | regex_findall_index(rgx) -%}
              {{- (v|float / 3600000)|round(2) -}}
            {%- else -%}
              0.0
            {%- endif -%}
          {%- endif -%}
      openevse_state:
        friendly_name: "OpenEVSE State"
        icon_template: >-
          {% set value = states('sensor.openevse_mqtt_state') %}
          {% if value == "1" %}
            mdi:power-plug-off
          {% elif value == "2" %}
            mdi:car-electric
          {% elif value == "3" %}
            mdi:battery-charging
          {% else %}
            mdi:battery-unknown
          {% endif %}
        value_template: >-
          {% set value = states('sensor.openevse_mqtt_state') %}
          {% if value == "1" %}
            Disconnected
          {% elif value == "2" %}
            Idle
          {% elif value == "3" %}
            Charging
          {% else %}
            Unknown-{{ value }}
          {% endif %}
  # OpenEVSE MQTT Tracker
  - platform: mqtt
    name: "OpenEVSE Temp 1"
    state_topic: "openevse/temp1"
    unit_of_measurement: '°F'
    device_class: temperature
    value_template: >-
      {%- macro C2F(temperature) -%}
      {% set tmp = (((temperature *9) /50.0) + 32) %}
      {{- "%0.2f" % tmp -}}
      {%- endmacro -%}
      {{- C2F(value|float)|float -}}
  - platform: mqtt
    name: "OpenEVSE Charging Current"
    icon: mdi:current-ac
    state_topic: "openevse/amp"
    unit_of_measurement: "A"
    value_template: >-
      {{- (value|float / 1000.0) | round(1) -}}
  - platform: mqtt
    name: "OpenEVSE Pilot Current"
    icon: mdi:current-ac
    state_topic: "openevse/pilot"
    unit_of_measurement: "A"
    value_template: >-
      {{- value|int -}}
  - platform: mqtt
    name: "OpenEVSE Total Energy"
    icon: mdi:gauge-full
    state_topic: "openevse/wh"
    unit_of_measurement: "kWh"
    value_template: >-
      {{- value|float / 1000 | round(2) -}}
  - platform: mqtt
    name: "OpenEVSE MQTT State"
    state_topic: "openevse/state"

Lovelace UI

      - title: Garage
        id: garage
        type: entities
        show_header_toggle: false
        entities:
          - sensor.openevse_state
          - sensor.openevse_total_energy
          - sensor.openevse_pilot_current
          - sensor.openevse_charging_current
          - sensor.openevse_session_energy
1 Like

I just noticed that my REST sensor was no longer updating (I’d suspected this for a while, but I hadn’t really payed any attention recently.) I don’t know when it broke but it was a while ago.

Turns out that the “digest” authentication does not work anymore with the OpenEVSE service. I changed to “basic” and it started working again.

Second, I also made some changes to clean up a few potential warnings by avoiding use of None or “unknown” in cases where values aren’t available.

Thirdly, I reviewed the source code and updated my state values to match the OpenEVSE, e.g., “Ready” instead of “Disconnected”, etc.

sensor:
  # Use OpenEVSE RAPI API to Retrieve the active charging current
  # https://www.home-assistant.io/components/sensor.rest/
  # Example: 
  #  curl --digest --user 'user:pass' 'http://openevse.local/r?json=1&rapi=$GU'
  #  $OK 40629846 165327^27
  - platform: rest
    name: "OpenEVSE RAPI $GU"
    resource: 'http://openevse.local/r?json=1&rapi=$GU'
    force_update: yes
    authentication: basic
    username: !secret OPENEVSE_USERNAME
    password: !secret OPENEVSE_PASSWORD
    headers:
        User-Agent: Home Assistant
        Content-Type: application/json
    json_attributes: [ 'cmd', 'ret' ]
    value_template: '{{state_attr("sensor.openevse_rapi_gu", "ret")}}'

  # Custom Sensors
  - platform: template
    sensors:
      openevse_session_energy:
        friendly_name: "OpenEVSE Session Energy"
        icon_template: mdi:gauge
        unit_of_measurement: 'kWh'
        value_template: >-
          {%- if states('sensor.openevse_rapi_gu') == 'unknown' -%}
            0.0
          {%- else -%}
            {%- set ret = state_attr('sensor.openevse_rapi_gu', 'ret') -%}
            {%- if ret == None -%}
              0.0
            {%- else -%}
              {%- set rgx = '(?<=^\$OK )[0-9]+' -%}
              {%- if ret|regex_search(rgx) -%}
                {%- set v = ret | regex_findall_index(rgx) -%}
                {{- (v|float / 3600000)|round(2) -}}
              {%- else -%}
                0.0
              {%- endif -%}
            {%- endif -%}
          {%- endif -%}
      openevse_state:
        friendly_name: "OpenEVSE State"
        icon_template: >-
          {%- if states('sensor.openevse_mqtt_state') | regex_match('^[01]$') -%}
            mdi:power-plug-off
          {%- elif is_state('sensor.openevse_mqtt_state', '2') -%}
            mdi:car-electric
          {%- elif is_state('sensor.openevse_mqtt_state', '3') -%}
            mdi:battery-charging
          {%- elif states('sensor.openevse_mqtt_state') | regex_match('^([456789]|10)$') -%}
            mdi:battery-alert
          {%- elif is_state('sensor.openevse_mqtt_state', '254') -%}
            mdi:sleep
          {%- elif is_state('sensor.openevse_mqtt_state', '255') -%}
            mdi:power-off
          {%- else -%}
            mdi:battery-unknown
          {%- endif -%}
        value_template: >-
          {%- if states('sensor.openevse_mqtt_state') | regex_match('^[01]$') -%}
            Ready
          {%- elif is_state('sensor.openevse_mqtt_state', '2') -%}
            Connected
          {%- elif is_state('sensor.openevse_mqtt_state', '3') -%}
            Charging
          {%- elif states('sensor.openevse_mqtt_state') | regex_match('^([456789]|10)$') -%}
            Error
          {%- elif is_state('sensor.openevse_mqtt_state', '254') -%}
            Sleep
          {%- elif is_state('sensor.openevse_mqtt_state', '255') -%}
            Disabled
          {%- else -%}
            Unknown-{{- value -}}
          {%- endif -%}

  # OpenEVSE MQTT Tracker
  - platform: mqtt
    name: "OpenEVSE Temp 1"
    state_topic: "openevse/temp1"
    unit_of_measurement: '°F'
    device_class: temperature
    value_template: >-
      {%- macro C2F(temperature) -%}
      {% set tmp = (((temperature *9) /50.0) + 32) %}
      {{- "%0.2f" % tmp -}}
      {%- endmacro -%}
      {{- C2F(value|float)|float -}}

  - platform: mqtt
    name: "OpenEVSE Charging Current"
    icon: mdi:current-ac
    state_topic: "openevse/amp"
    unit_of_measurement: "A"
    value_template: >-
      {{- (value|float / 1000.0) | round(1) -}}

  - platform: mqtt
    name: "OpenEVSE Pilot Current"
    icon: mdi:current-ac
    state_topic: "openevse/pilot"
    unit_of_measurement: "A"
    value_template: >-
      {{- value|int -}}

  - platform: mqtt
    name: "OpenEVSE Total Energy"
    icon: mdi:gauge-full
    state_topic: "openevse/wh"
    unit_of_measurement: "kWh"
    value_template: >-
      {{- value|float / 1000 | round(2) -}}

  - platform: mqtt
    name: "OpenEVSE MQTT State"
    state_topic: "openevse/state"

And finally, Someone was asking about updating the charger in addition to only reading data. This is relatively straightforward by using the RAPI REST API. In theory MQTT is more efficient, but it is easier to get the REST commands working first, so that is what I did.

My first configuration for write control is a simple switch to enable/disable the charger.

rest_command:
  openevse_enable:
    url: 'http://openevse.local./r?json=1&rapi=$FE'
    username: !secret OPENEVSE_USERNAME
    password: !secret OPENEVSE_PASSWORD
    headers:
        User-Agent: Home Assistant
  openevse_disable:
    url: 'http://openevse.local./r?json=1&rapi=$FD'
    username: !secret OPENEVSE_USERNAME
    password: !secret OPENEVSE_PASSWORD
    headers:
        User-Agent: Home Assistant
  openevse_sleep:
    url: 'http://openevse.local./r?json=1&rapi=$FS'
    username: !secret OPENEVSE_USERNAME
    password: !secret OPENEVSE_PASSWORD
    headers:
        User-Agent: Home Assistant

# Switches
switch:
  - platform: template
    switches:

      openevse_enable:
        friendly_name: "OpenEVSE Enable"
        value_template: >-
          {{- states('sensor.openevse_mqtt_state') | regex_match ("^[0123]$") -}}
        icon_template: >-
          {%- if states('sensor.openevse_mqtt_state') | regex_match ("^[0123]$") -%}
            mdi:power-plug
          {%- else -%}
            mdi:power-plug-off
          {%- endif -%}
        turn_off:
          - service: rest_command.openevse_sleep
        turn_on:
          - service: rest_command.openevse_enable

Additional RAPI commands:

1 Like

Great, thanks for the update!

OK, that was a bit painful, but I have Enable/Disable and Current Limits implemented using a mix of MQTT and HTTP services. The MQTT is much quicker to respond than HTTP so I am using MQTT wherever possible.

I moved all configuration to a package. If you want to try this, you’ll need:

  1. OpenEVSE on network with MQTT set up to publish to “openevse” base topic
  2. Place openevse.yaml into config/packages
  3. Add these custom components to config/custom_components:
  4. Load the package(s) by adding this to `config/configuration.yaml’:
    homeassistant:
      packages: !include_dir_named packages
    
  5. Add secrets for OPENEVSE_USER, OPENEVSE_PASSWORD, OPENEVSE_HOST
  6. You will also have to search openevse.yaml for my hostname openevse.local. and replace it with your own hostname or ip. I haven’t gotten the URLs all parameterized yet.

I created a bug against the OpenEVSE WiFi service to hopefully improve the RAPI API for MQTT that will allow significant performance improvements.

I’m going to let this rest for a few days now since I have some other tasks that have been backup up the last couple days.

3 Likes

Hi Tony
I want to follow your guide for adding my openevse charger. I see that some of your file destinations have changed since this write-up above. Would you mind updating the instructions again, please?

Thanks

Dolf

Ah yes, the custom_components folder structure was changed to comply with requirements around the 0.97 release.

You still need those files, but the names and locations are different. See my custom_components folder in github and copy the folder structure and contents of both input_number and input_select folders to your custom_components folder.

1 Like

any word on if the openevse integration will be fixed?

I tried your package and I have it kind of working (thank you). Am I supposed to get a readable value from the RAPI badges that were created? I get $OK…

Also, I could get your custom integrations to work, I had to remove all of that from the package to get it to work. i assume that you needed to modify the ones built in to HA is why it requires compontents already in HA core? Do we need to put something in our config to get it to read from that directory like with enabling the package dir?