Skip to content

Commit 9f44930

Browse files
committed
Lots of fixes and improvements thanks to forum feedback:
- Peak/OffPeak indexes swaped in P1 meters - Update rate greatly reduced to avoid clogging database - IMAX information now ignored - PPOT (triphasé only) now handled - Messages in alerts are now properly handled and will not cause crashes. Problem was with object lifetime being to short to be consumed by asynchronous thread - Texts are (I hope) more explicit - Wiki is updated and more....
1 parent 39bcdf8 commit 9f44930

File tree

8 files changed

+173
-136
lines changed

8 files changed

+173
-136
lines changed

hardware/DomoticzHardware.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ void CDomoticzHardwareBase::SendAlertSensor(const int NodeID, const int BatteryL
835835
gDevice.subtype = sTypeAlert;
836836
gDevice.id = (unsigned char)NodeID;
837837
gDevice.intval1 = alertLevel;
838-
gDevice.text = message;
838+
sprintf(gDevice.text, "%.199s", message.c_str());
839839
sDecodeRXMessage(this, (const unsigned char *)&gDevice, defaultname.c_str(), BatteryLevel);
840840
}
841841

hardware/EcoDevices.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,7 @@ void CEcoDevices::DecodeXML2Teleinfo(const std::string &sResult, Teleinfo &telei
151151
teleinfo.IINST1 = i_xpath_int(XMLdoc.RootElement(),"/response/IINST1/text()");
152152
teleinfo.IINST2 = i_xpath_int(XMLdoc.RootElement(),"/response/IINST2/text()");
153153
teleinfo.IINST3 = i_xpath_int(XMLdoc.RootElement(),"/response/IINST3/text()");
154-
teleinfo.IMAX = i_xpath_int(XMLdoc.RootElement(),"/response/IMAX/text()");
155-
teleinfo.IMAX1 =i_xpath_int(XMLdoc.RootElement(),"/response/IMAX1/text()");
156-
teleinfo.IMAX2 = i_xpath_int(XMLdoc.RootElement(),"/response/IMAX2/text()");
157-
teleinfo.IMAX3 = i_xpath_int(XMLdoc.RootElement(),"/response/IMAX3/text()");
154+
teleinfo.PPOT = i_xpath_int(XMLdoc.RootElement(),"/response/PPOT/text()");
158155
teleinfo.ADPS = i_xpath_int(XMLdoc.RootElement(),"/response/ADPS/text()");
159156

160157
#ifdef DEBUG_EcoDevices

hardware/TeleinfoBase.cpp

Lines changed: 129 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
Domoticz Software : http://domoticz.com/
33
File : TeleinfoBase.cpp
44
Author : Blaise Thauvin
5-
Version : 1.1
5+
Version : 1.2
66
Description : This class is used by various Teleinfo hardware decoders to process and display data
77
It is currently used by EcoDevices, TeleinfoSerial
88
Detailed information on the Teleinfo protocol can be found at (version 5, 16/03/2015)
9-
http://www.enedis.fr/sites/default/files/ERDF-NOI-CPT_02E.pdf
9+
http://www.enedis.fr/sites/default/files/Enedis-NOI-CPT_02E.pdf
1010
1111
History :
1212
0.1 2017-03-03 : Creation
1313
1.0 2017-03-15 : Release candidate
1414
1.1 2017-03-18 : Updated to benefit from new messages in Alert sensors rather than simple text sensors
15+
1.2 2017-03-21 : Various bug fix and reverting to using P1SmartMeter as users requested
1516
*/
1617

1718
#include "stdafx.h"
@@ -20,6 +21,10 @@ History :
2021
#include "../main/localtime_r.h"
2122

2223

24+
#ifdef _DEBUG
25+
#define DEBUG_TeleinfoBase
26+
#endif
27+
2328
CTeleinfoBase::CTeleinfoBase()
2429
{
2530
m_p1power.ID = 1;
@@ -35,30 +40,40 @@ void CTeleinfoBase::ProcessTeleinfo(Teleinfo &teleinfo)
3540
}
3641

3742

38-
// Alert level is 1 up to 100% usage, 2 then 3 above 100% load and 4 for maximum load (IMAX)
39-
int CTeleinfoBase::AlertLevel(int Iinst, int Imax, int Isousc)
43+
// Alert level is 1 up to 80% usage, 2 between 80% and 90%, 3 between 90% and 98%, 4 above
44+
int CTeleinfoBase::AlertLevel(int Iinst, int Isousc, char* text)
4045
{
4146
int level;
42-
double flevel;
47+
float flevel;
4348

44-
if ((Imax - Isousc) == 0)
45-
return 0;
46-
if ((Imax - Iinst ) <=0)
47-
level = 4;
48-
else
49-
flevel = (3.0 * Iinst + Imax- 4.0 * Isousc) / (Imax - Isousc);
50-
if (flevel > 4) flevel = 4;
51-
if (flevel < 1) flevel = 1;
52-
level = (int)round(flevel + 0.49);
49+
flevel = Iinst*100 / Isousc;
50+
level = 1;
51+
sprintf(text, " < 80%% de %iA souscrits", Isousc);
52+
if (flevel > 80)
53+
{
54+
level = 2;
55+
sprintf(text, ">80%% et <90%% de %iA souscrits", Isousc);
56+
}
57+
if (level > 90)
58+
{
59+
level = 3;
60+
sprintf(text, ">90%% et <98%% de %iA souscrits", Isousc);
61+
}
62+
if (level > 98)
63+
{
64+
level = 3;
65+
sprintf(text, ">98%% de %iA souscrits", Isousc);
66+
}
5367
return level;
5468
}
5569

5670

5771
void CTeleinfoBase::ProcessTeleinfo(const std::string &name, int rank, Teleinfo &teleinfo)
5872
{
59-
uint32_t m_pappHC, m_pappHP, m_pappHCJB, m_pappHPJB, m_pappHCJW, m_pappHPJW, m_pappHCJR, m_pappHPJR, checksum;
60-
int rate_alert = 0, color_alert = 0, demain = 0;
61-
std::stringstream ss;
73+
uint32_t m_pappHC, m_pappHP, m_pappHCJB, m_pappHPJB, m_pappHCJW, m_pappHPJW, m_pappHCJR, m_pappHPJR;
74+
int rate_alert = 0, color_alert = 0, demain_alert = 0;
75+
int alertI1, alertI2, alertI3, alertEJP, alertRate, alertPPOT;
76+
char szTmp[100];
6277
std::string message;
6378
time_t atime = mytime(NULL);
6479

@@ -68,12 +83,13 @@ void CTeleinfoBase::ProcessTeleinfo(const std::string &name, int rank, Teleinfo
6883
_log.Log(LOG_ERROR,"TeleinfoBase: Invalid rank passed to function (%i), must be between 1 and 4", rank);
6984
return;
7085
}
71-
rank = rank -1; // Now it is 0 to 3
86+
rank = rank -1; // Now it is 0 to 3
7287

7388
// Guess if we are running with one phase or three
74-
// (some devices like EcoDevices always send all variables regardless or the real setting)
75-
if ((teleinfo.triphase == true) || (teleinfo.IINST2 > 0) || (teleinfo.IINST3 > 0) || (teleinfo.IMAX2 > 0) || (teleinfo.IMAX3 > 0))
76-
teleinfo.triphase=true;
89+
// some devices like EcoDevices always send all variables so presence/absence of IINSTx is not significant
90+
// Also, EcoDevices sends always sends the same value for IINST and IINST1, so check must be done on IINST2 and IINST3
91+
if ((teleinfo.triphase == true) || (teleinfo.IINST2 > 0) || (teleinfo.IINST3 > 0))
92+
teleinfo.triphase = true;
7793

7894
// PAPP only exist on some meter versions. If not present, we can approximate it as (current x 230V)
7995
if ((teleinfo.PAPP == 0) && ((teleinfo.IINST > 0)||(teleinfo.IINST1 > 0)||(teleinfo.IINST2 > 0)||(teleinfo.IINST3 > 0)))
@@ -119,44 +135,49 @@ void CTeleinfoBase::ProcessTeleinfo(const std::string &name, int rank, Teleinfo
119135
rate_alert = 3;
120136
}
121137

122-
// Checksum to detect changes between measures
123-
checksum=teleinfo.BASE + teleinfo.HCHC + teleinfo.HCHP + teleinfo.EJPHN + teleinfo.EJPHPM + teleinfo.BBRHCJB + teleinfo.PEJP\
124-
+ teleinfo.BBRHPJB + teleinfo.BBRHCJW + teleinfo.BBRHPJB + teleinfo.BBRHCJR + teleinfo.BBRHPJR + teleinfo.PAPP;
125-
126138
//Send data if value changed, at most every minute and at least every 5 minutes
127-
if (((teleinfo.previous != checksum) && (difftime(atime, teleinfo.last) >= 60)) || (difftime(atime, teleinfo.last) >= 300))
139+
if (((teleinfo.pAlertPAPP != teleinfo.PAPP) && (difftime(atime, teleinfo.last) >= 60)) || (difftime(atime, teleinfo.last) >= 300))
128140
{
129-
teleinfo.previous = checksum;
141+
#ifdef DEBUG_TeleinfoBase
142+
_log.Log(LOG_STATUS,"Triphase=%s, I=%i, I1=%i, I2=%i, I3=%i", (teleinfo.triphase)?"True":"False",
143+
teleinfo.IINST, teleinfo.IINST1, teleinfo.IINST2, teleinfo.IINST3);
144+
#endif
145+
teleinfo.pAlertPAPP = teleinfo.PAPP;
130146
teleinfo.last = atime;
131147
m_p1power.usagecurrent = teleinfo.PAPP;
132148
if (teleinfo.OPTARIF == "BASE")
133149
{
134150
teleinfo.tariff="Tarif de Base";
135151
m_p1power.powerusage1 = teleinfo.BASE;
136152
m_p1power.powerusage2 = 0;
137-
sDecodeRXMessage(this, (const unsigned char *)&m_p1power, (name + " Total").c_str(), 255);
138-
SendKwhMeter(m_HwdID, 32*rank + 2, 255, teleinfo.PAPP, teleinfo.BASE/1000.0, name + " Index kWh");
153+
sDecodeRXMessage(this, (const unsigned char *)&m_p1power, (name + " kWh Total").c_str(), 255);
154+
// SendKwhMeter(m_HwdID, 32*rank + 2, 255, teleinfo.PAPP, teleinfo.BASE/1000.0, name + " kWh Total");
139155
}
140156
else if (teleinfo.OPTARIF == "HC..")
141157
{
142158
teleinfo.tariff="Tarif option Heures Creuses";
143159
SendKwhMeter(m_HwdID, 32*rank + 3, 255, m_pappHC, teleinfo.HCHC/1000.0, name + " kWh Heures Creuses");
144160
SendKwhMeter(m_HwdID, 32*rank + 4, 255, m_pappHP, teleinfo.HCHP/1000.0, name + " kWh Heures Pleines");
145-
m_p1power.powerusage1 = teleinfo.HCHC;
146-
m_p1power.powerusage2 = teleinfo.HCHP;
161+
m_p1power.powerusage1 = teleinfo.HCHP;
162+
m_p1power.powerusage2 = teleinfo.HCHC;
147163
sDecodeRXMessage(this, (const unsigned char *)&m_p1power, (name + " kWh Total").c_str(), 255);
148-
// SendKwhMeter(m_HwdID, 32*rank + 5, 255, teleinfo.PAPP, (teleinfo.HCHP + teleinfo.HCHC)/1000.0, name + " kWh Total");
164+
// SendKwhMeter(m_HwdID, 32*rank + 5, 255, teleinfo.PAPP, (teleinfo.HCHP + teleinfo.HCHC)/1000.0, name + " kWh Total");
149165
}
150166
else if (teleinfo.OPTARIF == "EJP.")
151167
{
152168
teleinfo.tariff="Tarif option EJP";
153169
SendKwhMeter(m_HwdID, 32*rank + 6, 255, m_pappHC, teleinfo.EJPHN/1000.0, name + " kWh Heures Normales");
154170
SendKwhMeter(m_HwdID, 32*rank + 7, 255, m_pappHP, teleinfo.EJPHPM/1000.0, name + " kWh Pointe Mobile");
155-
m_p1power.powerusage1 = teleinfo.EJPHN;
156-
m_p1power.powerusage2 = teleinfo.EJPHPM;
171+
m_p1power.powerusage1 = teleinfo.EJPHPM;
172+
m_p1power.powerusage2 = teleinfo.EJPHN;
157173
sDecodeRXMessage(this, (const unsigned char *)&m_p1power, (name + " kWh EJP").c_str(), 255);
158-
// SendKwhMeter(m_HwdID, 32*rank + 8, 255, teleinfo.PAPP, (teleinfo.EJPHN + teleinfo.EJPHPM)/1000.0, name + " Total");
159-
SendAlertSensor(32*rank + 2, 255, ((teleinfo.PEJP == 30) ? 4 : 1), teleinfo.rate, (name + " Preannonce Pointe Mobile"));
174+
// SendKwhMeter(m_HwdID, 32*rank + 8, 255, teleinfo.PAPP, (teleinfo.EJPHN + teleinfo.EJPHPM)/1000.0, name + "kWh Total");
175+
alertEJP = (teleinfo.PEJP == 30) ? 4 : 1;
176+
if (alertEJP != teleinfo.pAlertEJP)
177+
{
178+
SendAlertSensor(32*rank + 2, 255, alertEJP, teleinfo.rate, (name + " Preannonce Pointe Mobile"));
179+
teleinfo.pAlertEJP = alertEJP;
180+
}
160181
}
161182
else if (teleinfo.OPTARIF.substr(0,3) == "BBR")
162183
{
@@ -207,71 +228,100 @@ void CTeleinfoBase::ProcessTeleinfo(const std::string &name, int rank, Teleinfo
207228
//SendKwhMeter(m_HwdID, 32*rank + 15, 255, m_pappHPJR, teleinfo.BBRHCJR/1000.0, name + " Jour Rouge, Plein");
208229
SendKwhMeter(m_HwdID, 32*rank + 16, 255, teleinfo.PAPP, (teleinfo.BBRHCJB + teleinfo.BBRHPJB + teleinfo.BBRHCJW
209230
+ teleinfo.BBRHPJW + teleinfo.BBRHCJR + teleinfo.BBRHPJR)/1000.0, name + " kWh Total");
210-
m_p1power.powerusage1 = teleinfo.BBRHCJB;
211-
m_p1power.powerusage2 = teleinfo.BBRHPJB;
231+
m_p1power.powerusage1 = teleinfo.BBRHPJB;
232+
m_p1power.powerusage2 = teleinfo.BBRHCJB;
212233
m_p1power.usagecurrent = m_pappHCJB + m_pappHPJB;
213-
m_p2power.powerusage1 = teleinfo.BBRHCJW;
214-
m_p2power.powerusage2 = teleinfo.BBRHPJW;
234+
m_p2power.powerusage1 = teleinfo.BBRHPJW;
235+
m_p2power.powerusage2 = teleinfo.BBRHCJW;
215236
m_p2power.usagecurrent = m_pappHCJW + m_pappHPJW;
216-
m_p3power.powerusage1 = teleinfo.BBRHCJR;
217-
m_p3power.powerusage2 = teleinfo.BBRHPJR;
237+
m_p3power.powerusage1 = teleinfo.BBRHPJR;
238+
m_p3power.powerusage2 = teleinfo.BBRHCJR;
218239
m_p3power.usagecurrent = m_pappHCJR + m_pappHPJR;
219-
sDecodeRXMessage(this, (const unsigned char *)&m_p1power, (name + "Jours Bleus").c_str(), 255);
220-
sDecodeRXMessage(this, (const unsigned char *)&m_p2power, (name + "Jours Blancs").c_str(), 255);
221-
sDecodeRXMessage(this, (const unsigned char *)&m_p3power, (name + "Jours Rouges").c_str(), 255);
222-
SendAlertSensor(32*rank + 2, 255, color_alert, ("Jour " + teleinfo.color), (name + " Couleur du jour"));
240+
sDecodeRXMessage(this, (const unsigned char *)&m_p1power, (name + "kWh Jours Bleus").c_str(), 255);
241+
sDecodeRXMessage(this, (const unsigned char *)&m_p2power, (name + "kWh Jours Blancs").c_str(), 255);
242+
sDecodeRXMessage(this, (const unsigned char *)&m_p3power, (name + "kWh Jours Rouges").c_str(), 255);
243+
if (color_alert != teleinfo.pAlertColor)
244+
{
245+
SendAlertSensor(32*rank + 2, 255, color_alert, ("Jour " + teleinfo.color), (name + " Couleur du jour"));
246+
teleinfo.pAlertColor = color_alert;
247+
}
223248
if (teleinfo.DEMAIN == "BLEU")
224-
demain = 1;
249+
demain_alert = 1;
225250
else if (teleinfo.DEMAIN == "BLANC")
226-
demain = 2;
251+
demain_alert = 2;
227252
else if (teleinfo.DEMAIN == "ROUG")
228253
{
229-
demain = 3;
254+
demain_alert = 3;
230255
teleinfo.DEMAIN = "ROUGE";
231256
}
232-
else demain = 0;
233-
SendAlertSensor(32*rank + 3, 255, demain, ("Demain, jour " + teleinfo.DEMAIN) , (name + " Couleur demain"));
257+
else demain_alert = 0;
258+
if (demain_alert != teleinfo.pAlertDemain)
259+
{
260+
SendAlertSensor(32*rank + 3, 255, demain_alert, ("Demain, jour " + teleinfo.DEMAIN) , (name + " Couleur demain"));
261+
teleinfo.pAlertDemain = demain_alert;
262+
}
234263
}
235264
// Common sensors for all rates
236-
SendAlertSensor(32*rank + 1, 255, rate_alert, teleinfo.rate, (name + " Tarif en cours"));
265+
if (rate_alert != teleinfo.pAlertRate)
266+
{
267+
SendAlertSensor(32*rank + 1, 255, rate_alert, teleinfo.rate, name + " Tarif en cours");
268+
teleinfo.pAlertRate = rate_alert;
269+
}
237270
if (teleinfo.triphase == false)
238271
{
239272
SendCurrentSensor(m_HwdID + rank, 255, (float)teleinfo.IINST, 0, 0, name + " Courant");
240-
ss.clear();
241-
ss << teleinfo.IINST << "A, sur " << teleinfo.ISOUSC << "A souscrits";
242-
message = ss.str();
243-
SendAlertSensor(32*rank + 4, 255, AlertLevel(teleinfo.IINST, teleinfo.IMAX, teleinfo.ISOUSC),
244-
message, (name + " Alerte courant maximal"));
245-
SendPercentageSensor(32* rank + 1, 0, 255, (teleinfo.IINST*100)/float(teleinfo.IMAX), name + " Intensite souscrite");
273+
alertI1 = AlertLevel(teleinfo.IINST, teleinfo.ISOUSC, szTmp);
274+
if (alertI1 != teleinfo.pAlertI1)
275+
{
276+
SendAlertSensor(32*rank + 4, 255, alertI1, szTmp, name + " Alerte courant");
277+
teleinfo.pAlertI1 = alertI1;
278+
}
279+
SendPercentageSensor(32* rank + 1, 0, 255, (teleinfo.IINST*100)/float(teleinfo.ISOUSC), name + " Pourcentage de Charge");
246280
}
247281
else
248282
{
249283
SendCurrentSensor(m_HwdID + rank, 255, (float)teleinfo.IINST1, (float)teleinfo.IINST2, (float)teleinfo.IINST3,
250284
name + " Courant");
251-
ss.clear();
252-
ss << teleinfo.IINST1 << "A, sur " << teleinfo.ISOUSC << "A souscrits";
253-
message = ss.str();
254-
SendAlertSensor(32*rank + 4, 255, AlertLevel(teleinfo.IINST1, teleinfo.IMAX1, teleinfo.ISOUSC),
255-
message, (name + " Alerte courant phase 1"));
256-
ss.clear();
257-
ss << teleinfo.IINST2 << "A, sur " << teleinfo.ISOUSC << "A souscrits";
258-
message = ss.str();
259-
SendAlertSensor(32*rank + 5, 255, AlertLevel(teleinfo.IINST2, teleinfo.IMAX2, teleinfo.ISOUSC),
260-
message, (name + " Alerte courant phase 2"));
261-
ss.clear();
262-
ss << teleinfo.IINST3 << "A, sur " << teleinfo.ISOUSC << "A souscrits";
263-
message = ss.str();
264-
SendAlertSensor(32*rank + 6, 255, AlertLevel(teleinfo.IINST3, teleinfo.IMAX3, teleinfo.ISOUSC),
265-
message, (name + " Alerte courant phase 3"));
266-
if (teleinfo.IMAX1 > 0)
267-
SendPercentageSensor(32 * rank + 1, 0, 255, (teleinfo.IINST1*100)/float(teleinfo.IMAX1),
285+
alertI1 = AlertLevel(teleinfo.IINST1, teleinfo.ISOUSC, szTmp);
286+
if (alertI1 != teleinfo.pAlertI1)
287+
{
288+
SendAlertSensor(32*rank + 4, 255, alertI1, szTmp, name + " Alerte phase 1");
289+
teleinfo.pAlertI1 = alertI1;
290+
}
291+
alertI2 = AlertLevel(teleinfo.IINST2, teleinfo.ISOUSC, szTmp);
292+
if (alertI2 != teleinfo.pAlertI2)
293+
{
294+
SendAlertSensor(32*rank + 5, 255, alertI2, szTmp, name + " Alerte phase 2");
295+
teleinfo.pAlertI2 = alertI2;
296+
}
297+
alertI3 = AlertLevel(teleinfo.IINST3, teleinfo.ISOUSC, szTmp);
298+
if (alertI3 != teleinfo.pAlertI3)
299+
{
300+
SendAlertSensor(32*rank + 6, 255, alertI3, szTmp, name + " Alerte phase 3");
301+
teleinfo.pAlertI3 = alertI3;
302+
}
303+
if (teleinfo.PPOT != teleinfo.pAlertPPOT)
304+
{
305+
if (teleinfo.PPOT !=0)
306+
alertPPOT = 4;
307+
else
308+
alertPPOT = 1;
309+
teleinfo.pAlertPPOT = teleinfo.PPOT;
310+
teleinfo.PPOT>>=1;
311+
std::stringstream ss;
312+
ss << "Bitmap phases: " <<std::bitset<3>(~teleinfo.PPOT);
313+
message = ss.str();
314+
SendAlertSensor(32*rank+7, 255, alertPPOT, message, " Alerte Potentiels");
315+
}
316+
if (teleinfo.ISOUSC > 0)
317+
{
318+
SendPercentageSensor(32 * rank + 1, 0, 255, (teleinfo.IINST1*100)/float(teleinfo.ISOUSC),
268319
name + " Charge phase 1");
269-
if (teleinfo.IMAX2 > 0)
270-
SendPercentageSensor(32 * rank + 2, 0, 255, (teleinfo.IINST2*100)/float(teleinfo.IMAX2),
320+
SendPercentageSensor(32 * rank + 2, 0, 255, (teleinfo.IINST2*100)/float(teleinfo.ISOUSC),
271321
name + " Charge phase 2");
272-
if (teleinfo.IMAX3 > 0)
273-
SendPercentageSensor(32 * rank + 3, 0, 255, (teleinfo.IINST3*100)/float(teleinfo.IMAX3),
322+
SendPercentageSensor(32 * rank + 3, 0, 255, (teleinfo.IINST3*100)/float(teleinfo.ISOUSC),
274323
name + " charge phase 3");
324+
}
275325
}
276326
}
277327
}

0 commit comments

Comments
 (0)