J’ai fixé le json mais c’est bizarre car ça fonctionne chez moi aussi sans le fix.
hello, suites aux quelques issues et PR sur le sujet, j’ai fait une beta qui change le moyen d’avoir les infos des stations:
on prend la datasource mergée d’OSM puis on override par le fichier local qu’on avait déjà actuellement
si certains peuvent tester la dernière beta (dispo via HACS), cf la PR
Hello @Aohzan
Merci pour l'intégration, c'est elle qui fait tout le travail ingrat.
Pour l'affichage, j'ai écrit une carte Lovelace qui se branche directement dessus :
Prix Carburant Card — GitHub - Pulpyyyy/carte-burant: Carte Lovelace pour Home Assistant : tableau des prix des carburants par station et par carburant, à partir de l'intégration Prix Carburant. · GitHub


Une ligne par station, une colonne par carburant. Elle lit les entités de
l'intégration par leurs attributs (station_id + fuel_type) et non par
leur entity_id : renommer une entité ne casse rien, et il n'y a aucun sensor
template à écrire.
En vrac :
- choix et ordre des stations et des colonnes, à la souris comme en YAML ;
- tri configurable, et clic sur les en-têtes pour trier à la volée ;
- prix le plus bas en vert, le plus haut en rouge, ex æquo compris ;
- noms et villes surchargeables, logos par enseigne ;
- éditeur graphique complet, en français et en anglais.
Installation : HACS → dépôt personnalisé → catégorie Lovelace. Sans aucune
configuration, elle trouve toutes les stations remontées par l'intégration,
triées par distance :
type: custom:prix-carburant-card
Je voulais juste faire un petit bouton pour rechercher les stations autour de moi quand je suis ailleurs qu'a la maison.
Ensuite il fallait que ca ne jure pas trop avec la carte de @Pulpy-Luke donc on copie le style au mieux.
Ensuite pourquoi limiter l'affichage à un seul carburant donc on lance plusieur recherche et on fusionne l'affichage.
Ensuite je ne suis pas tout seul a la maison donc le bouton doit prendre en compte quel utilisateur clicque dessus... bref ca termine en monstre ![]()
Par defaut j'affiche la carte de @Pulpy-Luke
Quand un membre de la famille clique sur le bouton "Stations autour de moi", ca execute un script de recherche et j'affiche les stations-service trouvées. Les informations remontées étant beaucoup moins détaillées (cf doc de l'integration), c'est moins jolie mais ca reste très pratique. Les noms des stations-service sont cliquables et ouvrent directement Google Maps sur la localisation de la station (<- Peut etre une option à ajouter sur ta carte @Pulpy-Luke ?)
Pour en arriver la, il faut:
Un template sensor à ajouter dans le fichier templates.yaml (le monstre)
Il est gros mais il fait la fusion de toutes les recherches par stations-services.
- trigger:
- platform: event
event_type: nearby_gas_stations
sensor:
- name: Gas Stations Near Me
unique_id: gas_stations_near_me
state: "{{ now().isoformat() }}"
attributes:
stations: >
{% set e10 = trigger.event.data.stations_e10 or [] %}
{% set sp95 = trigger.event.data.stations_sp95 or [] %}
{% set sp98 = trigger.event.data.stations_sp98 or [] %}
{% set gazole = trigger.event.data.stations_gazole or [] %}
{% set e85 = trigger.event.data.stations_e85 or [] %}
{% set gpl = trigger.event.data.stations_gpl or [] %}
{% set gas_stations = namespace(items=[]) %}
{% for e in e10 %}
{% set match_sp95 = sp95
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set match_sp98 = sp98
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set match_gazole = gazole
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set match_e85 = e85
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set match_gpl = gpl
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': e.name,
'address': e.address,
'latitude': e.latitude,
'longitude': e.longitude,
'e10': e.price,
'sp95': match_sp95[0].price if match_sp95 | count > 0 else none,
'sp98': match_sp98[0].price if match_sp98 | count > 0 else none,
'gazole': match_gazole[0].price if match_gazole | count > 0 else none,
'e85': match_e85[0].price if match_e85 | count > 0 else none,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endfor %}
{% for s in sp95 %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set match_sp98 = sp98
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_gazole = gazole
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_e85 = e85
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_gpl = gpl
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': s.price,
'sp98': match_sp98[0].price if match_sp98 | count > 0 else none,
'gazole': match_gazole[0].price if match_gazole | count > 0 else none,
'e85': match_e85[0].price if match_e85 | count > 0 else none,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endif %}
{% endfor %}
{% for s in sp98 %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set match_gazole = gazole
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_e85 = e85
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_gpl = gpl
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': none,
'sp98': s.price,
'gazole': match_gazole[0].price if match_gazole | count > 0 else none,
'e85': match_e85[0].price if match_e85 | count > 0 else none,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endif %}
{% endfor %}
{% for s in gazole %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set match_e85 = e85
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_gpl = gpl
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': none,
'sp98': none,
'gazole': s.price,
'e85': match_e85[0].price if match_e85 | count > 0 else none,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endif %}
{% endfor %}
{% for s in e85 %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set match_gpl = gpl
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': none,
'sp98': none,
'gazole': none,
'e85': s.price,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endif %}
{% endfor %}
{% for s in gpl %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': none,
'sp98': none,
'gazole': none,
'e85': none,
'gpl': s.price
}] %}
{% endif %}
{% endfor %}
{{ gas_stations.items }}
Un bouton pour lancer la recherche
Ici il faut remplacer les tracker par les vôtres "Pierre": "person.pierre"
A gauche, indiquez le nom exact de l'utilisateur Home Assistant.
A droite, indiquez l'entité person (ou le tracker) associée à cet utilisateur.
Carte utilisé: button-card
type: custom:button-card
show_icon: true
show_name: true
show_state: false
show_label: true
color_type: icon
layout: icon_name
name: Stations autour de moi
icon: mdi:target
tap_action:
action: perform-action
perform_action: script.find_gas_stations_near_me
data:
tracker: |
[[[
const map = {
"Pierre": "person.pierre",
"Paul": "person.paul",
"Jack": "person.jack"
};
return map[hass.user.name];
]]]
styles:
card:
- border-radius: 18px
- padding: 5px
grid:
- grid-template-areas: '"i n"'
- grid-template-columns: 56px auto
- grid-template-rows: auto auto
- column-gap: 0px
- row-gap: 0px
- align-items: center
img_cell:
- width: 40px
- height: 40px
- border-radius: 50%
- display: flex
- align-items: center
- justify-content: center
- justify-self: start
- align-self: center
icon:
- width: 24px
- height: 24px
name:
- font-size: 14px
- font-weight: 700
- line-height: 1.2
- justify-self: start
- white-space: nowrap
- overflow: hidden
- text-overflow: ellipsis
- margin-left: -5px
Le script éxécuté par le bouton
Ici, vous pouvez supprimer les carburants qui ne vous intéressent pas et ajuster le rayon de recherche (ici 5 km).
alias: Find Gas Stations Near Me
sequence:
- action: prix_carburant.find_nearest_stations
data:
distance: 5
entity_id: '{{ tracker }}'
fuel: E10
response_variable: stations_e10
- action: prix_carburant.find_nearest_stations
data:
distance: 5
entity_id: '{{ tracker }}'
fuel: SP95
response_variable: stations_sp95
- action: prix_carburant.find_nearest_stations
data:
distance: 5
entity_id: '{{ tracker }}'
fuel: SP98
response_variable: stations_sp98
- action: prix_carburant.find_nearest_stations
data:
distance: 5
entity_id: '{{ tracker }}'
fuel: Gazole
response_variable: stations_gazole
#- action: prix_carburant.find_nearest_stations
# data:
# distance: 5
# entity_id: '{{ tracker }}'
# fuel: E85
# response_variable: stations_e85
#- action: prix_carburant.find_nearest_stations
# data:
# distance: 5
# entity_id: '{{ tracker }}'
# fuel: GPLc
# response_variable: stations_gpl
- event: nearby_gas_stations
event_data:
stations_e10: '{{ stations_e10.stations }}'
stations_sp95: '{{ stations_sp95.stations }}'
stations_sp98: '{{ stations_sp98.stations }}'
stations_gazole: '{{ stations_gazole.stations }}'
#stations_e85: '{{ stations_e85.stations }}'
#stations_gpl: '{{ stations_gpl.stations }}'
fields:
tracker:
description: Person entity or device_tracker
La carte pour afficher les stations-service
Carte utilisé: HTML Jinja2 Template card
type: custom:html-template-card
ignore_line_breaks: true
entities:
- sensor.gas_stations_near_me
content: >-
{% set stations = state_attr('sensor.gas_stations_near_me', 'stations') or [] %}
{% set e10_prices = stations | map(attribute='e10') | reject('none') | list %}
{% set sp95_prices = stations | map(attribute='sp95') | reject('none') | list %}
{% set sp98_prices = stations | map(attribute='sp98') | reject('none') | list %}
{% set gazole_prices = stations | map(attribute='gazole') | reject('none') | list %}
{% set best_e10 = e10_prices | min if e10_prices else none %}
{% set worst_e10 = e10_prices | max if e10_prices else none %}
{% set best_sp95 = sp95_prices | min if sp95_prices else none %}
{% set worst_sp95 = sp95_prices | max if sp95_prices else none %}
{% set best_sp98 = sp98_prices | min if sp98_prices else none %}
{% set worst_sp98 = sp98_prices | max if sp98_prices else none %}
{% set best_gazole = gazole_prices | min if gazole_prices else none %}
{% set worst_gazole = gazole_prices | max if gazole_prices else none %}
<style>
.center { text-align: center; }
.gas-wrapper {
overflow-x: auto;
max-width: 100%;
border-radius: 12px;
}
.gas-table {
min-width: 850px;
width: 100%;
border-collapse: collapse;
font-size: 14px;
color: #ffffff;
}
.gas-table th {
background: #1d1d1d;
color: #a3a3a3;
padding: 4px 6px;
text-align: left;
white-space: nowrap;
font-weight: 600;
border-bottom: 1px solid #333333;
margin-bottom: 4px;
}
.gas-table td {
padding: 4px 6px;
border-bottom: 1px solid #2a2a2a;
white-space: nowrap;
vertical-align: middle;
}
.gas-table tr:nth-child(even) {
background: #282828;
}
.gas-table tr:nth-child(odd) {
background: #1c1c1C;
}
.gas-table td:first-child {
min-width: 170px;
max-width: 170px;
overflow: hidden;
text-overflow: ellipsis;
}
.gas-table th:first-child {
background: #1d1d1d;
}
.gas-table tbody tr:hover {
background: #323232;
}
.gas-table tbody tr:hover td {
background: #323232;
}
.gas-table tbody tr:hover td:first-child {
background: #323232;
}
.gas-title {
margin: 0 0 10px 0;
font-weight: 700;
font-size: 14px;
color: #ffffff;
}
.station-link,
.station-link:visited {
color: #ffffff;
text-decoration: underline;
text-decoration-style: dotted;
text-underline-offset: 2px;
font-size: 14px;
display: inline-block;
max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
.station-link:hover {
color: #369bd4;
text-decoration: underline;
text-decoration-style: dotted;
text-underline-offset: 2px;
}
.station-link:active {
color: #369bd4;
}
.price {
text-align: right;
font-size: 14px;
}
.best-price {
color: #4caa40;
font-size: 14px;
font-weight: 700;
text-align: center;
}
.middle-price {
font-size: 14px;
text-align: center;
}
.worst-price {
color: #e05252;
font-size: 14px;
font-weight: 700;
text-align: center;
}
.empty-price {
color: #ffffff;
text-align: center;
}
.address {
font-size: 14px;
}
</style>
<div class="gas-title">
⛽ {{ stations | count }} stations trouvées
</div>
<div class="gas-wrapper">
<table class="gas-table">
<thead>
<tr>
<th>Station</th>
<th>E10 €/L</th>
<th>SP95 €/L</th>
<th>SP98 €/L</th>
<th>Diesel €/L</th>
<th>City</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{% for s in stations %}
{% set address_parts = s.address.split(',') %}
{% set street = address_parts[0].strip() %}
{% set city_raw = address_parts[-1].strip() %}
{% set city = city_raw | regex_replace('^[0-9]{5}\\s*', '') %}
{% set maps_url = 'https://www.google.com/maps/search/?api=1&query=' ~ s.latitude ~ ',' ~ s.longitude %}
<tr>
<td title="{{ s.name }}">
<a class="station-link" target="_blank" href="{{ maps_url }}">{{ s.name }}</a>
</a>
</td>
{% if s.e10 is not none %}
{% if s.e10 == best_e10 %}
<td class="best-price">{{ s.e10 }}</td>
{% elif s.e10 == worst_e10 %}
<td class="worst-price">{{ s.e10 }}</td>
{% else %}
<td class="middle-price">{{ s.e10 }}</td>
{% endif %}
{% else %}
<td class="empty-price">-</td>
{% endif %}
{% if s.sp95 is not none %}
{% if s.sp95 == best_sp95 %}
<td class="best-price">{{ s.sp95 }}</td>
{% elif s.sp95 == worst_sp95 %}
<td class="worst-price">{{ s.sp95 }}</td>
{% else %}
<td class="middle-price">{{ s.sp95 }}</td>
{% endif %}
{% else %}
<td class="empty-price">-</td>
{% endif %}
{% if s.sp98 is not none %}
{% if s.sp98 == best_sp98 %}
<td class="best-price">{{ s.sp98 }}</td>
{% elif s.sp98 == worst_sp98 %}
<td class="worst-price">{{ s.sp98 }}</td>
{% else %}
<td class="middle-price">{{ s.sp98 }}</td>
{% endif %}
{% else %}
<td class="empty-price">-</td>
{% endif %}
{% if s.gazole is not none %}
{% if s.gazole == best_gazole %}
<td class="best-price">{{ s.gazole }}</td>
{% elif s.gazole == worst_gazole %}
<td class="worst-price">{{ s.gazole }}</td>
{% else %}
<td class="middle-price">{{ s.gazole }}</td>
{% endif %}
{% else %}
<td class="empty-price">-</td>
{% endif %}
<td class="address">{{ city }}</td>
<td class="address">{{ street }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
Bonne idée @Kro, c'est en place ! ![]()
La 1.0.5 de la carte vient de sortir (mise à jour via HACS) : le nom de la station devient un lien qui l'ouvre dans une app de cartes — et si la colonne nom n'est pas affichée, le lien se pose sur la ville, l'adresse ou l'enseigne.
Pour l'activer : éditeur graphique → section Affichage → « Ouvrir la station sur une carte », ou en YAML :
map_link: auto # ou google | apple | waze
- google, apple (Plans) ou waze : le même service partout ;
- auto : selon l'appareil — sélecteur d'applications sur Android (lien geo:, qui respecte l'app carto préférée, Waze comprise), Plans sur iPhone, Google Maps sur PC.
Petite déception au passage : il n'existe pas d'URL « magique » qui ouvre partout l'app choisie par l'utilisateur donc geo: n'existe que sur Android, et iOS n'ouvre que Plans ou le site du service visé. auto est la meilleure approximation possible.
La station s'ouvre pile sur sa position GPS et si l'intégration ne la fournit pas, la recherche se fait sur son adresse. Le reste ne change pas : un clic ailleurs sur la ligne ouvre toujours la fiche de l'entité.
Petite amélioration visuelle, à la demande de la famille, pour pouvoir modifier dynamiquement le rayon de recherche des stations à proximité.

Prérequies: button-card et HTML Jinja2 Template card
Mise en place:
Un template sensor à ajouter dans le fichier templates.yaml
# Fusionne les résultats de plusieurs recherches par carburant afin d'obtenir
# une seule liste de stations avec tous les prix disponibles
- trigger:
- platform: event
event_type: nearby_gas_stations
sensor:
- name: Gas Stations Near Me
unique_id: gas_stations_near_me
state: "{{ now().isoformat() }}"
attributes:
stations: >
{% set e10 = trigger.event.data.stations_e10 or [] %}
{% set sp95 = trigger.event.data.stations_sp95 or [] %}
{% set sp98 = trigger.event.data.stations_sp98 or [] %}
{% set gazole = trigger.event.data.stations_gazole or [] %}
{% set e85 = trigger.event.data.stations_e85 or [] %}
{% set gpl = trigger.event.data.stations_gpl or [] %}
{% set gas_stations = namespace(items=[]) %}
{% for e in e10 %}
{% set match_sp95 = sp95
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set match_sp98 = sp98
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set match_gazole = gazole
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set match_e85 = e85
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set match_gpl = gpl
| selectattr('name', 'eq', e.name)
| selectattr('address', 'eq', e.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': e.name,
'address': e.address,
'latitude': e.latitude,
'longitude': e.longitude,
'e10': e.price,
'sp95': match_sp95[0].price if match_sp95 | count > 0 else none,
'sp98': match_sp98[0].price if match_sp98 | count > 0 else none,
'gazole': match_gazole[0].price if match_gazole | count > 0 else none,
'e85': match_e85[0].price if match_e85 | count > 0 else none,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endfor %}
{% for s in sp95 %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set match_sp98 = sp98
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_gazole = gazole
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_e85 = e85
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_gpl = gpl
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': s.price,
'sp98': match_sp98[0].price if match_sp98 | count > 0 else none,
'gazole': match_gazole[0].price if match_gazole | count > 0 else none,
'e85': match_e85[0].price if match_e85 | count > 0 else none,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endif %}
{% endfor %}
{% for s in sp98 %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set match_gazole = gazole
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_e85 = e85
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_gpl = gpl
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': none,
'sp98': s.price,
'gazole': match_gazole[0].price if match_gazole | count > 0 else none,
'e85': match_e85[0].price if match_e85 | count > 0 else none,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endif %}
{% endfor %}
{% for s in gazole %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set match_e85 = e85
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set match_gpl = gpl
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': none,
'sp98': none,
'gazole': s.price,
'e85': match_e85[0].price if match_e85 | count > 0 else none,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endif %}
{% endfor %}
{% for s in e85 %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set match_gpl = gpl
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': none,
'sp98': none,
'gazole': none,
'e85': s.price,
'gpl': match_gpl[0].price if match_gpl | count > 0 else none
}] %}
{% endif %}
{% endfor %}
{% for s in gpl %}
{% set existing = gas_stations.items
| selectattr('name', 'eq', s.name)
| selectattr('address', 'eq', s.address)
| list
%}
{% if existing | count == 0 %}
{% set gas_stations.items = gas_stations.items + [{
'name': s.name,
'address': s.address,
'latitude': s.latitude,
'longitude': s.longitude,
'e10': none,
'sp95': none,
'sp98': none,
'gazole': none,
'e85': none,
'gpl': s.price
}] %}
{% endif %}
{% endfor %}
{{ gas_stations.items }}
Le script éxécuté par le bouton de recherche
alias: Find Gas Stations Near Me
sequence:
- action: prix_carburant.find_nearest_stations
data:
distance: '{{ distance }}'
entity_id: '{{ tracker }}'
fuel: E10
response_variable: stations_e10
- action: prix_carburant.find_nearest_stations
data:
distance: '{{ distance }}'
entity_id: '{{ tracker }}'
fuel: SP95
response_variable: stations_sp95
- action: prix_carburant.find_nearest_stations
data:
distance: '{{ distance }}'
entity_id: '{{ tracker }}'
fuel: SP98
response_variable: stations_sp98
- action: prix_carburant.find_nearest_stations
data:
distance: '{{ distance }}'
entity_id: '{{ tracker }}'
fuel: Gazole
response_variable: stations_gazole
- event: nearby_gas_stations
event_data:
stations_e10: '{{ stations_e10.stations }}'
stations_sp95: '{{ stations_sp95.stations }}'
stations_sp98: '{{ stations_sp98.stations }}'
stations_gazole: '{{ stations_gazole.stations }}'
fields:
tracker:
description: Person entity or device_tracker
Le script éxécuté par le bouton de reinitialisation
sequence:
- event: nearby_gas_stations
event_data:
stations: []
alias: Reset Gas Stations Near Me
description: ''
Le code de la carte principale
Ici il faut remplacer les tracker par les vôtres "Pierre": "person.pierre"
A gauche, indiquez le nom exact de l'utilisateur Home Assistant.
A droite, indiquez l'entité person (ou le tracker) associée à cet utilisateur.
type: vertical-stack
cards:
- type: heading
icon: mdi:gas-station
heading: Prix des carburants
heading_style: title
- type: custom:button-card
entity: input_number.gas_station_radius
name: Stations à proximité
icon: mdi:target
show_icon: true
show_name: true
show_state: true
show_label: false
state_display: |
[[[
const radius = parseInt(states['input_number.gas_station_radius']?.state ?? 5);
return `Rayon actuel : ${radius} km`;
]]]
tap_action:
action: perform-action
perform_action: script.find_gas_stations_near_me
data:
tracker: |
[[[
const map = {
"Pierre": "person.pierre",
"Paul": "person.paul",
"Jack": "person.jack"
};
return map[hass.user.name];
]]]
distance: |
[[[
return parseInt(states['input_number.gas_station_radius'].state);
]]]
custom_fields:
controls:
card:
type: horizontal-stack
cards:
- type: custom:button-card
icon: mdi:minus
tap_action:
action: perform-action
perform_action: input_number.decrement
target:
entity_id: input_number.gas_station_radius
styles:
card:
- width: 40px
- height: 40px
- border-radius: 50%
- background: '#FFFFFF29'
- box-shadow: none
- padding: 0
icon:
- color: white
- width: 18px
- type: custom:button-card
icon: mdi:plus
tap_action:
action: perform-action
perform_action: input_number.increment
target:
entity_id: input_number.gas_station_radius
styles:
card:
- width: 40px
- height: 40px
- border-radius: 50%
- background: '#FFFFFF29'
- box-shadow: none
- padding: 0
icon:
- color: white
- width: 18px
styles:
card:
- border-radius: 18px
- padding: 10px
grid:
- grid-template-areas: |
"i n controls"
"i s ."
- grid-template-columns: 56px 1fr 100px
- column-gap: 15px
- align-items: center
img_cell:
- width: 44px
- height: 44px
- border-radius: 50%
- background: '#FFFFFF29'
- display: flex
- align-items: center
- justify-content: center
- justify-self: start
icon:
- color: white
- width: 25px
- height: 25px
name:
- color: white
- font-size: 15px
- font-weight: 700
- line-height: 1.2
- white-space: nowrap
- overflow: hidden
- text-overflow: ellipsis
- justify-self: start
- margin-left: -18px
- margin-top: -20px
state:
- color: '#FFFFFFC7'
- font-size: 12px
- justify-self: start
- margin-left: -18px
- margin-top: -18px
custom_fields:
controls:
- grid-area: controls
- display: flex
- justify-content: flex-end
- title: Fuel prices
show_title: false
stations: []
columns:
- logo
- distance
- E10
- SP95
- SP98
- Gazole
- city
- address
- updated
decimals: 3
highlight: true
unit: €/L
sort: E10
sort_desc: false
sortable: true
more_info: true
map_link: auto
background: null
color_min: '#4caa40'
color_max: '#e05252'
type: custom:prix-carburant-card
visibility:
- condition: state
attribute: stations
entity: sensor.gas_stations_near_me
state: ''
Le code de la carte du resultat de la recherche
type: vertical-stack
cards:
- type: heading
icon: mdi:gas-station
heading: Prix des carburants
heading_style: title
- type: custom:button-card
show_icon: true
show_name: true
show_state: false
show_label: true
color_type: icon
layout: icon_name
name: Réinitialiser
icon: mdi:gas-station-off
tap_action:
action: perform-action
perform_action: script.reset_gas_stations_near_me
styles:
card:
- border-radius: 18px
- padding: 5px
grid:
- grid-template-areas: '"i n"'
- grid-template-columns: 56px auto
- grid-template-rows: auto auto
- column-gap: 0px
- row-gap: 0px
- align-items: center
img_cell:
- width: 40px
- height: 40px
- border-radius: 50%
- display: flex
- align-items: center
- justify-content: center
- justify-self: start
- align-self: center
icon:
- width: 24px
- height: 24px
name:
- font-size: 14px
- font-weight: 700
- line-height: 1.2
- justify-self: start
- white-space: nowrap
- overflow: hidden
- text-overflow: ellipsis
- margin-left: -5px
label:
- font-size: 10px
- opacity: 0.7
- justify-self: start
- align-self: start
- white-space: nowrap
- overflow: hidden
- text-overflow: ellipsis
- margin-left: -5px
- type: custom:html-template-card
ignore_line_breaks: true
entities:
- sensor.gas_stations_near_me
content: >-
{% set stations = state_attr('sensor.gas_stations_near_me', 'stations') or
[] %}
{% set e10_prices = stations | map(attribute='e10') | reject('none') |
list %}
{% set sp95_prices = stations | map(attribute='sp95') | reject('none') |
list %}
{% set sp98_prices = stations | map(attribute='sp98') | reject('none') |
list %}
{% set gazole_prices = stations | map(attribute='gazole') | reject('none')
| list %}
{% set best_e10 = e10_prices | min if e10_prices else none %}
{% set worst_e10 = e10_prices | max if e10_prices else none %}
{% set best_sp95 = sp95_prices | min if sp95_prices else none %}
{% set worst_sp95 = sp95_prices | max if sp95_prices else none %}
{% set best_sp98 = sp98_prices | min if sp98_prices else none %}
{% set worst_sp98 = sp98_prices | max if sp98_prices else none %}
{% set best_gazole = gazole_prices | min if gazole_prices else none %}
{% set worst_gazole = gazole_prices | max if gazole_prices else none %}
<style>
.center {
text-align: center;
}
.gas-wrapper {
overflow-x: auto;
max-width: 100%;
border-radius: 12px;
}
.gas-table {
min-width: 850px;
width: 100%;
border-collapse: collapse;
font-size: 14px;
color: var(--primary-text-color);
}
.gas-table th {
background: var(--card-background-color);
color: var(--secondary-text-color);
padding: 4px 6px;
text-align: left;
white-space: nowrap;
font-weight: 600;
border-bottom: 1px solid var(--divider-color);
}
.gas-table td {
padding: 4px 6px;
border-bottom: 1px solid var(--divider-color);
white-space: nowrap;
vertical-align: middle;
color: var(--primary-text-color);
}
.gas-table tr:nth-child(even) {
background: color-mix(
in srgb,
var(--card-background-color) 92%,
var(--primary-text-color) 8%
);
}
.gas-table tr:nth-child(odd) {
background: var(--card-background-color);
}
.gas-table td:first-child {
min-width: 170px;
max-width: 170px;
overflow: hidden;
text-overflow: ellipsis;
}
.gas-table th:first-child {
background: var(--card-background-color);
}
.gas-table tbody tr:hover,
.gas-table tbody tr:hover td,
.gas-table tbody tr:hover td:first-child {
background: var(--secondary-background-color);
}
.gas-title {
margin: 0 0 10px 0;
font-weight: 700;
font-size: 14px;
color: var(--primary-text-color);
}
.station-link,
.station-link:visited {
color: var(--primary-text-color);
text-decoration: underline;
text-decoration-style: dotted;
text-underline-offset: 2px;
font-size: 14px;
display: inline-block;
max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
.station-link:hover,
.station-link:active {
color: var(--primary-color);
}
.price {
text-align: right;
font-size: 14px;
}
.best-price {
color: var(--success-color, #4caf50) !important;
font-size: 14px;
font-weight: 700;
text-align: center;
}
.middle-price {
color: var(--primary-text-color);
font-size: 14px;
text-align: center;
}
.worst-price {
color: var(--error-color, #f44336) !important;
font-size: 14px;
font-weight: 700;
text-align: center;
}
.empty-price {
color: var(--secondary-text-color);
text-align: center;
}
.address {
color: var(--primary-text-color);
font-size: 14px;
}
</style>
<div class="gas-title">
⛽ {{ stations | count }} stations trouvées dans un rayon de {{ states['input_number.gas_station_radius'].state | int }} km
</div>
<div class="gas-wrapper">
<table class="gas-table">
<thead>
<tr>
<th>Station</th>
<th>E10 €/L</th>
<th>SP95 €/L</th>
<th>SP98 €/L</th>
<th>Diesel €/L</th>
<th>City</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{% for s in stations %}
{% set address_parts = s.address.split(',') %}
{% set street = address_parts[0].strip() %}
{% set city_raw = address_parts[-1].strip() %}
{% set city = city_raw | regex_replace('^[0-9]{5}\\s*', '') %}
{% set maps_url = 'https://www.google.com/maps/search/?api=1&query=' ~ s.latitude ~ ',' ~ s.longitude %}
<tr>
<td title="{{ s.name }}">
<a class="station-link" target="_blank" href="{{ maps_url }}">{{ s.name }}</a>
</a>
</td>
{% if s.e10 is not none %}
{% if s.e10 == best_e10 %}
<td class="best-price">{{ s.e10 }}</td>
{% elif s.e10 == worst_e10 %}
<td class="worst-price">{{ s.e10 }}</td>
{% else %}
<td class="middle-price">{{ s.e10 }}</td>
{% endif %}
{% else %}
<td class="empty-price">-</td>
{% endif %}
{% if s.sp95 is not none %}
{% if s.sp95 == best_sp95 %}
<td class="best-price">{{ s.sp95 }}</td>
{% elif s.sp95 == worst_sp95 %}
<td class="worst-price">{{ s.sp95 }}</td>
{% else %}
<td class="middle-price">{{ s.sp95 }}</td>
{% endif %}
{% else %}
<td class="empty-price">-</td>
{% endif %}
{% if s.sp98 is not none %}
{% if s.sp98 == best_sp98 %}
<td class="best-price">{{ s.sp98 }}</td>
{% elif s.sp98 == worst_sp98 %}
<td class="worst-price">{{ s.sp98 }}</td>
{% else %}
<td class="middle-price">{{ s.sp98 }}</td>
{% endif %}
{% else %}
<td class="empty-price">-</td>
{% endif %}
{% if s.gazole is not none %}
{% if s.gazole == best_gazole %}
<td class="best-price">{{ s.gazole }}</td>
{% elif s.gazole == worst_gazole %}
<td class="worst-price">{{ s.gazole }}</td>
{% else %}
<td class="middle-price">{{ s.gazole }}</td>
{% endif %}
{% else %}
<td class="empty-price">-</td>
{% endif %}
<td class="address">{{ city }}</td>
<td class="address">{{ street }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
visibility:
- condition: state
attribute: stations
entity: sensor.gas_stations_near_me
state_not: ''
EDIT: Information obselete, la fonciton de recherche est inclu depuis la version 1.0.6 de la carte carburant
Merci pour la carte, je gérer via un truc fait maison avec du custom etc...
Je viens de remplacer par ta carte c'est top !!!
Merci encore.
Bonjour !
Bravo à tous les 2 pour le boulot !
Je suis vraiment intéressé par ce qu'à fait Kro : "Station à proximité".
Est-ce prévu un article de A à Z pour obtenir le résultat de l'image ?
ça serait tellement bien et je pense que la communauté serait très intéressé surtout en ce moment ^^"
Bonjour @jojo007,
Effectivement, cela nécessite un peu de bricolage.
Pour resumer, il faut installer via HACS:
Ensuite, suis pas à pas la partie mise en place de mon post et tu auras exactement le même rendu.
EDIT: Information obselete, la fonciton de recherche est inclu depuis la version 1.0.6 de la carte carburant
OK merci beaucoup, je vais tester ça asap ![]()
Si tu peux patienter jusqu’à la semaine prochaine, je proposerai une PR à @Pulpy-Luke qui intégre la fonctionnalité de recherche. Plus aucune dependance à button-card et HTML-Jinja2 et plus rien a creer a la main.
Teaser:
Une petite semaine ![]()
Je regarde plus en détail (j'ai vu 2 ou 3 trucs) et je publie, merci
Nouvelle version de la carte 1.0.6 : elle peut maintenant chercher les stations les moins chères autour de toi, directement depuis le tableau de bord.
Un grand merci à @Kro ! Il avait monté ça de son côté (sensor template, script et carte maison, voir son message plus haut), puis a proposé de l'intégrer directement à la carte : c'est sa contribution qui est à l'origine de cette version. Et merci encore pour l'idée du lien vers Google Maps / Plans / Waze de la 1.0.5.
Ce que ça donne
- une barre au-dessus du tableau : − / + pour le rayon (1 à 30 km),
pour lancer la recherche ; - des pastilles pour choisir les carburants, parmi ceux que remonte l'intégration. Le choix est mémorisé par compte Home Assistant : le même sur le téléphone et sur l'ordi ;
- la recherche part de ta position (la personne liée à ton compte), sinon du domicile : ça marche aussi sur une tablette murale ;
- aucune requête sans clic sur
, donc l'API des prix n'est pas sollicitée pour rien.
Pour l'activer
Dans l'éditeur, nouvelle section « Recherche à proximité », ou en YAML :
Configuration YAML
type: custom:prix-carburant-card
search: true
Elle est désactivée par défaut : rien ne change pour les cartes existantes.
Il faut une version de l'intégration Prix Carburant qui propose le service
prix_carburant.find_nearest_stations.
Mise à jour via HACS ; le détail est dans les notes de version et le README :
Salut,
Ton erreur est vraiment bizarre... j'imagine que ton ha est à jour, non ?
Ta carte est dans une pile horizontale/verticale ou une popup ? Si oui, tu peux essayer la mettre juste en direct dans un dashboard ?
Je viens d'installer prix carburant et la carte... c'est vraiment cool mais le plus pertinent en ce moment c'est savoir si la station essence est en rupture
J'ai l'impression que la valeur du prix passe en statut "inconnu" lorsque la station est en rupture, savez vous si c'est le cas ?
Inconnu c'est ce que traduit HA quand le capteur n'a pas de valeur. Et la rupture ne provoque sans doute pas ça, tu dois pouvoir continuer à voir le prix à dernière mise à jour.
A priori un carburant en rupture contient un attribut "shortage_since" avec une date si c'est le cas
ca serait bien que ca soit affiché sur la carte alors
Par contre le jour où on sera à 9.999 le litre ca marchera plus, y a quelques mois j'aurais dit aucune chance que ca arrive mais maintenant..






