node-red-contrib-energymeterplus 0.2.1 → 0.2.3
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/README.md +24 -2
- package/energyMeterPlus.html +7 -0
- package/energyMeterPlus.js +52 -24
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#### **EnergyMeterPlus Node Version 0.2.
|
|
1
|
+
#### **EnergyMeterPlus Node Version 0.2.3**
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
@@ -50,7 +50,7 @@ EnergyMeterPlus is a custom Node‑RED function node designed to convert instant
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
##### **Configuration:**
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
|
|
@@ -164,3 +164,25 @@ After 24 hours → \~108.6 kWh added to daily total.
|
|
|
164
164
|
|
|
165
165
|
Costs scale automatically with your configured unit cost.
|
|
166
166
|
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
##### **Updates 2.3:**
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
Cleared bug where baseline values remain visible after applying the values
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
Cleared the rollover logic to eliminate double-counting.
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
Baselines now applied once and stored in context.
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
updated counters to continuous absorption, no transfer at rollover
|
|
188
|
+
|
package/energyMeterPlus.html
CHANGED
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
icon: "sun.png",
|
|
19
19
|
label: function() {
|
|
20
20
|
return this.name || "energyMeterPlus";
|
|
21
|
+
},
|
|
22
|
+
oneditsave: function() {
|
|
23
|
+
// Cosmetic blanking: clear baseline fields in the editor UI after deploy
|
|
24
|
+
$("#node-input-baselineDaily").val("");
|
|
25
|
+
$("#node-input-baselineWeekly").val("");
|
|
26
|
+
$("#node-input-baselineMonthly").val("");
|
|
27
|
+
$("#node-input-baselineYearly").val("");
|
|
21
28
|
}
|
|
22
29
|
});
|
|
23
30
|
</script>
|
package/energyMeterPlus.js
CHANGED
|
@@ -11,7 +11,7 @@ module.exports = function(RED) {
|
|
|
11
11
|
let inputUnit = config.inputUnit || "W";
|
|
12
12
|
let currencyCode = config.currency || "USD";
|
|
13
13
|
|
|
14
|
-
// Baseline corrections
|
|
14
|
+
// Baseline corrections (numeric values from config)
|
|
15
15
|
let baselineDaily = Number(config.baselineDaily) || 0;
|
|
16
16
|
let baselineWeekly = Number(config.baselineWeekly) || 0;
|
|
17
17
|
let baselineMonthly = Number(config.baselineMonthly) || 0;
|
|
@@ -25,6 +25,14 @@ module.exports = function(RED) {
|
|
|
25
25
|
yearly: 0
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
// Store numeric baselines separately so resets don’t pull from blanked config
|
|
29
|
+
let storedBaselines = node.context().get("storedBaselines") || {
|
|
30
|
+
daily: baselineDaily,
|
|
31
|
+
weekly: baselineWeekly,
|
|
32
|
+
monthly: baselineMonthly,
|
|
33
|
+
yearly: baselineYearly
|
|
34
|
+
};
|
|
35
|
+
|
|
28
36
|
// Apply baselines if new values entered
|
|
29
37
|
let baselineApplied = node.context().get("baselineApplied") || false;
|
|
30
38
|
if (!baselineApplied || baselineDaily || baselineWeekly || baselineMonthly || baselineYearly) {
|
|
@@ -33,7 +41,15 @@ module.exports = function(RED) {
|
|
|
33
41
|
baseline.monthly += baselineMonthly;
|
|
34
42
|
baseline.yearly += baselineYearly;
|
|
35
43
|
|
|
44
|
+
storedBaselines = {
|
|
45
|
+
daily: baselineDaily,
|
|
46
|
+
weekly: baselineWeekly,
|
|
47
|
+
monthly: baselineMonthly,
|
|
48
|
+
yearly: baselineYearly
|
|
49
|
+
};
|
|
50
|
+
|
|
36
51
|
node.context().set("baselineApplied", true);
|
|
52
|
+
node.context().set("storedBaselines", storedBaselines);
|
|
37
53
|
|
|
38
54
|
// Cosmetic blanking: clear config fields so they show empty in UI
|
|
39
55
|
config.baselineDaily = "";
|
|
@@ -55,46 +71,54 @@ module.exports = function(RED) {
|
|
|
55
71
|
}
|
|
56
72
|
}
|
|
57
73
|
|
|
74
|
+
// Safe rounding helper
|
|
75
|
+
function round2(val) {
|
|
76
|
+
if (val === null || val === undefined || isNaN(val)) return 0;
|
|
77
|
+
return Number(val.toFixed(2));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Archive yearly totals
|
|
81
|
+
function archiveYearly(total, year) {
|
|
82
|
+
try {
|
|
83
|
+
const archivePath = path.join(path.dirname(filePath), "yearly_archive.json");
|
|
84
|
+
let archive = [];
|
|
85
|
+
if (fs.existsSync(archivePath)) {
|
|
86
|
+
archive = JSON.parse(fs.readFileSync(archivePath));
|
|
87
|
+
}
|
|
88
|
+
archive.push({
|
|
89
|
+
year: year,
|
|
90
|
+
total_kWh: total,
|
|
91
|
+
timestamp: new Date().toISOString()
|
|
92
|
+
});
|
|
93
|
+
fs.writeFileSync(archivePath, JSON.stringify(archive, null, 2));
|
|
94
|
+
} catch (err) {
|
|
95
|
+
node.error("Failed to archive yearly total: " + err);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
58
99
|
// Rollover logic
|
|
59
100
|
function checkRollover() {
|
|
60
101
|
let now = new Date();
|
|
61
102
|
|
|
62
103
|
// Daily rollover (midnight)
|
|
63
104
|
if (now.getDate() !== lastCheck.getDate()) {
|
|
64
|
-
baseline.
|
|
65
|
-
baseline.daily = 0;
|
|
105
|
+
baseline.daily = storedBaselines.daily;
|
|
66
106
|
}
|
|
67
107
|
|
|
68
108
|
// Weekly rollover (Sunday → Monday)
|
|
69
109
|
if (now.getDay() === 1 && lastCheck.getDay() !== 1) {
|
|
70
|
-
baseline.
|
|
71
|
-
baseline.weekly = 0;
|
|
110
|
+
baseline.weekly = storedBaselines.weekly;
|
|
72
111
|
}
|
|
73
112
|
|
|
74
113
|
// Monthly rollover (1st of month)
|
|
75
114
|
if (now.getMonth() !== lastCheck.getMonth()) {
|
|
76
|
-
baseline.
|
|
77
|
-
baseline.monthly = 0;
|
|
115
|
+
baseline.monthly = storedBaselines.monthly;
|
|
78
116
|
}
|
|
79
117
|
|
|
80
118
|
// Yearly rollover (Jan 1)
|
|
81
119
|
if (now.getFullYear() !== lastCheck.getFullYear()) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
let archive = [];
|
|
85
|
-
if (fs.existsSync(archivePath)) {
|
|
86
|
-
archive = JSON.parse(fs.readFileSync(archivePath));
|
|
87
|
-
}
|
|
88
|
-
archive.push({
|
|
89
|
-
year: lastCheck.getFullYear(),
|
|
90
|
-
total_kWh: baseline.yearly,
|
|
91
|
-
timestamp: new Date().toISOString()
|
|
92
|
-
});
|
|
93
|
-
fs.writeFileSync(archivePath, JSON.stringify(archive, null, 2));
|
|
94
|
-
} catch (err) {
|
|
95
|
-
node.error("Failed to archive yearly total: " + err);
|
|
96
|
-
}
|
|
97
|
-
baseline.yearly = 0;
|
|
120
|
+
archiveYearly(baseline.yearly, lastCheck.getFullYear());
|
|
121
|
+
baseline.yearly = storedBaselines.yearly;
|
|
98
122
|
}
|
|
99
123
|
|
|
100
124
|
lastCheck = now;
|
|
@@ -114,9 +138,13 @@ module.exports = function(RED) {
|
|
|
114
138
|
|
|
115
139
|
let energyIncrement = power_kW * durationHours;
|
|
116
140
|
|
|
141
|
+
// Add increment to daily
|
|
117
142
|
baseline.daily += energyIncrement;
|
|
118
143
|
|
|
119
|
-
|
|
144
|
+
// Continuous absorption
|
|
145
|
+
baseline.weekly += energyIncrement;
|
|
146
|
+
baseline.monthly += energyIncrement;
|
|
147
|
+
baseline.yearly += energyIncrement;
|
|
120
148
|
|
|
121
149
|
msg.payload = {
|
|
122
150
|
daily_kWh: round2(baseline.daily),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-energymeterplus",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "A custom Node-RED node that integrates power readings into energy totals with persistence and cost calculation.",
|
|
5
5
|
"author": "Arcfrankye",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,4 +13,3 @@
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
|