@bldgblocks/node-red-contrib-control 0.1.4
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 +43 -0
- package/nodes/accumulate-block.html +71 -0
- package/nodes/accumulate-block.js +104 -0
- package/nodes/add-block.html +67 -0
- package/nodes/add-block.js +97 -0
- package/nodes/analog-switch-block.html +65 -0
- package/nodes/analog-switch-block.js +129 -0
- package/nodes/and-block.html +64 -0
- package/nodes/and-block.js +73 -0
- package/nodes/average-block.html +97 -0
- package/nodes/average-block.js +137 -0
- package/nodes/boolean-switch-block.html +59 -0
- package/nodes/boolean-switch-block.js +88 -0
- package/nodes/boolean-to-number-block.html +59 -0
- package/nodes/boolean-to-number-block.js +45 -0
- package/nodes/cache-block.html +69 -0
- package/nodes/cache-block.js +106 -0
- package/nodes/call-status-block.html +111 -0
- package/nodes/call-status-block.js +274 -0
- package/nodes/changeover-block.html +234 -0
- package/nodes/changeover-block.js +392 -0
- package/nodes/comment-block.html +83 -0
- package/nodes/comment-block.js +53 -0
- package/nodes/compare-block.html +64 -0
- package/nodes/compare-block.js +84 -0
- package/nodes/contextual-label-block.html +67 -0
- package/nodes/contextual-label-block.js +52 -0
- package/nodes/convert-block.html +179 -0
- package/nodes/convert-block.js +289 -0
- package/nodes/count-block.html +57 -0
- package/nodes/count-block.js +92 -0
- package/nodes/debounce-block.html +64 -0
- package/nodes/debounce-block.js +140 -0
- package/nodes/delay-block.html +104 -0
- package/nodes/delay-block.js +180 -0
- package/nodes/divide-block.html +65 -0
- package/nodes/divide-block.js +123 -0
- package/nodes/edge-block.html +71 -0
- package/nodes/edge-block.js +120 -0
- package/nodes/frequency-block.html +55 -0
- package/nodes/frequency-block.js +140 -0
- package/nodes/hysteresis-block.html +131 -0
- package/nodes/hysteresis-block.js +142 -0
- package/nodes/interpolate-block.html +74 -0
- package/nodes/interpolate-block.js +141 -0
- package/nodes/load-sequence-block.html +134 -0
- package/nodes/load-sequence-block.js +272 -0
- package/nodes/max-block.html +76 -0
- package/nodes/max-block.js +103 -0
- package/nodes/memory-block.html +90 -0
- package/nodes/memory-block.js +241 -0
- package/nodes/min-block.html +77 -0
- package/nodes/min-block.js +106 -0
- package/nodes/minmax-block.html +89 -0
- package/nodes/minmax-block.js +119 -0
- package/nodes/modulo-block.html +73 -0
- package/nodes/modulo-block.js +126 -0
- package/nodes/multiply-block.html +63 -0
- package/nodes/multiply-block.js +115 -0
- package/nodes/negate-block.html +55 -0
- package/nodes/negate-block.js +91 -0
- package/nodes/nullify-block.html +111 -0
- package/nodes/nullify-block.js +78 -0
- package/nodes/on-change-block.html +79 -0
- package/nodes/on-change-block.js +191 -0
- package/nodes/oneshot-block.html +96 -0
- package/nodes/oneshot-block.js +169 -0
- package/nodes/or-block.html +64 -0
- package/nodes/or-block.js +73 -0
- package/nodes/pid-block.html +205 -0
- package/nodes/pid-block.js +407 -0
- package/nodes/priority-block.html +66 -0
- package/nodes/priority-block.js +239 -0
- package/nodes/rate-limit-block.html +99 -0
- package/nodes/rate-limit-block.js +221 -0
- package/nodes/round-block.html +73 -0
- package/nodes/round-block.js +89 -0
- package/nodes/saw-tooth-wave-block.html +87 -0
- package/nodes/saw-tooth-wave-block.js +161 -0
- package/nodes/scale-range-block.html +90 -0
- package/nodes/scale-range-block.js +137 -0
- package/nodes/sine-wave-block.html +88 -0
- package/nodes/sine-wave-block.js +142 -0
- package/nodes/subtract-block.html +64 -0
- package/nodes/subtract-block.js +103 -0
- package/nodes/thermistor-block.html +81 -0
- package/nodes/thermistor-block.js +146 -0
- package/nodes/tick-tock-block.html +66 -0
- package/nodes/tick-tock-block.js +110 -0
- package/nodes/time-sequence-block.html +67 -0
- package/nodes/time-sequence-block.js +144 -0
- package/nodes/triangle-wave-block.html +86 -0
- package/nodes/triangle-wave-block.js +154 -0
- package/nodes/tstat-block.html +311 -0
- package/nodes/tstat-block.js +499 -0
- package/nodes/units-block.html +150 -0
- package/nodes/units-block.js +106 -0
- package/package.json +73 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
<script type="text/html" data-template-name="tstat-block">
|
|
2
|
+
<style>
|
|
3
|
+
.input-error {
|
|
4
|
+
border: 2px solid red !important;
|
|
5
|
+
background-color: #ffe6e6 !important;
|
|
6
|
+
}
|
|
7
|
+
</style>
|
|
8
|
+
<div class="form-row">
|
|
9
|
+
<label for="node-input-name" title="Display name shown on the canvas"><i class="fa fa-tag"></i> Name</label>
|
|
10
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
11
|
+
</div>
|
|
12
|
+
<div class="form-row">
|
|
13
|
+
<label for="node-input-algorithm" title="Algorithm: single setpoint with diff, split setpoints, or specified setpoints"><i class="fa fa-cog"></i> Algorithm</label>
|
|
14
|
+
<select id="node-input-algorithm">
|
|
15
|
+
<option value="single">Single Setpoint</option>
|
|
16
|
+
<option value="split">Split Setpoint</option>
|
|
17
|
+
<option value="specified">Specified Setpoint</option>
|
|
18
|
+
</select>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="form-row single-setpoint">
|
|
21
|
+
<label for="node-input-setpoint" title="Target temperature setpoint (number from num, msg, flow, or global)"><i class="fa fa-crosshairs"></i> Setpoint</label>
|
|
22
|
+
<input type="text" id="node-input-setpoint" laceholder="70">
|
|
23
|
+
<input type="hidden" id="node-input-setpointType">
|
|
24
|
+
</div>
|
|
25
|
+
<div class="form-row split-setpoint" style="display: none;">
|
|
26
|
+
<label for="node-input-heatingSetpoint" title="Target temperature for heating (number from num, msg, flow, or global)"><i class="fa fa-crosshairs"></i> Heating Setpoint</label>
|
|
27
|
+
<input type="text" id="node-input-heatingSetpoint" placeholder="68">
|
|
28
|
+
<input type="hidden" id="node-input-heatingSetpointType">
|
|
29
|
+
</div>
|
|
30
|
+
<div class="form-row split-setpoint" style="display: none;">
|
|
31
|
+
<label for="node-input-coolingSetpoint" title="Target temperature for cooling (number from num, msg, flow, or global)"><i class="fa fa-crosshairs"></i> Cooling Setpoint</label>
|
|
32
|
+
<input type="text" id="node-input-coolingSetpoint" placeholder="74">
|
|
33
|
+
<input type="hidden" id="node-input-coolingSetpointType">
|
|
34
|
+
</div>
|
|
35
|
+
<div class="form-row split-setpoint" style="display: none;">
|
|
36
|
+
<div id="split-setpoint-warning" style="color: red; display: none; margin-top: 5px;">
|
|
37
|
+
Cooling setpoint must be greater than heating setpoint
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="form-row specified-setpoint" style="display: none;">
|
|
41
|
+
<label for="node-input-coolingOn" title="Temperature to turn cooling on (number from num, msg, flow, or global)"><i class="fa fa-snowflake-o"></i> Cooling On</label>
|
|
42
|
+
<input type="text" id="node-input-coolingOn" placeholder="74">
|
|
43
|
+
<input type="hidden" id="node-input-coolingOnType">
|
|
44
|
+
</div>
|
|
45
|
+
<div class="form-row specified-setpoint" style="display: none;">
|
|
46
|
+
<label for="node-input-coolingOff" title="Temperature to turn cooling off (number from num, msg, flow, or global)"><i class="fa fa-snowflake-o"></i> Cooling Off</label>
|
|
47
|
+
<input type="text" id="node-input-coolingOff" placeholder="72">
|
|
48
|
+
<input type="hidden" id="node-input-coolingOffType">
|
|
49
|
+
</div>
|
|
50
|
+
<div class="form-row specified-setpoint" style="display: none;">
|
|
51
|
+
<label for="node-input-heatingOff" title="Temperature to turn heating off (number from num, msg, flow, or global)"><i class="fa fa-fire"></i> Heating Off</label>
|
|
52
|
+
<input type="text" id="node-input-heatingOff" placeholder="68">
|
|
53
|
+
<input type="hidden" id="node-input-heatingOffType">
|
|
54
|
+
</div>
|
|
55
|
+
<div class="form-row specified-setpoint" style="display: none;">
|
|
56
|
+
<label for="node-input-heatingOn" title="Temperature to turn heating on (number from num, msg, flow, or global)"><i class="fa fa-fire"></i> Heating On</label>
|
|
57
|
+
<input type="text" id="node-input-heatingOn" placeholder="66">
|
|
58
|
+
<input type="hidden" id="node-input-heatingOnType">
|
|
59
|
+
</div>
|
|
60
|
+
<div class="form-row specified-setpoint" style="display: none;">
|
|
61
|
+
<div id="specified-setpoint-warning" style="color: red; display: none; margin-top: 5px;">
|
|
62
|
+
Cooling setpoints must be greater than or equal to heating setpoints (coolingOn >= coolingOff >= heatingOff >= heatingOn)
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="form-row single-setpoint">
|
|
66
|
+
<label for="node-input-diff" title="Differential for hysteresis (positive number, used in single algorithm)"><i class="fa fa-arrows-v"></i> Differential</label>
|
|
67
|
+
<input type="text" id="node-input-diff" placeholder="2">
|
|
68
|
+
<input type="hidden" id="node-input-diffType">
|
|
69
|
+
</div>
|
|
70
|
+
<div class="form-row">
|
|
71
|
+
<label for="node-input-anticipator" title="Temperature offset to stop heating/cooling early (non-negative number from num, msg, flow, or global)"><i class="fa fa-tachometer"></i> Anticipator</label>
|
|
72
|
+
<input type="text" id="node-input-anticipator" placeholder="0.5">
|
|
73
|
+
<input type="hidden" id="node-input-anticipatorType">
|
|
74
|
+
</div>
|
|
75
|
+
<div class="form-row">
|
|
76
|
+
<label for="node-input-ignoreAnticipatorCycles" title="Number of cycles to ignore anticipator after mode change (non-negative integer from num, msg, flow, or global)"><i class="fa fa-repeat"></i> Ignore Anticipator Cycles</label>
|
|
77
|
+
<input type="text" id="node-input-ignoreAnticipatorCycles" placeholder="1">
|
|
78
|
+
<input type="hidden" id="node-input-ignoreAnticipatorCyclesType">
|
|
79
|
+
</div>
|
|
80
|
+
<div class="form-row">
|
|
81
|
+
<label for="node-input-isHeating" title="Heating mode (true) or cooling mode (false)"><i class="fa fa-fire"></i> Heating Mode</label>
|
|
82
|
+
<input type="checkbox" id="node-input-isHeating" style="width: auto; vertical-align: middle;">
|
|
83
|
+
</div>
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<script type="text/javascript">
|
|
87
|
+
RED.nodes.registerType("tstat-block", {
|
|
88
|
+
category: "control",
|
|
89
|
+
color: "#301934",
|
|
90
|
+
defaults: {
|
|
91
|
+
name: { value: "" },
|
|
92
|
+
algorithm: { value: "single" },
|
|
93
|
+
setpoint: { value: "70" },
|
|
94
|
+
setpointType: { value: "num" },
|
|
95
|
+
heatingSetpoint: { value: "68" },
|
|
96
|
+
heatingSetpointType: { value: "num" },
|
|
97
|
+
coolingSetpoint: { value: "74" },
|
|
98
|
+
coolingSetpointType: { value: "num" },
|
|
99
|
+
coolingOn: { value: "74" },
|
|
100
|
+
coolingOnType: { value: "num" },
|
|
101
|
+
coolingOff: { value: "72" },
|
|
102
|
+
coolingOffType: { value: "num" },
|
|
103
|
+
heatingOff: { value: "68" },
|
|
104
|
+
heatingOffType: { value: "num" },
|
|
105
|
+
heatingOn: { value: "66" },
|
|
106
|
+
heatingOnType: { value: "num" },
|
|
107
|
+
diff: { value: "2" },
|
|
108
|
+
diffType: { value: "num" },
|
|
109
|
+
anticipator: { value: "0.5" },
|
|
110
|
+
anticipatorType: { value: "num" },
|
|
111
|
+
ignoreAnticipatorCycles: { value: "1" },
|
|
112
|
+
ignoreAnticipatorCyclesType: { value: "num" },
|
|
113
|
+
isHeating: { value: false }
|
|
114
|
+
},
|
|
115
|
+
inputs: 1,
|
|
116
|
+
outputs: 3,
|
|
117
|
+
outputLabels: ["isHeating", "above", "below"],
|
|
118
|
+
inputLabels: ["input"],
|
|
119
|
+
icon: "font-awesome/fa-thermometer-half",
|
|
120
|
+
paletteLabel: "tstat",
|
|
121
|
+
label: function() {
|
|
122
|
+
return this.name || "tstat";
|
|
123
|
+
},
|
|
124
|
+
oneditprepare: function() {
|
|
125
|
+
const node = this;
|
|
126
|
+
try {
|
|
127
|
+
const $algorithm = $("#node-input-algorithm");
|
|
128
|
+
const $singleFields = $(".single-setpoint");
|
|
129
|
+
const $splitFields = $(".split-setpoint");
|
|
130
|
+
const $specifiedFields = $(".specified-setpoint");
|
|
131
|
+
|
|
132
|
+
$("#node-input-name").val(node.name || "");
|
|
133
|
+
$("#node-input-algorithm").val(node.algorithm || "single");
|
|
134
|
+
$("#node-input-isHeating").prop("checked", node.isHeating === true);
|
|
135
|
+
|
|
136
|
+
const typedInputs = [
|
|
137
|
+
{ id: "node-input-setpoint", typeId: "node-input-setpointType", defaultValue: "70", defaultType: "num" },
|
|
138
|
+
{ id: "node-input-heatingSetpoint", typeId: "node-input-heatingSetpointType", defaultValue: "68", defaultType: "num" },
|
|
139
|
+
{ id: "node-input-coolingSetpoint", typeId: "node-input-coolingSetpointType", defaultValue: "74", defaultType: "num" },
|
|
140
|
+
{ id: "node-input-coolingOn", typeId: "node-input-coolingOnType", defaultValue: "74", defaultType: "num" },
|
|
141
|
+
{ id: "node-input-coolingOff", typeId: "node-input-coolingOffType", defaultValue: "72", defaultType: "num" },
|
|
142
|
+
{ id: "node-input-heatingOff", typeId: "node-input-heatingOffType", defaultValue: "68", defaultType: "num" },
|
|
143
|
+
{ id: "node-input-heatingOn", typeId: "node-input-heatingOnType", defaultValue: "66", defaultType: "num" },
|
|
144
|
+
{ id: "node-input-diff", typeId: "node-input-diffType", defaultValue: "2", defaultType: "num" },
|
|
145
|
+
{ id: "node-input-anticipator", typeId: "node-input-anticipatorType", defaultValue: "0.5", defaultType: "num" },
|
|
146
|
+
{ id: "node-input-ignoreAnticipatorCycles", typeId: "node-input-ignoreAnticipatorCyclesType", defaultValue: "1", defaultType: "num" }
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
typedInputs.forEach(input => {
|
|
150
|
+
try {
|
|
151
|
+
const fieldName = input.id.replace("node-input-", "");
|
|
152
|
+
const storedValue = node[fieldName] !== undefined ? node[fieldName] : input.defaultValue;
|
|
153
|
+
const storedType = node[`${fieldName}Type`] || input.defaultType;
|
|
154
|
+
|
|
155
|
+
$(`#${input.id}`).typedInput({
|
|
156
|
+
default: input.defaultType,
|
|
157
|
+
types: ["num", "msg", "flow", "global"],
|
|
158
|
+
typeField: `#${input.typeId}`
|
|
159
|
+
}).typedInput("type", storedType)
|
|
160
|
+
.typedInput("value", storedValue);
|
|
161
|
+
} catch (err) {
|
|
162
|
+
console.error(`Error initializing typedInput for ${input.id}:`, err);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
function toggleFields() {
|
|
168
|
+
const algorithm = $algorithm.val();
|
|
169
|
+
if (algorithm === "single") {
|
|
170
|
+
$singleFields.show();
|
|
171
|
+
$splitFields.hide();
|
|
172
|
+
$specifiedFields.hide();
|
|
173
|
+
$("#split-setpoint-warning").hide();
|
|
174
|
+
$("#specified-setpoint-warning").hide();
|
|
175
|
+
$("#node-input-heatingSetpoint").removeClass("input-error");
|
|
176
|
+
$("#node-input-coolingSetpoint").removeClass("input-error");
|
|
177
|
+
$("#node-input-coolingOn").removeClass("input-error");
|
|
178
|
+
$("#node-input-coolingOff").removeClass("input-error");
|
|
179
|
+
$("#node-input-heatingOff").removeClass("input-error");
|
|
180
|
+
$("#node-input-heatingOn").removeClass("input-error");
|
|
181
|
+
} else if (algorithm === "split") {
|
|
182
|
+
$singleFields.hide();
|
|
183
|
+
$splitFields.show();
|
|
184
|
+
$specifiedFields.hide();
|
|
185
|
+
$("#specified-setpoint-warning").hide();
|
|
186
|
+
$("#node-input-coolingOn").removeClass("input-error");
|
|
187
|
+
$("#node-input-coolingOff").removeClass("input-error");
|
|
188
|
+
$("#node-input-heatingOff").removeClass("input-error");
|
|
189
|
+
$("#node-input-heatingOn").removeClass("input-error");
|
|
190
|
+
validateSplitSetpoints();
|
|
191
|
+
} else {
|
|
192
|
+
$singleFields.hide();
|
|
193
|
+
$splitFields.hide();
|
|
194
|
+
$specifiedFields.show();
|
|
195
|
+
$("#split-setpoint-warning").hide();
|
|
196
|
+
$("#node-input-heatingSetpoint").removeClass("input-error");
|
|
197
|
+
$("#node-input-coolingSetpoint").removeClass("input-error");
|
|
198
|
+
validateSpecifiedSetpoints();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
$algorithm.on("change", function() {
|
|
203
|
+
toggleFields();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
toggleFields();
|
|
207
|
+
} catch (err) {
|
|
208
|
+
console.error("Error in tstat-block oneditprepare:", err.message, err.stack);
|
|
209
|
+
$("#node-runtime-changes").text("Effective Setpoints: Error initializing UI - check browser console");
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
oneditsave: function() {
|
|
213
|
+
// Standard config properties are automatically saved by Node-RED
|
|
214
|
+
},
|
|
215
|
+
oneditvalidate: function() {
|
|
216
|
+
return validateInputs();
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
</script>
|
|
220
|
+
|
|
221
|
+
<script type="text/markdown" data-help-name="tstat-block">
|
|
222
|
+
Thermostat controller for heating/cooling with single, split, or specified setpoint operation, hysteresis, and anticipation to prevent or allow overshoot for testing.
|
|
223
|
+
|
|
224
|
+
### Inputs
|
|
225
|
+
: context (string) : Configures node (`"algorithm"`, `"setpoint"`, `"heatingSetpoint"`, `"coolingSetpoint"`, `"coolingOn"`, `"coolingOff"`, `"heatingOff"`, `"heatingOn"`, `"diff"`, `"anticipator"`, `"ignoreAnticipatorCycles"`, `"isHeating"`, `"status"`).
|
|
226
|
+
: payload (number | boolean | string) : Number for temperature or config values, boolean for `isHeating`, string for `algorithm` (`"single"`, `"split"`, `"specified"`).
|
|
227
|
+
|
|
228
|
+
### Outputs
|
|
229
|
+
All output messages include a `msg.status` object containing runtime information
|
|
230
|
+
: isHeating (boolean) : `true` for heating mode, `false` for cooling mode. Includes `msg.context = "isHeating"`.
|
|
231
|
+
: above (boolean) : `true` if input exceeds cooling on threshold.
|
|
232
|
+
: below (boolean) : `true` if input is below heating on threshold.
|
|
233
|
+
: status (object) : Contains detailed runtime information including
|
|
234
|
+
- `algorithm` Current algorithm in use
|
|
235
|
+
- `input` Current temperature input value
|
|
236
|
+
- `isHeating` Current heating mode
|
|
237
|
+
- `above/below` Current output states
|
|
238
|
+
- Algorithm-specific setpoints and values
|
|
239
|
+
- `modeChanged` If mode recently changed
|
|
240
|
+
- `cyclesSinceModeChange` Count since last mode change
|
|
241
|
+
- `effectiveAnticipator` Current anticipator value after mode change adjustments
|
|
242
|
+
|
|
243
|
+
### Status Monitoring
|
|
244
|
+
Instead of a dedicated status output, all outputs include comprehensive status information
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"status": {
|
|
248
|
+
"algorithm": "single",
|
|
249
|
+
"input": 68.5,
|
|
250
|
+
"isHeating": true,
|
|
251
|
+
"above": false,
|
|
252
|
+
"below": true,
|
|
253
|
+
"setpoint": 70,
|
|
254
|
+
"diff": 2,
|
|
255
|
+
"anticipator": 0.5,
|
|
256
|
+
"modeChanged": false,
|
|
257
|
+
"cyclesSinceModeChange": 3,
|
|
258
|
+
"effectiveAnticipator": 0.5
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Algorithms
|
|
264
|
+
- Single Setpoint
|
|
265
|
+
- Uses `setpoint`, `diff`, and `anticipator`.
|
|
266
|
+
- Sets `above` if `input > setpoint + diff/2`, clears when `input < setpoint + anticipator`.
|
|
267
|
+
- Sets `below` if `input < setpoint - diff/2`, clears when `input > setpoint - anticipator`.
|
|
268
|
+
- For positive `anticipator`, stops early to prevent overshoot. For negative `anticipator`, delays turn-off to overshoot setpoint, lengthen runtime, or straddle setpoint.
|
|
269
|
+
|
|
270
|
+
- Split Setpoint
|
|
271
|
+
- Uses `heatingSetpoint`, `coolingSetpoint`, `diff`, and `anticipator`.
|
|
272
|
+
- For `isHeating = true`
|
|
273
|
+
- Sets `below` if `input < heatingSetpoint - diff/2`, clears when `input > heatingSetpoint - anticipator`.
|
|
274
|
+
- `above` is `false`.
|
|
275
|
+
- For `isHeating = false`
|
|
276
|
+
- Sets `above` if `input > coolingSetpoint + diff/2`, clears when `input < coolingSetpoint + anticipator`.
|
|
277
|
+
- `below` is `false`.
|
|
278
|
+
- Ensures `heatingSetpoint < coolingSetpoint`.
|
|
279
|
+
|
|
280
|
+
- Specified Setpoint
|
|
281
|
+
- Uses `coolingOn`, `coolingOff`, `heatingOff`, `heatingOn`, and `anticipator`.
|
|
282
|
+
- For `isHeating = false`
|
|
283
|
+
- Sets `above` if `input > coolingOn`, clears when `input < coolingOff + anticipator`.
|
|
284
|
+
- `below` is `false`.
|
|
285
|
+
- For `isHeating = true`
|
|
286
|
+
- Sets `below` if `input < heatingOn`, clears when `input > heatingOff - anticipator`.
|
|
287
|
+
- `above` is `false`.
|
|
288
|
+
- Validates `coolingOn >= coolingOff >= heatingOff >= heatingOn`.
|
|
289
|
+
|
|
290
|
+
### Details
|
|
291
|
+
Compares a numeric temperature input (`msg.payload`) against setpoints to control heating or cooling.
|
|
292
|
+
|
|
293
|
+
The `differential` (`diff`) applies to the `single` and `split` setpoint algorithms, providing hysteresis.
|
|
294
|
+
|
|
295
|
+
The `anticipator` adjusts turn-off points. Positive values stop early to prevent overshoot (subtracts for heating, adds for cooling);
|
|
296
|
+
|
|
297
|
+
The `isHeating` flag (typically from a changeover node) sets output 1 and selects the active setpoint(s).
|
|
298
|
+
|
|
299
|
+
The `ignoreAnticipatorCycles` setting allows ignoring the anticipator for a specified number of cycles after a mode change to reduce short-cycling due to latent heat effects.
|
|
300
|
+
|
|
301
|
+
### Status
|
|
302
|
+
- Green (dot): Configuration update
|
|
303
|
+
- Blue (dot): State changed
|
|
304
|
+
- Blue (ring): State unchanged
|
|
305
|
+
- Red (ring): Error
|
|
306
|
+
- Yellow (ring): Warning
|
|
307
|
+
|
|
308
|
+
### References
|
|
309
|
+
- [Node-RED Documentation](https://nodered.org/docs/)
|
|
310
|
+
- [GitHub Repository](https://github.com/BldgBlocks/node-red-contrib-buildingblocks-control.git)
|
|
311
|
+
</script>
|