Même pb chez moi, ok via /dev/ttyAMA0 mais rien sous domoticz
Je contaste aussi que dans les cas qui fonctionne la valeur renvoyé PAPP est présente, pas chez moi
Code : Tout sélectionner
Bonjour,
-j'ai deux compteur a la maison 1 edf maison & 1 edf photovoltaique
-je valide tout le hardware par le faite que le photovoltaique fonctionne
-et je vois les trames du edf maison dans putty
Ci joint les trames téléinfo
Compteur photovoltaique : Sagem S10C4 (fonctionnel)
Trame du photovoltaique
ADCO 020828497082 I
OPTARIF BASE 0
ISOUSC 15 <
BASE 011697323 +
PTEC TH.. $
IINST 001 X
IMAX 009 H
PAPP 00260 )
MOTDETAT 400000 F
puis environ 3min plus tard
ADCO 020828497082 I
OPTARIF BASE 0
ISOUSC 15 <
BASE 011697324 ,
PTEC TH.. $
IINST 001 X
IMAX 009 H
PAPP 00250 (
MOTDETAT 400000 F
Compteur edf : Sagem S10C1 (non fonctionnel sous domoticz , ok sous putty)
OPTARIF HC.. <
ISOUSC 30 9
HCHC 057479903 2
HCHP 056420235 .
PTEC HP..
IINST 001 X
IMAX 031 C
HHPHC D /
MOTDETAT 000000 B
puis quelque sec plus tard
ADCO 029701401358 ?
OPTARIF HC.. <
ISOUSC 30 9
HCHC 057479903 2
HCHP 056420239 2
PTEC HP..
IINST 001 X
IMAX 031 C
HHPHC D /
MOTDETAT 000000 B
Montage fonctionnel activation du p1 smart meter via le photovoltaique fonctionnement ok.
Passage sur le edf non fonctionnel (sans rien recreer)
Voila si vous avez des idéesMaintenant que tu en parle c'est vrai que mon photo voltaique qui fonctionne envoye du PAPP tandis que mon edf non reconnu sous domoticz (mais ok sous putty) n'envoye pas de PAPP...dbocart a écrit :Bonjour,
Même pb chez moi, ok via /dev/ttyAMA0 mais rien sous domoticz
Je contaste aussi que dans les cas qui fonctionne la valeur renvoyé PAPP est présente, pas chez moi
Patrice => Es ce que ca vaut le cout d'informer le fofo anglais de l'éventuel cause du PAPP pour la non reconnaissance des compteurs?Puissance apparente : Certains compteurs ne renvoie pas l'information PAPP. Pour cela un calcul à été implémenté afin d'obtenir une moyenne de consommation en W toutes les minutes.
dbocart a écrit : Patrice => Es ce que ca vaut le cout d'informer le fofo anglais de l'éventuel cause du PAPP pour la non reconnaissance des compteurs?
Code : Tout sélectionner
La puissance apparente
La puissance apparente est la somme (trigonométrique) de la puissance active et réactive. C'est par ailleurs la puissance souscrite (kVA) pour abonnement ERDF. Elle se calcule comme suit : S=U.I S = Puissance apparente (VA) (homogène à des Watts)
U = Tension (V)
I = Intensité (A)
La puissance apparente est l'hypothénuse du triangle des puissances. On peut donc, grâce à ce bon vieux Pythagore, la calculer à partir des deux autres puissances : S=√(P²+Q²) S = Puissance apparente (VA) (Volt-Ampère)
P = Puissance active (W)
Q = Puissance réactive (VAR)Code : Tout sélectionner
Index: hardware/Teleinfo.cpp
===================================================================
--- hardware/Teleinfo.cpp (révision 2383)
+++ hardware/Teleinfo.cpp (copie de travail)
@@ -45,7 +45,7 @@
#define TE_ADCO "ADCO" //meter id
#define TE_OPTARIF "OPTARIF"//pricing option
-#define TE_ISOUSC "ISOUC"//current power subscribe //A
+#define TE_ISOUSC "ISOUSC"//current power subscribe //A
#define TE_BASE "BASE"//total power usage normal tariff in base option
#define TE_HCHC "HCHC"// total power usage low tariff in HC option
#define TE_HCHP "HCHP"// total power usage normal tariff in HC option
@@ -61,8 +61,9 @@
#define TE_IINST "IINST"//instant current power usage
#define TE_IMAX "IMAX"//maximal current power usage
#define TE_PAPP "PAPP"//apparent power
+#define TE_MOTDETAT "MOTDETAT"//mot d'etat
-Teleinfo::Match Teleinfo::m_matchlist[18] = {
+Teleinfo::Match Teleinfo::m_matchlist[19] = {
{ STD, TELEINFO_TYPE_ADCO, TE_ADCO, 12 },
{ STD, TELEINFO_TYPE_OPTARIF, TE_OPTARIF, 4 },
{ STD, TELEINFO_TYPE_ISOUSC, TE_ISOUSC, 2 },
@@ -80,7 +81,8 @@
{ STD, TELEINFO_TYPE_PTEC, TE_PTEC, 4 },
{ STD, TELEINFO_TYPE_IINST, TE_IINST, 3 },
{ STD, TELEINFO_TYPE_IMAX, TE_IMAX, 3 },
- { STD, TELEINFO_TYPE_PAPP, TE_PAPP, 5 }
+ { STD, TELEINFO_TYPE_PAPP, TE_PAPP, 5 },
+ { STD, TELEINFO_TYPE_MOTDETAT, TE_MOTDETAT, 6 }
};
Teleinfo::Teleinfo(const int ID, const std::string& devname, unsigned int baud_rate)
@@ -278,26 +280,42 @@
break;
case TELEINFO_TYPE_IINST:
//we convert A to W setting RFXMeter/Counter Dividers Energy to 1000 / voltage => 1000/230 = 4.35
- //m_p1power.usagecurrent = ulValue;
+ m_p1power.usagecurrent = ulValue;
break;
case TELEINFO_TYPE_IMAX:
break;
case TELEINFO_TYPE_PAPP:
//we count to prevent add each block but only one every 10 seconds
m_p1power.usagecurrent += ulValue;
+// m_counter++;
+// if (m_counter >= NumberOfFrameToSendOne)
+// {
+// _log.Log(LOG_NORM,"Teleinfo frame complete");
+// _log.Log(LOG_NORM,"powerusage1 = %lu", m_p1power.powerusage1);
+// _log.Log(LOG_NORM,"powerusage2 = %lu", m_p1power.powerusage2);
+// _log.Log(LOG_NORM,"usagecurrent = %lu", m_p1power.usagecurrent);
+// m_p1power.usagecurrent /= m_counter;
+// sDecodeRXMessage(this, (const unsigned char *)&m_p1power);
+// m_counter = 0;
+// m_p1power.usagecurrent = 0;
+// }
+ break;
+ case TELEINFO_TYPE_MOTDETAT:
m_counter++;
if (m_counter >= NumberOfFrameToSendOne)
{
- //_log.Log(LOG_NORM,"Teleinfo frame complete");
- //_log.Log(LOG_NORM,"powerusage1 = %lu", m_p1power.powerusage1);
- //_log.Log(LOG_NORM,"powerusage2 = %lu", m_p1power.powerusage2);
- //_log.Log(LOG_NORM,"usagecurrent = %lu", m_p1power.usagecurrent);
+ _log.Log(LOG_NORM,"Teleinfo frame complete");
+ _log.Log(LOG_NORM,"powerusage1 = %lu", m_p1power.powerusage1);
+ _log.Log(LOG_NORM,"powerusage2 = %lu", m_p1power.powerusage2);
+ _log.Log(LOG_NORM,"usagecurrent = %lu", m_p1power.usagecurrent);
m_p1power.usagecurrent /= m_counter;
sDecodeRXMessage(this, (const unsigned char *)&m_p1power);
m_counter = 0;
m_p1power.usagecurrent = 0;
}
break;
+ default:
+ _log.Log(LOG_ERROR, "Teleinfo: label '%s' not handled!", t.key);
}
return;
}
@@ -310,7 +328,7 @@
{
const unsigned char c = pData[ii];
- if ((c == 0x0d) || (c == 0x00))
+ if ((c == 0x0d) || (c == 0x00) || (c == 0x02) || (c == 0x03))
{
ii++;
continue;
Index: hardware/Teleinfo.h
===================================================================
--- hardware/Teleinfo.h (révision 2383)
+++ hardware/Teleinfo.h (copie de travail)
@@ -73,6 +73,7 @@
TELEINFO_TYPE_IINST,
TELEINFO_TYPE_IMAX,
TELEINFO_TYPE_PAPP,
+ TELEINFO_TYPE_MOTDETAT,
} Type;
typedef struct _tMatch {
@@ -116,5 +117,5 @@
unsigned char m_buffer[readBufferSize];
int m_bufferpos;
- static Teleinfo::Match m_matchlist[18];
+ static Teleinfo::Match m_matchlist[19];
};
Code : Tout sélectionner
/*
Domoticz Software : http://domoticz.com/
File : Teleinfo.cpp
Author : Nicolas HILAIRE
Version : 1.2
Description : This class manage the Teleinfo Signal
History :
- 2013-11-01 : Creation
- 2014-10-29 : Add 'EJP' contract (Laurent MEY)
- 2014-12-13 : Add 'Tempo' contract (Kevin NICOLAS)
*/
#include "stdafx.h"
#include "Teleinfo.h"
#include "hardwaretypes.h"
#include "../main/localtime_r.h"
#include "../main/Logger.h"
#include <string>
#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>
#include <ctime>
//Teleinfo for EDF power meter. Only "Base" and "Heures creuses" are suported
//Teleinfo official specification :
//http://www.planete-domotique.com/notices/ERDF-NOI-CPT_O2E.pdf
//Example of data received by EDF power meter
//ADCO 271028237723 C
//OPTARIF HC.. <
//ISOUSC 45 ?
//HCHC 013149843 '
//HCHP 013016759 3
//PTEC HP..
//IINST 002 Y
//IMAX 049 L
//PAPP 00450 *
//HHPHC D /
//MOTDETAT 000000 B
#define TE_ADCO "ADCO" //meter id
#define TE_OPTARIF "OPTARIF"//pricing option
#define TE_ISOUSC "ISOUC"//current power subscribe //A
#define TE_BASE "BASE"//total power usage normal tariff in base option
#define TE_HCHC "HCHC"// total power usage low tariff in HC option
#define TE_HCHP "HCHP"// total power usage normal tariff in HC option
#define TE_EJPHPM "EJPHPM"// total power usage normal tariff in PM option
#define TE_EJPHN "EJPHN"// total power usage low tariff in HN option
#define TE_BBRHCJB "BBRHCJB"// total power usage low tariff in HC option tempo blue
#define TE_BBRHPJB "BBRHPJB"// total power usage normal tariff in HC option tempo blue
#define TE_BBRHCJW "BBRHCJW"// total power usage low tariff in HC option tempo white
#define TE_BBRHPJW "BBRHPJW"// total power usage normal tariff in HC option tempo white
#define TE_BBRHCJR "BBRHCJR"// total power usage low tariff in HC option tempo red
#define TE_BBRHPJR "BBRHPJR"// total power usage normal tariff in HC option tempo red
#define TE_PTEC "PTEC"//current tariff period
#define TE_IINST "IINST"//instant current power usage
#define TE_IMAX "IMAX"//maximal current power usage
#define TE_PAPP "PAPP"//apparent power
Teleinfo::Match Teleinfo::m_matchlist[18] = {
{ STD, TELEINFO_TYPE_ADCO, TE_ADCO, 12 },
{ STD, TELEINFO_TYPE_OPTARIF, TE_OPTARIF, 4 },
{ STD, TELEINFO_TYPE_ISOUSC, TE_ISOUSC, 2 },
{ STD, TELEINFO_TYPE_BASE, TE_BASE, 9 },
{ STD, TELEINFO_TYPE_HCHC, TE_HCHC, 9 },
{ STD, TELEINFO_TYPE_HCHP, TE_HCHP, 9 },
{ STD, TELEINFO_TYPE_EJPHPM, TE_EJPHPM, 9 },
{ STD, TELEINFO_TYPE_EJPHN, TE_EJPHN, 9 },
{ STD, TELEINFO_TYPE_BBRHCJB, TE_BBRHCJB, 9 },
{ STD, TELEINFO_TYPE_BBRHPJB, TE_BBRHPJB, 9 },
{ STD, TELEINFO_TYPE_BBRHCJW, TE_BBRHCJW, 9 },
{ STD, TELEINFO_TYPE_BBRHPJW, TE_BBRHPJW, 9 },
{ STD, TELEINFO_TYPE_BBRHCJR, TE_BBRHCJR, 9 },
{ STD, TELEINFO_TYPE_BBRHPJR, TE_BBRHPJR, 9 },
{ STD, TELEINFO_TYPE_PTEC, TE_PTEC, 4 },
{ STD, TELEINFO_TYPE_IINST, TE_IINST, 3 },
{ STD, TELEINFO_TYPE_IMAX, TE_IMAX, 3 },
{ STD, TELEINFO_TYPE_PAPP, TE_PAPP, 5 }
};
Teleinfo::Teleinfo(const std::string& devname,
unsigned int baud_rate,
boost::asio::serial_port_base::parity opt_parity,
boost::asio::serial_port_base::character_size opt_csize,
boost::asio::serial_port_base::flow_control opt_flow,
boost::asio::serial_port_base::stop_bits opt_stop)
:AsyncSerial(devname, baud_rate, opt_parity, opt_csize, opt_flow, opt_stop)
{
m_szSerialPort = devname;
m_iBaudRate = baud_rate;
m_iOptParity = opt_parity;
m_iOptCsize = opt_csize;
m_iOptFlow = opt_flow;
m_iOptStop = opt_stop;
Init();
}
Teleinfo::Teleinfo(const int ID, const std::string& devname, unsigned int baud_rate)
{
m_szSerialPort = devname;
m_iBaudRate = baud_rate;
m_iOptParity = boost::asio::serial_port_base::parity(TELEINFO_PARITY);
m_iOptCsize = boost::asio::serial_port_base::character_size(TELEINFO_CARACTER_SIZE);
m_iOptFlow = boost::asio::serial_port_base::flow_control(TELEINFO_FLOW_CONTROL);
m_iOptStop = boost::asio::serial_port_base::stop_bits(TELEINFO_STOP_BITS);
Init();
}
Teleinfo::~Teleinfo(void)
{
StopHardware();
}
void Teleinfo::Init()
{
m_bufferpos = 0;
memset(&m_buffer, 0, sizeof(m_buffer));
memset(&m_p1power, 0, sizeof(m_p1power));
m_p1power.len = sizeof(P1Power) - 1;
m_p1power.type = pTypeP1Power;
m_p1power.subtype = sTypeP1Power;
m_counter = 0;
}
bool Teleinfo::StartHardware()
{
StartHeartbeatThread();
//Try to open the Serial Port
try
{
_log.Log(LOG_STATUS, "Teleinfo: Using serial port: %s", m_szSerialPort.c_str());
open(
m_szSerialPort,
m_iBaudRate,
m_iOptParity,
m_iOptCsize
);
}
catch (boost::exception & e)
{
_log.Log(LOG_ERROR, "Teleinfo: Error opening serial port!");
#ifdef _DEBUG
_log.Log(LOG_ERROR, "-----------------\n%s\n-----------------", boost::diagnostic_information(e).c_str());
#endif
return false;
}
catch (...)
{
_log.Log(LOG_ERROR, "Teleinfo: Error opening serial port!!!");
return false;
}
setReadCallback(boost::bind(&Teleinfo::readCallback, this, _1, _2));
m_bIsStarted = true;
sOnConnected(this);
return true;
}
bool Teleinfo::StopHardware()
{
if (isOpen())
{
try {
clearReadCallback();
close();
}
catch (...)
{
//Don't throw from a Stop command
}
}
StopHeartbeatThread();
m_bIsStarted = false;
return true;
}
void Teleinfo::readCallback(const char *data, size_t len)
{
boost::lock_guard<boost::mutex> l(readQueueMutex);
if (!m_bEnableReceive)
return; //receiving not enabled
ParseData((const unsigned char*)data, static_cast<int>(len));
}
void Teleinfo::MatchLine()
{
if ((strlen((const char*)&m_buffer)<1) || (m_buffer[0] == 0x0a))
return;
uint8_t i;
uint8_t found = 0;
Teleinfo::Match t;
char value[20] = "";
std::string vString;
//_log.Log(LOG_NORM,"Frame : #%s#", m_buffer);
for (i = 0; (i<sizeof(m_matchlist) / sizeof(Teleinfo::Match))&(!found); i++)
{
t = m_matchlist[i];
switch (t.matchtype)
{
case STD:
if (strncmp(t.key, (const char*)&m_buffer, strlen(t.key)) == 0) {
found = 1;
}
break;
} //switch
if (!found)
continue;
if (t.matchtype == STD)
{
//We get the width car after the space
unsigned char * pos = (unsigned char *)strchr((char*)m_buffer, ' ');
if (pos == NULL)
continue;
int position = int(pos - (unsigned char*)&m_buffer);
strncpy(value, (char*)&(m_buffer[position + 1]), t.width);
value[t.width] = 0;
}
unsigned long ulValue = (unsigned long)atoi(value);
switch (t.type)
{
case TELEINFO_TYPE_ADCO:
/*
//structure initialization
memset(&m_p1power,0,sizeof(m_p1power));
m_p1power.len=sizeof(P1Power)-1;
m_p1power.type=pTypeP1Power;
m_p1power.subtype=sTypeP1Power;
*/
break;
case TELEINFO_TYPE_OPTARIF:
break;
case TELEINFO_TYPE_ISOUSC:
break;
case TELEINFO_TYPE_BASE:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_HCHC:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_HCHP:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_EJPHPM:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_EJPHN:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_BBRHCJB:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_BBRHPJB:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_BBRHCJW:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_BBRHPJW:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_BBRHCJR:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_BBRHPJR:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_PTEC:
break;
case TELEINFO_TYPE_IINST:
//we convert A to W setting RFXMeter/Counter Dividers Energy to 1000 / voltage => 1000/230 = 4.35
//m_p1power.usagecurrent = ulValue;
break;
case TELEINFO_TYPE_IMAX:
break;
case TELEINFO_TYPE_PAPP:
//we count to prevent add each block but only one every 10 seconds
m_p1power.usagecurrent += ulValue;
m_counter++;
if (m_counter >= NumberOfFrameToSendOne)
{
//_log.Log(LOG_NORM,"Teleinfo frame complete");
//_log.Log(LOG_NORM,"powerusage1 = %lu", m_p1power.powerusage1);
//_log.Log(LOG_NORM,"powerusage2 = %lu", m_p1power.powerusage2);
//_log.Log(LOG_NORM,"usagecurrent = %lu", m_p1power.usagecurrent);
m_p1power.usagecurrent /= m_counter;
sDecodeRXMessage(this, (const unsigned char *)&m_p1power);
m_counter = 0;
m_p1power.usagecurrent = 0;
}
break;
}
return;
}
}
void Teleinfo::ParseData(const unsigned char *pData, int Len)
{
int ii = 0;
while (ii<Len)
{
const unsigned char c = pData[ii];
if ((c == 0x0d) || (c == 0x00))
{
ii++;
continue;
}
m_buffer[m_bufferpos] = c;
if (c == 0x0a || m_bufferpos == sizeof(m_buffer) - 1)
{
// discard newline, close string, parse line and clear it.
if (m_bufferpos > 0)
m_buffer[m_bufferpos] = 0;
//We check the line only if the checksum is ok
if (isCheckSumOk())
MatchLine();
m_bufferpos = 0;
}
else
{
m_bufferpos++;
}
ii++;
}
}
/* Explanation of the checksum computation issued from the official EDF specification
a "checksum" is calculated on the set of characters from the beginning of the label field to the end of the field given character SP included.
We first make ??the sum of all ASCII codes of all characters.
to avoid introduce ASCII (00 to 1F hex) functions, it retains only the six least significant bits of
result (this translates into a logical AND between the amount previously calculated and 03Fh).
Finally, we added 20 hexadecimal. The result will always be a printable ASCII character (sign, digit,
capital letter) of from 0x20 to hexadecimal 0x5F
La "checksum" est calculÈe sur l'ensemble des caractËres allant du dÈbut du champ Ètiquette ‡ la fin du champ
donnÈe, caractËre SP inclus. On fait tout d'abord la somme des codes ASCII de tous ces caractËres. Pour Èviter
d'introduire des fonctions ASCII (00 ‡ 1F en hexadÈcimal), on ne conserve que les six bits de poids faible du
rÈsultat obtenu (cette opÈration se traduit par un ET logique entre la somme prÈcÈdemment calculÈe et 03Fh).
Enfin, on ajoute 20 en hexadÈcimal. Le rÈsultat sera donc toujours un caractËre ASCII imprimable (signe, chiffre,
lettre majuscule) allant de 20 ‡ 5F en hexadÈcimal.
*/
bool Teleinfo::isCheckSumOk()
{
unsigned int checksum = 0x00;
int i;
for (i = 0; i < int(strlen((char*)m_buffer)) - 2; i++)
{
checksum += m_buffer[i];
}
checksum = (checksum & 0x3F) + 0x20;
return (checksum == m_buffer[strlen((char*)m_buffer) - 1]);
}
void Teleinfo::WriteToHardware(const char *pdata, const unsigned char length)
{
}
Code : Tout sélectionner
/*
Domoticz Software : http://domoticz.com/
File : Teleinfo.h
Author : Nicolas HILAIRE
Version : 1.2
Description : This class manage the Teleinfo Signal
History :
- 2013-11-01 : Creation
- 2014-10-29 : Add 'EJP' contract (Laurent MEY)
- 2014-12-13 : Add 'Tempo' contract (Kevin NICOLAS)
*/
#pragma once
#include "DomoticzHardware.h"
#include "P1MeterBase.h"
#include "ASyncSerial.h"
/*
typedef struct _teleinfoData {
unsigned char len;
unsigned char type;
unsigned char subtype;
char optTariff[4];
unsigned long powerusage1; // normal tariff at power Usage in Wh
unsigned long powerusage2; // low tariff at power Usage in Wh
unsigned long currentPowerSubscribe; //in A
char currentTariffPeriod[4];
unsigned long instantCurrentPowerUsage; //in A
unsigned long maximalCurrentPowerUsage; //in A
unsigned long apparentPower; //in VA
} TeleinfoData;
*/
#define TELEINFO_BAUD_RATE 1200
#define TELEINFO_PARITY boost::asio::serial_port_base::parity::even
#define TELEINFO_CARACTER_SIZE 7
#define TELEINFO_FLOW_CONTROL boost::asio::serial_port_base::flow_control::none
#define TELEINFO_STOP_BITS boost::asio::serial_port_base::stop_bits::one
class Teleinfo : public CDomoticzHardwareBase, AsyncSerial
{
typedef enum {
ID = 0,
STD,
} MatchType;
//typedef enum {
// TELEINFO_OPTION_BASE, //single tariff
// TELEINFO_OPTION_HC, //double tariff (low and normal)
// TELEINFO_OPTION_EJP, //EJP Option, (test)
// TELEINFO_OPTION_TEMPO, //Tempo option, (test)
//} Option;
typedef enum {
TELEINFO_TYPE_ADCO,
TELEINFO_TYPE_OPTARIF,
TELEINFO_TYPE_ISOUSC,
TELEINFO_TYPE_BASE,
TELEINFO_TYPE_HCHC,
TELEINFO_TYPE_HCHP,
TELEINFO_TYPE_EJPHN,
TELEINFO_TYPE_EJPHPM,
TELEINFO_TYPE_BBRHCJB,
TELEINFO_TYPE_BBRHPJB,
TELEINFO_TYPE_BBRHCJW,
TELEINFO_TYPE_BBRHPJW,
TELEINFO_TYPE_BBRHCJR,
TELEINFO_TYPE_BBRHPJR,
TELEINFO_TYPE_PTEC,
TELEINFO_TYPE_IINST,
TELEINFO_TYPE_IMAX,
TELEINFO_TYPE_PAPP,
} Type;
typedef struct _tMatch {
MatchType matchtype;
Type type;
const char* key;
int width;
} Match;
public:
Teleinfo(const int ID, const std::string& devname, unsigned int baud_rate = TELEINFO_BAUD_RATE);
/**
* Opens a serial device.
* \param devname serial device name, example "/dev/ttyAMA0" or "COM1"
* \param baud_rate serial baud rate, default 1200
* \param opt_parity serial parity, default even
* \param opt_csize serial character size, default 7bit
* \param opt_flow serial flow control, default none
* \param opt_stop serial stop bits, default 1
* \throws boost::system::system_error if cannot open the
* serial device
*/
Teleinfo(const std::string& devname, unsigned int baud_rate = TELEINFO_BAUD_RATE,
boost::asio::serial_port_base::parity opt_parity = boost::asio::serial_port_base::parity(TELEINFO_PARITY),
boost::asio::serial_port_base::character_size opt_csize = boost::asio::serial_port_base::character_size(TELEINFO_CARACTER_SIZE),
boost::asio::serial_port_base::flow_control opt_flow = boost::asio::serial_port_base::flow_control(TELEINFO_FLOW_CONTROL),
boost::asio::serial_port_base::stop_bits opt_stop = boost::asio::serial_port_base::stop_bits(TELEINFO_STOP_BITS));
~Teleinfo();
std::string m_szSerialPort;
P1Power m_p1power;
void WriteToHardware(const char *pdata, const unsigned char length);
private:
bool StartHardware();
bool StopHardware();
/**
* Read callback, stores data in the buffer
*/
void readCallback(const char *data, size_t len);
unsigned int m_iBaudRate;
boost::asio::serial_port_base::parity m_iOptParity;
boost::asio::serial_port_base::character_size m_iOptCsize;
boost::asio::serial_port_base::flow_control m_iOptFlow;
boost::asio::serial_port_base::stop_bits m_iOptStop;
int m_counter;
static const int readBufferSize = 1028;
static const int NumberOfFrameToSendOne = 8;
void Init();
void MatchLine();
void ParseData(const unsigned char *pData, int Len);
bool isCheckSumOk();
unsigned char m_buffer[readBufferSize];
int m_bufferpos;
static Teleinfo::Match m_matchlist[18];
};
Code : Tout sélectionner
/*
Domoticz Software : http://domoticz.com/
File : Teleinfo.cpp
Author : Nicolas HILAIRE
Version : 1.2
Description : This class manage the Teleinfo Signal
History :
- 2013-11-01 : Creation
- 2014-10-29 : Add 'EJP' contract (Laurent MEY)
- 2014-12-13 : Add 'Tempo' contract (Kevin NICOLAS)
*/
#include "stdafx.h"
#include "Teleinfo.h"
#include "hardwaretypes.h"
#include "../main/localtime_r.h"
#include "../main/Logger.h"
#include <string>
#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>
#include <ctime>
//Teleinfo for EDF power meter. Only "Base" and "Heures creuses" are suported
//Teleinfo official specification :
//http://www.planete-domotique.com/notices/ERDF-NOI-CPT_O2E.pdf
//Example of data received by EDF power meter
//ADCO 271028237723 C
//OPTARIF HC.. <
//ISOUSC 45 ?
//HCHC 013149843 '
//HCHP 013016759 3
//PTEC HP..
//IINST 002 Y
//IMAX 049 L
//PAPP 00450 *
//HHPHC D /
//MOTDETAT 000000 B
#define TE_ADCO "ADCO" //meter id
#define TE_OPTARIF "OPTARIF"//pricing option
#define TE_ISOUSC "ISOUSC"//current power subscribe //A
#define TE_BASE "BASE"//total power usage normal tariff in base option
#define TE_HCHC "HCHC"// total power usage low tariff in HC option
#define TE_HCHP "HCHP"// total power usage normal tariff in HC option
#define TE_EJPHPM "EJPHPM"// total power usage normal tariff in PM option
#define TE_EJPHN "EJPHN"// total power usage low tariff in HN option
#define TE_BBRHCJB "BBRHCJB"// total power usage low tariff in HC option tempo blue
#define TE_BBRHPJB "BBRHPJB"// total power usage normal tariff in HC option tempo blue
#define TE_BBRHCJW "BBRHCJW"// total power usage low tariff in HC option tempo white
#define TE_BBRHPJW "BBRHPJW"// total power usage normal tariff in HC option tempo white
#define TE_BBRHCJR "BBRHCJR"// total power usage low tariff in HC option tempo red
#define TE_BBRHPJR "BBRHPJR"// total power usage normal tariff in HC option tempo red
#define TE_PTEC "PTEC"//current tariff period
#define TE_IINST "IINST"//instant current power usage
#define TE_IMAX "IMAX"//maximal current power usage
#define TE_PAPP "PAPP"//apparent power
#define TE_MOTDETAT "MOTDETAT"//mot d'etat
Teleinfo::Match Teleinfo::m_matchlist[19] = {
{ STD, TELEINFO_TYPE_ADCO, TE_ADCO, 12 },
{ STD, TELEINFO_TYPE_OPTARIF, TE_OPTARIF, 4 },
{ STD, TELEINFO_TYPE_ISOUSC, TE_ISOUSC, 2 },
{ STD, TELEINFO_TYPE_BASE, TE_BASE, 9 },
{ STD, TELEINFO_TYPE_HCHC, TE_HCHC, 9 },
{ STD, TELEINFO_TYPE_HCHP, TE_HCHP, 9 },
{ STD, TELEINFO_TYPE_EJPHPM, TE_EJPHPM, 9 },
{ STD, TELEINFO_TYPE_EJPHN, TE_EJPHN, 9 },
{ STD, TELEINFO_TYPE_BBRHCJB, TE_BBRHCJB, 9 },
{ STD, TELEINFO_TYPE_BBRHPJB, TE_BBRHPJB, 9 },
{ STD, TELEINFO_TYPE_BBRHCJW, TE_BBRHCJW, 9 },
{ STD, TELEINFO_TYPE_BBRHPJW, TE_BBRHPJW, 9 },
{ STD, TELEINFO_TYPE_BBRHCJR, TE_BBRHCJR, 9 },
{ STD, TELEINFO_TYPE_BBRHPJR, TE_BBRHPJR, 9 },
{ STD, TELEINFO_TYPE_PTEC, TE_PTEC, 4 },
{ STD, TELEINFO_TYPE_IINST, TE_IINST, 3 },
{ STD, TELEINFO_TYPE_IMAX, TE_IMAX, 3 },
{ STD, TELEINFO_TYPE_PAPP, TE_PAPP, 5 },
{ STD, TELEINFO_TYPE_MOTDETAT, TE_MOTDETAT, 6 }
};
Teleinfo::Teleinfo(const std::string& devname,
unsigned int baud_rate,
boost::asio::serial_port_base::parity opt_parity,
boost::asio::serial_port_base::character_size opt_csize,
boost::asio::serial_port_base::flow_control opt_flow,
boost::asio::serial_port_base::stop_bits opt_stop)
:AsyncSerial(devname, baud_rate, opt_parity, opt_csize, opt_flow, opt_stop)
{
m_szSerialPort = devname;
m_iBaudRate = baud_rate;
m_iOptParity = opt_parity;
m_iOptCsize = opt_csize;
m_iOptFlow = opt_flow;
m_iOptStop = opt_stop;
Init();
}
Teleinfo::Teleinfo(const int ID, const std::string& devname, unsigned int baud_rate)
{
m_szSerialPort = devname;
m_iBaudRate = baud_rate;
m_iOptParity = boost::asio::serial_port_base::parity(TELEINFO_PARITY);
m_iOptCsize = boost::asio::serial_port_base::character_size(TELEINFO_CARACTER_SIZE);
m_iOptFlow = boost::asio::serial_port_base::flow_control(TELEINFO_FLOW_CONTROL);
m_iOptStop = boost::asio::serial_port_base::stop_bits(TELEINFO_STOP_BITS);
Init();
}
Teleinfo::~Teleinfo(void)
{
StopHardware();
}
void Teleinfo::Init()
{
m_bufferpos = 0;
memset(&m_buffer, 0, sizeof(m_buffer));
memset(&m_p1power, 0, sizeof(m_p1power));
m_p1power.len = sizeof(P1Power) - 1;
m_p1power.type = pTypeP1Power;
m_p1power.subtype = sTypeP1Power;
m_counter = 0;
}
bool Teleinfo::StartHardware()
{
StartHeartbeatThread();
//Try to open the Serial Port
try
{
_log.Log(LOG_STATUS, "Teleinfo: Using serial port: %s", m_szSerialPort.c_str());
open(
m_szSerialPort,
m_iBaudRate,
m_iOptParity,
m_iOptCsize
);
}
catch (boost::exception & e)
{
_log.Log(LOG_ERROR, "Teleinfo: Error opening serial port!");
#ifdef _DEBUG
_log.Log(LOG_ERROR, "-----------------\n%s\n-----------------", boost::diagnostic_information(e).c_str());
#endif
return false;
}
catch (...)
{
_log.Log(LOG_ERROR, "Teleinfo: Error opening serial port!!!");
return false;
}
setReadCallback(boost::bind(&Teleinfo::readCallback, this, _1, _2));
m_bIsStarted = true;
sOnConnected(this);
return true;
}
bool Teleinfo::StopHardware()
{
if (isOpen())
{
try {
clearReadCallback();
close();
}
catch (...)
{
//Don't throw from a Stop command
}
}
StopHeartbeatThread();
m_bIsStarted = false;
return true;
}
void Teleinfo::readCallback(const char *data, size_t len)
{
boost::lock_guard<boost::mutex> l(readQueueMutex);
if (!m_bEnableReceive)
return; //receiving not enabled
ParseData((const unsigned char*)data, static_cast<int>(len));
}
void Teleinfo::MatchLine()
{
if ((strlen((const char*)&m_buffer)<1) || (m_buffer[0] == 0x0a))
return;
uint8_t i;
uint8_t found = 0;
Teleinfo::Match t;
char value[20] = "";
std::string vString;
//_log.Log(LOG_NORM,"Frame : #%s#", m_buffer);
for (i = 0; (i<sizeof(m_matchlist) / sizeof(Teleinfo::Match))&(!found); i++)
{
t = m_matchlist[i];
switch (t.matchtype)
{
case STD:
if (strncmp(t.key, (const char*)&m_buffer, strlen(t.key)) == 0) {
found = 1;
}
break;
} //switch
if (!found)
continue;
if (t.matchtype == STD)
{
//We get the width car after the space
unsigned char * pos = (unsigned char *)strchr((char*)m_buffer, ' ');
if (pos == NULL)
continue;
int position = int(pos - (unsigned char*)&m_buffer);
strncpy(value, (char*)&(m_buffer[position + 1]), t.width);
value[t.width] = 0;
}
unsigned long ulValue = (unsigned long)atoi(value);
switch (t.type)
{
case TELEINFO_TYPE_ADCO:
/*
//structure initialization
memset(&m_p1power,0,sizeof(m_p1power));
m_p1power.len=sizeof(P1Power)-1;
m_p1power.type=pTypeP1Power;
m_p1power.subtype=sTypeP1Power;
*/
break;
case TELEINFO_TYPE_OPTARIF:
break;
case TELEINFO_TYPE_ISOUSC:
break;
case TELEINFO_TYPE_BASE:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_HCHC:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_HCHP:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_EJPHPM:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_EJPHN:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_BBRHCJB:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_BBRHPJB:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_BBRHCJW:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_BBRHPJW:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_BBRHCJR:
if (ulValue != 0)
m_p1power.powerusage2 = ulValue;
break;
case TELEINFO_TYPE_BBRHPJR:
if (ulValue != 0)
m_p1power.powerusage1 = ulValue;
break;
case TELEINFO_TYPE_PTEC:
break;
case TELEINFO_TYPE_IINST:
//we convert A to W setting RFXMeter/Counter Dividers Energy to 1000 / voltage => 1000/230 = 4.35
m_p1power.usagecurrent = ulValue;
break;
case TELEINFO_TYPE_IMAX:
break;
case TELEINFO_TYPE_PAPP:
//we count to prevent add each block but only one every 10 seconds
m_p1power.usagecurrent += ulValue;
//m_counter++;
//if (m_counter >= NumberOfFrameToSendOne)
//{
//_log.Log(LOG_NORM,"Teleinfo frame complete");
//_log.Log(LOG_NORM,"powerusage1 = %lu", m_p1power.powerusage1);
//_log.Log(LOG_NORM,"powerusage2 = %lu", m_p1power.powerusage2);
//_log.Log(LOG_NORM,"usagecurrent = %lu", m_p1power.usagecurrent);
//m_p1power.usagecurrent /= m_counter;
//sDecodeRXMessage(this, (const unsigned char *)&m_p1power);
//m_counter = 0;
//m_p1power.usagecurrent = 0;
//}
break;
case TELEINFO_TYPE_MOTDETAT:
m_counter++;
if (m_counter >= NumberOfFrameToSendOne)
{
+ _log.Log(LOG_NORM,"Teleinfo frame complete");
+ _log.Log(LOG_NORM,"powerusage1 = %lu", m_p1power.powerusage1);
+ _log.Log(LOG_NORM,"powerusage2 = %lu", m_p1power.powerusage2);
+ _log.Log(LOG_NORM,"usagecurrent = %lu", m_p1power.usagecurrent);
m_p1power.usagecurrent /= m_counter;
sDecodeRXMessage(this, (const unsigned char *)&m_p1power);
m_counter = 0;
m_p1power.usagecurrent = 0;
}
break;
+ default:
+ _log.Log(LOG_ERROR, "Teleinfo: label '%s' not handled!", t.key);
}
return;
}
break;
}
return;
}
}
void Teleinfo::ParseData(const unsigned char *pData, int Len)
{
int ii = 0;
while (ii<Len)
{
const unsigned char c = pData[ii];
if ((c == 0x0d) || (c == 0x00) || (c == 0x02) || (c == 0x03))
{
ii++;
continue;
}
m_buffer[m_bufferpos] = c;
if (c == 0x0a || m_bufferpos == sizeof(m_buffer) - 1)
{
// discard newline, close string, parse line and clear it.
if (m_bufferpos > 0)
m_buffer[m_bufferpos] = 0;
//We check the line only if the checksum is ok
if (isCheckSumOk())
MatchLine();
m_bufferpos = 0;
}
else
{
m_bufferpos++;
}
ii++;
}
}
/* Explanation of the checksum computation issued from the official EDF specification
a "checksum" is calculated on the set of characters from the beginning of the label field to the end of the field given character SP included.
We first make ??the sum of all ASCII codes of all characters.
to avoid introduce ASCII (00 to 1F hex) functions, it retains only the six least significant bits of
result (this translates into a logical AND between the amount previously calculated and 03Fh).
Finally, we added 20 hexadecimal. The result will always be a printable ASCII character (sign, digit,
capital letter) of from 0x20 to hexadecimal 0x5F
La "checksum" est calculÈe sur l'ensemble des caractËres allant du dÈbut du champ Ètiquette ‡ la fin du champ
donnÈe, caractËre SP inclus. On fait tout d'abord la somme des codes ASCII de tous ces caractËres. Pour Èviter
d'introduire des fonctions ASCII (00 ‡ 1F en hexadÈcimal), on ne conserve que les six bits de poids faible du
rÈsultat obtenu (cette opÈration se traduit par un ET logique entre la somme prÈcÈdemment calculÈe et 03Fh).
Enfin, on ajoute 20 en hexadÈcimal. Le rÈsultat sera donc toujours un caractËre ASCII imprimable (signe, chiffre,
lettre majuscule) allant de 20 ‡ 5F en hexadÈcimal.
*/
bool Teleinfo::isCheckSumOk()
{
unsigned int checksum = 0x00;
int i;
for (i = 0; i < int(strlen((char*)m_buffer)) - 2; i++)
{
checksum += m_buffer[i];
}
checksum = (checksum & 0x3F) + 0x20;
return (checksum == m_buffer[strlen((char*)m_buffer) - 1]);
}
void Teleinfo::WriteToHardware(const char *pdata, const unsigned char length)
{
}
Code : Tout sélectionner
/*
Domoticz Software : http://domoticz.com/
File : Teleinfo.h
Author : Nicolas HILAIRE
Version : 1.2
Description : This class manage the Teleinfo Signal
History :
- 2013-11-01 : Creation
- 2014-10-29 : Add 'EJP' contract (Laurent MEY)
- 2014-12-13 : Add 'Tempo' contract (Kevin NICOLAS)
*/
#pragma once
#include "DomoticzHardware.h"
#include "P1MeterBase.h"
#include "ASyncSerial.h"
/*
typedef struct _teleinfoData {
unsigned char len;
unsigned char type;
unsigned char subtype;
char optTariff[4];
unsigned long powerusage1; // normal tariff at power Usage in Wh
unsigned long powerusage2; // low tariff at power Usage in Wh
unsigned long currentPowerSubscribe; //in A
char currentTariffPeriod[4];
unsigned long instantCurrentPowerUsage; //in A
unsigned long maximalCurrentPowerUsage; //in A
unsigned long apparentPower; //in VA
} TeleinfoData;
*/
#define TELEINFO_BAUD_RATE 1200
#define TELEINFO_PARITY boost::asio::serial_port_base::parity::even
#define TELEINFO_CARACTER_SIZE 7
#define TELEINFO_FLOW_CONTROL boost::asio::serial_port_base::flow_control::none
#define TELEINFO_STOP_BITS boost::asio::serial_port_base::stop_bits::one
class Teleinfo : public CDomoticzHardwareBase, AsyncSerial
{
typedef enum {
ID = 0,
STD,
} MatchType;
//typedef enum {
// TELEINFO_OPTION_BASE, //single tariff
// TELEINFO_OPTION_HC, //double tariff (low and normal)
// TELEINFO_OPTION_EJP, //EJP Option, (test)
// TELEINFO_OPTION_TEMPO, //Tempo option, (test)
//} Option;
typedef enum {
TELEINFO_TYPE_ADCO,
TELEINFO_TYPE_OPTARIF,
TELEINFO_TYPE_ISOUSC,
TELEINFO_TYPE_BASE,
TELEINFO_TYPE_HCHC,
TELEINFO_TYPE_HCHP,
TELEINFO_TYPE_EJPHN,
TELEINFO_TYPE_EJPHPM,
TELEINFO_TYPE_BBRHCJB,
TELEINFO_TYPE_BBRHPJB,
TELEINFO_TYPE_BBRHCJW,
TELEINFO_TYPE_BBRHPJW,
TELEINFO_TYPE_BBRHCJR,
TELEINFO_TYPE_BBRHPJR,
TELEINFO_TYPE_PTEC,
TELEINFO_TYPE_IINST,
TELEINFO_TYPE_IMAX,
TELEINFO_TYPE_PAPP,
TELEINFO_TYPE_MOTDETAT,
} Type;
typedef struct _tMatch {
MatchType matchtype;
Type type;
const char* key;
int width;
} Match;
public:
Teleinfo(const int ID, const std::string& devname, unsigned int baud_rate = TELEINFO_BAUD_RATE);
/**
* Opens a serial device.
* \param devname serial device name, example "/dev/ttyAMA0" or "COM1"
* \param baud_rate serial baud rate, default 1200
* \param opt_parity serial parity, default even
* \param opt_csize serial character size, default 7bit
* \param opt_flow serial flow control, default none
* \param opt_stop serial stop bits, default 1
* \throws boost::system::system_error if cannot open the
* serial device
*/
Teleinfo(const std::string& devname, unsigned int baud_rate = TELEINFO_BAUD_RATE,
boost::asio::serial_port_base::parity opt_parity = boost::asio::serial_port_base::parity(TELEINFO_PARITY),
boost::asio::serial_port_base::character_size opt_csize = boost::asio::serial_port_base::character_size(TELEINFO_CARACTER_SIZE),
boost::asio::serial_port_base::flow_control opt_flow = boost::asio::serial_port_base::flow_control(TELEINFO_FLOW_CONTROL),
boost::asio::serial_port_base::stop_bits opt_stop = boost::asio::serial_port_base::stop_bits(TELEINFO_STOP_BITS));
~Teleinfo();
std::string m_szSerialPort;
P1Power m_p1power;
void WriteToHardware(const char *pdata, const unsigned char length);
private:
bool StartHardware();
bool StopHardware();
/**
* Read callback, stores data in the buffer
*/
void readCallback(const char *data, size_t len);
unsigned int m_iBaudRate;
boost::asio::serial_port_base::parity m_iOptParity;
boost::asio::serial_port_base::character_size m_iOptCsize;
boost::asio::serial_port_base::flow_control m_iOptFlow;
boost::asio::serial_port_base::stop_bits m_iOptStop;
int m_counter;
static const int readBufferSize = 1028;
static const int NumberOfFrameToSendOne = 8;
void Init();
void MatchLine();
void ParseData(const unsigned char *pData, int Len);
bool isCheckSumOk();
unsigned char m_buffer[readBufferSize];
int m_bufferpos;
static Teleinfo::Match m_matchlist[19];
};
Code : Tout sélectionner
0xd 0x3 0x2 0xaCode : Tout sélectionner
0xd 0xa