Re,
Alors je suis parti du poste du grand fofo
http://www.domoticz.com/forum/viewtopic.php?f=6&t=6389 où le gars a l'air d'avoir réussi.
Le gars a posté ca :
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];
};
et en partant des fichiers d'origines dispo dans un fichier de création (compilation je croi) j'ai récupéré les deux fichiers téléinfo d'origine:
Le Teleinfo.cpp
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)
{
}
et le Teleinfo.h
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];
};
j'ai modifié selon ce que je comprennai des ecris du gars soit:
Pour le Teleinfo.cpp
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)
{
}
et pour le Teleinfo.h
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];
};
Voila mais du coup que ce soit sur le pi ou sur la version windob je ne sais pas quoi en faire...
Je peut pour ma part pas trop bidouillé il y a les panneaux solaire qui tourne sur le teleinfo mais le compteur edf ne teleinfo pas le meust serai de passer par un script mais bon.