node-red-contrib-energymeterplus 0.2.2 → 0.2.4
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 +44 -2
- package/energyMeterPlus.html +7 -0
- package/energyMeterPlus.js +43 -55
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#### **EnergyMeterPlus Node Version 0.2.
|
|
1
|
+
#### **EnergyMeterPlus Node Version 0.2.4**
|
|
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,45 @@ 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:**
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
###### **V2.3:**
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
Cleared bug where baseline values remain visible after applying the values
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
Cleared the rollover logic to eliminate double-counting.
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
Baselines now applied once and stored in context.
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
updated counters to continuous absorption, no transfer at rollover
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
###### v2.4
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
Fixed a bug where the internal counters were not updating incrementally.
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
Added payload validation
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
Fixed Baselines bug: Baselines captured once, stored in context, and survive after UI clears
|
|
208
|
+
|
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,12 +11,6 @@ module.exports = function(RED) {
|
|
|
11
11
|
let inputUnit = config.inputUnit || "W";
|
|
12
12
|
let currencyCode = config.currency || "USD";
|
|
13
13
|
|
|
14
|
-
// Baseline corrections
|
|
15
|
-
let baselineDaily = Number(config.baselineDaily) || 0;
|
|
16
|
-
let baselineWeekly = Number(config.baselineWeekly) || 0;
|
|
17
|
-
let baselineMonthly = Number(config.baselineMonthly) || 0;
|
|
18
|
-
let baselineYearly = Number(config.baselineYearly) || 0;
|
|
19
|
-
|
|
20
14
|
// Load persisted baseline or initialize
|
|
21
15
|
let baseline = node.context().get("baseline") || {
|
|
22
16
|
daily: 0,
|
|
@@ -25,21 +19,23 @@ module.exports = function(RED) {
|
|
|
25
19
|
yearly: 0
|
|
26
20
|
};
|
|
27
21
|
|
|
28
|
-
//
|
|
29
|
-
let
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
22
|
+
// Load stored numeric baselines (persisted separately)
|
|
23
|
+
let storedBaselines = node.context().get("storedBaselines") || {
|
|
24
|
+
daily: Number(config.baselineDaily) || 0,
|
|
25
|
+
weekly: Number(config.baselineWeekly) || 0,
|
|
26
|
+
monthly: Number(config.baselineMonthly) || 0,
|
|
27
|
+
yearly: Number(config.baselineYearly) || 0
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Apply baselines once if new values entered
|
|
31
|
+
if (config.baselineDaily || config.baselineWeekly || config.baselineMonthly || config.baselineYearly) {
|
|
32
|
+
baseline.daily += storedBaselines.daily;
|
|
33
|
+
baseline.weekly += storedBaselines.weekly;
|
|
34
|
+
baseline.monthly += storedBaselines.monthly;
|
|
35
|
+
baseline.yearly += storedBaselines.yearly;
|
|
36
|
+
|
|
37
|
+
node.context().set("baseline", baseline);
|
|
38
|
+
node.context().set("storedBaselines", storedBaselines);
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
// Load last timestamp or initialize
|
|
@@ -55,6 +51,12 @@ module.exports = function(RED) {
|
|
|
55
51
|
}
|
|
56
52
|
}
|
|
57
53
|
|
|
54
|
+
// Safe rounding helper
|
|
55
|
+
function round2(val) {
|
|
56
|
+
if (val === null || val === undefined || isNaN(val)) return 0;
|
|
57
|
+
return Number(val.toFixed(2));
|
|
58
|
+
}
|
|
59
|
+
|
|
58
60
|
// Archive yearly totals
|
|
59
61
|
function archiveYearly(total, year) {
|
|
60
62
|
try {
|
|
@@ -74,36 +76,22 @@ module.exports = function(RED) {
|
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
78
|
|
|
77
|
-
//
|
|
78
|
-
function round2(val) {
|
|
79
|
-
if (val === null || val === undefined || isNaN(val)) return 0;
|
|
80
|
-
return Number(val.toFixed(2));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Rollover logic with baseline reset
|
|
79
|
+
// Rollover logic
|
|
84
80
|
function checkRollover() {
|
|
85
81
|
let now = new Date();
|
|
86
82
|
|
|
87
|
-
// Daily rollover (midnight)
|
|
88
83
|
if (now.getDate() !== lastCheck.getDate()) {
|
|
89
|
-
|
|
90
|
-
baseline.daily = baselineDaily;
|
|
84
|
+
baseline.daily = storedBaselines.daily;
|
|
91
85
|
}
|
|
92
|
-
|
|
93
|
-
// Weekly rollover (Sunday → Monday)
|
|
94
86
|
if (now.getDay() === 1 && lastCheck.getDay() !== 1) {
|
|
95
|
-
baseline.weekly =
|
|
87
|
+
baseline.weekly = storedBaselines.weekly;
|
|
96
88
|
}
|
|
97
|
-
|
|
98
|
-
// Monthly rollover (1st of month)
|
|
99
89
|
if (now.getMonth() !== lastCheck.getMonth()) {
|
|
100
|
-
baseline.monthly =
|
|
90
|
+
baseline.monthly = storedBaselines.monthly;
|
|
101
91
|
}
|
|
102
|
-
|
|
103
|
-
// Yearly rollover (Jan 1)
|
|
104
92
|
if (now.getFullYear() !== lastCheck.getFullYear()) {
|
|
105
93
|
archiveYearly(baseline.yearly, lastCheck.getFullYear());
|
|
106
|
-
baseline.yearly =
|
|
94
|
+
baseline.yearly = storedBaselines.yearly;
|
|
107
95
|
}
|
|
108
96
|
|
|
109
97
|
lastCheck = now;
|
|
@@ -114,24 +102,25 @@ module.exports = function(RED) {
|
|
|
114
102
|
|
|
115
103
|
node.on('input', function(msg) {
|
|
116
104
|
let now = new Date();
|
|
117
|
-
let durationHours = (now - lastCheck) / (1000 * 3600);
|
|
118
|
-
lastCheck = now;
|
|
119
|
-
node.context().set("lastCheck", lastCheck);
|
|
120
105
|
|
|
121
|
-
|
|
122
|
-
let
|
|
123
|
-
|
|
124
|
-
let energyIncrement = power_kW * durationHours;
|
|
106
|
+
// Calculate duration BEFORE updating lastCheck
|
|
107
|
+
let durationHours = (now - lastCheck) / (1000 * 3600);
|
|
125
108
|
|
|
126
|
-
|
|
127
|
-
|
|
109
|
+
let power = Number(msg.payload);
|
|
110
|
+
if (!isNaN(power)) {
|
|
111
|
+
let power_kW = (inputUnit === "W") ? power / 1000 : power;
|
|
112
|
+
let energyIncrement = power_kW * durationHours;
|
|
128
113
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
114
|
+
// Apply increment
|
|
115
|
+
baseline.daily += energyIncrement;
|
|
116
|
+
baseline.weekly += energyIncrement;
|
|
117
|
+
baseline.monthly += energyIncrement;
|
|
118
|
+
baseline.yearly += energyIncrement;
|
|
119
|
+
}
|
|
133
120
|
|
|
134
|
-
|
|
121
|
+
// Update lastCheck AFTER increment
|
|
122
|
+
lastCheck = now;
|
|
123
|
+
node.context().set("lastCheck", lastCheck);
|
|
135
124
|
|
|
136
125
|
msg.payload = {
|
|
137
126
|
daily_kWh: round2(baseline.daily),
|
|
@@ -151,7 +140,6 @@ module.exports = function(RED) {
|
|
|
151
140
|
fs.mkdirSync(dir, { recursive: true });
|
|
152
141
|
}
|
|
153
142
|
|
|
154
|
-
// Write snapshot safely
|
|
155
143
|
try {
|
|
156
144
|
fs.writeFileSync(filePath, JSON.stringify(msg.payload, null, 2));
|
|
157
145
|
} catch (err) {
|
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.4",
|
|
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",
|