/
EnergyManager.class.php
603 lines (546 loc) · 17.9 KB
/
EnergyManager.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
<?
/**
* EnergyManager class
*
* This class manages all power meters (their counters, current consumption, power costs, etc.).
*
* TODO: power failure methods, keep switch on, reporting, etc.
*
* @link https://github.com/florianprobst/ips-energymanager project website
*
* @author Florian Probst <florian.probst@gmx.de>
*
* @license GNU
* GNU General Public License, version 3
*/
require_once 'PowerMeters/IPowerMeter.interface.php';
require_once 'PowerMeters/HomeMaticPowerMeterHM_ES_PMSw1_Pl.class.php';
require_once 'ips-library/IPSVariable.class.php';
require_once 'ips-library/IPSVariableProfile.class.php';
require_once 'ips-library/IPSScript.class.php';
require_once 'ips-library/IPSTimerEvent.class.php';
require_once 'Devices/IDevice.interface.php';
require_once 'Devices/Device.class.php';
/**
* class EnergyManager
*
* @uses IPowerMeter as power meter interface
*/
class EnergyManager{
/**
* config script id for EnergyManager
*
* @var integer
* @access private
*/
private $configId;
/**
* webfront id
*
* @var integer
* @access private
*/
private $webfrontId;
/**
* array of managed power meter devices and their variables
*
* @var IPowerMeter
* @access private
*/
private $powermeters = array();
/**
* array of managed devices
*
* @var IDevice
* @access private
*/
private $devices = array();
/**
* parent object id for all variables created by this script
*
* @var integer
* @access private
*/
private $parentId;
/**
* variable name prefix to identify variables and variable profiles created by this script
*
* @var string
* @access private
*/
private $prefix;
/**
* debug: enables / disables debug information
*
* @var boolean
* @access private
*/
private $debug;
/**
* array of all energymanager variable profiles
*
* @var IPSVariableProfile
* @access private
*/
private $variableProfiles = array();
/**
* array of all scripts created by EnergyManager
*
* @var scripts
* @access private
*/
private $scripts = array();
/**
* array of all events created by EnergyManager
*
* @var events
* @access private
*/
private $events = array();
/**
* instance id of the archive control (usually located in IPS\core)
*
* @var integer
* @access private
*/
private $archiveId;
/**
* interval of status update checks
*
* @var IPSVariable
* @access private
*/
private $update_interval;
/**
* pricing of 1 kWh
*
* @var float
* @access private
*/
private $price_per_kwh;
/**
* statistics variable: contains html to present the statistics and data from all power meters
* handled by this class
*
* @var IPSVariable
* @access private
*/
private $statistics;
/**
* IPS - datatype boolean
* @const tBOOL
* @access private
*/
const tBOOL = 0;
/**
* IPS - datatype integer
* @const tINT
* @access private
*/
const tINT = 1;
/**
* IPS - datatype float
* @const tFLOAT
* @access private
*/
const tFLOAT = 2;
/**
* IPS - datatype string
* @const tSTRING
* @access private
*/
const tSTRING = 3;
//Farbcodes, von "schlecht" nach "gut"
const hColor1 = 0xFF0000; //rot (schlecht)
const hColor2 = 0xFF9D00; //orange
const hColor3 = 0xFFF700; //gelb
const hColor4 = 0x9DFF00; //hellgrün
const hColor5 = 0x46F700; //grün
const hColor6 = 0x46F700; //grün
/**
* Constructor
*
* @param integer $parentId set the parent object for all items this script creates
* @param integer $archiveId instance id of the archive control (usually located in IPS\core)
* @param integer $update_interval interval of status updates in seconds
* @param string $prefix the variable name prefix to identify variables and variable profiles created by this script
* @param boolean $debug enables / disables debug information
* @access public
*/
public function __construct($configId, $webfrontId, $parentId, $archiveId, $price_per_kwh, $update_interval, $prefix = "EM_", $debug = false){
$this->configId = $configId;
$this->webfrontId = $webfrontId;
$this->parentId = $parentId;
$this->archiveId = $archiveId;
$this->update_interval = $update_interval;
$this->price_per_kwh = $price_per_kwh;
$this->debug = $debug;
$this->prefix = $prefix;
//create variable profiles
array_push($this->variableProfiles, new IPSVariableProfile($this->prefix . "Watthours", self::tFLOAT, "", " Wh", NULL, $this->debug));
array_push($this->variableProfiles, new IPSVariableProfile("~HTMLBox", self::tFLOAT, "", "", NULL, $this->debug));
$assoc[0] = ["val"=>0, "name"=>"n.A.", "icon" => "", "color" => self::hColor2];
$assoc[1] = ["val"=>1, "name"=>"An", "icon" => "", "color" => self::hColor5];
$assoc[2] = ["val"=>2, "name"=>"Standby", "icon" => "", "color" => self::hColor3];
$assoc[3] = ["val"=>3, "name"=>"Aus", "icon" => "", "color" => self::hColor1];
array_push($this->variableProfiles, new IPSVariableProfile($this->prefix . "Device_State", self::tINT, "", "", $assoc, $this->debug));
unset($assoc);
$this->statistics = new IPSVariable($this->prefix . "Statistics", self::tSTRING, $this->parentId, $this->variableProfiles[1], false, NULL, 0, $this->debug);
//create scripts
//script contents
$script_includes = '<?require_once(IPS_GetScript('. $this->configId . ')["ScriptFile"]);';
$script_update_status = $script_includes . '$energymanager->update();?>';
$script_check_devices = $script_includes . '$energymanager->checkdevices();?>';
array_push($this->scripts, new IPSScript($this->parentId, $this->prefix . "update_status", $script_update_status, $this->debug));
array_push($this->scripts, new IPSScript($this->parentId, $this->prefix . "check_devices", $script_check_devices, $this->debug));
//create events
array_push($this->events, new IPSTimerEvent($this->getScriptByName("update_status")->getInstanceId(), $this->prefix ."check_update_status", $this->update_interval, $this->debug));
array_push($this->events, new IPSTimerEvent($this->getScriptByName("check_devices")->getInstanceId(), $this->prefix ."check_devices_status", 30, $this->debug));
}
/**
* getScriptByName
*
* @return LightControlScript if found else false
* @access private
*/
private function getScriptByName($name){
foreach($this->scripts as &$s){
if($s->getName() == $this->prefix . $name){
return $s;
}
}
return false;
}
/**
* registerPowerMeter
*
* @return boolean true if register was successful
* @access public
*/
public function registerPowerMeter($powermeter){
if(!($powermeter instanceof IPowerMeter))
throw new Exception("Parameter \$powermeter is not of type IPowerMeter");
//add new power meter to list, create variables and reference them to power meter
$tmp = array(
"device" => $powermeter,
"current_consumption" => new IPSVariable($powermeter->getCurrentConsumptionInstanceId(), $this->variableProfiles[0], true, $this->archiveId, 0, $this->debug),
"energy_counter" =>new IPSVariable($this->prefix . "Energy_Counter_" . $powermeter->getInstanceId(), self::tFLOAT, $this->parentId, $this->variableProfiles[0], false, $this->archiveId, 0, $this->debug),
"energy_counter_last_read" => new IPSVariable($this->prefix . "Energy_Counter_last_read_" . $powermeter->getInstanceId(), self::tFLOAT, $this->parentId, $this->variableProfiles[0], false, NULL, 0, $this->debug)
);
array_push($this->powermeters, $tmp);
return true;
}
/**
* registerDevice
*
* @return boolean true if register was successful
* @access public
*/
public function registerDevice($name, $powermeterId, $standbylevel, $poweronlevel, $manufacturer, $model){
$powermeter = $this->getPowerMeterById($powermeterId);
$tmp = array(
"device" => new Device($name, $powermeter, $standbylevel, $poweronlevel, $manufacturer, $model),
"state" => new IPSVariable($this->prefix . "State_" . $name . "_" . $powermeterId, self::tINT, $this->parentId, $this->variableProfiles[2], false, NULL, 0, $this->debug),
"pstate" => new IPSVariable($this->prefix . "PState_" . $name . "_" . $powermeterId, self::tINT, $this->parentId, null, false, NULL, 0, $this->debug)
);
//add new device to list
array_push($this->devices, $tmp);
unset($tmp);
return true;
}
/**
* checkdevices
*
*
*/
public function checkdevices(){
foreach($this->devices as $d){
$state = $d["device"]->getState();
$oldstate = $d["state"]->getValue();
$pstate = $d["pstate"]->getValue();
//if pstate <= 0 switch to off, if pstate >= 3 switch to on
$poff = 0;
$pon = 3;
if($state == Device::DEVICE_ON){
$pstate++;
$d["pstate"]->setValue($pstate);
if($pstate > $pon){
$pstate = $pon;
$d["pstate"]->setValue($pstate);
if($oldstate != Device::DEVICE_ON){
$d["state"]->setValue(Device::DEVICE_ON);
WFC_PushNotification(16219 /* WebFront */, 'EnergyManager', $d["device"]->getName() . " läuft jetzt", 'buzzer', 0);
}
}
}else if($state == Device::DEVICE_OFF){
$pstate--;
$d["pstate"]->setValue($pstate);
if($pstate < $poff){
$pstate = $poff;
$d["pstate"]->setValue($pstate);
if($oldstate != Device::DEVICE_OFF){
$d["state"]->setValue(Device::DEVICE_OFF);
WFC_PushNotification(16219 /* WebFront */, 'EnergyManager', $d["device"]->getName() . " ist nun ausgeschaltet", 'buzzer', 0);
}
}
}
/*
$d["state"]->setValue($dstate);
if($oldstate != $state){
$msg = $d["device"]->getName();
if($state == Device::DEVICE_ON)
$msg .= " läuft jetzt";
if($state == Device::DEVICE_STANDBY)
$msg .= " ist fertig";
if($state == Device::DEVICE_OFF)
$msg .= " ist nun ausgeschaltet";
WFC_PushNotification(16219, 'EnergyManager', $msg, 'buzzer', 0);
*/
/*
alarm
bell
boom
buzzer
connected
dark
digital
drums
duck
full
happy
horn
inception
kazoo
roll
siren
space
trickling
turn
*/
//}
}
}
/**
* returns all power meters registered with this class
*
* @return array containing all power meters
* @access public
*/
public function getPowerMeters(){
return $this->powermeters;
}
/**
* get PowerMeter by id
*
* @return IPowerMeter powermeter device
* @access private
*/
private function getPowerMeterById($instanceId){
foreach ($this->powermeters as &$p) {
if($p["device"]->getInstanceId() == $instanceId){
return $p["device"];
}
}
}
/**
* average power consumption per month in watt hours (only available datasets, if data covers only 6 days, only 6 days will be used)
* on a 30 day base
*
* @param IPSVariable $variable logging enabled power consumption variable of the powermeter to check
* @param integer $limit max count of data sets (0 = no limit, but there is a hard-coded 10000 records limit which cant be exceeded)
* @throws Exception if logging is not enabled for this variable
* @throws Exception if param $variable is not of type IPSVariable
* @return float average power consumption per month in watt hours
* @access public
*/
public function getAverageWattsByLastMonth($variable, $limit = 0){
if(!($variable instanceof IPSVariable))
throw new Exception("Parameter \$variable is not of type IPSVariable");
if($variable->isLoggingEnabled() == false)
throw new Exception("Logging is not enabled for this variable '".$variable->getName()."'");
$startTimestamp = time()-24*60*60*30;
$endTimestamp = time();
$values = AC_GetAggregatedValues($variable->getArchiveId(), $variable->getId(), 3, $startTimestamp, $endTimestamp, $limit);
return round($values[0]["Avg"],2);
}
/**
* average power consumption per year in watt hours (only available datasets, if data covers only 6 month, only 6 month will be used)
* on a 365 day base
*
* @param IPSVariable $variable logging enabled power consumption variable of the powermeter to check
* @param integer $limit max count of data sets (0 = no limit, but there is a hard-coded 10000 records limit which cant be exceeded)
* @throws Exception if logging is not enabled for this variable
* @throws Exception if param $variable is not of type IPSVariable
* @return float average power consumption per month in watt hours
* @access public
*/
public function getAverageWattsByLastYear($variable, $limit = 0){
if(!($variable instanceof IPSVariable))
throw new Exception("Parameter \$variable is not of type IPSVariable");
if($variable->isLoggingEnabled() == false)
throw new Exception("Logging is not enabled for this variable '".$variable->getName()."'");
$startTimestamp = time()-24*60*60*365;
$endTimestamp = time();
$values = AC_GetAggregatedValues($variable->getArchiveId(), $variable->getId(), 4, $startTimestamp, $endTimestamp, $limit);
return round($values[0]["Avg"],2);
}
/**
* calculates the power costs per day
*
* @param float $watts average power consumption
* @return float power costs per day
* @access public
*/
public function getCostsPerDay($watts){
return round(($watts / 1000) * $this->price_per_kwh * 24, 2);
}
/**
* calculates the power costs per month
*
* @param float $watts average power consumption
* @return float power costs per month
* @access public
*/
public function getCostsPerMonth($watts){
return round(($watts / 1000) * $this->price_per_kwh * 24 * 30, 2);
}
/**
* calculates the power costs per year
*
* @param float $watts average power consumption
* @return float power costs per year
* @access public
*/
public function getCostsPerYear($watts){
return round(($watts / 1000) * $this->price_per_kwh * 24 * 365, 2);
}
/**
* collects all power meters counters and stores them in the energy manager variables
* since some products do erase the counter value to 0 as soon as they lose power
* we need to store the value in separate ips variables.
*
* @access public
*/
public function update(){
foreach($this->powermeters as &$p){
//current counter value from power meter (warning: depending on manufacturer / model this value
//can be resetted to 0 when the device was disconnected.
$current = $p["device"]->getEnergyCounterWattHours();
//last read value stored to ips
$last = $p["energy_counter_last_read"]->getValue();
//the energy counter value we want to have
$counter = $p["energy_counter"]->getValue();
if($current < $last){
//counter was reset (maybe power failure)
$last = 0;
}
//calculate incremental value between last counter read and current counter read
$increment = $current - $last;
//add increment to the counter
$counter += $increment;
//save last read value to ips variable
$p["energy_counter_last_read"]->setValue($current);
//save counter value to ips variable
$counter = $p["energy_counter"]->setValue($counter);
}
//now we have to create the statistics
$this->statistics->setValue($this->createHTML());
}
/**
* creates an html string containing the statistics table for all power meters
*
* @access private
*/
private function createHTML(){
$doc = new DOMDocument();
$html = "<html><head></head>";
$html .= "<style>";
$html .= "#em_table, #em_table tr, #em_table td { border: 1px solid black; border-collapse: collapse; }";
$html .= "#em_thead { font-size: 14px; font-weight: normal }";
$html .= "#em_tbody { font-size: 12px }";
$html .= "#em_p { font-size: 10px }";
$html .= "</style>";
$html .= "<body>";
$html .= "<table id='em_table' width='100%'>";
$html .= "<thead id='em_thead'><tr>";
$html .= "<td width='25%' rowspan='3'>";
$html .= "Gerät";
$html .= "</td>";
$html .= "<td width='10%' rowspan='3'>";
$html .= "Aktueller Verbrauch in Watt";
$html .= "</td>";
$html .= "<td width='10%' rowspan='3'>";
$html .= "Zählerstand in Kilowatt";
$html .= "</td>";
$html .= "<td width='55%' colspan='4'>";
$html .= "Durchschnittsverbauch und Kosten je Monat";
$html .= "</td>";
$html .= "</tr>";
$html .= "<tr>";
$html .= "<td colspan='2'>";
$html .= "der letzten 30 Tage";
$html .= "</td>";
$html .= "<td colspan='2'>";
$html .= "der letzten 365 Tage";
$html .= "</td>";
$html .= "</tr>";
$html .= "<tr>";
$html .= "<td>";
$html .= "Watt";
$html .= "</td>";
$html .= "<td>";
$html .= "Kosten";
$html .= "</td>";
$html .= "<td>";
$html .= "Watt";
$html .= "</td>";
$html .= "<td>";
$html .= "Kosten";
$html .= "</td>";
$html .= "</tr></thead><tbody id='em_tbody'>";
//start daten
$total_costs_last_year = 0;
foreach($this->powermeters as &$p){
$name = $p["device"]->getName();
$current_watts = $p["device"]->getCurrentWatts();
$counter = round($p["energy_counter"]->getValue() / 1000,2);
$avgwatts_lastmonth = $this->getAverageWattsByLastMonth($p["current_consumption"]);
$avgwatts_lastyear = $this->getAverageWattsByLastYear($p["current_consumption"]);
$costs1 = $this->getCostsPerMonth($avgwatts_lastmonth);
$costs2 = $this->getCostsPerMonth($avgwatts_lastyear);
$total_costs_last_year += $costs2;
$html .= "<tr>";
$html .= "<td>";
$html .= $name;
$html .= "</td>";
$html .= "<td>";
$html .= $current_watts;
$html .= "</td>";
$html .= "<td>";
$html .= $counter;
$html .= "</td>";
$html .= "<td>";
$html .= $avgwatts_lastmonth;
$html .= "</td>";
$html .= "<td>";
$html .= $costs1 . " €";
$html .= "</td>";
$html .= "<td>";
$html .= $avgwatts_lastyear;
$html .= "</td>";
$html .= "<td>";
$html .= $costs2 . " €";
$html .= "</td>";
$html .= "</tr>";
}
//end daten
$html .= "</tbody></table>";
$html .= "<p id='em_p'>Insgesamt belaufen sich die Kosten aller überwachten Geräte auf: <b>" . $total_costs_last_year * 12 . " € im Jahr</b> (Basis ist der Durschnittsverbrauch der letzten 365 Tage)</p>";
$html .= "</body>";
$html .= "</html>";
$doc->loadHTML($html);
$val = $doc->saveHTML();
return $val;
}
}
?>