node-red-contrib-energymeterplus 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/energyMeterPlus.html +36 -8
- package/energyMeterPlus.js +34 -42
- package/package.json +1 -1
package/energyMeterPlus.html
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
2
|
RED.nodes.registerType('energyMeterPlus', {
|
|
3
3
|
category: 'energy',
|
|
4
|
-
color: '#
|
|
4
|
+
color: '#d9910cdb', <!-- Orange -->
|
|
5
5
|
defaults: {
|
|
6
6
|
name: {value:""},
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
baselineDaily: {value:0},
|
|
8
|
+
baselineWeekly: {value:0},
|
|
9
|
+
baselineMonthly: {value:0},
|
|
10
|
+
baselineYearly: {value:0},
|
|
11
|
+
unitCost: {value:0.15},
|
|
12
|
+
filePath: {value:"/addon_configs/a0d7b954_nodered/node_red/solarGen_data.json"},
|
|
13
|
+
inputUnit: {value:"kW"}
|
|
9
14
|
},
|
|
10
15
|
inputs:1,
|
|
11
16
|
outputs:1,
|
|
12
|
-
icon: "
|
|
17
|
+
icon: "sun.png",
|
|
13
18
|
label: function() {
|
|
14
19
|
return this.name || "energyMeterPlus";
|
|
15
20
|
}
|
|
@@ -22,11 +27,34 @@
|
|
|
22
27
|
<input type="text" id="node-input-name">
|
|
23
28
|
</div>
|
|
24
29
|
<div class="form-row">
|
|
25
|
-
<label for="node-input-
|
|
26
|
-
<input type="number" id="node-input-
|
|
30
|
+
<label for="node-input-baselineDaily">Baseline Daily (kWh)</label>
|
|
31
|
+
<input type="number" id="node-input-baselineDaily">
|
|
27
32
|
</div>
|
|
28
33
|
<div class="form-row">
|
|
29
|
-
<label for="node-input-
|
|
30
|
-
<input type="number" id="node-input-
|
|
34
|
+
<label for="node-input-baselineWeekly">Baseline Weekly (kWh)</label>
|
|
35
|
+
<input type="number" id="node-input-baselineWeekly">
|
|
36
|
+
</div>
|
|
37
|
+
<div class="form-row">
|
|
38
|
+
<label for="node-input-baselineMonthly">Baseline Monthly (kWh)</label>
|
|
39
|
+
<input type="number" id="node-input-baselineMonthly">
|
|
40
|
+
</div>
|
|
41
|
+
<div class="form-row">
|
|
42
|
+
<label for="node-input-baselineYearly">Baseline Yearly (kWh)</label>
|
|
43
|
+
<input type="number" id="node-input-baselineYearly">
|
|
44
|
+
</div>
|
|
45
|
+
<div class="form-row">
|
|
46
|
+
<label for="node-input-unitCost">Cost per Unit</label>
|
|
47
|
+
<input type="number" id="node-input-unitCost" step="0.01">
|
|
48
|
+
</div>
|
|
49
|
+
<div class="form-row">
|
|
50
|
+
<label for="node-input-filePath">Filepath</label>
|
|
51
|
+
<input type="text" id="node-input-filePath">
|
|
52
|
+
</div>
|
|
53
|
+
<div class="form-row">
|
|
54
|
+
<label for="node-input-inputUnit">Input Unit</label>
|
|
55
|
+
<select id="node-input-inputUnit">
|
|
56
|
+
<option value="kW">kW</option>
|
|
57
|
+
<option value="W">W</option>
|
|
58
|
+
</select>
|
|
31
59
|
</div>
|
|
32
60
|
</script>
|
package/energyMeterPlus.js
CHANGED
|
@@ -7,73 +7,62 @@ module.exports = function(RED) {
|
|
|
7
7
|
|
|
8
8
|
let unitCost = Number(config.unitCost) || 0;
|
|
9
9
|
let filePath = config.filePath || "/addon_configs/a0d7b954_nodered/node_red/solarGen_data.json";
|
|
10
|
-
let
|
|
10
|
+
let inputUnit = config.inputUnit || "kW";
|
|
11
|
+
|
|
12
|
+
// Numeric baseline corrections
|
|
13
|
+
let baselineDaily = Number(config.baselineDaily) || 0;
|
|
14
|
+
let baselineWeekly = Number(config.baselineWeekly) || 0;
|
|
15
|
+
let baselineMonthly = Number(config.baselineMonthly) || 0;
|
|
16
|
+
let baselineYearly = Number(config.baselineYearly) || 0;
|
|
11
17
|
|
|
12
18
|
// Baseline counters
|
|
13
|
-
let baseline = { daily:
|
|
19
|
+
let baseline = { daily: baselineDaily, weekly: baselineWeekly, monthly: baselineMonthly, yearly: baselineYearly };
|
|
14
20
|
let lastCheck = new Date();
|
|
15
21
|
|
|
16
|
-
// Apply correction if provided
|
|
17
|
-
if (baselineCorrection) {
|
|
18
|
-
try {
|
|
19
|
-
let correction = JSON.parse(baselineCorrection);
|
|
20
|
-
baseline = { ...baseline, ...correction };
|
|
21
|
-
} catch (err) {
|
|
22
|
-
node.error("Invalid baseline correction JSON");
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
22
|
// Function to handle rollover
|
|
27
23
|
function checkRollover() {
|
|
28
24
|
let now = new Date();
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
if (now.
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Weekly rollover (Sunday = 0)
|
|
36
|
-
if (now.getDay() === 0 && lastCheck.getDay() !== 0) {
|
|
37
|
-
baseline.weekly = 0;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Monthly rollover
|
|
41
|
-
if (now.getMonth() !== lastCheck.getMonth()) {
|
|
42
|
-
baseline.monthly = 0;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Yearly rollover
|
|
26
|
+
if (now.getDate() !== lastCheck.getDate()) baseline.daily = baselineDaily;
|
|
27
|
+
if (now.getDay() === 0 && lastCheck.getDay() !== 0) baseline.weekly = baselineWeekly;
|
|
28
|
+
if (now.getMonth() !== lastCheck.getMonth()) baseline.monthly = baselineMonthly;
|
|
46
29
|
if (now.getFullYear() !== lastCheck.getFullYear()) {
|
|
47
|
-
// Archive previous year
|
|
48
30
|
let archiveName = filePath.replace(".json", `_${lastCheck.getFullYear()}.json`);
|
|
49
31
|
try {
|
|
50
32
|
fs.writeFileSync(archiveName, JSON.stringify(baseline, null, 2));
|
|
51
33
|
} catch (err) {
|
|
52
34
|
node.error("Failed to archive yearly file: " + err);
|
|
53
35
|
}
|
|
54
|
-
baseline.yearly =
|
|
36
|
+
baseline.yearly = baselineYearly;
|
|
55
37
|
}
|
|
56
38
|
|
|
57
39
|
lastCheck = now;
|
|
58
40
|
}
|
|
59
41
|
|
|
60
|
-
// Run rollover check every minute
|
|
61
42
|
setInterval(checkRollover, 60000);
|
|
62
43
|
|
|
63
44
|
node.on('input', function(msg) {
|
|
64
|
-
let
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
45
|
+
let factor = (inputUnit === "W") ? 0.001 : 1;
|
|
46
|
+
|
|
47
|
+
// Accept either raw number or JSON object
|
|
48
|
+
if (typeof msg.payload === "number") {
|
|
49
|
+
let power = msg.payload * factor;
|
|
50
|
+
baseline.daily += power;
|
|
51
|
+
baseline.weekly += power;
|
|
52
|
+
baseline.monthly += power;
|
|
53
|
+
baseline.yearly += power;
|
|
54
|
+
} else if (typeof msg.payload === "object") {
|
|
55
|
+
baseline.daily = (msg.payload.daily_kWh || baseline.daily) * factor;
|
|
56
|
+
baseline.weekly = (msg.payload.weekly_kWh || baseline.weekly) * factor;
|
|
57
|
+
baseline.monthly = (msg.payload.monthly_kWh || baseline.monthly) * factor;
|
|
58
|
+
baseline.yearly = (msg.payload.yearly_kWh || baseline.yearly) * factor;
|
|
59
|
+
}
|
|
71
60
|
|
|
72
61
|
// Calculate costs
|
|
73
|
-
let daily_cost = baseline.daily
|
|
74
|
-
let weekly_cost = baseline.weekly
|
|
62
|
+
let daily_cost = baseline.daily * unitCost;
|
|
63
|
+
let weekly_cost = baseline.weekly * unitCost;
|
|
75
64
|
let monthly_cost = baseline.monthly * unitCost;
|
|
76
|
-
let yearly_cost = baseline.yearly
|
|
65
|
+
let yearly_cost = baseline.yearly * unitCost;
|
|
77
66
|
|
|
78
67
|
// Build Output
|
|
79
68
|
msg.payload = {
|
|
@@ -97,5 +86,8 @@ module.exports = function(RED) {
|
|
|
97
86
|
node.send(msg);
|
|
98
87
|
});
|
|
99
88
|
}
|
|
100
|
-
|
|
89
|
+
|
|
90
|
+
RED.nodes.registerType("energyMeterPlus", EnergyMeterPlus, {
|
|
91
|
+
color: "#d9910cdb" // Orange node color
|
|
92
|
+
});
|
|
101
93
|
}
|
package/package.json
CHANGED