node-red-contrib-energymeterplus 0.2.3 → 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 +22 -2
- package/energyMeterPlus.js +27 -52
- 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
|
|
|
@@ -168,7 +168,11 @@ Costs scale automatically with your configured unit cost.
|
|
|
168
168
|
|
|
169
169
|
|
|
170
170
|
|
|
171
|
-
##### **Updates
|
|
171
|
+
##### **Updates:**
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
###### **V2.3:**
|
|
172
176
|
|
|
173
177
|
|
|
174
178
|
|
|
@@ -186,3 +190,19 @@ Baselines now applied once and stored in context.
|
|
|
186
190
|
|
|
187
191
|
updated counters to continuous absorption, no transfer at rollover
|
|
188
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.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 (numeric values from config)
|
|
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,37 +19,23 @@ module.exports = function(RED) {
|
|
|
25
19
|
yearly: 0
|
|
26
20
|
};
|
|
27
21
|
|
|
28
|
-
//
|
|
22
|
+
// Load stored numeric baselines (persisted separately)
|
|
29
23
|
let storedBaselines = node.context().get("storedBaselines") || {
|
|
30
|
-
daily: baselineDaily,
|
|
31
|
-
weekly: baselineWeekly,
|
|
32
|
-
monthly: baselineMonthly,
|
|
33
|
-
yearly: baselineYearly
|
|
24
|
+
daily: Number(config.baselineDaily) || 0,
|
|
25
|
+
weekly: Number(config.baselineWeekly) || 0,
|
|
26
|
+
monthly: Number(config.baselineMonthly) || 0,
|
|
27
|
+
yearly: Number(config.baselineYearly) || 0
|
|
34
28
|
};
|
|
35
29
|
|
|
36
|
-
// Apply baselines if new values entered
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
baseline.
|
|
40
|
-
baseline.
|
|
41
|
-
baseline.
|
|
42
|
-
baseline.yearly += baselineYearly;
|
|
43
|
-
|
|
44
|
-
storedBaselines = {
|
|
45
|
-
daily: baselineDaily,
|
|
46
|
-
weekly: baselineWeekly,
|
|
47
|
-
monthly: baselineMonthly,
|
|
48
|
-
yearly: baselineYearly
|
|
49
|
-
};
|
|
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;
|
|
50
36
|
|
|
51
|
-
node.context().set("
|
|
37
|
+
node.context().set("baseline", baseline);
|
|
52
38
|
node.context().set("storedBaselines", storedBaselines);
|
|
53
|
-
|
|
54
|
-
// Cosmetic blanking: clear config fields so they show empty in UI
|
|
55
|
-
config.baselineDaily = "";
|
|
56
|
-
config.baselineWeekly = "";
|
|
57
|
-
config.baselineMonthly = "";
|
|
58
|
-
config.baselineYearly = "";
|
|
59
39
|
}
|
|
60
40
|
|
|
61
41
|
// Load last timestamp or initialize
|
|
@@ -100,22 +80,15 @@ module.exports = function(RED) {
|
|
|
100
80
|
function checkRollover() {
|
|
101
81
|
let now = new Date();
|
|
102
82
|
|
|
103
|
-
// Daily rollover (midnight)
|
|
104
83
|
if (now.getDate() !== lastCheck.getDate()) {
|
|
105
84
|
baseline.daily = storedBaselines.daily;
|
|
106
85
|
}
|
|
107
|
-
|
|
108
|
-
// Weekly rollover (Sunday → Monday)
|
|
109
86
|
if (now.getDay() === 1 && lastCheck.getDay() !== 1) {
|
|
110
87
|
baseline.weekly = storedBaselines.weekly;
|
|
111
88
|
}
|
|
112
|
-
|
|
113
|
-
// Monthly rollover (1st of month)
|
|
114
89
|
if (now.getMonth() !== lastCheck.getMonth()) {
|
|
115
90
|
baseline.monthly = storedBaselines.monthly;
|
|
116
91
|
}
|
|
117
|
-
|
|
118
|
-
// Yearly rollover (Jan 1)
|
|
119
92
|
if (now.getFullYear() !== lastCheck.getFullYear()) {
|
|
120
93
|
archiveYearly(baseline.yearly, lastCheck.getFullYear());
|
|
121
94
|
baseline.yearly = storedBaselines.yearly;
|
|
@@ -129,22 +102,25 @@ module.exports = function(RED) {
|
|
|
129
102
|
|
|
130
103
|
node.on('input', function(msg) {
|
|
131
104
|
let now = new Date();
|
|
132
|
-
let durationHours = (now - lastCheck) / (1000 * 3600);
|
|
133
|
-
lastCheck = now;
|
|
134
|
-
node.context().set("lastCheck", lastCheck);
|
|
135
105
|
|
|
136
|
-
|
|
137
|
-
let
|
|
106
|
+
// Calculate duration BEFORE updating lastCheck
|
|
107
|
+
let durationHours = (now - lastCheck) / (1000 * 3600);
|
|
138
108
|
|
|
139
|
-
let
|
|
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;
|
|
140
113
|
|
|
141
|
-
|
|
142
|
-
|
|
114
|
+
// Apply increment
|
|
115
|
+
baseline.daily += energyIncrement;
|
|
116
|
+
baseline.weekly += energyIncrement;
|
|
117
|
+
baseline.monthly += energyIncrement;
|
|
118
|
+
baseline.yearly += energyIncrement;
|
|
119
|
+
}
|
|
143
120
|
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
baseline.yearly += energyIncrement;
|
|
121
|
+
// Update lastCheck AFTER increment
|
|
122
|
+
lastCheck = now;
|
|
123
|
+
node.context().set("lastCheck", lastCheck);
|
|
148
124
|
|
|
149
125
|
msg.payload = {
|
|
150
126
|
daily_kWh: round2(baseline.daily),
|
|
@@ -164,7 +140,6 @@ module.exports = function(RED) {
|
|
|
164
140
|
fs.mkdirSync(dir, { recursive: true });
|
|
165
141
|
}
|
|
166
142
|
|
|
167
|
-
// Write snapshot safely
|
|
168
143
|
try {
|
|
169
144
|
fs.writeFileSync(filePath, JSON.stringify(msg.payload, null, 2));
|
|
170
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",
|