HA-Teleinformation Linky-Mode Standard

Intro

Dans un article précédent https://domo.rem81.com/ha-teleinformation-linky-mode-historique/ , je décrivais la mis en oeuvre d’une communication entre un Linky et Home Assistant en mode Historique.

Après avoir fonctionné un temps en mode « Historique », je suis passé au mode « Standard ». Celui ci offre un plus grand nombre de données.

Raccordement de la télé information de mon compteur Linky. Rien de bien méchant il suffit de se raccorder aux bornes i1/i2 du linky, le plus délicat fut le passage du câble de 60 ml entre le compteur Linky et mon tableau électrique.

Raccordement du Linky

Mises à jour

du 23/11/2023:

Ajout d’une version EDF « Tempo »

du 16/08/2022

Ajout du « filter out » dans les HP,HC permettant de rejeter les valeurs nulles si besoin.

du 12/04/2022

Suite à passage Home Assistant 2022.4.0, modification du changement de tarif des utility meter https://www.home-assistant.io/integrations/utility_meter

Pré requis

Mes fichiers « .yaml » sont regroupés dans un dossier « config/packages ». J’utilise la directive « !include_dir_named packages » dans mon « configuration.yaml » très pratique pour organiser son HA.


homeassistant:
  name: Crochon
  latitude: !secret latitude
  longitude: !secret longitude
  unit_system: metric
  packages: !include_dir_named packages
  external_url: !secret external-url
  internal_url: !secret internal-url

Choix du matériel

Les informations transmises par le Linky ne sont pas directement exploitables par un ESP, elles nécessitent un adaptateur, vous trouverez beaucoup de modèles sur le Net, perso j’ai choisi la facilité en achetant un module Wemos Teleinfo.

WeMos Teleinfo 2

C’est un module pas très cher, correctement étudié et bien fini, compatible avec les esp8266 et ESP32 Mini, qui dispose également d’une Led WS2812 RGB programmable, d’un connecteur I2C disponible pour un afficheur OLED ou autres capteurs compatibles, et d’une led indiquant l’état de la connexion avec le Linky qui se raccorde sur le bornier vert.

Perso j’utilise un L’ESP32 Mini, en effet l’ESP8266 est trop juste en puissance de calcul si on utilise l’intégration ESPHOME plus un afficheur, j’ai galéré avec, je ne le recommande pas, le constructeur du wemos téléinfo non plus d’ailleurs.

L’ESP32 Mini est un ESP32 au format ESP8266 D1, pratique si l’on souhaite utiliser des cartes d’extension, mais avec une puissance de calcul et de traitement bien supérieure.

Descriptif fonctionnel

Les compteurs Linky disposent de 2 modes de téléinformation :
• Le mode Historique, qui correspond à l’ancien mode des compteurs électroniques.
• Le mode Standard, qui est le nouveau format et qui comporte plus d’informations.

Vous trouverez les informations détaillées dans le document Enedis suivant:

Le module WEMOS Teleinfo est compatible, le changement de mode passe obligatoirement par une demande auprès de votre fournisseur d’énergie qui relaye vers Enedis.

Concernant l’intégration dans HA, pas de problème particulier grâce à « teleinfo » disponible sur ESP Home, il est compatible avec les deux modes, les différences étant dans la vitesse de transmission et la validation du mode historique ou pas:

Mode Historique

Mode Standard

Informations collectées

J’utilise le W et non le VA pour l’entité « SINSTS » afin d’exploiter les « Statistiques Longues Durée » qui ne reconnait pas les « Volt Ampéres ». Pour mémoire, en monophasé P en W= P en VA multiplie cos phi, mais come le Linky ne remonte pas le cos phi on se contentera d’un cos phi de 1, les puristes ne m’en voudront pas.

Je divise par 1000 le total de l’énergie active soutirée « EAST » pour obtenir des kWh. C’est cette entité que j’utilise dans les « utility meter » de HA pour calculer mes consommations journalière, semaine, mois, année.

Je calcul en % dans un « template » « Linky P/Pcoup » le ratio entre la puissance instantanée « SINST » et la puissance de coupure « PCOUP », ce qui donne une idée de la réserve de puissance disponible et plus tard, s’en servir pour vérifier si l’abonnement peut être revue à la baisse.

« UMOY1 » nous donne la tension moyenne du secteur.

« IRMS1 » nous donne l’intensité efficace de la phase 1.

« NTARF » nous indique si le tarif est en heure creuse (=1) ou heure pleine (=2), variable utilisée dans l’automatisme de comptabilisation de l’énergie avec les « utility_meter ». J’en profite pour afficher en clair dans un « template », le tarif en cours.

Je remonte la consommation journalière depuis HA vers l’ESP afin de l’afficher en local.

Tableau des informations disponibles

Certaines sont dispo uniquement en tri-phasé et/ou en tant que producteur d’énergie.

Code ESP

Si vous avez des difficultés de flashage avec ESPHome, parcourez mon article https://domo.rem81.com/home-assistant_esp-home/ cela devrait vous aider.

L’afficheur utilise une police de caractère « Arial », vous pouvez télécharger le fichier arial.ttf ici puis le transférer dans un dossier « fonts » de votre « /config/esphome ». Bien entendu vous pouvez utiliser une autre police de caractères, « size » détermine la taille des caractères.

Version « Tempo »

les filtres « filter_out: 0.0 » sont à mettre en action si et seulement si les index sont supérieurs à 0 sinon vous afficherez « indisponible ».

Le filtre « Lambda » permet d’éviter des incohérences dans l’évolution des index, il m’est arrivé de lire des valeurs très faibles mais supérieure à 0 pour des raisons que j’ignore.

L’écart se regle dans la variable « globals » ecart_max.

substitutions:
  device_name: esp124-tic
  adress_ip: "192.168.0.124"
  friendly_name: esp124
  time_timezone: "Europe/Paris"
  
esphome:
  name: ${device_name}
  platform: ESP32
  board: mhetesp32minikit
  project:
    name: "rem81.esp124-TIC"
    version: "1.0.1"
  platformio_options:
    lib_deps: NeoPixelBus@2.6.0
  on_boot:
    then:
      - light.control:
          id: led1
          brightness: 0.25
          state: on
wifi:
  networks:
    - ssid: !secret wifi_esp
      password: !secret mdpwifi_esp
      priority: 1
    - ssid: !secret wifi
      password: !secret mdpwifi
      priority: 0
  reboot_timeout: 5min

  manual_ip:
    static_ip: ${adress_ip}
    gateway: 192.168.0.254
    subnet: 255.255.255.0

# Enable logging
logger:
#  baud_rate: 0
# Enable Home Assistant API
api:

ota:

web_server:
  port: 80

font:
  - file: "fonts/arial.ttf"
    id: arial
    size: 15

i2c:
  sda: GPIO21 #D2=pin 19
  scl: GPIO22 #D1=pin 20
  scan: True
  id: bus_a
  
# 
uart:
  id: uart_a
  rx_pin: GPIO23
#  tx_pin: GPIO1
  baud_rate: 9600
  parity: EVEN
  data_bits: 7

teleinfo:
  id: myteleinfo
  uart_id: uart_a
  update_interval: 10s
  historical_mode: false
  
# Led WS2812 RGB  
light:
  - platform: partition
    name: led1
    id: led1
    default_transition_length: 0s
    segments:
      - id: rgb_led
        from: 0
        to: 0

  - platform: neopixelbus
    num_leds: 1
    pin: GPIO18
    name: "RGB strip"
    variant: ws2812
    id: rgb_led
    default_transition_length: 0s  

globals:
  # Ecart maximum admissible entre deux lectures
   - id: ecart_max
     type: float
     restore_value: no
     initial_value: '50'


sensor:
# Energie Active soutirée totale
  - platform: teleinfo
    id: hc_hp
    tag_name: "EAST"
    name: "Linky HPHC KWH"
    unit_of_measurement: "kWh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    device_class: "energy"
    state_class: "total_increasing"  
    filters:
      - filter_out: 0.0
      - lambda: |-
          return x/1000;
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};          
          

# Energie Active soutirée Index01 HC Bleu
  - platform: teleinfo
    id: hcbleu
    tag_name: "EASF01"
    name: "Linky HC Bleu kWh"
    unit_of_measurement: "kWh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    device_class: "energy"
    state_class: "total_increasing"      
    filters:
      - lambda: return x / 1000;
      - filter_out: 0.0
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};      

# Energie Active soutirée Index02 HP Bleu
  - platform: teleinfo
    id: hpbleu
    tag_name: "EASF02"
    name: "Linky HP Bleu kWh"
    unit_of_measurement: "kWh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    device_class: "energy"
    state_class: "total_increasing"      
    filters:
      - lambda: return x / 1000;      
      - filter_out: 0.0
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};      

# Energie Active soutirée Index03 HC Blanc
  - platform: teleinfo
    id: hcblanc
    tag_name: "EASF03"
    name: "Linky HC Blanc kWh"
    unit_of_measurement: "kWh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    device_class: "energy"
    state_class: "total_increasing"      
    filters:
      - lambda: return x / 1000;
      - filter_out: 0.0
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};      

# Energie Active soutirée Index04 HP Blanc
  - platform: teleinfo
    id: hpblanc
    tag_name: "EASF04"
    name: "Linky HP Blanc kWh"
    unit_of_measurement: "kWh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    device_class: "energy"
    state_class: "total_increasing"      
    filters:
      - lambda: return x / 1000;
      - filter_out: 0.0   
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};       

# Energie Active soutirée Index05 HC Rouge
  - platform: teleinfo
    id: hcrouge
    tag_name: "EASF05"
    name: "Linky HC Rouge kWh"
    unit_of_measurement: "kWh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    device_class: "energy"
    state_class: "total_increasing"      
    filters:
      - multiply: 0.001
      - filter_out: 0.0
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};
# Energie Active soutirée Index06 HP Rouge
  - platform: teleinfo
    id: hprouge
    tag_name: "EASF06"
    name: "Linky HP Rouge kWh"
    unit_of_measurement: "kWh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    device_class: "energy"
    state_class: "total_increasing"  
    filters:
      - lambda: return x / 1000;
      - filter_out: 0.0   
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};       

#Puissance apparente de coupure
  - platform: teleinfo
    id: pcoup
    tag_name: "PCOUP"
    name: "Linky PCOUP"
    unit_of_measurement: "kVA"
    icon: mdi:flash
    teleinfo_id: myteleinfo

#Puissance apparente instantanée ph1 

  - platform: teleinfo
    id: papp
    tag_name: "SINSTS"
    name: "Linky PAPP"
    unit_of_measurement: "VA"
    device_class: "power"
    state_class: "measurement"  
    icon: mdi:flash
    teleinfo_id: myteleinfo


#Tension moyenne ph1
  - platform: teleinfo
    id: umoy1
    tag_name: "UMOY1"
    name: "Linky Umoy"
    unit_of_measurement: "V"
    icon: mdi:flash
    teleinfo_id: myteleinfo

#Courant efficace ph1
  - platform: teleinfo
    id: iinst
    tag_name: "IRMS1"
    name: "Linky I Inst"
    unit_of_measurement: "A"
    icon: mdi:flash
    teleinfo_id: myteleinfo

# Numero du Tarif en cours
  - platform: teleinfo
    id: ntarif
    tag_name: "NTARF"
    name: "linky N Tarif"
    unit_of_measurement: ""
    icon: mdi:flash
    teleinfo_id: myteleinfo

############### TEMPLATE  ######################"
# Calcul du ratio de la puissance apparente utilisée en % par rapport au contrat
  - platform: template
    name: "Linky P/PCoup"
    id: p100
    icon: mdi:flash
    unit_of_measurement: "%"
    accuracy_decimals: 0
    lambda: |-
      return ((id(papp).state/1000)/id(pcoup).state*100);

# Lecture dans HA de la conso du jour
  - platform: homeassistant
    name: "HCHP J"
    unit_of_measurement: "kWh"
    entity_id: sensor.compteur_energie_total_jour_tous_tarifs
    id: hphcj

    
#######################################
text_sensor:
# Registre de statuts
  - platform: teleinfo
    id: stge
    tag_name: "STGE"
    name: "linky Statuts"
    icon: mdi:flash
    teleinfo_id: myteleinfo

# nom du calendrier tarifaire
  - platform: teleinfo
    id: ngtf
    tag_name: "NGTF"
    name: "linky Nom calendrier tarifaire"
    icon: mdi:flash
    teleinfo_id: myteleinfo

# Libellé tarif fournisseur en cours
  - platform: teleinfo
    id: ltarf
    tag_name: "LTARF"
    name: "linky Libelle tarif fournisseur en cours"
    icon: mdi:flash
    teleinfo_id: myteleinfo

# Convertion du tarif en cours
  - platform: template
    id: tarif
    name: "Linky PTEC"
    lambda: |-
      if ( id(ntarif).state == 1 || id(ntarif).state == 3 || id(ntarif).state == 5){
        return { "HC.." };
      } else {
        return { "HP.." };
      }

#Etat de la connection
binary_sensor:
  - platform: status
    name: "${friendly_name} Status"

switch:
  - platform: restart
    name: "${friendly_name} Restart"

# Affichage
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    brightness: 100%
    lambda: |-
      it.printf(0,0,id(arial),"P=%.0f VA",id(papp).state);
      it.printf(75,0,id(arial),"-%.0f %%",id(p100).state);
      it.printf(0,15,id(arial),"I Inst=%.0f A",id(iinst).state);
      it.printf(0,30,id(arial),"ConsoJ=%.0f kWh",id(hphcj).state);
      std::string tarif_ = id(ltarf).state;
      it.printf(0,45,id(arial), tarif_.c_str());      
##      it.printf(0,45,id(arial), "Tarif:%s", tarif_.c_str());      


interval:
  - interval: 1s
    then:
      - script.execute: calcul_led_jour

# ------------------------  Scripts
script:
# 
# Couleur du Jour en cours
  - id: calcul_led_jour
    mode: single
    then:
      - logger.log:
          format: "Ltarf= %f"
          args: [ 'id(ntarif).state']

      - if: 
          condition:
            - lambda: |-
                return ( id(ntarif).state == 1 || id(ntarif).state == 2);

          then:
            - light.control:
                id: led1
                red: 0% 
                green: 0%
                blue: 100%    

      - if: 
          condition:
            - lambda: |-
                return ( id(ntarif).state == 3 || id(ntarif).state == 4);
          then:
            - light.control:
                id: led1
                red: 100% 
                green: 100%
                blue: 100%    
          
      - if: 
          condition:
            - lambda: |-
                return ( id(ntarif).state == 5 || id(ntarif).state == 6);
          then:
            - light.control:
                id: led1
                red: 100% 
                green: 0%
                blue: 0%    

Version HC/HP

les filtres « filter_out: 0.0 » sont à mettre en action si et seulement si les index sont supérieurs à 0 sinon vous afficherez « indisponible ».

Le filtre « Lambda » permet d’éviter des incohérences dans l’évolution des index, il m’est arrivé de lire des valeurs très faibles mais supérieure à 0 pour des raisons que j’ignore.

L’écart se regle dans la variable « globals » ecart_max

substitutions:
  device_name: esp124-tic
  adress_ip: "192.168.0.124"
  friendly_name: esp124
  time_timezone: "Europe/Paris"
  
esphome:
  name: ${device_name}
  platform: ESP32
  board: mhetesp32minikit
  project:
    name: "rem81.esp124-TIC"
    version: "1.0.1"
  platformio_options:
    lib_deps: NeoPixelBus@2.6.0
  on_boot:
    then:
      - light.control:
          id: led1
          brightness: 0.25
          state: on
wifi:
  networks:
    - ssid: !secret wifi_mi4
      password: !secret mdpwifi_mi4
      priority: 2  
    - ssid: !secret wifi_esp
      password: !secret mdpwifi_esp
      priority: 1
    - ssid: !secret wifi
      password: !secret mdpwifi
      priority: 0
  reboot_timeout: 5min

  manual_ip:
    static_ip: ${adress_ip}
    gateway: 192.168.0.254
    subnet: 255.255.255.0


# Enable logging
logger:
#  baud_rate: 0
# Enable Home Assistant API
api:

ota:

web_server:
  port: 80

font:
  - file: "fonts/arial.ttf"
    id: arial
    size: 15

i2c:
  sda: GPIO21 #D2=pin 19
  scl: GPIO22 #D1=pin 20
  scan: True
  id: bus_a
  
# 
uart:
  id: uart_a
  rx_pin: GPIO23
#  tx_pin: GPIO1
  baud_rate: 9600
  parity: EVEN
  data_bits: 7

teleinfo:
  id: myteleinfo
  uart_id: uart_a
  update_interval: 10s
  historical_mode: false
  
# Led WS2812 RGB  
light:
  - platform: partition
    name: led1
    id: led1
    default_transition_length: 0s
    segments:
      - id: rgb_led
        from: 0
        to: 0

  - platform: neopixelbus
    num_leds: 1
    pin: GPIO18
    name: "RGB strip"
    variant: ws2812
    id: rgb_led
    default_transition_length: 0s  

globals:
  # Ecart maximum admissible entre deux lectures
   - id: ecart_max
     type: float
     restore_value: no
     initial_value: '50'

sensor:
# Energie Active soutirée totale
  - platform: teleinfo
    id: hc_hp
    tag_name: "EAST"
    name: "Linky HPHC KWH"
    unit_of_measurement: "kWh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    device_class: "energy"
    state_class: "total_increasing"  
    filters:
      - filter_out: 0.0
      - lambda: |-
          return x/1000;


# Energie Active soutirée Index01
  - platform: teleinfo
    id: hchc
    tag_name: "EASF01"
    name: "Linky HC Wh"
    unit_of_measurement: "Wh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    filters:
      - filter_out: 0.0
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};    
    
# Energie Active soutirée Index02    
  - platform: teleinfo
    id: hchp
    tag_name: "EASF02"
    name: "Linky HP Wh"
    unit_of_measurement: "Wh"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    filters:
      - filter_out: 0.0    
      - lambda: |-
          float MAX_DIFFERENCE = id(ecart_max);  // Difference max entre de lecture, à ajuster selon votre cas de figure.
          static float last_value = NAN;
          if (isnan(last_value) || std::abs(x - last_value) < MAX_DIFFERENCE)
            return last_value = x;
          else
            return {};    

#Puissance apparente de coupure
  - platform: teleinfo
    id: pcoup
    tag_name: "PCOUP"
    name: "Linky PCOUP"
    unit_of_measurement: "kVA"
    icon: mdi:flash
    teleinfo_id: myteleinfo

#Puissance apparente instantanée ph1 

  - platform: teleinfo
    id: papp
    tag_name: "SINSTS"
    name: "Linky PAPP"
    unit_of_measurement: "VA"
    device_class: "power"
    state_class: "measurement"  
    icon: mdi:flash
    teleinfo_id: myteleinfo
    on_value:
      - if:
          condition:
            sensor.in_range:
              id: papp
              below: 1000
          then: 
            - light.control:
                id: led1
                red: 0%
                green: 100% # vert
                blue: 0%
      - if:
          condition:
            sensor.in_range:
              id: papp
              above: 1000
              below: 3000
          then: 
            - light.control:
                id: led1
                red: 0%
                green: 0% # bleu
                blue: 100%
      - if:
          condition:
            sensor.in_range:
              id: papp
              above: 3000
          then: 
            - light.control:
                id: led1
                red: 100% #rouge
                green: 0%
                blue: 0%    

#Tension moyenne ph1
  - platform: teleinfo
    id: umoy1
    tag_name: "UMOY1"
    name: "Linky Umoy"
    unit_of_measurement: "V"
    icon: mdi:flash
    teleinfo_id: myteleinfo

#Courant efficace ph1
  - platform: teleinfo
    id: iinst
    tag_name: "IRMS1"
    name: "Linky I Inst"
    unit_of_measurement: "A"
    icon: mdi:flash
    teleinfo_id: myteleinfo

# Numero du Tarif en cours
  - platform: teleinfo
    id: ntarif
    tag_name: "NTARF"
    name: "linky N Tarif"
    unit_of_measurement: ""
    icon: mdi:flash
    teleinfo_id: myteleinfo

############### TEMPLATE  ######################"
# Calcul du ratio de la puissance apparente utilisée en % par rapport au contrat
  - platform: template
    name: "Linky P/PCoup"
    id: p100
    icon: mdi:flash
    unit_of_measurement: "%"
    accuracy_decimals: 0
    lambda: |-
      return ((id(papp).state/1000)/id(pcoup).state*100);

# Lecture dans HA de la conso du jour
  - platform: homeassistant
    name: "HCHP J"
    unit_of_measurement: "kWh"
    entity_id: sensor.energie_totale_jour
    id: hphcj

# Puissance du signal WIFI
  - platform: wifi_signal
    id: wif
    name: "${friendly_name} WiFi Signal Sensor"
    update_interval: 60s
# Temps de fonctionnement de l'ESP    
  - platform: uptime
    id: uptime_seconds
    name: "${friendly_name} Uptime"
    update_interval: 60s
    unit_of_measurement: s
    accuracy_decimals: 0
    force_update: false
    icon: mdi:timer
    
#######################################
text_sensor:
# Registre de statuts
  - platform: teleinfo
    id: stge
    tag_name: "STGE"
    name: "linky Statuts"
    icon: mdi:flash
    teleinfo_id: myteleinfo
    
# Convertion du tarif en cours
  - platform: template
    id: tarif
    name: "Linky PTEC"
    lambda: |-
      if ( id(ntarif).state == 1 ) {
        return { "HC.." };
      } else {
        return { "HP.." };
      }
# Affichage du temps de fonctionnement
  - platform: template
    name: "${friendly_name} Uptime"
    update_interval: 60s
    icon: mdi:clock-start
    lambda: |-
      int seconds = (id(uptime_seconds).state);
      int days = seconds / (24 * 3600);
      seconds = seconds % (24 * 3600);
      int hours = seconds / 3600;
      seconds = seconds % 3600;
      int minutes = seconds /  60;
      seconds = seconds % 60;
      if ( days ) {
        return { (String(days) +"d " + String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
      } else if ( hours ) {
        return { (String(hours) +"h " + String(minutes) +"m "+ String(seconds) +"s").c_str() };
      } else if ( minutes ) {
        return { (String(minutes) +"m "+ String(seconds) +"s").c_str() };
      } else {
        return { (String(seconds) +"s").c_str() };
      }

#Etat de la connection
binary_sensor:
  - platform: status
    name: "${friendly_name} Status"
# Restart de l'ESP
switch:   
  - platform: restart
    name: "${friendly_name} Restart"

# Affichage
display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    brightness: 100%
    lambda: |-
      it.printf(0,0,id(arial),"P=%.0f VA",id(papp).state);
      it.printf(75,0,id(arial),"-%.0f %%",id(p100).state);
      it.printf(0,15,id(arial),"I Inst=%.0f A",id(iinst).state);
      it.printf(0,30,id(arial),"ConsoJ=%.0f kWh",id(hphcj).state);
      std::string tarif_ = id(tarif).state;
      it.printf(0,45,id(arial), "Tarif: %s", tarif_.c_str());      


      
   

Registre de Statuts

Le registre de statuts « STGE » (uniquement dispo en mode standard) nous donne un état du Linky en général. Il remonte dans un format de huit caractères ascii. Chaque caractères est codés sur 4 bits qui correspondent à une ou plusieurs informations. Le détail est donné au chapitre 6.2.3.14 du document Enedis ci dessous:

J’ai écrit une routine qui décode les caractères du registre de statuts permettent de l’exploiter dans HA via l’Addon AppDaemon.

Celle ci convertit les 8 caractères du registre Statuts de l’ASCII vers du Binaire.

Addon Appdaemon

Cet Addon, pour ceux qui ne connaissent pas, permet d’écrire des programmes en Python très élaborés.

Je décrit son installation dans cet article cet article.

Vous trouverez ci après les fichiers « .yaml » et « .py » à installer dans « votre AppDaemon. »

Code de « linky_status.yaml »


Linky:
  class: LinkyStatuts
  module: linky_statuts
  registre: input_text.linky_test_status
#  registre: sensor.linky_statuts

Vous pouvez faire des tests en de-commentant le « registre: input_text.linky_test_status » et en commentant le « registre: input_text.linky_test_status » (il faut un seul « registre » actif à la fois).

Code de « linky_status.py »

import hassapi as hass

# Conversion ASCII vers binaire codé décimal
def repr_bin2(str):
    caract = 0
    decod=""        
    for caract in str:
        decod += bin(int(caract,16))[2::].zfill(4)
    return decod

class LinkyStatuts(hass.Hass):
    def initialize(self):
        self.listen_state(self.statuts_change, self.args["registre"])
        self.log("Initialisation Linky..", log="linky_log")

    def statuts_change(self, entity, attribute, old, new, kwargs):
        statuts = new
        if len(statuts)!=8:
            self.log(f"Erreur format registre de statuts= {statuts}", log="linky_log")
        else:
            self.convertion_status(kwargs)

#  Lecture et conversion du registre de statuts du Linky 
    def convertion_status(self, kwargs):
        statuts = self.get_state(self.args["registre"])
        statuts_binaire=(repr_bin2(statuts))

        # Exploitation des 32 bits du statuts poids forts en tête #
        # Bit 0:Contact Sec#
        bit_0= statuts_binaire[31]
        if bit_0 == "0":
            contact_sec = "Ferme"
        else:
            contact_sec = "Ouvert"

        # Bits 1 à 3: Organe de coupure #
        bit_1_3= statuts_binaire[28:31]
        if bit_1_3 == "000":
            organe_de_coupure = "Ferme"
        elif bit_1_3 == "001":
            organe_de_coupure = "Ouvert sur Surpuissance"
        elif bit_1_3 == "010":
            organe_de_coupure = "Ouvert sur Surtension"
        elif bit_1_3 == "011":
            organe_de_coupure = "Ouvert sur Delestage"
        elif bit_1_3 == "100":
            organe_de_coupure = "Ouvert sur Ordre CPL ou Euridis"
        elif bit_1_3 == "101":
            organe_de_coupure = "Ouvert sur Surchauffe avec I>Imax"
        elif bit_1_3 == "110":
            organe_de_coupure = "Ouvert sur Surchauffe avec I<Imax"
        else:
            organe_de_coupure = "??"

        # Bit 4: Etat du cache borne #
        bit_4= statuts_binaire[27]
        if bit_4 == "0":
            cache_borne = "Ferme"
        else:
            cache_borne = "Ouvert"

        # Bit 5: Non utilisé toujours à 0 #

        # Bit 6: Surtension sur une des phases #
        bit_6= statuts_binaire[25]
        if bit_6 == "0":
            surtension = "Pas de Surtension"
        else:
            surtension = "Surtension"

        # Bit 7: Dépassement Puissance de Référence #
        bit_7= statuts_binaire[24]
        if bit_7 == "0":
            dep_pref = "Pas de Depassement"
        else:
            dep_pref = "Depassement en Cours"

        # Bit 8: Producteur ou Consommateur #
        bit_8= statuts_binaire[23]
        if bit_8 == "0":
            fonct_prod_conso = "Consommateur"
        else:
            fonct_prod_conso = "Producteur"

        # Bit 9: Sens de L'énergie active #
        bit_9= statuts_binaire[22]
        if bit_9 == "0":
            sens_energie_act = "Energie active positive"
        else:
            sens_energie_act = "Energie active negative"

        # Bits 10 à 13: Tarif en cours contrat fourniture #
        bit_10_13= statuts_binaire[18:22]
        if bit_10_13 == "0000":
            tarif_fourniture = "Energie ventilee sur index 1"
        elif bit_10_13 == "0001":
            tarif_fourniture = "Energie ventilee sur index 2"
        elif bit_10_13 == "0010":
            tarif_fourniture = "Energie ventilee sur index 3"
        elif bit_10_13 == "0011":
            tarif_fourniture = "Energie ventilee sur index 4"
        elif bit_10_13 == "0100":
            tarif_fourniture = "Energie ventilee sur index 5"
        elif bit_10_13 == "0101":
            tarif_fourniture = "Energie ventilee sur index 6"
        elif bit_10_13 == "0110":
            tarif_fourniture = "Energie ventilee sur index 7"
        elif bit_10_13 == "0111":
            tarif_fourniture = "Energie ventilee sur index 8"
        elif bit_10_13 == "1000":
            tarif_fourniture = "Energie ventilee sur index 9"
        elif bit_10_13 == "1001":
            tarif_fourniture = "Energie ventilee sur index 10"
        else:
            tarif_fourniture = "??"

        # Bits 14 à 15: Tarif en cours contrat fourniture #
        bit_14_15= statuts_binaire[16:18]
        if bit_14_15 == "00":
            tarif_distributeur = "Energie ventilee sur index 1"
        elif bit_14_15 == "01":
            tarif_distributeur = "Energie ventilee sur index 2"
        elif bit_14_15 == "10":
            tarif_distributeur = "Energie ventilee sur index 3"
        elif bit_14_15 == "11":
            tarif_distributeur = "Energie ventilee sur index 4"

        # Bit 16: Mode dégradé horloge #
        bit_16= statuts_binaire[15]
        if bit_16 == "0":
            mode_horloge = "Horloge correcte"
        else:
            mode_horloge = "Horloge mode degrade"

        # Bit 17: Etat TIC #
        bit_17= statuts_binaire[14]
        if bit_17 == "0":
            etat_tic = "Mode Historique"
        else:
            etat_tic = "Mode Standard"

        # Bit 18: Non utilisé #

        # Bits 19 à 20: Etat de la com Euridis #
        bit_19_20= statuts_binaire[11:13]
        if bit_19_20 == "00":
            com_euridis = "Com desactivee"
        elif bit_19_20 == "01":
            com_euridis = "Com Active sans securite"
        elif bit_19_20 == "11":
            com_euridis = "Com Active avec securite"
        else:
            com_euridis = "Com ??"

        # Bits 21 à 22: Statut du CPL #
        bit_21_22= statuts_binaire[9:11]
        if bit_21_22 == "00":
            statut_cpl = "New/unlock"
        elif bit_21_22 == "01":
            statut_cpl = "New/Lock"
        elif bit_21_22 == "11":
            statut_cpl = "Registered"
        else:
            statut_cpl = "Com ??"

        # Bit 23: Synchro CPL #
        bit_23= statuts_binaire[8]
        if bit_23 == "0":
            synchro_cpl = "Compteur non synchronise"
        else:
            synchro_cpl = "Compteur synchronise"

        # Bits 24_25: Couleur du jour contrat historique Tempo #
        bit_24_25= statuts_binaire[6:8]
        if bit_24_25 == "00":
            couleur_j_tempo = "Contrat non Tempo"
        elif bit_24_25 == "01":
            couleur_j_tempo = "Bleu"
        elif bit_24_25 == "10":
            couleur_j_tempo = "Blanc"
        elif bit_24_25 == "11":
            couleur_j_tempo = "Rouge"
        else:
            couleur_j_tempo = "Couleur J tempo indefinie"

        # Bits 26_27: Couleur du J+1 contrat historique Tempo #
        bit_26_27= statuts_binaire[4:6]
        if bit_26_27 == "00":
            couleur_j1_tempo = "Contrat non Tempo"
        elif bit_26_27 == "01":
            couleur_j1_tempo = "Bleu"
        elif bit_26_27 == "10":
            couleur_j1_tempo = "Blanc"
        elif bit_26_27 == "11":
            couleur_j1_tempo = "Rouge"
        else:
            couleur_j1_tempo = "Couleur J+1 tempo indefinie"

        # Bits 28_29: Préavis Pointes mobiles #
        bit_28_29= statuts_binaire[2:4]
        if bit_28_29 == "00":
            préavis_p_mobiles = "pas de preavis en cours"
        elif bit_28_29 == "01":
            préavis_p_mobiles = "Preavis PM1 en cours"
        elif bit_28_29 == "10":
            préavis_p_mobiles = "Preavis PM2 en cours"
        elif bit_28_29 == "11":
            préavis_p_mobiles = "Preavis PM3 en cours"
        else:
            préavis_p_mobiles = "Preavis en cours indéfini"
            
        # Bits 30_31: Préavis Pointes mobiles #
        bit_30_31= statuts_binaire[2:4]
        if bit_30_31 == "00":
            pointe_mobile = "Pas de pointe mobile"
        elif bit_30_31 == "01":
            pointe_mobile = "PM1 en cours"
        elif bit_30_31 == "10":
            pointe_mobile = "PM2 en cours"
        elif bit_30_31 == "11":
            pointe_mobile = "PM3 en cours"
        else:
            pointe_mobile = "Pointe mobile indefinie"

        #### Creation et Mise à jour des entités HA  ####

        # Etat du contact Sec (= 1 = fermé en Heure Creuse) #
        if bit_0 == "0":
            self.set_state("binary_sensor.linky_contact_sec", state="on", replace=True, attributes= {"icon": "mdi:flash"})  
        else:
            self.set_state("binary_sensor.linky_contact_sec", state="off", replace=True, attributes= {"icon": "mdi:flash"})  
        
        # Etat de l'organe de coupure #
        self.set_state("sensor.linky_organe_de_coupure", state=organe_de_coupure, replace=True, attributes= {"icon": "mdi:flash"})

        #  Sens de l'énergie #
        if bit_9 == "0":
            self.set_state("binary_sensor.linky_sens_energie_active", state="on", replace=True, attributes= {"icon": "mdi:flash"})   
        else:
            self.set_state("binary_sensor.linky_sens_energie_active", state="off", replace=True, attributes= {"icon": "mdi:flash"})   
        self.set_state("sensor.linky_sens_energie_active", state=sens_energie_act, replace=True, attributes= {"icon": "mdi:flash"})           


        ####   Log de Déboggage   
        #    A commenter ou supprimer si inutile #
        self.log(f"Statuts={statuts}", log="linky_log")
        self.log(f"Statuts Binaire={statuts_binaire}", log="linky_log")
        self.log(f"bit_0={bit_0} / Contact Sec={contact_sec}", log="linky_log")
        self.log(f"bit_1_3={bit_1_3} / Organe de coupure={organe_de_coupure}", log="linky_log")
        self.log(f"bit_4={bit_4} / Cache_borne={cache_borne}", log="linky_log")
        self.log(f"bit_6={bit_6} / Surtension={surtension}", log="linky_log")
        self.log(f"bit_7={bit_7} / Depassement Pref={dep_pref}", log="linky_log")
        self.log(f"bit_8={bit_8} / Fonctionnement={fonct_prod_conso}", log="linky_log")
        self.log(f"bit_9={bit_9} / Sens Energie Active={sens_energie_act}", log="linky_log")
        self.log(f"bit_10_13={bit_10_13} / Tarif fourniture={tarif_fourniture}", log="linky_log")
        self.log(f"bit_14_15={bit_14_15} / Tarif distributeur={tarif_distributeur}", log="linky_log")
        self.log(f"bit_16={bit_16} / Mode degrade horloge={mode_horloge}", log="linky_log")
        self.log(f"bit_17={bit_17} / Etat TIC={etat_tic}", log="linky_log")
        self.log(f"bit_19_20={bit_19_20} / Com Euridis={com_euridis}", log="linky_log")
        self.log(f"bit_21_22={bit_21_22} / Statut CPL={statut_cpl}", log="linky_log")
        self.log(f"bit_23={bit_23} / Synchro CPL={synchro_cpl}", log="linky_log")
        self.log(f"bit_24_25={bit_24_25} / Couleur Jour tempo={couleur_j_tempo}", log="linky_log")
        self.log(f"bit_26_27={bit_26_27} / Couleur J+1 tempo={couleur_j1_tempo}", log="linky_log")
        self.log(f"bit_28_29={bit_28_29} / Preavis Pointes Mobiles={préavis_p_mobiles}", log="linky_log")
        self.log(f"bit_30_31={bit_30_31} / Pointe Mobile={pointe_mobile}", log="linky_log")        
        self.log(f"Statuts Linky:{statuts}", log="linky_log")
        self.log(f"Statuts Binaire: {statuts_binaire}", log="linky_log")
        self.log(f"Sens Energie Active: {sens_energie_act}", log="linky_log")
    
#        self.call_service('notify/telegram', message="Statuts Linky:" + format(statuts))
#        self.call_service('notify/telegram', message="Sens Energie Active: " + format(sens_energie_act))
#        self.call_service('notify/telegram', message="Tarif Fourniture: " +format(tarif_fourniture))

Dans la rubrique « Mise à jour des entités HA » du code ci-dessus, vous personnalisez les entités que vous souhaitez exploiter. Elles sont crées et mise à jour dans HA. J’en ai quatre dans mon cas.

Les intitulés parlent d’eux-même. Si vous souhaitez en ajouter d’autre, il suffit de les ajouter dans le fichier ci-dessus.

Vous pouvez visualiser vos entités dans HA:

Dans un premier temps, utilisez le mode test et amusez vous, puis basculer sur la lecture du statuts et exploitez les infos via des automatismes ou autres.

Alternative manuelle d’exploitation du statut hors HA

Si vous ne voulez par utilisé « Appdaemon » vous pouvez toujours exploiter vote statut en utilisant le fichier tableur ci- après que j’ai récupéré sur un forum Jeedom (merci à l’auteur dont j’ai perdu le nom!). Je vous le propose en téléchargement, il suffit de saisir votre code du registre.

Affichage local

J’affiche quelques valeurs en local sur un oled SSD1306 128×64, pratique pour une visu rapide à la puissance et l’intensité instantanée, du ratio P/ Pref , la conso du jour.

Je joue également avec la Led WS2812 RGB connectée sur le GPIO18. En fonction de la puissance la led change de couleur:

  • Verte de 0 à 1000 VA
  • Bleu entre 1000 et 3000 VA
  • Rouge si supérieure à 3000 VA
  • Les combinaisons sont infinies et facilement programmables.

Codes du fichier linky.yaml Version HC/HP

On y retrouve:

  • les « utility meter » qui comptabilisent les energies consommées HC/HP par jour, semaine, mois, année
  • Un « input_boolean com_linky » indiquant l’état de la communication avec le Linky = 1 si com ok
  • deux « input_number » cout d’un kWh aux HC et HP
  • un ‘binary_sensor » HC utilisé dans l’affichage des graphiques de puissance permettant de matérialiser la zone HC
  • les « templates » qui cumulent les HC/HP des utility meter et calculent en € les coûts de consommations
  • Les entités du registre de statuts
####################################################
#                                                  #
#                       LINKY                      #
#                                                  #
####################################################


utility_meter:
# usage jour  
  energy_total_usage_daily:
    source: sensor.linky_hphc_kwh
    cycle: daily
    tariffs:
      - hp
      - hc
# usage semaine
  energy_total_usage_weekly:
    source: sensor.linky_hphc_kwh
    cycle: weekly
    tariffs:
      - hp
      - hc
# usage mois
  energy_total_usage_monthly:
    source: sensor.linky_hphc_kwh
    cycle: monthly
    tariffs:
      - hp
      - hc
#usage an
  energy_total_usage_yearly:
    source: sensor.linky_hphc_kwh
    cycle: yearly
    tariffs:
      - hp
      - hc
## 
input_boolean:
  com_linky:
    name: Comm Linky OK=On

input_number:
  # Calcul des coûts journaliers
  cout_kwh_hp:
    name: Cout du Kwh HP
    min: 0
    max: 10
    unit_of_measurement: €
    icon: mdi:currency-eur
    step: 0.00001
    mode: box

  cout_kwh_hc:
    name: Cout du Kwh HC
    min: 0
    max: 10
    unit_of_measurement: €
    icon: mdi:currency-eur
    step: 0.00001
    mode: box

input_text:
  # Permet de simuler des Statuts pour les tests unitaires
  linky_test_status:   
    name: Test statuts Linky

template:
  - binary_sensor:
    # Utilisé dans l'affichage des graphiques de puissance permettant de matérialiser la zone HC
    # = true si HC
    - name: "display_hp_hc"
      unique_id: "display_hp_hc"
      state: >-
        {{ (states.sensor.linky_n_tarif.state == '1') }}" # =1 si HC =2 si H

# Consommation journalière HP + HC - addition des utility meter
  - sensor:
    - name: "Energie Totale Jour"
      unique_id: "energy_total_daily"
      state: >-
        {% set p = states('sensor.energy_total_usage_daily_hp') | float(default=0) | round(2) %}
        {% set o = states('sensor.energy_total_usage_daily_hc') | float(default=0) | round(2) %}
        {{ (o + p) | round(2) }}
      unit_of_measurement: "kWh"
      device_class: "energy"
      state_class: "total"

# Consommation semaine HP + HC
    - name: "energy_total_weekly"
      state: >-
        {% set p = states('sensor.energy_total_usage_weekly_hp') | float(default=0) | round(2) %}
        {% set o = states('sensor.energy_total_usage_weekly_hc') | float(default=0) | round(2) %}
        {{ (o + p) | round(2) }}
      unit_of_measurement: "kWh"
      device_class: "energy"
      state_class: "total"  

# Consommation mensuelle HP + HC
    - name: "energy_total_monthly"
      state: >-
        {% set p = states('sensor.energy_total_usage_monthly_hp') | float(default=0) | round(2) %}
        {% set o = states('sensor.energy_total_usage_monthly_hc') | float(default=0) | round(2) %}
        {{ (o + p) | round(2) }}
      unit_of_measurement: "kWh"
      device_class: "energy"
      state_class: "total"  

# Consommation annuelle HP + HC
    - name: "energy_total_yearly"
      state: >-
        {% set p = states('sensor.energy_total_usage_yearly_hp') | float(default=0) | round(2) %}
        {% set o = states('sensor.energy_total_usage_yearly_hc') | float(default=0) | round(2) %}
        {{ (o + p) | round(2) }}
      unit_of_measurement: "kWh"
      device_class: "energy"
      state_class: "total"  

# Cout de l'Energie
# les couts du kWh HP et HC sont calculés dans excel en fonction des factures recues
# et saisis manuellement dans HA

    - name: "Cout Energy Total Jour HPHC"
      state: >-
        {% set hp = states('sensor.energy_total_usage_daily_hp') | float(default=0) | round(2) %}
        {% set hc = states('sensor.energy_total_usage_daily_hc') | float(default=0) | round(2) %}
        {% set chp = states('input_number.cout_kwh_hp') | float(default=0) | round(5) %}
        {% set chc = states('input_number.cout_kwh_hc') | float(default=0) | round(5) %}
        {{((hc*chc) + (hp*chp)) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energy_total_jour_hphc"

    - name: "Cout Energy Total Jour HP"
      state: >-
        {% set hp = states('sensor.energy_total_usage_daily_hp') | float(default=0) | round(2) %}
        {% set chp = states('input_number.cout_kwh_hp') | float(default=0) | round(5) %}
        {{(hp*chp) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energy_total_jour_hp"
      
    - name: "Cout Energy Total Jour HC"
      state: >-
        {% set hc = states('sensor.energy_total_usage_daily_hc') | float(default=0) | round(2) %}
        {% set chc = states('input_number.cout_kwh_hc') | float(default=0) | round(5) %}
        {{(hc*chc) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energy_total_jour_hc"
      

Codes du fichier linky.yaml Version « Tempo »

####################################################
#                                                  #
#                       LINKY                      #
#                                                  #
####################################################

# Sensor à conserver l'historique dans le tableau Energy
# le sensor sensor.linky_hphc_kwh est mis à zero dans tic Linky 
# depuis le 3/12/2023
# Date à laquelle le comptage des tarifs tempo a été mis en place
#utility_meter:
# usage jour  
#  energy_total_usage_daily:
#    source: sensor.linky_hphc_kwh
#    cycle: daily
#    tariffs:
#      - hp
#      - hc

## 
input_boolean:
  com_linky:
    name: Comm Linky OK=On



input_text:
  # Permet de simuler des Statuts pour les tests unitaires
  linky_test_status:   
    name: Test statuts Linky

template:
  - binary_sensor:
    # Utilisé dans l'affichage des graphiques de puissance permettant de materialiser la zone HC
    # = true si HC
    - name: "display_hp_hc"
      unique_id: "display_hp_hc"
      state: >-
        {{ states('sensor.linky_ptec')|int(default=0) == "HC.." }} # =on si HC =off si HP

  - sensor:

# Template utilisés dans le tableau Energy, ils ont pris le relais des Utility Meter supprimés le 3/11/2023
# Donc NE PAS SUPPRIMER sinon perte de l'historique des consommations

    - name: "energy_total_usage_daily_hc"
      unique_id: "energy_total_usage_daily_hc"
      state: >-
        {{ 0 }}
      unit_of_measurement: "kWh"
      device_class: "energy"
      state_class: "total_increasing"    

    - name: "energy_total_usage_daily_hp"
      unique_id: "energy_total_usage_daily_hp"
      state: >-
        {{ 0 }}
      unit_of_measurement: "kWh"
      device_class: "energy"
      state_class: "total_increasing"

# Calcul du Cout Journalier de l'Energie en fonction du tarif en cours
# Apres passage en Tempo le 3/11/2023
    - name: "Cout Energie HC Bleu Jour"
      state: >-
        {% set en = states('sensor.compteur_energie_hc_bleu_jour') | float(default=0) | round(2) %}
        {% set ct = states('input_number.tarif_edf_tempo_bleu_hc') | float(default=0) | round(2) %}
        {{(en*ct) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energie_hc_bleu_jour"

    - name: "Cout Energie HP Bleu Jour"
      state: >-
        {% set en = states('sensor.compteur_energie_hp_bleu_jour') | float(default=0) | round(2) %}
        {% set ct = states('input_number.tarif_edf_tempo_bleu_hp') | float(default=0) | round(2) %}
        {{(en*ct) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energie_hp_bleu_jour"

    - name: "Cout Energie HC Blanc Jour"
      state: >-
        {% set en = states('sensor.compteur_energie_hc_blanc_jour') | float(default=0) | round(2) %}
        {% set ct = states('input_number.tarif_edf_tempo_blanc_hc') | float(default=0) | round(2) %}
        {{(en*ct) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energie_hc_blanc_jour"

    - name: "Cout Energie HP Blanc Jour"
      state: >-
        {% set en = states('sensor.compteur_energie_hp_blanc_jour') | float(default=0) | round(2) %}
        {% set ct = states('input_number.tarif_edf_tempo_blanc_hp') | float(default=0) | round(2) %}
        {{(en*ct) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energie_hp_blanc_jour"

    - name: "Cout Energie HC Rouge Jour"
      state: >-
        {% set en = states('sensor.compteur_energie_hc_rouge_jour') | float(default=0) | round(2) %}
        {% set ct = states('input_number.tarif_edf_tempo_rouge_hc') | float(default=0) | round(2) %}
        {{(en*ct) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energie_hc_rouge_jour"

    - name: "Cout Energie HP Rouge Jour"
      state: >-
        {% set en = states('sensor.compteur_energie_hp_rouge_jour') | float(default=0) | round(2) %}
        {% set ct = states('input_number.tarif_edf_tempo_rouge_hp') | float(default=0) | round(2) %}
        {{(en*ct) | round(2) }}
      unit_of_measurement: "€"
      device_class: "monetary"
      state_class: "total"  
      unique_id: "cout_energie_hp_rouge_jour"

Automatismes

Commutation de HP vers HC et Inversement

Il permet de permuter la tarification des utiliy meter en fonction du tarif récupéré dans le Linky (PTEC)

Code de l’automatisme Simplifié

N’oubliez pas de supprimer les « utility_meter » qui ne vous concerne pas.

alias: 6_1_0 Energie Changement HP<->HC
description: ''
trigger:
  - platform: state
    entity_id: sensor.linky_n_tarif
    id: tarif_hc
    from: '2'
    to: '1'
  - platform: state
    entity_id: sensor.linky_n_tarif
    from: '1'
    id: tarif_hp
    to: '2'
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: tarif_hc
        sequence:
          - service: select.select_option
            data:
              option: hc
            target:
              entity_id:
                - select.energy_total_usage_daily
                - select.energy_total_usage_weekly
                - select.energy_total_usage_monthly
                - select.energy_total_usage_yearly
                - select.energy_pisc_usage_daily
                - select.energy_pisc_usage_weekly
                - select.energy_pisc_usage_monthly
                - select.energy_pisc_usage_yearly
                - select.energy_sdb_usage_daily
                - select.energy_sdb_usage_weekly
                - select.energy_sdb_usage_monthly
                - select.energy_sdb_usage_yearly
                - select.energy_ecs1_usage_daily
                - select.energy_ecs1_usage_weekly
                - select.energy_ecs1_usage_monthly
                - select.energy_ecs1_usage_yearly
                - select.energy_pac1_usage_daily
                - select.energy_pac1_usage_weekly
                - select.energy_pac1_usage_monthly
                - select.energy_pac1_usage_yearly
                - select.energy_mal_usage_daily
                - select.energy_mal_usage_monthly
                - select.energy_mal_usage_weekly
                - select.energy_mal_usage_yearly
                - select.energy_autres_usage_daily
                - select.energy_autres_usage_monthly
                - select.energy_autres_usage_weekly
                - select.energy_autres_usage_yearly
                - select.energy_vmc_usage_daily
      - conditions:
          - condition: trigger
            id: tarif_hp
        sequence:
          - service: select.select_option
            data:
              option: hp
            target:
              entity_id:
                - select.energy_total_usage_daily
                - select.energy_total_usage_weekly
                - select.energy_total_usage_monthly
                - select.energy_total_usage_yearly
                - select.energy_pisc_usage_daily
                - select.energy_pisc_usage_weekly
                - select.energy_pisc_usage_monthly
                - select.energy_pisc_usage_yearly
                - select.energy_sdb_usage_daily
                - select.energy_sdb_usage_weekly
                - select.energy_sdb_usage_monthly
                - select.energy_sdb_usage_yearly
                - select.energy_ecs1_usage_daily
                - select.energy_ecs1_usage_weekly
                - select.energy_ecs1_usage_monthly
                - select.energy_ecs1_usage_yearly
                - select.energy_pac1_usage_daily
                - select.energy_pac1_usage_weekly
                - select.energy_pac1_usage_monthly
                - select.energy_pac1_usage_yearly
                - select.energy_mal_usage_daily
                - select.energy_mal_usage_monthly
                - select.energy_mal_usage_weekly
                - select.energy_mal_usage_yearly
                - select.energy_autres_usage_daily
                - select.energy_autres_usage_monthly
                - select.energy_autres_usage_weekly
                - select.energy_autres_usage_yearly
                - select.energy_vmc_usage_daily
    default: []
mode: single

Automatisme de contrôle de la communication du Linky avec « Automation »

Descriptif fonctionnel

Le but est de surveiller si la communication entre le Linky et HA est établie.

A chaque changement d’état de l’entité « sensor.linky_umoy », l’automatisme est déclenché:

  • l' »input_boolean.com_linky » signifiant que la communication entre le linky et HA est OK est forcé sur On
  • Un délai d’une heure est déclenché,
  • si durant ce délai U_MOY change d’état, l’automatisme est relancé (mode:restart) et « input_boolean.com_linky » reste sur On
  • sinon, passé ce délai, l' »input_boolean.com_linky » est forcé sur Off, et la communication est considérée en défaut, il sera remis sur On au prochain changement d’état de PAPP

Je surveillance la puissance PAPP, c’est la valeur plus évolutive, mais il arrive que quelques fois, surtout de nuit que la puissance reste stable pas et déclare donc un défaut fantôme.

Code de l’automatisme avec le module « Automatisation » classique de HA:

Je surveille la tension moyenne car elle varie très souvent contrairement à la puissance ou l’intensité qui peuvent restés stables plus d’une heure la nuit notamment.

- id: '1638118858848'
  alias: 2_2_2 Alarme_Notification Time Out Linky
  description: ' '
  trigger:
  - platform: state
    entity_id: sensor.linky_umoy
  condition: []
  action:
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.com_linky
  - delay:
      hours: 1
      minutes: 0
      seconds: 0
      milliseconds: 0
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.com_linky
  mode: restart

Code de l’automatisme avec le module « AppDaemon »:

Ce module surveille l’évolution de « sensor.linky_umoy » pendant 1 h, si pas de changement on déclare la communication avec le Linky « KO ».

Cet Addon, pour ceux qui ne connaissent pas, permet d’écrire des programmes en Python très élaborés.

Je décrit son installation dans cet article cet article.

Vous trouverez ci après les fichiers « .yaml » et « .py » à installer dans « votre AppDaemon. »

Code de « surveille_activite.yaml »

surveille_com_linky:
  module: surveille_activite
  class: SurveilleActivite
  entite: sensor.linky_umoy #sensor.linky_i_inst # sensor.linky_papp #sensor.linky_umoy #
  #entite: input_text.linky_test_status
  tempo: 3600 # Tempo de surveillance en secondes
  activite_ok: input_boolean.com_linky #switch.test_com_out

  

Code de « surveille_activite.py »

Les services de notifications sont à adapter à votre configuration.

import hassapi as hass

class SurveilleActivite(hass.Hass):
    def initialize(self):
        self.listen_state(self.change,self.args["entite"])
        nom_entité = self.get_state(self.args["entite"],attribute="entity_id")
        duree_tempo=int(self.args["tempo"])
        self.turn_on(self.args["activite_ok"])
        self.tempo=self.run_in(self.notification, duree_tempo,entité=nom_entité,temps=duree_tempo)
        self.log(f'Initialisation de: {nom_entité} pour {duree_tempo}s et {self.tempo}.', log="surveille_log")

    def change(self, entity, attribute, old, new, kwargs):
        heure = str(self.time())[:8]
        duree_tempo=int(self.args["tempo"])
        tempo_on = str(entity)
        nom_entité = str(entity)
        nouvelle_valeur = new
        # Mise à on de Com_Ok
        self.turn_on(self.args["activite_ok"])
        self.log(f'Nouvelle valeur de {entity}: {nouvelle_valeur}-Tempo={duree_tempo}', log="surveille_log")
        cle_tempo = self.tempo
        if cle_tempo != None:
            self.tempo = self.cancel_timer(cle_tempo) 
            #self.log(f'Info tempo: {self.info_timer(cle_tempo)}', log="surveille_log")
            #self.log(f'Fin tempo {cle_tempo}', log="surveille_log")

        self.tempo = self.run_in(self.notification, duree_tempo,entité=nom_entité,temps=duree_tempo)

    def notification(self, kwargs):
        heure = str(self.time())[:8]
        nom_entité = kwargs["entité"]
        duree_temps= kwargs["temps"]
        # Mise à off de Com_Ok
        self.turn_off(self.args["activite_ok"])
        self.log(f'Alerte! {nom_entité} est out depuis {duree_temps} sec.', log="surveille_log")
        message_notification=format(heure)+"Alerte!"+ format(nom_entité)+"est out depuis: "+format(duree_temps)+" sec."
        self.call_service('notify/telegram', message_notification)
        self.call_service('dwains_dashboard/notification_create', message=message_notification)

Blueprint Notification défaut communication:

J’exploite le défaut avec un blueprint « Nagging Alerting Notification Automation » plus pratique que l’intégration « alert » qui nécessite un redémarrage de HA à chaque modification.

J’utilise également ce blueprint dans d’autres cas de surveillance, portes, température, communication, etc..

Ici aussi, les services de notification sont à adapter à votre configuration.

alias: 2_1_11 Alarme Blueprints Notification Def Com Linky
description: Blue Print
use_blueprint:
  path: pavax/nagging_alert_notification.yaml
  input:
    condition_entity_state: 'on'
    sensor_entity: input_boolean.com_linky
    alert_state: 'off'
    alert_action:
      - service: notify.telegram
        data:
          message: Com Linky off Line{{-"\n"-}}{{states("sensor.date_time") }}
          title: Etat Reseau !!!
      - service: dwains_dashboard.notification_create
        data:
          message: Com Linky Off Line {{-"\n"-}}{{states("sensor.date_time") }}
    resolved_action:
      - service: notify.telegram
        data:
          message: Com Linky On Line{{-"\n"-}} {{states("sensor.date_time") }}
          title: Etat RESEAU!!!
      - service: dwains_dashboard.notification_create
        data:
          message: Com Linky On Line{{-"\n"-}}{{states("sensor.date_time") }}
    notify_device: 62cdce054a9d3448484b4df8e44cc499
    repeat_delay: 300
    initial_delay: 1
    max_alerts: 100
    resolved_message: Alerte {{ entity_name }} Résolu
    notify_message: Alerte {{ entity_name }}Déclenché

Lovelace

Exemple d’affichage des données

Un autre exemple d’affichage utilisant « custom:mini-graph-card » de HACS

type: vertical-stack
cards:
  - type: custom:mini-graph-card
    entities:
      - entity: sensor.energie_totale_jour
    name: Conso Linky 7j
    hours_to_show: 168
    aggregate_func: max
    group_by: date
    show:
      graph: bar
    icon: mdi:flash
  - type: custom:mini-graph-card
    color_thresholds:
      - color: '#00FF00'
        value: 0
      - color: '#FF9900'
        value: 4000
      - color: '#EA9999'
        value: 6000
      - color: '#CC0000'
        value: 10000
    color_thresholds_transition: hard
    line_width: 2
    icon: mdi:flash
    show:
      extrema: true
      fill: true
      icon: true
      labels: false
      name: true
      state: true
    hour24: true
    points_per_hour: 4
    hours_to_show: 24
    group: false
    state_map:
      - label: hp
        value: 'off'
      - label: hc
        value: 'on'
    style: |
      ha-card {
        border: solid 2px var(--primary-color);
      }
    entities:
      - entity: sensor.linky_papp
        name: Totale
      - color: '#CCC0cCC'
        entity: binary_sensor.display_hp_hc
        name: HC
        show_line: false
        y_axis: secondary
    name: Puissance Linky 24h

Un autre exemple d’affichage utilisant « custom:apexcharts-card » de HACS

type: custom:apexcharts-card
chart_type: donut
header:
  show: true
  title: Conso du Jour
  show_states: false
  colorize_states: true
series:
  - entity: sensor.energy_total_usage_daily_hp
    name: HP
    color: green
  - entity: sensor.energy_total_usage_daily_hc
    name: HC
    color: blue

Affichage du tableau Energie

Affichage dans Grafana

Vous trouverez ci-après le fichier Graphana correspondant.

Conclusion

Pas grand chose d’autre à ajouter, c’est simple à mettre en oeuvre (si le Linky est accessible), fiable et peu onéreux, il ne reste plus qu’a exploiter les informations.

Publication en lien avec cet article:

https://domo.rem81.com/ha-teleinformation-linky-mode-historique/

41 Comments on “HA-Teleinformation Linky-Mode Standard”

  1. Article vraiment top
    Complet et bien écrit

    Un lien pour le boîtier avec le couvercle transparent ? Comment fais tu tenir le montage à l’intérieur

  2. bonjour, apres avoir testé pleins de solutions dont bcp non fonctionnelles :p , celle ci me semble idéale …
    je vais donc tester .

    par contre, j ai pas un BASE ni un HP/HC , mais un HP/HC/WE …. je vais essayer de modifier tes scripts et si cela fonctionne, je partagerais 🙂 (mais pas de suite, je fais les choses lentement )

    1. Ok Jérôme, si besoin n’hésites pas à me solliciter, et merci d’avance pour ton retour d’expérience.

      1. Bonjour, Alors, l ESP est en place et me remonte des infos ( il sert aussi pour le gaz et l eau , le gaz ça marche et l eau j ai pas encore recu le capteur inductif )

        coté linky, tout ne remonte pas, deja , j ai les entités suivantes vides :
        HCHP J = Inconnu
        Index Linky kWh = Inconnu
        le reste est OK ( j ai un index HP, HC , le pourcentage d utilisation, ect, meme l affichage OLED marche ( saut la conso jour et veille qui affiche NaN )

        nous sommes le WE , et donc ej suis pile dans un cas spécial , le ‘linky N tarif = 3  »

        mes connaissance en programmation sont limitées, comment modifier ceci pour prendre en compte le « 3 » ? ( il me faudrait juste un truc genre 1=HC, 3=WE sinon HP

        # Convertion du tarif en cours
        – platform: template
        id: tarif
        name: « Linky PTEC »
        lambda: |-
        if ( id(ntarif).state == 1 ) {
        return { « HC.. » };
        } else {
        return { « HP.. » };
        }

        ( en fait je bloque sur la syntaxe )

        la page energy ne me permet pas de choisir les entités Linky HC et linky HP , j ai raté une definition quelque part ?

        ps : une fois que tout fonctionnera je t enverrais la liste des modifs pour publication et que d autres en profitent 🙂

        1. Bonjour
          pour récuperer le troisième index il te faut ajouter dans l’esp apres EAFS02 par ex:
          # Energie Active soutirée Index03
          – platform: teleinfo
          id: we <- Mets ici le nom de l'index souhaitée tag_name: "EASF03" name: "Linky WE Wh" <- Mets ici le nom de l'entité souhaitée unit_of_measurement: "Wh" icon: mdi:flash teleinfo_id: myteleinfo Concernant "Index Linky kWh" c'est fourni par le linky label EAST donc cela doit fonctionné, regarde ta syntax: # Energie Active soutirée totale - platform: teleinfo id: hc_hp tag_name: "EAST" name: "Linky HPHC KWH" unit_of_measurement: "kWh" icon: mdi:flash teleinfo_id: myteleinfo device_class: "energy" state_class: "total_increasing" filters: lambda: |- return x/1000; Concernant HCHP J c'est calculé dans HA dans le linky.yaml Je te réponds dans le commentaire suivant.

        1. J’ai ajouté un chapitre « prè requis » expliquant que mes fichiers de configuration « .yaml » sont contenus dans un dossier spécifique « config/packages » et qu’il faut ajouter une ligne « packages: !include_dir_named packages » dans « configuration.yaml » qui indique à HA ou trouver les fichiers de configuration (apres reboot) et donc c’est dans ce dossier qu’il faut déposer le « linky.yaml ». avec cette organisation tu peux mélanger dans un même fichier des « sensors, binary_sensor, template, utility-meter, etc.. »
          Regarde dans mon github https://github.com/remycrochon/home-assistant tu comprendra mon organisation.
          Une fois fait, tu retrouvera notamment le template « sensor.energie_totale_jour » et appelé dans l’ESP « HPHC J »
          Bon courage.

          1. bonjour, alors j ai bien avancé, je recupere bien bcp de choses, mais je rencontre les soucis suivants :

            1) pour le graph en donut , je n ai pas sensor.energy_total_linky_usage_daily_hp ( ni hc ) , il est créé a quel moment ?

            2 )pour l autre graph , je n’ai pas le sensor.energie_totale_linky_jour pourtant j ai bien dans l ESP :
            – platform: homeassistant
            name: « HCHP J »
            unit_of_measurement: « kWh »
            entity_id: sensor.energie_totale_linky_jour
            id: hphcj
            il y a une raison pour que cela ne remonte pas ?

            3) la led verte ne s allume pas , elle est basée sur sensor.linky_index , il ne me semble pas avoir ce sensor …

            4) j ai un soucis de sytaxe sur le passage HP/HC pour rajouter le WE
            comment je dois ré-écrire ce paragraphe ? ( 3=WE )

            # Convertion du tarif en cours
            – platform: template
            id: tarif
            name: « Linky PTEC »
            lambda: |-
            if ( id(ntarif).state == 1 ) {
            return { « HC.. » };
            } else {
            return { « HP.. » };
            }

            voila déjà les questions du jour 🙂 merci pour ton aide

          2. Salut
            J’ai mis à jour le tuto, notamment les utility-meter du fichier linky.yaml, le donut, le code ESP, veille à mettre en concordance les utility-meter déclarés dans le linky.yaml et utilisés dans l’ESP, l’affichage, l’automatisme, etc.. Une fois fait ça doit fonctionner. C’est peut être pas facile à suivre mais je le fais évolué de mon coté également, pour suivre les modifications tu peux regarder regarde dans les fichiers github qui sont mis à jour quasi en temps réels (une fois le fichier ouvert cliquer sur hytory en haut à droite..)
            Pour la Led dans mon code elle est calculée dans:
            #Puissance apparente instantanée ph1
            – platform: teleinfo
            id: papp
            tag_name: « SINSTS »
            name: « Linky PAPP »

            Concernant ta syntaxe essaye ceci:

            lambda: |-
            if ( id(ntarif).state == 1 ) {
            return { « HC.. » };
            } else if ( id(ntarif).state == 2 ) {
            return { « HP.. » };
            else {
            return { « WE.. » };
            }

            Tu peux inspirer du template:
            # Affichage du temps de fonctionnement
            – platform: template
            name: « ${friendly_name} Uptime »

            @+

    2. Bonjour Jérome, suite à ta conversation avec Rem81, je n’arrive pas à trouver l’étiquette qui remonte les heures Week-end. Si tu peux m’aider je t’en serai gré.
      Merci d’avance et @+

  3. Bonjour ( et merci pour tes réponses )

    (il n y a pas le bouton répondre sur ta dernière réponse )

    alors pour la led verte, c est le nom du sensor qui n était pas le bon
    maintenant que les infos remontent bien,( il me manque les valeurs dans les graphs, peut etre attendre 24h vu que c est des totaux jour ) j ai re modifié les fichier pour prendre en compte le WE , verdict … ce WE pour tester 🙂
    si tout est OK je t enverais la liste des modifs, cela pourra toujours aider ceux qui sont en contrat non classique ( ni BASE ni HPHC )

    je bloque toujours sur la syntaxe pour le HP/HC/WE ( quand on débute il n y a pas a dire mais le yaml c est chiant :p ) , mais a priori il ne sert que pour l affichage OLED , j ai donc modifié 2=plein tarif sinon tarif réduit … a voir si ca pose des soucis sur d autre scripts.

    Jerome

  4. pfui, je cherchais un article de ce type et la quelle claque, super descriptions et explication.

    j’ai un module qui ce connecte directement en USB mais je ne trouve rien de bien concluant pour faire l’intégration complete.
    je vais surement réfléchir a la solution proposer et voir pour la mettre en place, et je vais aussi regarder les autre article et le github pour avoir de idée 😉

  5. Rémi,

    Vous êtes à un niveau « pro » avec Home Assistant (et pas seulement) , je vous admire : c’est juste impréssionant tout ce que vous faites.

    Je suis parti sur une autre solution: une clé Lixee (bien plus chère que la solution que vous avez utilisée), et qui plus est, en utilisant ZHA au lieu de zigbee2mqtt qui marche sans bidouille.

    J’ai fait toutes les adaptations pour que le panneau Énergie montre mes infos… et rien.
    J’ai compris que la cause est justement mon Linky qui est en mode TIC historique au lieu de standard.

    Donc, comment avez-vous réussi à activer le fichu mode Standard du Linky ? Pour moi, jusque-là, c’est une aventure :

    1) J’ai appelé Enedis : ils m’ont dit que ça se fait directement sur leur espace client ;

    2) Je me suis connecté sur mon espace Enedis, j’ai ajouté mon compteur et j’ai autorisé la collecte de données historiques (vu qu’il n’y a aucune option TIC standard/historique), mais quelques semaines après, mon compteur reste toujours sur mode historique ;

    3) Je me connecte sur le site Enedis à nouveau, et il me dit qu’ils ont un ‘problème technique’, pour connecter plus tard ;

    4) J’ai appelé EDF : la personne au bout du fil ne savait pas ce qui était mode TIC … après insister, elle me dit que la manip se fait par l’espace-client …

    5) Je rentre sur l’espace client, et il n’y a rien de spécifique « TIC Historique/Standard ». J’ai essayé à nouveau – cette fois au site EDF – d’activer les options de suivi à chaque 30 min dans l’espoir que ça m’active le mode standard…

    … bref, si vous avez une méthode « coup-sûr » pour changer le TIC en mode standard, je suis preneur ! 🙂

    Merci encore une fois.

    PS: l’app de contrôle de la piscine marche toujours nickel, inébranlable !

    1. Bonjour, pour le passage en mode standard, il faut faire la dde auprès de ton fournisseur d’énergie. Perso je suis chez Engie, la dde se fait sur son compte internet, assez réactif, ça a dû mettre une semaine. Pour mon fils, chez EDF, ça été plus laborieux, dde par tel, mais plus long à réagir, après de multiples relances par tel, il est passé au mode standard plus d’1 mois après. Bon courage et merci pour tes retours d’expériences. Slts

  6. Bonjour
    je fonctionnais en mode historique lorsque je passe en standard j’ai le message suivant:

    [11:10:20][W][teleinfo:060]: Internal buffer full

    ou faut il modifier la valeur du buffer
    Cdlt

    1. Oups désolé cela fonctionne j’avais omis de modifier le UART en mettant 9600 pour le Baud rate en lieu et place de 1200

  7. Bravo Rémi,
    J’ai appliqué tes recommandations concernant le mode HISTORIQUE mais étant chez Engie avec un contrat HP-HC-WE, la remontée des HC et HP et WE ne se fait pas. D’où ma décision de passer en mode standard. Demande en cours et en attente de validation…
    J’ai parcouru tonexplication qui me paraît très complète et je te tiendrai au courant des résultats.
    En core merci.
    @ suivre
    Paul

  8. Bonjour rémi, l’article est vraiment …. super.
    Je démare avec HA, j’ai ajouté mon linky réseau, et un sonoff pow comme appareil individuel.
    mais il n’apparait pas comme sur ton graphique, je n’ai que deux ronds « réseau » et « maison ».

    Sur ton graphique tu as deux equipements aprés ta maison (58W et 1W)

  9. Bonjour,
    Ce système est intégré avec succès à mon HA depuis fin 2022. Mais en regardant le panel « Energie », je me rends compte que j’ai parfois des valeurs aberrantes qui plombent mes statistiques (du genre : une valeur de milliers de GigaWatts ! Non, je n’ai pas de centrale nucléaire à la maison ;-)). Il arrive que ces valeurs erronées remontent plusieurs fois dans la même journée. Elle ne concernent que les Heures Creuses ( sensor.electricite_hc), et ce n’est pas lié au changement de tarif (HPHC).

    J’ai des difficultés à identifier la cause (bad CRC ? comm réseau ? MAJ ? etc…).
    Une idée ?

    1. Bonjour,
      Est ce le « sensor » des HC lu dans le Linky (tag_name: « EASF01 ») qui contient ces valeurs incohérentes ou bien c’est le « compteur de service public » journalier qui deconne?
      Dans le tableau « energy » tu utilise la valeur lue dans le linky ou bien « le compteur de service public »? Dans le deuxieme cas le passage d’un jour à l’autre dans le module energy et les « compteurs de service public » peux être désynchronisés. Dans le module Energy, Il est préférable de configurer directement les sensor du TIC (en kWh).
      Perso j’utilise les deux « compteur de service public » mais je n’ai pas de problème. J’ai eu par le passé des valeurs qui passaient à 0 de temps en temps, j’ai filtré au niveau de l’ESP avec « filter_ou:0.0 ».
      Voici quelques pistes de réflexion. Bon courage

      1. Bonjour,
        Merci pour ta réponse. J’utilise bien les valeurs lues dans le Linky dans le panneau Energy (sensor.electricite_hc).
        J’aurais bien posté une copie d’écran de l’historique sur une journée avec des valeurs incohérentes pour illustrer mais ce n’est pas possible ici.
        Il semblerait que ces valeurs soient négatives (un débordement, pb de représentation interne numérique ?). Exemple pris dans l’historique du sensor sur la journée du 30/08 :
        30 août 2023 à 00:45:51
        Electricité HC:
        -2 954 495 Wh

        En réalité, les valeurs enregistrées dans l’historique sont de cet ordre de grandeur entre 00:00:00 et 00:45:51, puis passent à des valeurs correctes (+900Wh).
        Plus tard, à 09:56:32, une seule valeur incohérente énorme et négative, puis d’autres encore plus tard dans la journée.

        C’est vraiment curieux, et seul le sensor HC est concerné. Autre point, j’ai un linky triphasé, mais je ne vois pas ce que cela change…

  10. Bonjour à tous,
    Je me permet de « m’incruster » juste pour une question sur un problème que je n’arrive pas à résoudre malgré mes recherches sur le Net ??
    A quoi sont dues ces différentes erreur qui me pourissent mes données ?
    Si vous avez un conseil et des idées, je suis preneur.
    Merci pour vos réponses.

    Paul

    16:18:04 [E] [teleinfo:038] bad crc: got 52 except 92
    16:18:04 [E] [teleinfo:038] bad crc: got 52 except 92
    16:18:04 [E] [teleinfo:038] bad crc: got 52 except 38
    16:18:04 [E] [teleinfo:038] bad crc: got 52 except 44
    16:18:04 [E] [teleinfo:038] bad crc: got 42 except 55
    16:18:04 [E] [teleinfo:038] bad crc: got 42 except 89
    16:18:04 [E] [teleinfo:038] bad crc: got 34 except 94
    16:18:04 [E] [teleinfo:133] No group found
    16:18:04 [W] [component:204] Component teleinfo took a long time for an operation (0.12 s).
    16:18:04 [W] [component:205] Components should block for at most 20-30ms.

    1. Bonjour, le crc permet de valider la trame reçue, en général les perturbations sont dues à des parasites sur la ligne, quelle longueur fait votre ligne et quelle section de cable utilisez vous?
      Est ce que ces erreurs sont systématiques? malgré cela arrivez vous à recueillir des données exploitables?
      Slts

      1. Bonjour,
        Désolé pour le retard à l’allumage, mais occupé ces derniers temps.
        Concernant mon équipement, c’est exactement celui décrit dans cet excellent post.
        Le cable utilisé est un JA28 (https://fr.rs-online.com/web/p/cables-audio/3729596)
        de 0.22 mm² sur unje longueur de 10-15 mètres environ dans la gaine de la commande J/N qui enclenche le relais des heures creuses. J’ai cherché partout, en tirant un câble différent en « volant » sur la pelouse et le résulat est absolument idem ?????
        Après mures réflexions, j’ai pensé que le signal était trop fort et j’ai mis en série avant d’attaquer la carte une résistance de 1.2 Kohms, ce qui m’a permis de résoudre ce problème et ce aujourd’hui (Alléluia…!) Il me reste encore un bad CRC très régulier celui-là qui est certainement dû à une mauvaise requête dans mon code. On progresse.
        Pour résumé, avant la remontée des données était d’une trentaine de minutes et les mises à jour étaient très aléatoires. Maintenant c’est INSTANTANE…
        J’en profite pour vous remercier de votre excellent article et vous en félicite. Maintent il faut que j’attaque le stockage de ces données ainsi que de beaux graphiques.
        Encore bravo et je ne manquerait pas de vous tenir au courant.
        Amitiés

  11. Bonjour Rem81, super Tuto qui m’a motivé ,
    je me lance pour son intégration dans mon Home Assistant pour un Linky Triphasé mode Tempo.
    j’ai déjà le module Wemos Teleinfo avec ESP32C3 mini qui tourne en mode « Standard » donc cela devrait être réalisable 🙂
    Eric

    1. Bonjour, oui bien sur sans soucis, il faut lire les variables spécifiques au triphasé, voir le document enedis à ce sujet. piur info j’ai ajouter des ficltres sur les sensors. Bon courage

      1. Merci Rem81, cela tourne maintenant depuis une dizaine de jours avec les infos du triphasé, j’ai un peu transpiré avec vos 2 petits modules appdaemon mais ça tourne maintenant et c’est bien efficace. Je vais décortiquer les utility-meter et le « panneau Energie » pour adapter cela au triphasé et retrouver les variables que vous utilisez. Merci encore pour le tuto.
        Ps: les prix de l’Energie en fonction des périodes sont « hard coded », n’est ce pas ? Ces infos ne seraient t’elles pas dispo quelque part dans le cloud?

  12. Bonjour, Novice en domotique je me lance avec HA, et étant producteur avec panneaux solaire et vente du surplus, je souhaite router le surplus sur mon ballon ESC. Je suis en attente du module optocoupleur pour raccorder un ESP32 sur le linky en mode standard. Le but est de récupérer notament l’énergie ou la puissance injectée par les panneaux sur le réseau pour la transferer vers un deuxieme ESP32 et un dimmer 16/24A auprés du chauffe-eau. J’ai bien regardé vos différnt code Yaml mais j’avous je suis perdu dans tout ça. Est-il possible d’avoir de l’aide dans la programmation des ESP32. ?
    Merci d’avance pour la réponse
    Cordialement

  13. bonjour
    bravo pour votre réalisation.
    j’ai une question concernant la led ws2812: je ne n’arrive pas a faire allumer en fonction du tarif.
    y’a t-il une astuce?
    merci pour votre retour

      1. Bonjour
        Oui le script existe bien en bas du programme la vérification de celui-ci ne donne aucune erreur.
        Je vois bien au niveau des logs s’afficher HC bleu, ou autre mais la led (ws2811) reste éteinte
        Merci pour votre retour

        1. Bonjour, j’utilise le GPIO18 pour la led, est ce que tu as pu vérifier que ton câblage ou platine correspond à ce GPIO?.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *