Decodeur TIC Linky, Le Retour

Bonsoir @sam59,

Merci pour le message.
Ta solution qui consite à arrêter la réception Linky pendant la transmission est bonne. Comme seule la PAPP est utile, tu ne dois pas perdre grand chose.

Tu peux aussi arrêter la réception par logiciel : il faut masquer l'interruption utilisée par SoftwareSerial.
Sur AVRMega328, si tu utilises la pin 10 = PORTB 2 = PCINT2 pour l'entrée SoftwareSerial, il faut se plonger dans la datasheet §14.3.1, puis §13.2.4 et suivants.

1- Pour arrêter la réception il faut masquer l'interruption PCIE0 dans le registre PCICR. On va aussi masquer le bit PCINT2 dans le registre PCMSK0

PCICR &= ~(1<<PCIE0);
PCMSK0 &= ~(1<<PCINT2);

2- Pour ré-activer la réception, il faut re-autoriser l'interruption PCIE0. Il faut d'abord remettre le flag PCIF0 dans PCIFR à 0 (en écrivant 1 dessus !!) pour annuler une éventuelle interruption en attente. Ensuite on autorise PCINT2 dans PCMSK0.

PCIFR |= (1<<PCIF0);
PCICR |= (1<<PCIE0);
PCMSK0 |= (1<<PCINT2);

Voilà, ça devrait rouler. Ce qui est sympa sur les AVR, c'est que les datasheets sont complètes et accessibles et que l'on peut accéder directement aux registres en C.

Bonne bidouille,

MicroQuettas

Bonsoir @MicroQuettas ,

Merci beaucoup pour ce retour, effectivement ca fonctionne puisque je suis parvenu a me passer de la AND exterieur avec le meme resultat.

Voici le code complet. Uniquement la puissance instantanee est envoyee par VirtualWire.

/***********************************************************************
                        Récepteur TIC Linky
                        Mode historique

  V03  : External SoftwareSerial. Tested OK on 07/03/18.
  V04  : Replaced available() by new(). Tested Ok on 08/03/18.
  V05  : Internal SoftwareSerial. Cf special construction syntax.
  V06  : Separate compilation version.

  V10a : Parametric version, initial. Tested OK on 23/10/19.
  V10b : fixed bug in ptecIsNew(). Tested OK on 24/10/19.
  V10c : added LKYSIMINPUT mode. Tested OK (partial) on 31/10/19.
  V10d : adapted to Arduino Uno and Mega. Tested Ok on 27/04/20.
  V10e : added optional ISOUSC. OK 26/11/22
  Modified version to add Emission of papp with VirtualWire (433MHz emission) through pin 2!

***********************************************************************
  Configuration parameters are defined in LinkyHistTIC.h

***********************************************************************/

/***************************** Includes *******************************/
#include <string.h>
#include <Streaming.h>

#include "LinkyHistTIC.h"

#include <PCD8544.h>                  // include the 5110 display library
#include <VirtualWire.h>              // include the virtualwire library

/****************************** Defines *******************************/
#define VERSION "V10e"

// A custom glyph (a smiley)...
static const byte glyph[] = { B00010000, B00110100, B00110000, B00110100, B00010000 };

static PCD8544 lcd;

// structure definition
typedef struct {
  char commande;
  int valeur;
} MaStructure;

MaStructure ticppap;
MaStructure ticbase;
MaStructure ticiinst;

/****************************** Constants *****************************/


/************************* Global variables ***************************/


/************************* Object instanciation ***********************/
LinkyHistTIC Linky(LKYRX_INPUT, LKYTXPIN);

/****************************  Routines  ******************************/


/******************************  Setup  *******************************/
void setup()
{

  /* Initialise serial link */
#ifndef LKYSIMINPUT
  Serial.begin(9600);
#endif

  /* Initialise virtualwire */
  vw_setup(2000);
  vw_set_tx_pin(2);

  /* Initialise the Linky receiver */
  Linky.Init();

  // PCD8544-compatible displays may have a different resolution...
  lcd.begin(84, 48);
  
  // Add the smiley to position "0" of the ASCII table...
  lcd.createChar(0, glyph);

  Serial << F("Bonjour - ") << VERSION << endl;

  ticppap.commande = 'U';   // PUISSANCE INSTANTANEE
  ticppap.valeur = 0;       //initializing to a certain value

  ticbase.commande = 'I';   // INDEX
  ticbase.valeur = 0;       //initializing to a certain value

  ticiinst.commande = 'C';  // COURANT
  ticiinst.valeur = 0;      //initializing to a certain value

}

/******************************* Loop *********************************/
void loop()
{

  uint8_t i;

  Linky.Update();

  if (Linky.pappIsNew())
  {
    Serial << F("Puis. app. = ") << Linky.papp() << F(" VA") << endl;

    ticppap.valeur = Linky.papp();

    // Write a piece of text on the first line...
    lcd.setCursor(0, 0);
    lcd.print("PPAP=");

    // Write a piece of text on the first line...
    lcd.setCursor(0, 1);
    lcd.print("            ");
    lcd.setCursor(0, 1);
    lcd.print(Linky.papp());

/*
1- Pour arrêter la réception il faut masquer l'interruption PCIE0 dans le registre PCICR. 
On va aussi masquer le bit PCINT2 dans le registre PCMSK0
*/

    PCICR &= ~(1<<PCIE0);
    PCMSK0 &= ~(1<<PCINT2);

    vw_send((byte*) &ticppap, sizeof(ticppap)); // On envoie le message
    vw_wait_tx(); 

/* 
2- Pour ré-activer la réception, il faut re-autoriser l'interruption PCIE0. 
Il faut d'abord remettre le flag PCIF0 dans PCIFR à 0 (en écrivant 1 dessus !!) pour annuler une éventuelle interruption en attente. 
Ensuite on autorise PCINT2 dans PCMSK0.
*/

    PCIFR |= (1<<PCIF0);
    PCICR |= (1<<PCIE0);
    PCMSK0 |= (1<<PCINT2);

  }

#ifdef LKY_Base
  if (Linky.baseIsNew())
  {
    Serial << F("Index base = ") << Linky.base() << F(" Wh") << endl;

    ticbase.valeur = Linky.base();

    // Write a piece of text on the first line...
    lcd.setCursor(0, 2);
    lcd.print("Index=");

    // Write a piece of text on the first line...
    lcd.setCursor(0, 3);
    lcd.print("            ");
    lcd.setCursor(0, 3);
    lcd.print(Linky.base());

  }
#endif

#ifdef LKY_IMono
  if (Linky.iinstIsNew())
  {
    Serial << F("I instant. = ") << Linky.iinst() << F(" A") << endl;
  
    ticiinst.valeur = Linky.iinst();
  }
#endif

};

Pour limiter les collisions, j'ai reduit le nombre d'emission de l'autre emetteur (temperature, humidite et pression), ce qui devrait me permettre de disposer des quatre infos sur le meme LCD!

Merci encore!

Bonsoir @sam59,

Bien content de voir que ça marche. Je ne cache pas que ça me fait plaisir...
Il y aurait des petites choses à peaufiner sur votre code, mais c'est sans impact fonctionnel.
A l'occasion, faites moi savoir si le montage marche en utilisant HW Serial.

Bonne bidouille,

Frédéric

Bnsoir à toutes et tous,

Voici une nouvelle version du décodeur qui prend en compte le tarif "tempo".

LkyRx_11c.zip (44.0 KB)

Bonne bidouille

MicroQuettas

Bonjour MicroQuettas, j'ai pour projet de réaliser à partie d'une nano , un simple afficheur puissance soutirée instantanée avec en plus 2 leds jour et jour+1. Etant en Tic historique, j'ai préparé l'interface à base d'un opto 814 et bs 170 me délivrant un creneau de 4 volts d'amplitude. je n'arrive cependant pas à trouver ou récupérer la librairie linkyhistoricTIC.h , ni par lIDE, Github ou google. j'ai vu que certains n'utilise pas l'entrée Rx de leur carte, voir pin 5 , 10 ou autre, est-ce sans réel importance? Merci.

linkyHistTIC.h
Dans le zip du message au-dessus du tiens.

Merci fdufnews.

Excuses-moi, c'est la première fois que je sois confronté à ce genre de problème. j'ai effectivement trouvé le fichier comme indiqué, je n'arrive pas à l'intégrer à l'IDE.
Etant dézippé, je ne peux le faire par l'IDE, et par copier collé dans arduino>librairie non plus. Comment dois-je procéder STP?

Sinon tu ouvres l'archive et tu copies son contenu dans répertoire_de_travail/libraries/LkyRx_10e.
Le répertoire de travail c'est celui dans lequel il y a tes sketches.
Si tu n'es pas sûr de toi prend la première solution.

Encore merci , c'est réussi- je ne savais pas qu'en ajoutant le dossier complet zip ( librairie et croquis), l'IDE sélectionnait la librairie seule, jusqu'à présent , toutes les librairies dont j'ai eu besoin, furent des codes librairies zip uniquement, récupérés sur github sans problème. je saurai pour l'avenir.

Bonsoir à tous et merci MicroQuettas pour ton remarquable travail.

J'avais utilisé une version précédente modifiée pour l'adapter tempo mais la 11 est vraiment bien.
Si vous voulez je peux essayé de déposer ma version à partir de la 11qui en plus communique en Modbus TCP. (c'était mon premier projet donc il faut être indulgent)
Pas de problème avec un aduino MEGA + shield ethernet.

Juste un ou deux constats avec un LINKY en TEMPO :

  • la mesure d'intensité est trop imprécise,
  • les index de consommation et une base de temps permettent de mesurer des kWh et plus ou moins le cos phi à partir des VA.
  • j'ai buté longtemps sur la valeur de la couleur du lendemain mais en fait c'est ENEDIS qui n'indique qu'en fin de journée. Il y a deux solutions mais je ne suis pas certain que l'on puisse avec un arduino :
    la première c'est d'interroger le site EDF avec cette simple requête et on a l'information vers 11h du matin
    https://particulier.edf.fr/services/rest/referentiel/searchTempoStore?dateRelevant=AAAA-MM-JJ
    La seconde est plus complexe et demande de Créer un compte sur RTE pour acceder à une API (c'est RTE qui deside des jours tempo) mais on gagne encore quelques heures
    par exemple dans cette discussion
    Récupération des couleurs Tempo EDF avec un ESP32

Bonsoir,
j'ai un peu de mal à suivre vos différents échanges un tant soit peu technique.
Y -a-t-il parmi vous un auteur qui s'est particulièrement intéressé à la valeur du tic: "PTEC" il me semble avoir vu qu'il pouvait prendre la valeur HPB... ce qui fait penser à Heure Pointe Bleu ou Blanc... avez vous pu trouver d'autres valeurs à ce PTEC par exemple HPR?
Si oui, serait-il possible avec un arduino de transformer cette information en un contact sec. et même plus, pour les HPB ou W blanches
L'objectif étant de gérer aux mieux les différents points de consommations ( par exemple d’arrêter la clim en été si les jours sont HP blancs)
Merci pour vos réflexions.

Bonjour,

A prori voici les informations fournies par le champ PTEC

La période tarifaire en cours (Groupe "PTEC") est codée sur 4 caractères alphanumériques
selon la syntaxe suivante.

  • TH..=> Toutes les Heures.
  • HC.. => Heures Creuses.
  • HP.. => Heures Pleines.
  • HN.. => Heures Normales.
  • PM.. => Heures de Pointe Mobile.

Issu de ce document: Enedis-NOI-CPT_02E-2.pdf que l'on trouve sur Internet

A+

Merci Jelopo, et le document indique aussi les valeurs suivantes des 4 caractères alpha pour PTEC:
""La période tarifaire en cours (donnée du groupe d’étiquette « PTEC »), est codée sur 4 caractères ASCII alphanumériques selon la syntaxe suivante :
 « TH.. » => Toutes les Heures,
 « HC.. » => Heures Creuses,
 « HP.. » => Heures Pleines,
 « HN.. » => Heures Normales,
 « PM.. » => Heures de Pointe Mobile,
 « HCJB » => Heures Creuses Jours Bleus,
 « HCJW » => Heures Creuses Jours Blancs (White),
 « HCJR » => Heures Creuses Jours Rouges,
 « HPJB » => Heures Pleines Jours Bleus,
 « HPJW » => Heures Pleines Jours Blancs (White),
 « HPJR » => Heures Pleines Jours Rouges.""

Je confirme, il y a bien un problème avec le Linky et la couleur du lendemain, c'est toujours bien en retard par rapport à la décision de RTE qui impose la couleur tempo du jour suivant (c'est vers 10h00). C'est même en retard avec EDF. Donc pour anticiper en J pour la période j+1 rouge c'est limite alors qu'avec RTE on a environ 20 heures.

Par exemple il est 15 heures et toujours pas la couleur bleu pour demain.

C'est même un comble puisque sur le site EDF c'est inscrit que c'est à 11h00 (pourquoi pas avant c'est mystérieux...) et effectivement c'est bien affiché à 15 heures.

Donc pour cette partie inutile de décoder la trame ...En cherchant il y a une API sur le site de RTE mais pour l'instant trop difficile pour moi....

En revanche j'ai trouvé celle ci qui est simple à implémenter sur un site
c'est ici : https://www.api-couleur-tempo.fr/

Donc sur mon site j'utilise deux requêtes today et tomorrow et j'ai un code jour 1, 2, 3 (rouge) et une période associée.


 <?php
// Appel à la première API
$url_today = 'https://www.api-couleur-tempo.fr/api/jourTempo/today';
$headers = array(
    'Accept: application/json'
);
$ch_today = curl_init($url_today);
curl_setopt($ch_today, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch_today, CURLOPT_RETURNTRANSFER, true);
$response_today = curl_exec($ch_today);
curl_close($ch_today);
// Appel à la deuxième API
$url_tomorrow = 'https://www.api-couleur-tempo.fr/api/jourTempo/tomorrow';
$ch_tomorrow = curl_init($url_tomorrow);
curl_setopt($ch_tomorrow, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch_tomorrow, CURLOPT_RETURNTRANSFER, true);
$response_tomorrow = curl_exec($ch_tomorrow);
curl_close($ch_tomorrow);
// Fusionner les réponses en un seul tableau
$data_today = json_decode($response_today, true);
$data_tomorrow = json_decode($response_tomorrow, true);
// Fusionner les données des deux API
$merged_data = array(
    "today" => $data_today,
    "tomorrow" => $data_tomorrow
);
// Retourner les données fusionnées au format JSON
header('Content-Type: application/json');
echo json_encode($merged_data);
?>
{"today":{"dateJour":"2024-04-01","codeJour":1,"periode":"2023-2024"},"tomorrow":{"dateJour":"2024-04-02","codeJour":1,"periode":"2023-2024"}}

reste à interroger vers 10h40 mon site et j'ai sur l'arduino (ici avec un UNO R4 et un shield ethernet) la couleur pour demain.


#include <SPI.h>
#include <Ethernet2.h>
#include <ArduinoJson.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x12 }; // Adresse MAC du shield Ethernet
byte ip[] = { 192, 168, 2, 26 };  

char server[] = "couvercelle.org";
char path[] = "/index.php";
int port = 80; // port 80 is the default for HTTP

char username[] = "admin";
char password[] = "Barbare!";

EthernetClient client;

void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  delay(1000);
  Serial.println("Init...");

}

void loop() {
  Serial.println("connecting...");
  
  if (client.connect(server, port)) {
    Serial.println("connected");
    
    client.print("GET ");
    client.print(path);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(server);
   
    client.println("Connection: close");
    client.println();
  } else {
    Serial.println("connection failed");
  }

  // Lecture de la réponse du serveur
  String response;
  bool jsonStarted = false;
  while (client.connected()) {
    if (client.available()) {
      String line = client.readStringUntil('\n');
      if (line.startsWith("{")) {
        jsonStarted = true;
        response += line;
      } else if (jsonStarted && line == "\r") {
        break;
      } else if (jsonStarted) {
        response += line;
      }
    }
  }

  // Déconnexion du serveur
  Serial.println("disconnecting.");
  client.stop();

  // Analyse de la réponse JSON
  DynamicJsonDocument doc(1024); // Choisissez une taille de document en fonction de vos besoins
  DeserializationError error = deserializeJson(doc, response);
  if (!error) {
    // Extraction des données JSON
    JsonObject today = doc["today"];
    JsonObject tomorrow = doc["tomorrow"];

    const char* dateJour_today = today["dateJour"];
    int codeJour_today = today["codeJour"];
    const char* periode_today = today["periode"];

    const char* dateJour_tomorrow = tomorrow["dateJour"];
    int codeJour_tomorrow = tomorrow["codeJour"];
    const char* periode_tomorrow = tomorrow["periode"];
    
    // Affichage des données extraites
    Serial.println("Data received:");
    Serial.println("Today:");
    Serial.print("Date du jour: ");
    Serial.println(dateJour_today);
    Serial.print("Code du jour: ");
    Serial.println(codeJour_today);
    Serial.print("Période: ");
    Serial.println(periode_today);

    Serial.println("Tomorrow:");
    Serial.print("Date du jour: ");
    Serial.println(dateJour_tomorrow);
    Serial.print("Code du jour: ");
    Serial.println(codeJour_tomorrow);
    Serial.print("Période: ");
    Serial.println(periode_tomorrow);
  } else {
    Serial.print("Failed to parse JSON: ");
    Serial.println(error.c_str());
  }
  // Attente avant la prochaine requête
  delay(10000); // Attendre une minute avant la prochaine requête
}

Re bonjour à tous et à MicoQuettas
De retour après une longue période sur d'autres projets et un enfant :wink:
J'ai depuis basculé sur la domotique avec une Home assistant. Je me posais la question dans quelle mesure tous ce travail pourrait être porté sur de la domotique et un hardware plus récent type ESP32 C6 (ce que j'ai actuellement connecté via ma domotique (mais qui je l'avoue est sous utilisé). Je pense que tout ce qui a été développé serait tout simplement génial couplé à un complément.
Je sais que je suis un peu hors sujet mais après lecture du fil c'est là que sont les têtes qui font avancer ce projet.
Cordialement

Je crois que home assistant, utilise MQTT entre autre pour recueillir les métriques.
Il doit être assez simple de modifier le programme pour envoyer les données récoltées sur le topic de ton choix.

Bonjour,

Tout d'abord merci à MicroQuettas, sans son travail sur le code je n'aurais pas pu faire cette réalisation que je souhaite vous partager.

Le système PULSADIS (système utilisé par les anciens boîtiers fourni aux contrats tempo) à disparu chez moi , enedis indique le le dispositif est progressivement arrêté , vu qu'avec le linky on peut récupérer l'info. du coup mon boitier tempo n'indiquait plus que les heures creuses et normale mais n'affichait plus les couleurs.

pour palier à cela , j'ai donc utilisé un atmega pour récupérer les infos tempo issu de la TIC.
le dispositif fonctionne nickel chez moi, j'ai deux cartes relais en sortie 18 et 19 pour couper la PAC les jours rouges et démarrer automatiquement la chaudière fuel ces jours là.

ci-joint le schéma avec les composants.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.