Complete readme and comments in tic.h
This commit is contained in:
parent
9adcf6506e
commit
d2da947fc4
174
README.md
174
README.md
@ -1,18 +1,10 @@
|
||||
# linkytic
|
||||
interface basique pour lire les données tic du compteur linky et les partager en format json via un esp8266/node-mcu.
|
||||
# Linky tic
|
||||
Interface basique pour lire les données TIC d'un compteur Linky et les partager au format JSON via un ESP8266/NodeMCU. L'ensemble est fonctionnel avec Home Assistant en définissant une interface REST.
|
||||
|
||||
## Configuration
|
||||
Créer un fichier secret.h (pour définir les logins et pwd du wifi.
|
||||
À partir du fichier secret-generic.h, créez un fichier secret.h pour définir les identifiants et mots de passe du Wi-Fi.
|
||||
'''
|
||||
// Secrets for your local home network
|
||||
|
||||
// This is a "hard way" to configure your local WiFi network name and passphrase
|
||||
// into the source code and the uploaded sketch.
|
||||
//
|
||||
// Using the WiFi Manager is preferred and avoids reprogramming when your network changes.
|
||||
// See https://homeding.github.io/#page=/wifimanager.md
|
||||
|
||||
// ssid and passPhrase can be used when compiling for a specific environment as a 2. option.
|
||||
|
||||
// add you wifi network name and PassPhrase or use WiFi Manager
|
||||
#ifndef STASSID
|
||||
#define STASSID "Wifi_Id"
|
||||
@ -23,15 +15,163 @@ const char *ssid = STASSID;
|
||||
const char *passPhrase = STAPSK;
|
||||
'''
|
||||
|
||||
Le code est prévu pour un linky en mode standard. Il devrait être fonctionel en mode historique en changent la vitesse du port (1500bps en historique, 9600bps en standard).
|
||||
Le code est prévu pour un Linky en mode standard. Il devrait également fonctionner en mode historique en changeant la vitesse du port (1500 bps en historique, 9600 bps en standard).
|
||||
|
||||
##Interface
|
||||
Un simple optocoupleur suffit.
|
||||
Le schéma disponible sur https://hallard.me/demystifier-la-teleinfo/ est fonctionel chez moi (sans ajout du transistor).
|
||||
## Interface
|
||||
Un simple optocoupleur suffit. Le schéma disponible sur https://hallard.me/demystifier-la-teleinfo/ fonctionne chez moi (sans ajout du transistor).
|
||||
|
||||
##Documents
|
||||
## Documents
|
||||
Enedis-NOI-CPT_54E version 3 (01/06/2018)
|
||||
|
||||
## Intégration dans Home Assistant
|
||||
Les informations Linky sont récupérées en définissant une interface REST. Pour faciliter la lecture du fichier configuration.yaml, j'ai intégré la définition dans un fichier spécifique que j'appelle via la commande :
|
||||
'''
|
||||
rest: !include NOM_FICHIER.yaml
|
||||
'''
|
||||
|
||||
Le contenu du fichier de configuration REST est présenté ci-dessous. Remplacez ADRESSE_IP par l'adresse IP de l'ESP8266 (ou son chemin réseau si le DNS est correctement configuré).
|
||||
Dans mon cas, le fichier contient de nombreux paramètres, mais il peut être simplifié pour se concentrer sur l'essentiel, comme le suivi de la consommation. Étant en triphasé, je surveille la consommation et la puissance sur chaque phase. Ayant des panneaux solaires, je contrôle également l'injection d'énergie. De plus, en participant à l'"effacement jour de pointe", je vérifie le tarif pour adapter ma domotique aux conditions actuelles.
|
||||
Les informations de puissance et de courant sont scannées toutes les 30 secondes, tandis que les informations tarifaires le sont toutes les minutes.
|
||||
Note : Pour cette utilisation, je trouve l'interface REST plus simple à mettre en œuvre que MQTT (ou d'autres protocoles). Modifier la fréquence de scan se fait facilement dans la configuration de Home Assistant. Cependant, la solution MQTT est aussi pertinente sur certains aspects.
|
||||
|
||||
'''
|
||||
- scan_interval: 30
|
||||
resource: http://ADRESSE_IP/ticbasic
|
||||
sensor:
|
||||
- name: "Index Conso totale"
|
||||
value_template: "{{ value_json.EAST | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Index 01 Conso"
|
||||
value_template: "{{ value_json.EASF01 | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Index 02 Conso"
|
||||
value_template: "{{ value_json.EASF02 | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Index 03 Conso"
|
||||
value_template: "{{ value_json.EASF03 | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Index 04 Conso"
|
||||
value_template: "{{ value_json.EASF04 | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Energie injectee total"
|
||||
value_template: "{{ value_json.EAIT | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Index 01 Generation"
|
||||
value_template: "{{ value_json.ERQ1 | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Index 02 Generation"
|
||||
value_template: "{{ value_json.ERQ2 | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Index 03 Generation"
|
||||
value_template: "{{ value_json.ERQ3 | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Index 04 Generation"
|
||||
value_template: "{{ value_json.ERQ4 | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: kWh
|
||||
device_class: energy
|
||||
state_class: total
|
||||
- name: "Puissance instantanée injectée"
|
||||
value_template: "{{ value_json.SINSTI | int / 1000 | round(1) }}"
|
||||
unit_of_measurement: VA
|
||||
device_class: energy
|
||||
state_class: measurement
|
||||
- name: "Courant Efficace Phase 1"
|
||||
value_template: "{{ value_json.IRMS1 }}"
|
||||
unit_of_measurement: A
|
||||
device_class: current
|
||||
state_class: measurement
|
||||
- name: "Courant Efficace Phase 2"
|
||||
value_template: "{{ value_json.IRMS2 }}"
|
||||
unit_of_measurement: A
|
||||
device_class: current
|
||||
state_class: measurement
|
||||
- name: "Courant Efficace Phase 3"
|
||||
value_template: "{{ value_json.IRMS3 }}"
|
||||
unit_of_measurement: A
|
||||
device_class: current
|
||||
state_class: measurement
|
||||
- name: "Tension Efficace Phase 1"
|
||||
value_template: "{{ value_json.URMS1 }}"
|
||||
unit_of_measurement: V
|
||||
device_class: voltage
|
||||
state_class: measurement
|
||||
- name: "Tension Efficace Phase 2"
|
||||
value_template: "{{ value_json.URMS2 }}"
|
||||
unit_of_measurement: V
|
||||
device_class: voltage
|
||||
state_class: measurement
|
||||
- name: "Tension Efficace Phase 3"
|
||||
value_template: "{{ value_json.URMS3 }}"
|
||||
unit_of_measurement: V
|
||||
device_class: voltage
|
||||
state_class: measurement
|
||||
- name: "Puissance apparente totale conso"
|
||||
value_template: "{{ value_json.SINSTS | round(1) }}"
|
||||
unit_of_measurement: VA
|
||||
device_class: apparent_power
|
||||
state_class: measurement
|
||||
- name: "Puissance apparente Phase 1 conso"
|
||||
value_template: "{{ value_json.SINSTS1 | round(1) }}"
|
||||
unit_of_measurement: VA
|
||||
device_class: apparent_power
|
||||
state_class: measurement
|
||||
- name: "Puissance apparente Phase 2 conso"
|
||||
value_template: "{{ value_json.SINSTS2 | round(1) }}"
|
||||
unit_of_measurement: VA
|
||||
device_class: apparent_power
|
||||
state_class: measurement
|
||||
- name: "Puissance apparente Phase 3 conso"
|
||||
value_template: "{{ value_json.SINSTS3 | round(1) }}"
|
||||
unit_of_measurement: VA
|
||||
device_class: apparent_power
|
||||
state_class: measurement
|
||||
- scan_interval: 10
|
||||
resource: http://ADRESSE_IP/ticdata
|
||||
sensor:
|
||||
- unique_id: Elec_Tarif_Code
|
||||
name: "Code Tarif"
|
||||
value_template: "{{ value_json.NTARF }}"
|
||||
- scan_interval: 60
|
||||
resource: http://ADRESSE_IP/ticdata
|
||||
sensor:
|
||||
- unique_id: Elec_Tarif
|
||||
name: "Tarif"
|
||||
value_template: "{{ value_json.LTARF }}"
|
||||
- name: "Message 1"
|
||||
value_template: "{{ value_json.MSG1 }}"
|
||||
- name: "Message 2"
|
||||
value_template: "{{ value_json.MSG2 }}"
|
||||
'''
|
||||
|
||||
## Compilation
|
||||
J'utilise Arduino IDE.
|
||||
Il faut ajouter http://arduino.esp8266.com/stable/package_esp8266com_index.json dans les paramétres.
|
||||
Ensuite, sélectionner la board "Noce MCU 1.0" (ou autre suivant votre technologie).
|
||||
|
||||
### Configuration
|
||||
La liste des paramètres à récupérer est définie dans tic.h sous SelectedEtiquette[NB_ETIQUETTE]. Il vous faudra aussi mettre à jour NB_ETIQUETTE.
|
||||
Les étiquettes sont celles définies dans le document ENEDIS.
|
||||
L'objectif initial de cette liste est de n'inclure dans le JSON que les informations pertinentes, permettant ainsi de gagner quelques millisecondes de traitement, quelques kilo-octets de données et quelques milliwatts de consommation. Bien que le JSON puisse contenir toutes les informations lues, cela n'est pas nécessairement utile pour un utilisateur standard, car jusqu'à 50 % des champs peuvent être vides ou sans réelle utilité domotique.
|
||||
En résumé, vous pouvez adapter cette liste selon vos besoins.
|
||||
|
||||
|
||||
|
||||
|
||||
|
133
tic.h
133
tic.h
@ -7,109 +7,131 @@
|
||||
|
||||
#define TIC
|
||||
|
||||
|
||||
// Définition des constantes pour les délimiteurs de trame TIC
|
||||
//CF document ENEDIS
|
||||
#define STX 0x02 // Début de la trame : 0x02 (<STX>)
|
||||
#define ETX 0x03 // Fin de la trame : 0x03 (<ETX>) End Of Text
|
||||
#define EOT 0x04 //End Of Transmission alias fin de transmission
|
||||
#define LF 0x0A // Code ASCII pour <LF>, debut de groupe d'information
|
||||
#define EOT 0x04 // Fin de transmission
|
||||
#define LF 0x0A /// Code ASCII pour <LF>, début de groupe d'information
|
||||
#define CR 0x0D // Fin de groupe d'information
|
||||
#define HT 0x09 //separateur dans groupe
|
||||
#define SP 0x20 //separateur dans groupe
|
||||
#define NONUTILE "NONUTILE"
|
||||
#define HT 0x09 // Séparateur dans le groupe
|
||||
#define SP 0x20 // Séparateur dans le groupe
|
||||
#define NONUTILE "NONUTILE" // Indicateur pour les champs non utilisés
|
||||
|
||||
#define MAX_CHAR_ETIQUETTE 9
|
||||
// Constantes pour la taille des étiquettes et le nombre d'étiquettes
|
||||
#define MAX_CHAR_ETIQUETTE 9 //CF doc ENEDIS
|
||||
#define NB_ETIQUETTE 45
|
||||
|
||||
// Structure pour stocker les détails d'un groupe TIC
|
||||
struct GroupDetail {
|
||||
String name;
|
||||
String value;
|
||||
String horodate;
|
||||
String name; // Nom de l'étiquette
|
||||
String value; // Valeur associée à l'étiquette
|
||||
String horodate; // Horodatage de la valeur
|
||||
};
|
||||
|
||||
// Structure pour les bits de statut du registre
|
||||
struct RegistreStatusBits {
|
||||
uint32_t contactsec : 1; //bit 0
|
||||
uint32_t organeCoupure : 3; //bit 1 - 3
|
||||
uint32_t cache : 1; //bit 4
|
||||
uint32_t contactsec : 1; //bit 0 - État du contact sec
|
||||
uint32_t organeCoupure : 3; //bit 1 / 3 - État de l'organe de coupure
|
||||
uint32_t cache : 1; //bit 4 - Cache
|
||||
uint32_t : 1; //bit 5
|
||||
uint32_t surtension : 1; //bit 6
|
||||
uint32_t depassementPuissance : 1; //bit 7-----
|
||||
uint32_t consoProd : 1; //bit 8
|
||||
uint32_t senseActiveEnergy : 1; //bit 9
|
||||
uint32_t tarifIndexConso : 4; //bit 10 -13
|
||||
uint32_t tarifIndexProd : 2; //bit 14 - 15 -----
|
||||
uint32_t horlogeState : 1; //bit 16
|
||||
uint32_t ticState : 1; //17
|
||||
uint32_t : 1; //18
|
||||
uint32_t comEuridis : 2; //19-20
|
||||
uint32_t cplState : 2; //21-22
|
||||
uint32_t cplSynchro : 1; //23
|
||||
uint32_t tempo : 2; //24-25
|
||||
uint32_t tempoNextDay : 2; //26-27
|
||||
uint32_t preavisPM : 2; //28-29
|
||||
uint32_t PM : 2; //30-31
|
||||
uint32_t surtension : 1; //bit 6 - Indicateur de surtension
|
||||
uint32_t depassementPuissance : 1; //bit 7 - Indicateur de dépassement de puissance
|
||||
uint32_t consoProd : 1; //bit 8 - Indicateur de consommation/production
|
||||
uint32_t senseActiveEnergy : 1; //bit 9 - Sens de l'énergie active
|
||||
uint32_t tarifIndexConso : 4; //bit 10/13 - Index tarifaire de consommation
|
||||
uint32_t tarifIndexProd : 2; //bit 14/15 - Index tarifaire de production
|
||||
uint32_t horlogeState : 1; //bit 16 - État de l'horloge
|
||||
uint32_t ticState : 1; //bit 17 - État du TIC
|
||||
uint32_t : 1; //bit 18
|
||||
uint32_t comEuridis : 2; //bit 19/20 - Communication Euridis
|
||||
uint32_t cplState : 2; //bit 21/22 - État du CPL
|
||||
uint32_t cplSynchro : 1; //bit 23 - Synchronisation CPL
|
||||
uint32_t tempo : 2; //bit 24/25 - Couleur du jour Tempo
|
||||
uint32_t tempoNextDay : 2; //bit 26/27 - Couleur du jour Tempo suivant
|
||||
uint32_t preavisPM : 2; //bit 28/29 - Préavis pointe mobile
|
||||
uint32_t PM : 2; //bit 30/31 - Pointe mobile
|
||||
};
|
||||
|
||||
// Structure pour les bits de statut des relais
|
||||
struct RelaisStatusBits {
|
||||
uint8_t relaisSec : 1; //bit 1
|
||||
uint8_t relais1 : 1; //bit 2
|
||||
uint8_t relaisSec : 1; //bit 1 - État du relais sec
|
||||
uint8_t relais1 : 1; //bit 2 - État du relais 1
|
||||
uint8_t relais2 : 1; //bit 3
|
||||
uint8_t relais3 : 1; //bit 4
|
||||
uint8_t relais4 : 1; //bit 5
|
||||
uint8_t relais5 : 1; //bit 6-----
|
||||
uint8_t relais6 : 1; //bit 7-----
|
||||
uint8_t relais7 : 1; //bit 8-----
|
||||
uint8_t relais5 : 1; //bit 6
|
||||
uint8_t relais6 : 1; //bit 7
|
||||
uint8_t relais7 : 1; //bit 8 - État du relais 7
|
||||
};
|
||||
|
||||
// Structure pour les bits d'actions du calendrier
|
||||
struct ActionsCalendrierBits {
|
||||
uint8_t index : 4; //bit 3 - 0-----
|
||||
uint8_t relais1 : 1; //bit 4-----
|
||||
uint8_t index : 4; // Index de l'action
|
||||
uint8_t relais1 : 1; //bit 4 - État du relais 1
|
||||
uint8_t relais2 : 1; //bit 8-----
|
||||
uint8_t relais3 : 1; //bit 8-----
|
||||
uint8_t relais4 : 1; //bit 8-----
|
||||
uint8_t relais5 : 1; //bit 7-----
|
||||
uint8_t relais6 : 1; //bit 6-----
|
||||
uint8_t relais7 : 1; //bit 10
|
||||
uint8_t relais7 : 1; //bit 10 - État du relais 7
|
||||
uint8_t : 3; //bit 11-13
|
||||
uint16_t relaisSec : 2; //Contact Sec bit 15-14
|
||||
uint16_t relaisSec : 2; ///État du relais sec
|
||||
};
|
||||
|
||||
// Union pour gérer les actions du calendrier
|
||||
union ActionCalendrier {
|
||||
uint16_t ui;
|
||||
ActionsCalendrierBits bits;
|
||||
};
|
||||
|
||||
// Structure pour une action programmée
|
||||
struct Action {
|
||||
char startTime[4];
|
||||
ActionCalendrier action;
|
||||
char startTime[4]; // Heure de début de l'action
|
||||
ActionCalendrier action; // Action associée
|
||||
};
|
||||
|
||||
// Union pour gérer le statut des relais
|
||||
union RelaisStatus {
|
||||
uint8_t ui;
|
||||
RelaisStatusBits bits;
|
||||
};
|
||||
|
||||
// Union pour gérer le statut du registre
|
||||
union RegistreStatus {
|
||||
uint32_t uli;
|
||||
RegistreStatusBits bits;
|
||||
};
|
||||
|
||||
const static String SelectedEtiquette[NB_ETIQUETTE] = {
|
||||
"ADSC", // Adresse du compteur
|
||||
"DATE", // Date et heure courantes
|
||||
"NGTF", // Numéro de gestionnaire de réseau de transport
|
||||
"LTARF", // Libellé du tarif en cours
|
||||
"EAST", // Énergie active soutirée totale
|
||||
"EASF01", "EASF02", "EASF03", "EASF04", // Énergie active soutirée par période tarifaire
|
||||
"EASD01", "EASD02", "EASD03", "EASD04", // Énergie active soutirée par période tarifaire (distribuée)
|
||||
"EAIT", // Énergie active injectée totale
|
||||
"ERQ1", "ERQ2", "ERQ3", "ERQ4", // Énergie réactive par quadrant
|
||||
"IRMS1", "IRMS2", "IRMS3", // Courant efficace par phase
|
||||
"URMS1", "URMS2", "URMS3", // Tension efficace par phase
|
||||
"PCOUP", // Puissance de coupure
|
||||
"SINSTS", "SINSTS1", "SINSTS2", "SINSTS3", // Puissance apparente soutirée totale et par phase
|
||||
"SINSTI", // Puissance apparente injectée
|
||||
"STGE", // État du registre de statuts
|
||||
"DPM1", "FPM1", "DPM2", "FPM2", "DPM3", "FPM3", // Début et fin de pointe mobile
|
||||
"RELAIS", // État des relais
|
||||
"NTARF", // Nom du tarif en cours
|
||||
"NJOURF", "NJOURF+1", "PJOURF+1", // Couleur du jour et du lendemain
|
||||
"MSG1", "MSG2", // Messages d'information
|
||||
"PPOINTE" // Préavis de pointe mobile
|
||||
};
|
||||
|
||||
|
||||
const static String SelectedEtiquette[NB_ETIQUETTE] = { "ADSC", "DATE",
|
||||
"NGTF", "LTARF",
|
||||
"EAST", "EASF01", "EASF02", "EASF03", "EASF04",
|
||||
"EASD01", "EASD02", "EASD03", "EASD04",
|
||||
"EAIT", "ERQ1", "ERQ2", "ERQ3","ERQ4",
|
||||
"IRMS1", "IRMS2", "IRMS3",
|
||||
"URMS1", "URMS2", "URMS3",
|
||||
"PCOUP",
|
||||
"SINSTS", "SINSTS1", "SINSTS2", "SINSTS3",
|
||||
"SINSTI",
|
||||
"STGE", "DPM1", "FPM1", "DPM2", "FPM2", "DPM3", "FPM3",
|
||||
"RELAIS", "NTARF", "NJOURF", "NJOURF+1", "PJOURF+1",
|
||||
"MSG1", "MSG2",
|
||||
"PPOINTE" };
|
||||
// Tableau pour stocker les valeurs des groupes TIC identifiés
|
||||
extern struct GroupDetail TicValues[NB_ETIQUETTE]; //records the values of the identified group
|
||||
|
||||
//Constantes pour definition des statuts
|
||||
// Constantes pour la définition des statuts
|
||||
const static String kContactStatus[2] = { "closed", "open" }; //relais et contacteurs
|
||||
const static String kCoupure[7] = { "closed",
|
||||
"open_overpower",
|
||||
@ -130,6 +152,7 @@ const static String kCplSynchro[2] = { "not_synchro", "synchro" };
|
||||
const static String kTempoColor[4] = { "no", "blue", "white", "red" };
|
||||
const static String kPointeMobile[4] = { "no", "PM1", "PM2", "PM3" };
|
||||
|
||||
// Prototypes des fonctions pour lire les données TIC et les convertir en JSON
|
||||
void readTicPort();
|
||||
String ticValuesAsJson();
|
||||
String ticBasicValuesAsJson();
|
||||
|
Loading…
Reference in New Issue
Block a user