node-red-contrib-energymeterplus 0.2.4 → 0.2.6

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 CHANGED
@@ -1,4 +1,4 @@
1
- #### **EnergyMeterPlus Node Version 0.2.4**
1
+ #### **EnergyMeterPlus Node Version 0.2.5**
2
2
 
3
3
 
4
4
 
@@ -206,3 +206,11 @@ Added payload validation
206
206
 
207
207
  Fixed Baselines bug: Baselines captured once, stored in context, and survive after UI clears
208
208
 
209
+
210
+
211
+ v2.5
212
+
213
+
214
+
215
+ Fixed internal counter bug
216
+
@@ -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
- // Load persisted baseline or initialize
14
+ // Counters always start from context or zero
15
15
  let baseline = node.context().get("baseline") || {
16
16
  daily: 0,
17
17
  weekly: 0,
@@ -19,7 +19,7 @@ module.exports = function(RED) {
19
19
  yearly: 0
20
20
  };
21
21
 
22
- // Load stored numeric baselines (persisted separately)
22
+ // Capture baselines once on deploy
23
23
  let storedBaselines = node.context().get("storedBaselines") || {
24
24
  daily: Number(config.baselineDaily) || 0,
25
25
  weekly: Number(config.baselineWeekly) || 0,
@@ -27,21 +27,19 @@ module.exports = function(RED) {
27
27
  yearly: Number(config.baselineYearly) || 0
28
28
  };
29
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;
30
+ // Apply each baseline only to its own counter
31
+ if (storedBaselines.daily) baseline.daily += storedBaselines.daily;
32
+ if (storedBaselines.weekly) baseline.weekly += storedBaselines.weekly;
33
+ if (storedBaselines.monthly) baseline.monthly += storedBaselines.monthly;
34
+ if (storedBaselines.yearly) baseline.yearly += storedBaselines.yearly;
36
35
 
37
- node.context().set("baseline", baseline);
38
- node.context().set("storedBaselines", storedBaselines);
39
- }
36
+ node.context().set("baseline", baseline);
37
+ node.context().set("storedBaselines", storedBaselines);
40
38
 
41
- // Load last timestamp or initialize
39
+ // Last timestamp
42
40
  let lastCheck = node.context().get("lastCheck") || new Date();
43
41
 
44
- // Currency symbol helper
42
+ // Helpers
45
43
  function currencySymbol(code) {
46
44
  switch (code) {
47
45
  case "USD": return "$";
@@ -50,14 +48,11 @@ module.exports = function(RED) {
50
48
  default: return code;
51
49
  }
52
50
  }
53
-
54
- // Safe rounding helper
55
51
  function round2(val) {
56
52
  if (val === null || val === undefined || isNaN(val)) return 0;
57
53
  return Number(val.toFixed(2));
58
54
  }
59
55
 
60
- // Archive yearly totals
61
56
  function archiveYearly(total, year) {
62
57
  try {
63
58
  const archivePath = path.join(path.dirname(filePath), "yearly_archive.json");
@@ -65,11 +60,7 @@ module.exports = function(RED) {
65
60
  if (fs.existsSync(archivePath)) {
66
61
  archive = JSON.parse(fs.readFileSync(archivePath));
67
62
  }
68
- archive.push({
69
- year: year,
70
- total_kWh: total,
71
- timestamp: new Date().toISOString()
72
- });
63
+ archive.push({ year, total_kWh: total, timestamp: new Date().toISOString() });
73
64
  fs.writeFileSync(archivePath, JSON.stringify(archive, null, 2));
74
65
  } catch (err) {
75
66
  node.error("Failed to archive yearly total: " + err);
@@ -79,19 +70,14 @@ module.exports = function(RED) {
79
70
  // Rollover logic
80
71
  function checkRollover() {
81
72
  let now = new Date();
73
+ let stored = node.context().get("storedBaselines") || { daily:0, weekly:0, monthly:0, yearly:0 };
82
74
 
83
- if (now.getDate() !== lastCheck.getDate()) {
84
- baseline.daily = storedBaselines.daily;
85
- }
86
- if (now.getDay() === 1 && lastCheck.getDay() !== 1) {
87
- baseline.weekly = storedBaselines.weekly;
88
- }
89
- if (now.getMonth() !== lastCheck.getMonth()) {
90
- baseline.monthly = storedBaselines.monthly;
91
- }
75
+ if (now.getDate() !== lastCheck.getDate()) baseline.daily = stored.daily;
76
+ if (now.getDay() === 1 && lastCheck.getDay() !== 1) baseline.weekly = stored.weekly;
77
+ if (now.getMonth() !== lastCheck.getMonth()) baseline.monthly = stored.monthly;
92
78
  if (now.getFullYear() !== lastCheck.getFullYear()) {
93
79
  archiveYearly(baseline.yearly, lastCheck.getFullYear());
94
- baseline.yearly = storedBaselines.yearly;
80
+ baseline.yearly = stored.yearly;
95
81
  }
96
82
 
97
83
  lastCheck = now;
@@ -100,27 +86,25 @@ module.exports = function(RED) {
100
86
  }
101
87
  setInterval(checkRollover, 60000);
102
88
 
89
+ // Input handler
103
90
  node.on('input', function(msg) {
104
91
  let now = new Date();
105
-
106
- // Calculate duration BEFORE updating lastCheck
107
92
  let durationHours = (now - lastCheck) / (1000 * 3600);
108
93
 
109
94
  let power = Number(msg.payload);
110
- if (!isNaN(power)) {
95
+ if (!isNaN(power) && durationHours > 0) {
111
96
  let power_kW = (inputUnit === "W") ? power / 1000 : power;
112
97
  let energyIncrement = power_kW * durationHours;
113
98
 
114
- // Apply increment
115
99
  baseline.daily += energyIncrement;
116
100
  baseline.weekly += energyIncrement;
117
101
  baseline.monthly += energyIncrement;
118
102
  baseline.yearly += energyIncrement;
119
103
  }
120
104
 
121
- // Update lastCheck AFTER increment
122
105
  lastCheck = now;
123
106
  node.context().set("lastCheck", lastCheck);
107
+ node.context().set("baseline", baseline);
124
108
 
125
109
  msg.payload = {
126
110
  daily_kWh: round2(baseline.daily),
@@ -134,17 +118,10 @@ module.exports = function(RED) {
134
118
  currency: currencySymbol(currencyCode)
135
119
  };
136
120
 
137
- // Ensure directory exists
138
121
  const dir = path.dirname(filePath);
139
- if (!fs.existsSync(dir)) {
140
- fs.mkdirSync(dir, { recursive: true });
141
- }
142
-
143
- try {
144
- fs.writeFileSync(filePath, JSON.stringify(msg.payload, null, 2));
145
- } catch (err) {
146
- node.error("Failed to write to file: " + err);
147
- }
122
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
123
+ try { fs.writeFileSync(filePath, JSON.stringify(msg.payload, null, 2)); }
124
+ catch (err) { node.error("Failed to write to file: " + err); }
148
125
 
149
126
  node.send(msg);
150
127
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-energymeterplus",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
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",