node-red-contrib-energymeterplus 0.2.4 → 0.2.5

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,8 +27,7 @@ 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) {
30
+ if (storedBaselines.daily || storedBaselines.weekly || storedBaselines.monthly || storedBaselines.yearly) {
32
31
  baseline.daily += storedBaselines.daily;
33
32
  baseline.weekly += storedBaselines.weekly;
34
33
  baseline.monthly += storedBaselines.monthly;
@@ -38,10 +37,10 @@ module.exports = function(RED) {
38
37
  node.context().set("storedBaselines", storedBaselines);
39
38
  }
40
39
 
41
- // Load last timestamp or initialize
40
+ // Last timestamp
42
41
  let lastCheck = node.context().get("lastCheck") || new Date();
43
42
 
44
- // Currency symbol helper
43
+ // Helpers
45
44
  function currencySymbol(code) {
46
45
  switch (code) {
47
46
  case "USD": return "$";
@@ -50,14 +49,11 @@ module.exports = function(RED) {
50
49
  default: return code;
51
50
  }
52
51
  }
53
-
54
- // Safe rounding helper
55
52
  function round2(val) {
56
53
  if (val === null || val === undefined || isNaN(val)) return 0;
57
54
  return Number(val.toFixed(2));
58
55
  }
59
56
 
60
- // Archive yearly totals
61
57
  function archiveYearly(total, year) {
62
58
  try {
63
59
  const archivePath = path.join(path.dirname(filePath), "yearly_archive.json");
@@ -65,11 +61,7 @@ module.exports = function(RED) {
65
61
  if (fs.existsSync(archivePath)) {
66
62
  archive = JSON.parse(fs.readFileSync(archivePath));
67
63
  }
68
- archive.push({
69
- year: year,
70
- total_kWh: total,
71
- timestamp: new Date().toISOString()
72
- });
64
+ archive.push({ year, total_kWh: total, timestamp: new Date().toISOString() });
73
65
  fs.writeFileSync(archivePath, JSON.stringify(archive, null, 2));
74
66
  } catch (err) {
75
67
  node.error("Failed to archive yearly total: " + err);
@@ -79,19 +71,14 @@ module.exports = function(RED) {
79
71
  // Rollover logic
80
72
  function checkRollover() {
81
73
  let now = new Date();
74
+ let stored = node.context().get("storedBaselines") || { daily:0, weekly:0, monthly:0, yearly:0 };
82
75
 
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
- }
76
+ if (now.getDate() !== lastCheck.getDate()) baseline.daily = stored.daily;
77
+ if (now.getDay() === 1 && lastCheck.getDay() !== 1) baseline.weekly = stored.weekly;
78
+ if (now.getMonth() !== lastCheck.getMonth()) baseline.monthly = stored.monthly;
92
79
  if (now.getFullYear() !== lastCheck.getFullYear()) {
93
80
  archiveYearly(baseline.yearly, lastCheck.getFullYear());
94
- baseline.yearly = storedBaselines.yearly;
81
+ baseline.yearly = stored.yearly;
95
82
  }
96
83
 
97
84
  lastCheck = now;
@@ -100,27 +87,25 @@ module.exports = function(RED) {
100
87
  }
101
88
  setInterval(checkRollover, 60000);
102
89
 
90
+ // Input handler
103
91
  node.on('input', function(msg) {
104
92
  let now = new Date();
105
-
106
- // Calculate duration BEFORE updating lastCheck
107
93
  let durationHours = (now - lastCheck) / (1000 * 3600);
108
94
 
109
95
  let power = Number(msg.payload);
110
- if (!isNaN(power)) {
96
+ if (!isNaN(power) && durationHours > 0) {
111
97
  let power_kW = (inputUnit === "W") ? power / 1000 : power;
112
98
  let energyIncrement = power_kW * durationHours;
113
99
 
114
- // Apply increment
115
100
  baseline.daily += energyIncrement;
116
101
  baseline.weekly += energyIncrement;
117
102
  baseline.monthly += energyIncrement;
118
103
  baseline.yearly += energyIncrement;
119
104
  }
120
105
 
121
- // Update lastCheck AFTER increment
122
106
  lastCheck = now;
123
107
  node.context().set("lastCheck", lastCheck);
108
+ node.context().set("baseline", baseline);
124
109
 
125
110
  msg.payload = {
126
111
  daily_kWh: round2(baseline.daily),
@@ -134,17 +119,10 @@ module.exports = function(RED) {
134
119
  currency: currencySymbol(currencyCode)
135
120
  };
136
121
 
137
- // Ensure directory exists
138
122
  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
- }
123
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
124
+ try { fs.writeFileSync(filePath, JSON.stringify(msg.payload, null, 2)); }
125
+ catch (err) { node.error("Failed to write to file: " + err); }
148
126
 
149
127
  node.send(msg);
150
128
  });
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.5",
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",