node-red-contrib-energymeterplus 0.3.0 → 0.3.2
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 +37 -50
- 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,21 +12,23 @@ 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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
node.context().set("accumulated", accumulated);
|
|
46
|
-
|
|
47
|
-
let lastCheck = node.context().get("lastCheck") || new Date();
|
|
23
|
+
let accumulated = node.context().get("accumulated") || {
|
|
24
|
+
daily:0, weekly:0, monthly:0, yearly:0
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Rehydrate lastCheck from context
|
|
28
|
+
let lastCheck = node.context().get("lastCheck");
|
|
29
|
+
if (!(lastCheck instanceof Date)) {
|
|
30
|
+
lastCheck = new Date(lastCheck || Date.now());
|
|
31
|
+
}
|
|
48
32
|
|
|
49
33
|
function currencySymbol(code) {
|
|
50
34
|
switch (code) {
|
|
@@ -66,46 +50,40 @@ module.exports = function(RED) {
|
|
|
66
50
|
if (fs.existsSync(archivePath)) {
|
|
67
51
|
archive = JSON.parse(fs.readFileSync(archivePath));
|
|
68
52
|
}
|
|
69
|
-
archive.push({ year, total
|
|
53
|
+
archive.push({ year, total, timestamp: new Date().toISOString() });
|
|
70
54
|
fs.writeFileSync(archivePath, JSON.stringify(archive, null, 2));
|
|
71
55
|
} catch (err) {
|
|
72
56
|
node.error("Failed to archive yearly total: " + err);
|
|
73
57
|
}
|
|
74
58
|
}
|
|
75
59
|
|
|
76
|
-
// Rollover logic
|
|
60
|
+
// Rollover logic
|
|
77
61
|
function checkRollover() {
|
|
78
62
|
let now = new Date();
|
|
79
63
|
|
|
80
|
-
//
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
baseline.daily = 0;
|
|
64
|
+
// Ensure lastCheck is a Date
|
|
65
|
+
if (!(lastCheck instanceof Date)) {
|
|
66
|
+
lastCheck = new Date(lastCheck || Date.now());
|
|
84
67
|
}
|
|
85
68
|
|
|
86
|
-
|
|
69
|
+
if (now.getDate() !== lastCheck.getDate()) {
|
|
70
|
+
accumulated.daily = 0; baseline.daily = 0;
|
|
71
|
+
}
|
|
87
72
|
if (now.getDay() === 1 && lastCheck.getDay() !== 1) {
|
|
88
|
-
accumulated.weekly = 0;
|
|
89
|
-
baseline.weekly = 0;
|
|
73
|
+
accumulated.weekly = 0; baseline.weekly = 0;
|
|
90
74
|
}
|
|
91
|
-
|
|
92
|
-
// Monthly reset
|
|
93
75
|
if (now.getMonth() !== lastCheck.getMonth()) {
|
|
94
|
-
accumulated.monthly = 0;
|
|
95
|
-
baseline.monthly = 0;
|
|
76
|
+
accumulated.monthly = 0; baseline.monthly = 0;
|
|
96
77
|
}
|
|
97
|
-
|
|
98
|
-
// Yearly reset
|
|
99
78
|
if (now.getFullYear() !== lastCheck.getFullYear()) {
|
|
100
79
|
archiveYearly(baseline.yearly + accumulated.yearly, lastCheck.getFullYear());
|
|
101
|
-
accumulated.yearly = 0;
|
|
102
|
-
baseline.yearly = 0;
|
|
80
|
+
accumulated.yearly = 0; baseline.yearly = 0;
|
|
103
81
|
}
|
|
104
82
|
|
|
105
83
|
lastCheck = now;
|
|
84
|
+
node.context().set("lastCheck", lastCheck);
|
|
106
85
|
node.context().set("accumulated", accumulated);
|
|
107
86
|
node.context().set("baseline", baseline);
|
|
108
|
-
node.context().set("lastCheck", lastCheck);
|
|
109
87
|
}
|
|
110
88
|
setInterval(checkRollover, 60000);
|
|
111
89
|
|
|
@@ -114,6 +92,16 @@ module.exports = function(RED) {
|
|
|
114
92
|
let now = new Date();
|
|
115
93
|
let durationHours = (now - lastCheck) / (1000 * 3600);
|
|
116
94
|
|
|
95
|
+
// Handle baseline updates
|
|
96
|
+
if (msg.topic === "applyBaseline" && msg.payload) {
|
|
97
|
+
baseline.daily += Number(msg.payload.daily) || 0;
|
|
98
|
+
baseline.weekly += Number(msg.payload.weekly) || 0;
|
|
99
|
+
baseline.monthly += Number(msg.payload.monthly) || 0;
|
|
100
|
+
baseline.yearly += Number(msg.payload.yearly) || 0;
|
|
101
|
+
node.context().set("baseline", baseline);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Handle power input
|
|
117
105
|
let power = Number(msg.payload);
|
|
118
106
|
if (!isNaN(power) && durationHours > 0) {
|
|
119
107
|
let power_kW = (inputUnit === "W") ? power / 1000 : power;
|
|
@@ -129,7 +117,6 @@ module.exports = function(RED) {
|
|
|
129
117
|
node.context().set("lastCheck", lastCheck);
|
|
130
118
|
node.context().set("accumulated", accumulated);
|
|
131
119
|
|
|
132
|
-
// Output = baseline + accumulated
|
|
133
120
|
msg.payload = {
|
|
134
121
|
energyDaily: round2(baseline.daily + accumulated.daily),
|
|
135
122
|
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.2",
|
|
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",
|