Home Assistant custom component to create sensors with information on the available EV Charging Station in a chosen area. This custom component has been built from the ground up to bring public site data to compare and save on your EV prices and integrate this information into Home Assistant. This integration is built against the public websites provided by Eneco.com and other similar sites. Sensors will be created for nearest stations of different speeds and availability.
Currently supporting charging stations in EU from Eneco and Shell.
This integration is in no way affiliated with Eneco.com. This integration is based on my other Carbu.com custom integration, which brings similar functionality for fuel/gas stations.
Large parts of the code base has been based on the Shell Recharge custom integration. The same functionality is available, but has been extended to support Eneco charging stations and to automatically find the stations that matches criteria.
For electricity price expectations this Entso-E HACS integration can be used.
With this integration it will be possible to:
- subscribe to specific charging point, to make it possible to get notified once available
- get sensors (can be shown on map) with:
- charging station nearest to location (straight line distance)
- available charging station nearest to location
- high speed charging station nearest to location
- high speed available charging station nearest to location
- super high speed charging station nearest to location
- super high speed available charging station nearest to
TODO : find cheapest charging station:
- cheapest charging stations and nearest to location
- available cheapest charging stations and nearest to location
- high speed charging station cheapest and nearest to location
- high speed available cheapest charging stations and nearest to location
- super high speed cheapest charging station and nearest to location
- super high speed available cheapest charging station and nearest to location
- HACS: search for Carbu in the default HACS repo list or use below button to navigate directly to it on your local system and install via HACS.
- Restart Home Assistant
- Add 'EV Charging Stations' integration via HA Settings > 'Devices and Services' > 'Integrations'
- Choose the type of charging station to setup: nearest public station, specific station or Shell station with credentials.
- For 'Public nearest station':
- Provide any 'origin': this can be a coordinate eg: "51.330436, 3.802043" or "street, city, country" or any sensor name which has latitude and longitutde coordinate attributes eg "person.fred" or "device_tracker.car_position"
- For 'Public single Shell charge station':
- Provide the unique serial number of the charging station: the serial number can be found in the details of a charging station on https://ui-map.shellrecharge.com
- For 'Private Shell charge station':
- Provide Shell credentials username and password
-
sensor.nearest_station_[origin]: sensor with info of nearest charging station -
sensor.nearest_available_station_[origin]: sensor with info of nearest available charging station -
sensor.nearest_highspeed_station_[origin]: sensor with info of nearest highspeed charging station (+50kWh) -
sensor.nearest_available_highspeed_station_[origin]: sensor with info of nearest available highspeed charging station (+50kWh) -
sensor.nearest_available_superhighspeed_station_[origin]: sensor with info of nearest superhighspeed charging station (+100kWh) -
sensor.nearest_available_superhighspeed_station_[origin]: sensor with info of nearest available superhighspeed charging station (+100kWh) -
Sensor attributes
Attribute Description State Status nameName of the charging station, ofter referring to the location typeType of the charging station, eg nearest_available_superhighspeed_station originOriginal origin provided during setup of the sensor to find nearest station addressAddress of the charging station postal_codePostal code of the charging station cityCity of the charging station countryCountry of the charging station latitudeLatitude of the charging station longitudeLongitude of the charging station straight_line_distanceApproximate straight_line_distance between charging station and set origin, used for selecting nearest stationroute_distanceApproximate Waze distance in km between charging station and set origin, NOT used for selecting nearest station, only calculated for selected stationsroute_durationApproximate Waze duration in minutes between charging station and set origin, NOT used for selecting nearest station, only calculated for selected stationsroute_nameApproximate straight_line_distance between charging station and set originoperator_nameName of the operator of the charging station urlDirect URL to the Eneco chargemap with details of the charging station facilitiesFacilities available close to the charging station avaialbe_connectorsTotal number of connectors available at the charging station number_of_connectorsTotal number of connectors at the charging station max_speed_kWhMax speed connector at the charging station min_speed_kWhMin speed connector at the charging station is_unlimitedIndication if any limitation applies at the charging station is_limitedIndication if any limitation applies at the charging station is_unkownIndication if the charging station is unknown allowedIndication if the charging station is allowed for Eneco charging card holders external_idExternal unique technical id of the charging station evse_idFunctional id of the charging station statusStatus indication of the charging station, any of "AVAILABLE", "CHARGING", "OUTOFORDER", "UNAVAILABLE", "UNKNOWN", "BLOCKED" last updateTimestamp of latest status info of charging station physical_referencePhysical reference id of the charging station connector_standardConnector standard info of the charging station, eg IEC_62196_T2 connector_typeConnector power type info of the charging station, eg AC_3_PHASE connector_formatConnector info of the charging station connector_max_powerConnector info max power in kWh of the charging station, eg 17kWh opentwentyfoursevenIndication if the charging station is open 24/7, true or false charging_costsPrice charging cost info of the charging station per Watt of charging or false charging_time_costsPrice charging cost info of the charging station per minute of charging or false start_tariffPrice charging cost info of the charging station to start charging session or false parking_time_costsPrice charging cost info of the charging station for parking during charging or false price_descriptionPrice charging cost info of the charging station map_labelAttribute that can be used to show on map, currently showning <available connectors>/<total connectors <max power>kWh
- Find the EV Charging Station nearest to a given location and meeting specific criteria.
-
It will return a JSON such as example below:
nearest_station: id: 7e71a916-d614-11f0-a74f-42010aa400b8 name: TNLP030017 address: streetAndHouseNumber: De Ruijterkade 46 postcode: 1012 AB city: Amsterdam country: NL ownerName: TotalEnergies isAllowed: true accessType: Public isTwentyFourSeven: true coordinates: lat: 52.38066774 lng: 4.89748098 evseSummary: total: 5 available: 4 maxSpeed: 120000 minSpeed: 43000 isUnlimited: true isLimited: false isUnknown: false owner: name: TotalEnergies website: https://ubitricity.com/nl/bestuurder/ source: Eneco evses: - uid: NL-GFX-ETNLP030017-1 status: AVAILABLE evseId: NL*GFX*ETNLP030017*1 lastUpdated: "2026-01-03T02:52:42+00:00" physicalReference: TNLP030017 connectors: - id: "1" standard: IEC_62196_T2 format: SOCKET powerType: AC_3_PHASE maxPower: 43000 prices: startTariff: 0.39 chargingCosts: 0.58 chargingTimeCosts: false parkingTimeCosts: false description: null - uid: NL-GFX-ETNLP030017-2 status: AVAILABLE evseId: NL*GFX*ETNLP030017*2 lastUpdated: "2026-01-03T20:10:11+00:00" physicalReference: TNLP030017 connectors: - id: "2" standard: IEC_62196_T2_COMBO format: CABLE powerType: DC maxPower: 50000 prices: startTariff: 0.39 chargingCosts: 0.8 chargingTimeCosts: false parkingTimeCosts: false description: null - uid: NL-GFX-ETNLP030017-3 status: AVAILABLE evseId: NL*GFX*ETNLP030017*3 lastUpdated: "2026-01-03T11:03:27+00:00" physicalReference: TNLP030017 connectors: - id: "3" standard: CHADEMO format: CABLE powerType: DC maxPower: 50000 prices: startTariff: 0.39 chargingCosts: 0.8 chargingTimeCosts: false parkingTimeCosts: false description: null - uid: NL-GFX-ETNLP030018-1 status: CHARGING evseId: NL*GFX*ETNLP030018*1 lastUpdated: "2026-01-03T20:59:06+00:00" physicalReference: TNLP030018 connectors: - id: "1" standard: IEC_62196_T2_COMBO format: CABLE powerType: DC maxPower: 120000 prices: startTariff: 0.39 chargingCosts: 0.8 chargingTimeCosts: false parkingTimeCosts: false description: null - uid: NL-GFX-ETNLP030018-2 status: AVAILABLE evseId: NL*GFX*ETNLP030018*2 lastUpdated: "2026-01-03T20:32:52+00:00" physicalReference: TNLP030018 connectors: - id: "2" standard: IEC_62196_T2_COMBO format: CABLE powerType: DC maxPower: 120000 prices: startTariff: 0.39 chargingCosts: 0.8 chargingTimeCosts: false parkingTimeCosts: false description: null facilities: - 14a (Public transport) - 13a (Public transport) - 11a (Public transport) - 10a (Public transport) - 8a (Public transport) straight_line_distance: 0.97 url: >- https://www.eneco-emobility.com/be-nl/chargemap#loc=52.38066774%2C4.89748098%2C17&selected=7e71a916-d614-11f0-a74f-42010aa400b8 route_distance: 1.29 route_duration: 4.28 route_name: Singel Amsterdam
Proof of concept status, still validating and extending functionalities. Issues section in GitHub.
The main logic and API connection related code can be found within source code Carbu.com/custom_components/Carbu.com:
All other files just contain boilerplat code for the integration to work wtihin HA or to have some constants/strings/translations.
If you would encounter some issues with this custom component, you can enable extra debug logging by adding below into your configuration.yaml:
logger:
default: info
logs:
custom_components.EVChargingStations: debug
To show a map in Home Assistant with all nearest charging stations you can use a setup such as shown below. It will show the max kWh charging power on map.
type: map
entities:
- entity: sensor.nearest_station_device_tracker_car_position
label_mode: attribute
attribute: map_label
focus: false
- entity: >-
sensor.nearest_available_station_device_tracker_car_position
label_mode: attribute
attribute: map_label
focus: true
- entity: >-
sensor.nearest_highspeed_station_device_tracker_car_position
label_mode: attribute
attribute: map_label
focus: false
- entity: >-
sensor.nearest_available_highspeed_station_device_tracker_car_position
label_mode: attribute
attribute: map_label
focus: true
- entity: >-
sensor.nearest_superhighspeed_station_device_tracker_car_position
label_mode: attribute
attribute: map_label
focus: false
- entity: >-
sensor.nearest_available_superhighspeed_station_device_tracker_car_position
label_mode: attribute
attribute: map_label
focus: true
- entity: device_tracker.car_position
theme_mode: auto
To show the Eneco charging map for a specific location linked to some sensor in Home Assistant IFrame you can:
-
install Config Template Card HACS
-
define a template sensor to dynamically build the website url based on sensor coordinates
- in
configuration.yaml
template: - sensor: - name: "Car Eneco Charging Station URL" state: > https://www.eneco-emobility.com/be-nl/chargemap#loc={{ state_attr('device_tracker.car_position', 'latitude') }}%2C{{ state_attr('device_tracker.car_position', 'longitude') }}%2C16 - in
-
create a new card in frontend with config such as shown below:
type: custom:config-template-card entities: - sensor.car_eneco_charging_station_url variables: - states card: type: iframe aspect_ratio: 185% url: ${states['sensor.car_eneco_charging_station_url'].state}
Below markdown will only show unique charging stations, so if nearest and nearest available are the same, it will only be shown once.
A link towards Eneco chargemap is available on the name of the charging stations
A link to Google maps directions from car to charging station is available on the address of the charging station
An indication of exepcted speed of charging (km/min and km/hour of charging)
To re-use, replace
device_tracker_car_positionwith origin used during setup of EVChargingStationdevice_tracker.car_positionwith entity id or sensor name of your car (or similar)sensor.car_socwith entity id of car battery charge status % SoCperson.jefwith entity id of person
type: markdown
content: >-
{% set soc = states('sensor.car_soc') | float(0) %}
{% set capacity = states('sensor.car_battery_kwh') | float(83) %}
{% set now_ts = now().timestamp() %}
{% set consumption = 19 | float %}
{% if soc < 10 %} {% set factor = 0.7 %}
{% elif soc < 40 %} {% set factor = 1.0 %}
{% elif soc < 60 %} {% set factor = 0.8 %}
{% elif soc < 80 %} {% set factor = 0.5 %}
{% else %} {% set factor = 0.2 %}
{% endif %}
{% macro calcTime(target, max_power_kw) %}
{% set taper_factor = 0.6 %}
{% if max_power_kw < 50 %}
{% set effective_power = 11.0 %}
{% else %}
{% set effective_power = max_power_kw %}
{% endif %}
{% if soc >= target %} Reeds ≥ {{ target }}%
{% else %}
{# Part 1: from current SOC to min(target,80) at full speed #}
{%- set first_limit = [target, 80] | min -%}
{%- set pct1 = (first_limit - soc) / 100 if soc < first_limit else 0 -%}
{%- set energy1 = capacity * pct1 -%}
{%- set time1 = energy1 / effective_power if effective_power > 0 else 0 -%}
{# Part 2: above 80% at reduced speed #}
{%- if target > 80 and soc < target -%}
{%- set pct2 = (target - 80) / 100 if soc < 80 else (target - soc) / 100 -%}
{%- set energy2 = capacity * pct2 -%}
{%- set time2 = energy2 / (effective_power * taper_factor) -%}
{%- else -%} {%- set time2 = 0 -%}
{%- endif -%}
{%- set total_h = time1 + time2 -%}
{%- set hours = total_h | int -%}
{%- set minutes = ((total_h - hours) * 60) | round(0) -%}
{%- if minutes >= 60 -%}
{%- set hours = hours + (minutes // 60) -%}
{%- set minutes = minutes % 60 -%}
{%- endif -%}
{%- set completion_ts = (now_ts + total_h * 3600) | int -%} till {{target}}%: {{ hours }}h {{ '%02d' % minutes }}m → {{ completion_ts | timestamp_custom('%a %H:%M', true) }}, auto currently at {{soc}}% till max {{capacity}}kWh at {{effective_power}}kWh
{% endif %}
{% endmacro %}
{% macro calcSpeed(target, max_power_kw) %}
{% if consumption > 0 %}
{{(((max_power_kw * factor) / 60) * (100 / consumption))| round(1)}}km/min, {{(((max_power_kw * factor)) * (100 / consumption))| round(0)}}km/h
{% endif %}
{% endmacro %}
{% macro generateOverview(sensor) %}
{% set max_power_kw = state_attr(sensor,'connector_max_power') | float %}
({{state_attr(sensor,'route_distance')}}km,
{{state_attr(sensor,'route_duration')}}min):
[{{state_attr(sensor,'name')}}]({{state_attr(sensor,'url')}})
> 🗺️[{{state_attr(sensor,'address')}}, {{state_attr(sensor,'postal_code')}}
{{state_attr(sensor,'city')}}](https://www.google.com/maps/dir/?api=1&origin={{state_attr('person.jef','latitude')}},{{state_attr('person.jef','longitude')}}&destination={{state_attr(sensor,'latitude')}},{{state_attr(sensor,'longitude')}}&travelmode=driving)
{{state_attr(sensor,'connector_max_power')}}kWh,
{{state_attr(sensor,'available_connectors')}}/{{state_attr(sensor,'number_of_connectors')}}
available
{{ calcSpeed(80, max_power_kw) }}
{{ calcTime(80, max_power_kw) }}
{{ calcTime(100, max_power_kw) }}
{{state_attr(sensor,'facilities')}}
{% endmacro %}
# Charging stations around person.jef
### Nearest available
{{ generateOverview('sensor.nearest_available_station_person_jef') }}
{% if state_attr('sensor.nearest_station_person_jef','external_id') !=
state_attr('sensor.nearest_available_station_person_jef','external_id') %}
### Nearest
{{ generateOverview('sensor.nearest_station_person_jef') }}
{% endif %}
{% if state_attr('sensor.nearest_available_station_person_jef','external_id') != state_attr('sensor.nearest_available_highspeed_station_person_jef','external_id') %}
### Highspeed nearest available {{
generateOverview('sensor.nearest_available_highspeed_station_person_jef') }}
{% endif %}
{% if state_attr('sensor.nearest_highspeed_station_person_jef','external_id') != state_attr('sensor.nearest_available_highspeed_station_person_jef','external_id') %}
### Highspeed
{{ generateOverview('sensor.nearest_highspeed_station_person_jef')}}
{% endif %}
{% if state_attr('sensor.nearest_available_superhighspeed_station_person_jef','external_id') != state_attr('sensor.nearest_available_highspeed_station_person_jef','external_id')
and state_attr('sensor.nearest_available_station_person_jef','external_id') !=
state_attr('sensor.nearest_available_superhighspeed_station_person_jef','external_id')%}
### Super highspeed available
{{ generateOverview('sensor.nearest_available_superhighspeed_station_person_jef') }}
{% endif %}
{% if state_attr('sensor.nearest_superhighspeed_station_person_jef','external_id') !=
state_attr('sensor.nearest_available_superhighspeed_station_person_jef','external_id')
and
state_attr('sensor.nearest_available_superhighspeed_station_person_jef','external_id')!=
state_attr('sensor.nearest_available_highspeed_station_person_jef','external_id')
%}
### Super highspeed
{{ generateOverview('sensor.nearest_superhighspeed_station_person_jef') }}
{% endif %}
grid_options:
columns: full


