2
2
Domoticz Software : http://domoticz.com/
3
3
File : TeleinfoBase.cpp
4
4
Author : Blaise Thauvin
5
- Version : 1.1
5
+ Version : 1.2
6
6
Description : This class is used by various Teleinfo hardware decoders to process and display data
7
7
It is currently used by EcoDevices, TeleinfoSerial
8
8
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
10
10
11
11
History :
12
12
0.1 2017-03-03 : Creation
13
13
1.0 2017-03-15 : Release candidate
14
14
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
15
16
*/
16
17
17
18
#include " stdafx.h"
@@ -20,6 +21,10 @@ History :
20
21
#include " ../main/localtime_r.h"
21
22
22
23
24
+ #ifdef _DEBUG
25
+ #define DEBUG_TeleinfoBase
26
+ #endif
27
+
23
28
CTeleinfoBase::CTeleinfoBase ()
24
29
{
25
30
m_p1power.ID = 1 ;
@@ -35,30 +40,40 @@ void CTeleinfoBase::ProcessTeleinfo(Teleinfo &teleinfo)
35
40
}
36
41
37
42
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 )
40
45
{
41
46
int level;
42
- double flevel;
47
+ float flevel;
43
48
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
+ }
53
67
return level;
54
68
}
55
69
56
70
57
71
void CTeleinfoBase::ProcessTeleinfo (const std::string &name, int rank, Teleinfo &teleinfo)
58
72
{
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 ];
62
77
std::string message;
63
78
time_t atime = mytime (NULL );
64
79
@@ -68,12 +83,13 @@ void CTeleinfoBase::ProcessTeleinfo(const std::string &name, int rank, Teleinfo
68
83
_log.Log (LOG_ERROR," TeleinfoBase: Invalid rank passed to function (%i), must be between 1 and 4" , rank);
69
84
return ;
70
85
}
71
- rank = rank -1 ; // Now it is 0 to 3
86
+ rank = rank -1 ; // Now it is 0 to 3
72
87
73
88
// 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 ;
77
93
78
94
// PAPP only exist on some meter versions. If not present, we can approximate it as (current x 230V)
79
95
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
119
135
rate_alert = 3 ;
120
136
}
121
137
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
-
126
138
// 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 ))
128
140
{
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 ;
130
146
teleinfo.last = atime;
131
147
m_p1power.usagecurrent = teleinfo.PAPP ;
132
148
if (teleinfo.OPTARIF == " BASE" )
133
149
{
134
150
teleinfo.tariff =" Tarif de Base" ;
135
151
m_p1power.powerusage1 = teleinfo.BASE ;
136
152
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 ");
139
155
}
140
156
else if (teleinfo.OPTARIF == " HC.." )
141
157
{
142
158
teleinfo.tariff =" Tarif option Heures Creuses" ;
143
159
SendKwhMeter (m_HwdID, 32 *rank + 3 , 255 , m_pappHC, teleinfo.HCHC /1000.0 , name + " kWh Heures Creuses" );
144
160
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 ;
147
163
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");
149
165
}
150
166
else if (teleinfo.OPTARIF == " EJP." )
151
167
{
152
168
teleinfo.tariff =" Tarif option EJP" ;
153
169
SendKwhMeter (m_HwdID, 32 *rank + 6 , 255 , m_pappHC, teleinfo.EJPHN /1000.0 , name + " kWh Heures Normales" );
154
170
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 ;
157
173
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
+ }
160
181
}
161
182
else if (teleinfo.OPTARIF .substr (0 ,3 ) == " BBR" )
162
183
{
@@ -207,71 +228,100 @@ void CTeleinfoBase::ProcessTeleinfo(const std::string &name, int rank, Teleinfo
207
228
// SendKwhMeter(m_HwdID, 32*rank + 15, 255, m_pappHPJR, teleinfo.BBRHCJR/1000.0, name + " Jour Rouge, Plein");
208
229
SendKwhMeter (m_HwdID, 32 *rank + 16 , 255 , teleinfo.PAPP , (teleinfo.BBRHCJB + teleinfo.BBRHPJB + teleinfo.BBRHCJW
209
230
+ 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 ;
212
233
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 ;
215
236
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 ;
218
239
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
+ }
223
248
if (teleinfo.DEMAIN == " BLEU" )
224
- demain = 1 ;
249
+ demain_alert = 1 ;
225
250
else if (teleinfo.DEMAIN == " BLANC" )
226
- demain = 2 ;
251
+ demain_alert = 2 ;
227
252
else if (teleinfo.DEMAIN == " ROUG" )
228
253
{
229
- demain = 3 ;
254
+ demain_alert = 3 ;
230
255
teleinfo.DEMAIN = " ROUGE" ;
231
256
}
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
+ }
234
263
}
235
264
// 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
+ }
237
270
if (teleinfo.triphase == false )
238
271
{
239
272
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" );
246
280
}
247
281
else
248
282
{
249
283
SendCurrentSensor (m_HwdID + rank, 255 , (float )teleinfo.IINST1 , (float )teleinfo.IINST2 , (float )teleinfo.IINST3 ,
250
284
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 ),
268
319
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 ),
271
321
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 ),
274
323
name + " charge phase 3" );
324
+ }
275
325
}
276
326
}
277
327
}
0 commit comments