EVCC - Gestion de la consommation électrique et optimisation solaire

Idem ici, véhicule de type Custom.
mais @dglaude également : Working config of EVCC for Tesla with BLE HTTP Proxy and Teslamate · GitHub

Je confirme, je suis en custom (pas tesla)…

C’est pas la recommendation de EVCC qui a rajouté une option Proxy pour faire un maximum de chose en BLE avec le HTTP Proxy et le reste en API Tesla.
Pour le moment, je suis satisfait par la solution (puisqu’elle marche) et je ne voudrais pas me séparer de Teslamate que je viens d’installer, ni de l’application eevee que j’utilisait avant.
Donc rajouter des requêtes pour EVCC me gène un peu.
Un petit détail, utiliser le mode tesla est payant puisqu’il faut un token de soutient GitHub à EVCC… je l’ai, je le paye, mais je pourrais arrêter en restant en custom.

Une mise à jour:

J’ai recommendé wimaha/TeslaBleHttpProxy (au lieu tesla-local-control/tesla_ble_mqtt_docker comme le poste parent).
C’était juste par facilité, et fonction de la réactivité du développeur de TeslaBleHttpProxy, et en raison de mon absence de maitrise de MQTT (HTTP on connait).
Il se trouver que GitHub - wimaha/TeslaBleHttpProxy: TeslaBleHttpProxy is a program written in Go that receives HTTP requests and forwards them via Bluetooth to a Tesla vehicle. The program can, for example, be easily used together with evcc. a bien évolué et avec la version 1.2 la création des clefs et l’établissement de la communication BLE avec la Tesla est super simplifié.
J’en ai aussi profité pour faire le déployement sur mon Rasbperry Pi4 (celui qui tourne déjà Teslamate) et c’était super facile avec « docker compose ».

Prochaine étape, je vais essayer de faire aussi tourner EVCC sur le même Pi4 et libérer mon NUC.

PS: Je pense que tesla_ble_mqtt_docker fait la même chose avec une facilité à créer la paire de clef et faire le pairing avec la voiture, donc c’est pas un argument pour la solution HTTP ou MQTT.

Pour être certain de saisir : dans votre cas, avec un véhicule de type custom, déplacer ce curseur dans EVCC :

image

Modifie de la même manière le niveau de charge dans l’application Tesla ? Pour ma part, sans automatisation HA via MQTT, le lien ne se fait pas.

Je n’ai pas de wall connector physique cela dit, ca vient peut être de la.

Je re-teste ce soir…

wimaha/TeslaBleHttpProxy support le message: « set_charge_limit »

Sauf que dans mes logs, je ne le vois pas être utilisé.
EVCC peut très bien arrêté la charge avec une décision locale (ce qui s’est passé hier soir).

Dans la config custom que j’utilise, je vois 3 actions:

  chargeenable:
  maxcurrent: # set charger max current (A)
  wakeup: # vehicle wake up command

Donc j’ai du halluciner, je ne vois pas comment la limite qu’on place dans EVCC pourrait être transmise à la voiture.
Avec ma configuration actuelle, on peut faire STOP, START, Réveil et choisir le MAX_CURRENT.

Je ne sais pas si dans le template custom on peut indiquer une commande pour utiliser « set_charge_limit », et je ne sais pas si EVCC utiliserait cela pour propager ce changement de configuration.

On a déjà eu quelques surprises où l’on donne une instruction à la voiture via l’application, mais derrière nous EVCC prend une autre décision et s’impose. A priori, quand tu commence à utiliser EVCC, il faut l’utiliser pour tout. Mais il faut faire des testes, genre limiter à 80% sur la voiture et à 90% sur EVCC… et vérifier qu’il n’y a pas une bataille « Jour/Nuit » entre deux contrôleurs.

C’est pas supporté: Tesla mit TWC und Teslamate - set Charge limit · evcc-io/evcc · Discussion #12660 · GitHub

Donc je pense qu’il faut mettre sa voiture avec une limite de 100% et puis contrôler le maximum local de EVCC.

Cette automatisation permet de synchroniser le SOC EVCC avec celui de Tesla. Modifier la première condition et les variables, ce devrait être bon pour vous. J’en ferai un blueprint quand j’aurais plus de recul.

Automatisation
alias: Link EVCC and Tesla Limit SOC
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.evcc_loadpoint_1_limit_soc
    id: evcc
  - platform: state
    entity_id:
      - number.chonk_charge_limit
    id: tesla
condition:
  - condition: template
    value_template: >-
      {{ states('sensor.evcc_loadpoint_1_limit_soc') !=
      states('number.chonk_charge_limit') }}
action:
  - variables:
      teslaSocEntity: number.chonk_charge_limit
      teslaSocBleEntity: number.tesla_ble_mqtt_VIN_charging_limit
      teslaSocState: "{{ states(teslaSocEntity) | int(50) }}"
      teslaBleTracker: device_tracker.chonk_ble_tracker
      teslaBleTrackerDesiredState: home
      evccSocEntity: sensor.evcc_loadpoint_1_limit_soc
      evccLoadpointId: 1
      evccSocState: "{{ states(evccSocEntity) | int(50) }}"
  - choose:
      - conditions:
          - condition: trigger
            id:
              - evcc
        sequence:
          - if:
              - condition: template
                value_template: "{{ states(teslaBleTracker) == teslaBleTrackerDesiredState }}"
            then:
              - service: input_number.set_value
                target:
                  entity_id: "{{ teslaSocBleEntity }}"
                data:
                  value: "{{ evccSocState }}"
              - wait_for_trigger:
                  - platform: template
                    value_template: "{{ states(teslaSocEntity) == evccSocState  }}"
                continue_on_timeout: false
                timeout:
                  hours: 0
                  minutes: 0
                  seconds: 30
                  milliseconds: 0
          - if:
              - condition: template
                value_template: "{{ states(teslaSocEntity) != evccSocState  }}"
            then:
              - service: number.set_value
                target:
                  entity_id: "{{ teslaSocEntity }}"
                data:
                  value: "{{ evccSocState }}"
              - wait_for_trigger:
                  - platform: template
                    value_template: "{{ states(teslaSocEntity) == evccSocState  }}"
                continue_on_timeout: false
                timeout:
                  hours: 0
                  minutes: 0
                  seconds: 30
                  milliseconds: 0
      - conditions:
          - condition: trigger
            id:
              - tesla
        sequence:
          - alias: Update EVCC loadpoint SOC
            service: mqtt.publish
            data:
              qos: "1"
              topic_template: "{{'evcc/loadpoints/' ~ evccLoadpointId ~ '/limitSoc/set'}}"
              payload_template: "{{ teslaSocState }}"
          - wait_for_trigger:
              - platform: template
                value_template: "{{ states(teslaSocEntity) == evccSocState  }}"
            continue_on_timeout: false
            timeout:
              hours: 0
              minutes: 0
              seconds: 30
              milliseconds: 0
mode: single
1 « J'aime »

Encore une petite question à laquelle je n’ai pas trouvé de réponse : ma voiture est programmée pour charger à 22h15.

A 22h15, la charge démarre et est coupée par EVCC qui est à ce moment là sur « OFF ».
Est-ce qu’on a une possibilité de le débrayer ?

Je suis obligé de laisser la planification de charge dans la voiture, afin que la charge ne démarre pas aussitôt qu’elle est branchée.

Quel est le besoin final, dans l’idéal ?

Quand la voiture déclenche la charge à 22:15, il ne faut pas que evcc arrête la charge. Pour le moment le soir j’éteins l’admin evcc via modules complémentaires / evcc / arrêter mais c’est pas super pratique

J’essaie de comprendre le besoin derrière, car EVCC semble pouvoir gérer cela en natif.

Si l’idée c’est de démarrer a 22h15 pour profiter des heures creuses, alors il est possible de définir le tariff de l’élec dans EVCC, et activer la fonction smartcost pour ne permettre la charge qu’à partir d’un certain seuil de prix.

Pour ma part je lui donne un forecast de prix, un seuil qui correspond à celui de mes heures creuses et il gère le reste. La charge tesla est planifiée pour 3h du matin (il faut laissert la planification sinon, en effet, la voiture démarre la charge quand on la branche), EVCC lance la charge aux alentours de 22h :

Merci pour ce tuto!
Possible de partager le code mqtt pour tempo qui alimente cette ligne ?

topic: tempo/grid/forecast # Source du forecast en JSON

Voici l’automatisation que j’utilise. Le code est immonde, mais ca fonctionne. L’intégration RTE Tempo est requise. Je nettoie tout cela quand j’aurais du temps libre.

alias: Publier via MQTT le tarif actuel tempo
description: ""
triggers:
  - entity_id:
      - sensor.rte_tempo_prochaine_couleur
    not_to:
      - unknown
      - unavailable
    trigger: state
  - event: start
    trigger: homeassistant
conditions: []
actions:
  - variables:
      isOffPeak: "{{ is_state('binary_sensor.rte_tempo_heures_creuses', 'on') }}"
      tempoColor: "{{ states('sensor.rte_tempo_couleur_actuelle') }}"
      tempoNextColor: "{{ states('sensor.rte_tempo_prochaine_couleur') }}"
      tempoTarif: |-
        {% if tempoColor == 'Bleu' %}
          {{ 0.1296 if isOffPeak else 0.1609 }}
        {% elif cotempoColorlor == 'Blanc' %}
          {{ 0.1486 if isOffPeak else 0.1894 }}
        {% elif tempoColor == 'Rouge' %}
          {{ 0.1568 if isOffPeak else 0.7562 }}
        {% else %}
          undefined
        {% endif %}
      tempoForecast: ""
  - metadata: {}
    data:
      qos: "0"
      retain: true
      topic: tempo/grid/price
      payload: "{{ tempoTarif }}"
    alias: Publier le prix via MQTT
    action: mqtt.publish
  - alias: Publier le prix via MQTT
    metadata: {}
    data:
      qos: "0"
      retain: true
      topic: tempo/grid/forecast
      payload: >-
        {% set current_color = states('sensor.rte_tempo_couleur_actuelle') %} 

        {% set next_color = states('sensor.rte_tempo_prochaine_couleur') %} 

        {% set isOffPeak = is_state('binary_sensor.rte_tempo_heures_creuses',
        'on') %} 

        {% set current_time = as_timestamp(utcnow()) |
        timestamp_custom('%Y-%m-%dT%H:%M:%SZ', false) %} 

        {% set next_period_sensor_state = 
        states('sensor.rte_tempo_heures_creuses_changement') %} 

        {% set next_period = as_timestamp(next_period_sensor_state) |
        timestamp_custom('%Y-%m-%dT%H:%M:%SZ', false)  %} 

        {% set next_color_sensor_date = 
        states('sensor.rte_tempo_prochaine_couleur_changement') %}

        {%- set tempoTariffs = {
            'peak_bleu' : 0.1609,
            'offpeak_bleu' : 0.1296,
            'peak_blanc' : 0.1894,
            'offpeak_blanc' : 0.1486,
            'peak_rouge' : 0.7562,
            'offpeak_rouge' : 0.1568
        }

        -%}

        {%- macro tempoTariff(tempoColor, offPeakHours) -%}
            {%- set tariff = '' -%}
            {%- if tempoColor == 'Bleu' -%}
                {%- if offPeakHours -%}
                    {%- set tariff = tempoTariffs.offpeak_bleu -%}
                {%- else -%}
                    {%- set tariff = tempoTariffs.peak_bleu -%}
                {%- endif -%}
            {%- elif tempoColor == 'Blanc' %}
                {%- if offPeakHours -%}
                    {%- set tariff = tempoTariffs.offpeak_blanc -%}
                {%- else -%}
                    {%- set tariff = tempoTariffs.peak_blanc -%}
                {%- endif -%}
            {%- elif tempoColor == 'Rouge' %}
                {%- if offPeakHours -%}
                    {%- set tariff = tempoTariffs.offpeak_rouge -%}
                {%- else -%}
                    {%- set tariff = tempoTariffs.peak_rouge -%}
                {%- endif -%}
            {%- else -%}
                {%- set tariff = 'unknown' -%}
            {%- endif -%}
            {{ tariff }}
        {%- endmacro -%}

        {% set forecast_items_count = 2 if next_color != 'unknown' and
        next_color != '' else 1 %}

        {% set forecast = [] %} {% set forecast = namespace(forecast_items=[])%}

        {# Loop to generate forecast items #} {% for i in
        range(forecast_items_count) %}
          {% set is_current_color = (i == 0) %}
          
          {% if is_current_color %}
            {% set color = current_color %}
            {% set start_time = current_time %}
            {% set end_time = next_period %}

            {% set forecast_item = {
              "start": start_time,
              "end": next_period,
              "price": tempoTariff(current_color, isOffPeak) | float
            } %}
          
            {% set forecast.forecast_items = forecast.forecast_items + [forecast_item] %}
            
            {% if is_current_color and not isOffPeak %}
          
                {% set color = current_color %}
                {% set start_time = current_time %}
                {% set end_time = next_period %}
              
                {% set forecast_item = {
                  "start": next_period,
                  "end": (as_timestamp(states('sensor.rte_tempo_heures_creuses_changement'))  + 8*3600 ) | timestamp_custom('%Y-%m-%dT%H:%M:%SZ', false),
                  "price": tempoTariff(current_color, not isOffPeak) | float
                } %}

            {% set forecast.forecast_items = forecast.forecast_items + [forecast_item] %}
            
            {% endif %}
          {% else %}

          {% set next_color_time = as_timestamp(states('sensor.rte_tempo_prochaine_couleur_changement')) | timestamp_custom('%Y-%m-%dT%H:%M:%SZ', false)  %}
        {% set next_color_peak_start = as_timestamp(next_color_sensor_date) |
        timestamp_custom('%Y-%m-%dT%H:%M:%SZ', false)  %} {% set
        next_color_peak_end = (as_timestamp(next_color_sensor_date) + 16*3600) |
        timestamp_custom('%Y-%m-%dT%H:%M:%SZ', false)  %} {% set
        next_color_offpeak_end = (as_timestamp(next_color_sensor_date) +
        24*3600) | timestamp_custom('%Y-%m-%dT%H:%M:%SZ', false)  %}

            {% set color = next_color %}
            {% set start_time = next_time %}

            {% set forecast_item = {
              "start": next_color_peak_start,
              "end": next_color_peak_end,
              "price": tempoTariff(next_color, false) | float
            } %}
          
            {% set forecast.forecast_items = forecast.forecast_items + [forecast_item] %}

            {% set forecast_item = {
              "start": next_color_peak_end,
              "end": next_color_offpeak_end,
              "price": tempoTariff(next_color, true) | float
            } %}
          
            {% set forecast.forecast_items = forecast.forecast_items + [forecast_item] %}
            
          {% endif %}
          
        {% endfor %}


        {{forecast.forecast_items | tojson }}
    action: mqtt.publish
mode: single

Merci
A la place de l’intégration RTE Tempo, il est possible de mettre ça dans rest.yalm, c’est un peu plus léger, sans doute aussi moins robuste à long terme:

- resource: https://www.api-couleur-tempo.fr/api/jourTempo/today
  scan_interval: 3600
  sensor:
    - name: "Tempo today"
      value_template: >
        {% set codes = {0: "inconnu", 1: "bleu", 2: "blanc", 3: "rouge"} %}
        {{ codes[value_json.codeJour] }}
      json_attributes:
        - dateJour
        - codeJour
        - periode

- resource: https://www.api-couleur-tempo.fr/api/jourTempo/tomorrow
  scan_interval: 60
  sensor:
    - name: "Tempo demain"
      value_template: >
        {% set codes = {0: "inconnu", 1: "bleu", 2: "blanc", 3: "rouge"} %}
        {{ codes[value_json.codeJour] }}
      json_attributes:
        - dateJour
        - codeJour
        - periode