node-red-contrib-energymeterplus 0.0.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/Solar_Energy.png +0 -0
- package/energyMeterPlus.html +24 -0
- package/energyMeterPlus.js +101 -0
- package/package.json +12 -0
- package/smartmeter.png +0 -0
package/Solar_Energy.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('energyMeterPlus',{
|
|
3
|
+
category: 'function',
|
|
4
|
+
color: '#a6bbcf',
|
|
5
|
+
defaults: {
|
|
6
|
+
name: {value:""},
|
|
7
|
+
unitCost: {value:""},
|
|
8
|
+
filePath: {value:""},
|
|
9
|
+
baselineCorrection: {value:""}
|
|
10
|
+
},
|
|
11
|
+
inputs:1,
|
|
12
|
+
outputs:1,
|
|
13
|
+
icon:"energymeter.png",
|
|
14
|
+
label: function() {
|
|
15
|
+
return this.name||"energyMeterPlus";
|
|
16
|
+
},
|
|
17
|
+
oneditprepare: function() {
|
|
18
|
+
// Add labels to the fields
|
|
19
|
+
$("#node-input-unitCost").attr("placeholder","Enter cost per kWh");
|
|
20
|
+
$("#node-input-filePath").attr("placeholder","Path to JSON file (e.g. C:/Users/Francis/Documents/energy.json)");
|
|
21
|
+
$("#node-input-baselineCorrection").attr("placeholder","Baseline correction in JSON (e.g. {\"daily\":10,\"weekly\":50})");
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
|
|
3
|
+
module.exports = function(RED) {
|
|
4
|
+
function EnergyMeterPlus(config) {
|
|
5
|
+
RED.nodes.createNode(this, config);
|
|
6
|
+
var node = this;
|
|
7
|
+
|
|
8
|
+
let unitCost = Number(config.unitCost) || 0;
|
|
9
|
+
let filePath = config.filePath || "/addon_configs/a0d7b954_nodered/node_red/solarGen_data.json";
|
|
10
|
+
let baselineCorrection = config.baselineCorrection || "";
|
|
11
|
+
|
|
12
|
+
// Baseline counters
|
|
13
|
+
let baseline = { daily: 0, weekly: 0, monthly: 0, yearly: 0 };
|
|
14
|
+
let lastCheck = new Date();
|
|
15
|
+
|
|
16
|
+
// Apply correction if provided
|
|
17
|
+
if (baselineCorrection) {
|
|
18
|
+
try {
|
|
19
|
+
let correction = JSON.parse(baselineCorrection);
|
|
20
|
+
baseline = { ...baseline, ...correction };
|
|
21
|
+
} catch (err) {
|
|
22
|
+
node.error("Invalid baseline correction JSON");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Function to handle rollover
|
|
27
|
+
function checkRollover() {
|
|
28
|
+
let now = new Date();
|
|
29
|
+
|
|
30
|
+
// Daily rollover
|
|
31
|
+
if (now.getDate() !== lastCheck.getDate()) {
|
|
32
|
+
baseline.daily = 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Weekly rollover (Sunday = 0)
|
|
36
|
+
if (now.getDay() === 0 && lastCheck.getDay() !== 0) {
|
|
37
|
+
baseline.weekly = 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Monthly rollover
|
|
41
|
+
if (now.getMonth() !== lastCheck.getMonth()) {
|
|
42
|
+
baseline.monthly = 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Yearly rollover
|
|
46
|
+
if (now.getFullYear() !== lastCheck.getFullYear()) {
|
|
47
|
+
// Archive previous year
|
|
48
|
+
let archiveName = filePath.replace(".json", `_${lastCheck.getFullYear()}.json`);
|
|
49
|
+
try {
|
|
50
|
+
fs.writeFileSync(archiveName, JSON.stringify(baseline, null, 2));
|
|
51
|
+
} catch (err) {
|
|
52
|
+
node.error("Failed to archive yearly file: " + err);
|
|
53
|
+
}
|
|
54
|
+
baseline.yearly = 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
lastCheck = now;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Run rollover check every minute
|
|
61
|
+
setInterval(checkRollover, 60000);
|
|
62
|
+
|
|
63
|
+
node.on('input', function(msg) {
|
|
64
|
+
let power = Number(msg.payload) || 0;
|
|
65
|
+
|
|
66
|
+
// Add to counters
|
|
67
|
+
baseline.daily += power;
|
|
68
|
+
baseline.weekly += power;
|
|
69
|
+
baseline.monthly += power;
|
|
70
|
+
baseline.yearly += power;
|
|
71
|
+
|
|
72
|
+
// Calculate costs
|
|
73
|
+
let daily_cost = baseline.daily * unitCost;
|
|
74
|
+
let weekly_cost = baseline.weekly * unitCost;
|
|
75
|
+
let monthly_cost = baseline.monthly * unitCost;
|
|
76
|
+
let yearly_cost = baseline.yearly * unitCost;
|
|
77
|
+
|
|
78
|
+
// Build Output
|
|
79
|
+
msg.payload = {
|
|
80
|
+
daily_kWh: baseline.daily,
|
|
81
|
+
weekly_kWh: baseline.weekly,
|
|
82
|
+
monthly_kWh: baseline.monthly,
|
|
83
|
+
yearly_kWh: baseline.yearly,
|
|
84
|
+
daily_cost,
|
|
85
|
+
weekly_cost,
|
|
86
|
+
monthly_cost,
|
|
87
|
+
yearly_cost
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Save snapshot
|
|
91
|
+
try {
|
|
92
|
+
fs.writeFileSync(filePath, JSON.stringify(msg.payload, null, 2));
|
|
93
|
+
} catch (err) {
|
|
94
|
+
node.error("Failed to write to file: " + err);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
node.send(msg);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
RED.nodes.registerType("energyMeterPlus", EnergyMeterPlus);
|
|
101
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "node-red-contrib-energymeterplus",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Custom energy meter node with baseline correction and cost calculation",
|
|
5
|
+
"author": "Arcfrankye",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"node-red": {
|
|
8
|
+
"nodes": {
|
|
9
|
+
"energyMeterPlus": "energyMeterPlus.js"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
package/smartmeter.png
ADDED
|
Binary file
|