node-red-contrib-energymeterplus 0.3.0 → 0.3.1
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/energyMeterPlus.js +25 -47
- package/package.json +1 -1
package/energyMeterPlus.js
CHANGED
|
@@ -2,24 +2,6 @@ const fs = require("fs");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
|
|
4
4
|
module.exports = function(RED) {
|
|
5
|
-
|
|
6
|
-
// Listener for baseline messages from the editor
|
|
7
|
-
RED.comms.subscribe("energyMeterPlus/applyBaseline", function(baselineMsg) {
|
|
8
|
-
const nodeInstance = RED.nodes.getNode(baselineMsg.nodeId);
|
|
9
|
-
if (nodeInstance) {
|
|
10
|
-
let baseline = nodeInstance.context().get("baseline") || {
|
|
11
|
-
daily:0, weekly:0, monthly:0, yearly:0
|
|
12
|
-
};
|
|
13
|
-
// Additive offsets
|
|
14
|
-
baseline.daily += baselineMsg.payload.daily;
|
|
15
|
-
baseline.weekly += baselineMsg.payload.weekly;
|
|
16
|
-
baseline.monthly += baselineMsg.payload.monthly;
|
|
17
|
-
baseline.yearly += baselineMsg.payload.yearly;
|
|
18
|
-
|
|
19
|
-
nodeInstance.context().set("baseline", baseline);
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
|
|
23
5
|
function EnergyMeterPlus(config) {
|
|
24
6
|
RED.nodes.createNode(this, config);
|
|
25
7
|
var node = this;
|
|
@@ -30,19 +12,17 @@ module.exports = function(RED) {
|
|
|
30
12
|
let currencyCode = config.currency || "USD";
|
|
31
13
|
|
|
32
14
|
// Baseline offsets
|
|
33
|
-
let baseline = node.context().get("baseline") || {
|
|
15
|
+
let baseline = node.context().get("baseline") || {
|
|
16
|
+
daily: Number(config.baselineDaily) || 0,
|
|
17
|
+
weekly: Number(config.baselineWeekly) || 0,
|
|
18
|
+
monthly: Number(config.baselineMonthly) || 0,
|
|
19
|
+
yearly: Number(config.baselineYearly) || 0
|
|
20
|
+
};
|
|
34
21
|
|
|
35
22
|
// Live increments
|
|
36
|
-
let accumulated = node.context().get("accumulated") || {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
baseline.daily += Number(config.baselineDaily) || 0;
|
|
40
|
-
baseline.weekly += Number(config.baselineWeekly) || 0;
|
|
41
|
-
baseline.monthly += Number(config.baselineMonthly) || 0;
|
|
42
|
-
baseline.yearly += Number(config.baselineYearly) || 0;
|
|
43
|
-
|
|
44
|
-
node.context().set("baseline", baseline);
|
|
45
|
-
node.context().set("accumulated", accumulated);
|
|
23
|
+
let accumulated = node.context().get("accumulated") || {
|
|
24
|
+
daily:0, weekly:0, monthly:0, yearly:0
|
|
25
|
+
};
|
|
46
26
|
|
|
47
27
|
let lastCheck = node.context().get("lastCheck") || new Date();
|
|
48
28
|
|
|
@@ -66,40 +46,29 @@ module.exports = function(RED) {
|
|
|
66
46
|
if (fs.existsSync(archivePath)) {
|
|
67
47
|
archive = JSON.parse(fs.readFileSync(archivePath));
|
|
68
48
|
}
|
|
69
|
-
archive.push({ year, total
|
|
49
|
+
archive.push({ year, total, timestamp: new Date().toISOString() });
|
|
70
50
|
fs.writeFileSync(archivePath, JSON.stringify(archive, null, 2));
|
|
71
51
|
} catch (err) {
|
|
72
52
|
node.error("Failed to archive yearly total: " + err);
|
|
73
53
|
}
|
|
74
54
|
}
|
|
75
55
|
|
|
76
|
-
// Rollover logic
|
|
56
|
+
// Rollover logic
|
|
77
57
|
function checkRollover() {
|
|
78
58
|
let now = new Date();
|
|
79
59
|
|
|
80
|
-
// Daily reset at midnight
|
|
81
60
|
if (now.getDate() !== lastCheck.getDate()) {
|
|
82
|
-
accumulated.daily = 0;
|
|
83
|
-
baseline.daily = 0;
|
|
61
|
+
accumulated.daily = 0; baseline.daily = 0;
|
|
84
62
|
}
|
|
85
|
-
|
|
86
|
-
// Weekly reset (Sunday midnight → Monday start)
|
|
87
63
|
if (now.getDay() === 1 && lastCheck.getDay() !== 1) {
|
|
88
|
-
accumulated.weekly = 0;
|
|
89
|
-
baseline.weekly = 0;
|
|
64
|
+
accumulated.weekly = 0; baseline.weekly = 0;
|
|
90
65
|
}
|
|
91
|
-
|
|
92
|
-
// Monthly reset
|
|
93
66
|
if (now.getMonth() !== lastCheck.getMonth()) {
|
|
94
|
-
accumulated.monthly = 0;
|
|
95
|
-
baseline.monthly = 0;
|
|
67
|
+
accumulated.monthly = 0; baseline.monthly = 0;
|
|
96
68
|
}
|
|
97
|
-
|
|
98
|
-
// Yearly reset
|
|
99
69
|
if (now.getFullYear() !== lastCheck.getFullYear()) {
|
|
100
70
|
archiveYearly(baseline.yearly + accumulated.yearly, lastCheck.getFullYear());
|
|
101
|
-
accumulated.yearly = 0;
|
|
102
|
-
baseline.yearly = 0;
|
|
71
|
+
accumulated.yearly = 0; baseline.yearly = 0;
|
|
103
72
|
}
|
|
104
73
|
|
|
105
74
|
lastCheck = now;
|
|
@@ -114,6 +83,16 @@ module.exports = function(RED) {
|
|
|
114
83
|
let now = new Date();
|
|
115
84
|
let durationHours = (now - lastCheck) / (1000 * 3600);
|
|
116
85
|
|
|
86
|
+
// Handle baseline updates
|
|
87
|
+
if (msg.topic === "applyBaseline" && msg.payload) {
|
|
88
|
+
baseline.daily += Number(msg.payload.daily) || 0;
|
|
89
|
+
baseline.weekly += Number(msg.payload.weekly) || 0;
|
|
90
|
+
baseline.monthly += Number(msg.payload.monthly) || 0;
|
|
91
|
+
baseline.yearly += Number(msg.payload.yearly) || 0;
|
|
92
|
+
node.context().set("baseline", baseline);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Handle power input
|
|
117
96
|
let power = Number(msg.payload);
|
|
118
97
|
if (!isNaN(power) && durationHours > 0) {
|
|
119
98
|
let power_kW = (inputUnit === "W") ? power / 1000 : power;
|
|
@@ -129,7 +108,6 @@ module.exports = function(RED) {
|
|
|
129
108
|
node.context().set("lastCheck", lastCheck);
|
|
130
109
|
node.context().set("accumulated", accumulated);
|
|
131
110
|
|
|
132
|
-
// Output = baseline + accumulated
|
|
133
111
|
msg.payload = {
|
|
134
112
|
energyDaily: round2(baseline.daily + accumulated.daily),
|
|
135
113
|
energyWeekly: round2(baseline.weekly + accumulated.weekly),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-energymeterplus",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
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",
|