node-red-contrib-power-genius 0.1.0 → 1.0.0
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/GeniusPGProtocol.js +135 -135
- package/LICENSE +21 -21
- package/README.md +106 -107
- package/examples/power-genius-example.json +238 -238
- package/package.json +61 -59
- package/power-genius-control.html +69 -69
- package/power-genius-control.js +94 -94
- package/power-genius-info.html +105 -105
- package/power-genius-info.js +63 -63
- package/power-genius-server.html +54 -54
- package/power-genius-server.js +216 -216
- package/power-genius-status.html +170 -170
- package/power-genius-status.js +96 -96
package/power-genius-status.html
CHANGED
|
@@ -1,170 +1,170 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
RED.nodes.registerType("power-genius-status", {
|
|
3
|
-
category: "Power Genius",
|
|
4
|
-
color: "#a6bbcf",
|
|
5
|
-
defaults: {
|
|
6
|
-
name: { value: "" },
|
|
7
|
-
server: { type: "power-genius-server", required: true },
|
|
8
|
-
property: { value: "*" },
|
|
9
|
-
onlyChange: { value: true },
|
|
10
|
-
deadband: { value: 0, validate: function (v) { return v === "" || v === undefined || (!isNaN(v) && Number(v) >= 0); } },
|
|
11
|
-
startDelay: { value: 1000, validate: function (v) { return v === "" || v === undefined || (!isNaN(v) && Number(v) >= 0); } },
|
|
12
|
-
},
|
|
13
|
-
inputs: 1,
|
|
14
|
-
outputs: 1,
|
|
15
|
-
icon: "bridge.svg",
|
|
16
|
-
label: function () {
|
|
17
|
-
if (this.name) return this.name;
|
|
18
|
-
return this.property && this.property !== "*" ? "pg " + this.property : "pg status";
|
|
19
|
-
},
|
|
20
|
-
oneditprepare: function () {
|
|
21
|
-
const select = $("#node-input-property-select");
|
|
22
|
-
const input = $("#node-input-property");
|
|
23
|
-
const known = select.find("option").map(function () { return this.value; }).get();
|
|
24
|
-
const current = input.val() || "*";
|
|
25
|
-
select.val(known.includes(current) ? current : "__custom__");
|
|
26
|
-
const sync = () => {
|
|
27
|
-
if (select.val() !== "__custom__") input.val(select.val());
|
|
28
|
-
input.toggle(select.val() === "__custom__");
|
|
29
|
-
const p = input.val();
|
|
30
|
-
$("#node-input-deadband-row").toggle(p !== "*" && p !== "");
|
|
31
|
-
};
|
|
32
|
-
select.on("change", sync);
|
|
33
|
-
input.on("input change", sync);
|
|
34
|
-
sync();
|
|
35
|
-
},
|
|
36
|
-
oneditsave: function () {
|
|
37
|
-
if (!$("#node-input-property").val().trim()) $("#node-input-property").val("*");
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
</script>
|
|
41
|
-
|
|
42
|
-
<script type="text/html" data-template-name="power-genius-status">
|
|
43
|
-
<div class="form-row">
|
|
44
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
45
|
-
<input type="text" id="node-input-name" />
|
|
46
|
-
</div>
|
|
47
|
-
<div class="form-row">
|
|
48
|
-
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
|
49
|
-
<input type="text" id="node-input-server" />
|
|
50
|
-
</div>
|
|
51
|
-
<div class="form-row">
|
|
52
|
-
<label for="node-input-property-select"><i class="fa fa-filter"></i> Property</label>
|
|
53
|
-
<select id="node-input-property-select" style="width:70%">
|
|
54
|
-
<option value="*">(all, as an object)</option>
|
|
55
|
-
<optgroup label="Device">
|
|
56
|
-
<option value="state">state</option>
|
|
57
|
-
<option value="fanmode">fanmode</option>
|
|
58
|
-
<option value="meffa">meffa</option>
|
|
59
|
-
<option value="unkey">unkey</option>
|
|
60
|
-
</optgroup>
|
|
61
|
-
<optgroup label="Power">
|
|
62
|
-
<option value="fwd">fwd</option>
|
|
63
|
-
<option value="peakfwd">peakfwd</option>
|
|
64
|
-
<option value="swr">swr</option>
|
|
65
|
-
<option value="vac">vac</option>
|
|
66
|
-
<option value="vdd">vdd</option>
|
|
67
|
-
<option value="id">id</option>
|
|
68
|
-
<option value="peakid">peakid</option>
|
|
69
|
-
<option value="temp">temp</option>
|
|
70
|
-
<option value="hltemp">hltemp</option>
|
|
71
|
-
</optgroup>
|
|
72
|
-
<optgroup label="Band and radio">
|
|
73
|
-
<option value="bandA">bandA</option>
|
|
74
|
-
<option value="bandB">bandB</option>
|
|
75
|
-
<option value="bsrcA">bsrcA</option>
|
|
76
|
-
<option value="bsrcB">bsrcB</option>
|
|
77
|
-
<option value="bsrcAutoA">bsrcAutoA</option>
|
|
78
|
-
<option value="bsrcAutoB">bsrcAutoB</option>
|
|
79
|
-
<option value="flexA">flexA</option>
|
|
80
|
-
<option value="flexB">flexB</option>
|
|
81
|
-
<option value="cntfreq">cntfreq</option>
|
|
82
|
-
<option value="cat1freq">cat1freq</option>
|
|
83
|
-
<option value="cat2freq">cat2freq</option>
|
|
84
|
-
<option value="biasA">biasA</option>
|
|
85
|
-
<option value="biasB">biasB</option>
|
|
86
|
-
</optgroup>
|
|
87
|
-
<optgroup label="Antenna switch">
|
|
88
|
-
<option value="antA">antA</option>
|
|
89
|
-
<option value="ants">ants</option>
|
|
90
|
-
</optgroup>
|
|
91
|
-
<option value="__custom__">other (type the name)...</option>
|
|
92
|
-
</select>
|
|
93
|
-
<input type="text" id="node-input-property" style="display:none; margin-top:5px; width:70%; margin-left:105px" />
|
|
94
|
-
</div>
|
|
95
|
-
<div class="form-row">
|
|
96
|
-
<label for="node-input-onlyChange"> </label>
|
|
97
|
-
<input type="checkbox" id="node-input-onlyChange" style="display:inline-block; width:auto; vertical-align:top;" />
|
|
98
|
-
<label for="node-input-onlyChange" style="width:70%">Only emit when the value changes</label>
|
|
99
|
-
</div>
|
|
100
|
-
<div class="form-row" id="node-input-deadband-row">
|
|
101
|
-
<label for="node-input-deadband"><i class="fa fa-arrows-v"></i> Deadband</label>
|
|
102
|
-
<input type="number" id="node-input-deadband" min="0" step="any" style="width:100px" />
|
|
103
|
-
<span style="margin-left:5px">numeric values: ignore smaller changes (0 = off)</span>
|
|
104
|
-
</div>
|
|
105
|
-
<div class="form-row">
|
|
106
|
-
<label for="node-input-startDelay"><i class="fa fa-hourglass-start"></i> Start delay</label>
|
|
107
|
-
<input type="number" id="node-input-startDelay" min="0" step="100" style="width:100px" />
|
|
108
|
-
<span style="margin-left:5px">ms before the first output after deploy</span>
|
|
109
|
-
</div>
|
|
110
|
-
</script>
|
|
111
|
-
|
|
112
|
-
<script type="text/markdown" data-help-name="power-genius-status">
|
|
113
|
-
Emits one Power Genius XL status property, or the whole status, when it changes.
|
|
114
|
-
|
|
115
|
-
Use one node per property you care about, for example `fwd`, `swr` or `state`. Choose *other* in the list to type
|
|
116
|
-
the name of any property the amplifier reports; leave it as *(all)* to get the whole object.
|
|
117
|
-
|
|
118
|
-
### Input
|
|
119
|
-
|
|
120
|
-
Any message emits the last known value, even if unchanged, and refreshes the status from the device.
|
|
121
|
-
|
|
122
|
-
### Output
|
|
123
|
-
|
|
124
|
-
: payload (number | string | object) : The value of the selected property, or the whole status object when `*` is selected.
|
|
125
|
-
: topic (string) : The property name, or `status` when `*` is selected.
|
|
126
|
-
: previous (number | string) : The previously emitted value (single property only; undefined for the first message).
|
|
127
|
-
|
|
128
|
-
### Properties
|
|
129
|
-
|
|
130
|
-
The `status` reply is a list of `key=value` pairs. Numeric values are emitted as numbers, everything else as text.
|
|
131
|
-
|
|
132
|
-
| Property | Meaning | Values / unit |
|
|
133
|
-
|---|---|---|
|
|
134
|
-
| `state` | Amplifier state | `STANDBY`, `IDLE` (operate, not transmitting), `TRANSMIT_A`, `TRANSMIT_B`; probably `FAULT` |
|
|
135
|
-
| `bandA`, `bandB` | Band of slice A / B | metres, e.g. `20` |
|
|
136
|
-
| `bsrcA`, `bsrcB` | Source of the band data | e.g. `FLEX` |
|
|
137
|
-
| `bsrcAutoA`, `bsrcAutoB` | Band source selected automatically | 1 = yes, 0 = no |
|
|
138
|
-
| `flexA`, `flexB` | FlexRadio nickname (FLEX mode) | text |
|
|
139
|
-
| `vac` | Mains voltage | V |
|
|
140
|
-
| `vdd` | Supply voltage | V; 0 when not transmitting |
|
|
141
|
-
| `id`, `peakid` | Drain current, and its peak | A; 0 when not transmitting |
|
|
142
|
-
| `fwd`, `peakfwd` | Forward power, and its peak | dBm; `fwd` is 30 (the meter minimum) when there is no RF, `peakfwd` keeps the last peak |
|
|
143
|
-
| `swr` | Return loss | dB (negative, e.g. -18; the FLEX `RL` meter); -60 when there is no RF |
|
|
144
|
-
| `temp` | PA temperature | °C |
|
|
145
|
-
| `hltemp` | Harmonic load temperature | °C |
|
|
146
|
-
| `cntfreq` | Frequency counted from the RF | kHz, e.g. 14098; 0 when there is no RF |
|
|
147
|
-
| `cat1freq`, `cat2freq` | Frequency from CAT port 1 / 2 (legacy radios with CAT or CI-V) | kHz; 0 in FLEX mode |
|
|
148
|
-
| `biasA`, `biasB` | Bias setting of input A / B, as `SOURCE_MODE` | e.g. `RADIO_AB`; others seen elsewhere: `AUTO_AAB`, `MANUAL_A` |
|
|
149
|
-
| `fanmode` | Fan mode | `STANDARD`, `CONTEST`, `BROADCAST` |
|
|
150
|
-
| `meffa` | MeFFA state | `OFF`, `ACTIVE`; may name a fault such as SWR, TEMP or CURRENT |
|
|
151
|
-
| `unkey` | Protection fault | 1 = active protection fault, 0 = normal operation |
|
|
152
|
-
| `antA` | Antenna selected on the antenna switch | Only on the 3-port antenna switch version; 0 on the SO2R version, which has no switch |
|
|
153
|
-
| `ants` | Antenna switch | 0 on the SO2R version (no antenna switch); values on the antenna switch version not seen yet |
|
|
154
|
-
|
|
155
|
-
Many status properties are only meaningful for some radio setups. With a FlexRadio (FLEX mode) the amplifier gets the
|
|
156
|
-
band and PTT from the radio over the network, and the properties for legacy radios using CAT or CI-V, such as
|
|
157
|
-
`cat1freq` and `cat2freq`, stay at 0. It is not known which of the remaining properties, for example `bsrcAutoA/B`,
|
|
158
|
-
belong to which mode, since the test amplifier is used with a FlexRadio.
|
|
159
|
-
|
|
160
|
-
Units are taken from the FLEX meter definitions in the API documentation and from observed values. There are two
|
|
161
|
-
hardware versions: SO2R, and one with a 3-port antenna switch. `antA` and `ants` were only seen on the SO2R version.
|
|
162
|
-
|
|
163
|
-
### Details
|
|
164
|
-
|
|
165
|
-
With *Only emit when the value changes* on, the first value after (re)connecting is always emitted.
|
|
166
|
-
The *Start delay* holds back all output for that many milliseconds after the flow is deployed, then emits
|
|
167
|
-
the latest known status. This gives downstream nodes such as dashboard widgets time to initialize.
|
|
168
|
-
The *Deadband* suppresses numeric changes smaller than the given amount, relative to the last emitted value,
|
|
169
|
-
which is useful for noisy values such as power and temperature.
|
|
170
|
-
</script>
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType("power-genius-status", {
|
|
3
|
+
category: "Power Genius",
|
|
4
|
+
color: "#a6bbcf",
|
|
5
|
+
defaults: {
|
|
6
|
+
name: { value: "" },
|
|
7
|
+
server: { type: "power-genius-server", required: true },
|
|
8
|
+
property: { value: "*" },
|
|
9
|
+
onlyChange: { value: true },
|
|
10
|
+
deadband: { value: 0, validate: function (v) { return v === "" || v === undefined || (!isNaN(v) && Number(v) >= 0); } },
|
|
11
|
+
startDelay: { value: 1000, validate: function (v) { return v === "" || v === undefined || (!isNaN(v) && Number(v) >= 0); } },
|
|
12
|
+
},
|
|
13
|
+
inputs: 1,
|
|
14
|
+
outputs: 1,
|
|
15
|
+
icon: "bridge.svg",
|
|
16
|
+
label: function () {
|
|
17
|
+
if (this.name) return this.name;
|
|
18
|
+
return this.property && this.property !== "*" ? "pg " + this.property : "pg status";
|
|
19
|
+
},
|
|
20
|
+
oneditprepare: function () {
|
|
21
|
+
const select = $("#node-input-property-select");
|
|
22
|
+
const input = $("#node-input-property");
|
|
23
|
+
const known = select.find("option").map(function () { return this.value; }).get();
|
|
24
|
+
const current = input.val() || "*";
|
|
25
|
+
select.val(known.includes(current) ? current : "__custom__");
|
|
26
|
+
const sync = () => {
|
|
27
|
+
if (select.val() !== "__custom__") input.val(select.val());
|
|
28
|
+
input.toggle(select.val() === "__custom__");
|
|
29
|
+
const p = input.val();
|
|
30
|
+
$("#node-input-deadband-row").toggle(p !== "*" && p !== "");
|
|
31
|
+
};
|
|
32
|
+
select.on("change", sync);
|
|
33
|
+
input.on("input change", sync);
|
|
34
|
+
sync();
|
|
35
|
+
},
|
|
36
|
+
oneditsave: function () {
|
|
37
|
+
if (!$("#node-input-property").val().trim()) $("#node-input-property").val("*");
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<script type="text/html" data-template-name="power-genius-status">
|
|
43
|
+
<div class="form-row">
|
|
44
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
45
|
+
<input type="text" id="node-input-name" />
|
|
46
|
+
</div>
|
|
47
|
+
<div class="form-row">
|
|
48
|
+
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
|
49
|
+
<input type="text" id="node-input-server" />
|
|
50
|
+
</div>
|
|
51
|
+
<div class="form-row">
|
|
52
|
+
<label for="node-input-property-select"><i class="fa fa-filter"></i> Property</label>
|
|
53
|
+
<select id="node-input-property-select" style="width:70%">
|
|
54
|
+
<option value="*">(all, as an object)</option>
|
|
55
|
+
<optgroup label="Device">
|
|
56
|
+
<option value="state">state</option>
|
|
57
|
+
<option value="fanmode">fanmode</option>
|
|
58
|
+
<option value="meffa">meffa</option>
|
|
59
|
+
<option value="unkey">unkey</option>
|
|
60
|
+
</optgroup>
|
|
61
|
+
<optgroup label="Power">
|
|
62
|
+
<option value="fwd">fwd</option>
|
|
63
|
+
<option value="peakfwd">peakfwd</option>
|
|
64
|
+
<option value="swr">swr</option>
|
|
65
|
+
<option value="vac">vac</option>
|
|
66
|
+
<option value="vdd">vdd</option>
|
|
67
|
+
<option value="id">id</option>
|
|
68
|
+
<option value="peakid">peakid</option>
|
|
69
|
+
<option value="temp">temp</option>
|
|
70
|
+
<option value="hltemp">hltemp</option>
|
|
71
|
+
</optgroup>
|
|
72
|
+
<optgroup label="Band and radio">
|
|
73
|
+
<option value="bandA">bandA</option>
|
|
74
|
+
<option value="bandB">bandB</option>
|
|
75
|
+
<option value="bsrcA">bsrcA</option>
|
|
76
|
+
<option value="bsrcB">bsrcB</option>
|
|
77
|
+
<option value="bsrcAutoA">bsrcAutoA</option>
|
|
78
|
+
<option value="bsrcAutoB">bsrcAutoB</option>
|
|
79
|
+
<option value="flexA">flexA</option>
|
|
80
|
+
<option value="flexB">flexB</option>
|
|
81
|
+
<option value="cntfreq">cntfreq</option>
|
|
82
|
+
<option value="cat1freq">cat1freq</option>
|
|
83
|
+
<option value="cat2freq">cat2freq</option>
|
|
84
|
+
<option value="biasA">biasA</option>
|
|
85
|
+
<option value="biasB">biasB</option>
|
|
86
|
+
</optgroup>
|
|
87
|
+
<optgroup label="Antenna switch">
|
|
88
|
+
<option value="antA">antA</option>
|
|
89
|
+
<option value="ants">ants</option>
|
|
90
|
+
</optgroup>
|
|
91
|
+
<option value="__custom__">other (type the name)...</option>
|
|
92
|
+
</select>
|
|
93
|
+
<input type="text" id="node-input-property" style="display:none; margin-top:5px; width:70%; margin-left:105px" />
|
|
94
|
+
</div>
|
|
95
|
+
<div class="form-row">
|
|
96
|
+
<label for="node-input-onlyChange"> </label>
|
|
97
|
+
<input type="checkbox" id="node-input-onlyChange" style="display:inline-block; width:auto; vertical-align:top;" />
|
|
98
|
+
<label for="node-input-onlyChange" style="width:70%">Only emit when the value changes</label>
|
|
99
|
+
</div>
|
|
100
|
+
<div class="form-row" id="node-input-deadband-row">
|
|
101
|
+
<label for="node-input-deadband"><i class="fa fa-arrows-v"></i> Deadband</label>
|
|
102
|
+
<input type="number" id="node-input-deadband" min="0" step="any" style="width:100px" />
|
|
103
|
+
<span style="margin-left:5px">numeric values: ignore smaller changes (0 = off)</span>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="form-row">
|
|
106
|
+
<label for="node-input-startDelay"><i class="fa fa-hourglass-start"></i> Start delay</label>
|
|
107
|
+
<input type="number" id="node-input-startDelay" min="0" step="100" style="width:100px" />
|
|
108
|
+
<span style="margin-left:5px">ms before the first output after deploy</span>
|
|
109
|
+
</div>
|
|
110
|
+
</script>
|
|
111
|
+
|
|
112
|
+
<script type="text/markdown" data-help-name="power-genius-status">
|
|
113
|
+
Emits one Power Genius XL status property, or the whole status, when it changes.
|
|
114
|
+
|
|
115
|
+
Use one node per property you care about, for example `fwd`, `swr` or `state`. Choose *other* in the list to type
|
|
116
|
+
the name of any property the amplifier reports; leave it as *(all)* to get the whole object.
|
|
117
|
+
|
|
118
|
+
### Input
|
|
119
|
+
|
|
120
|
+
Any message emits the last known value, even if unchanged, and refreshes the status from the device.
|
|
121
|
+
|
|
122
|
+
### Output
|
|
123
|
+
|
|
124
|
+
: payload (number | string | object) : The value of the selected property, or the whole status object when `*` is selected.
|
|
125
|
+
: topic (string) : The property name, or `status` when `*` is selected.
|
|
126
|
+
: previous (number | string) : The previously emitted value (single property only; undefined for the first message).
|
|
127
|
+
|
|
128
|
+
### Properties
|
|
129
|
+
|
|
130
|
+
The `status` reply is a list of `key=value` pairs. Numeric values are emitted as numbers, everything else as text.
|
|
131
|
+
|
|
132
|
+
| Property | Meaning | Values / unit |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `state` | Amplifier state | `STANDBY`, `IDLE` (operate, not transmitting), `TRANSMIT_A`, `TRANSMIT_B`; probably `FAULT` |
|
|
135
|
+
| `bandA`, `bandB` | Band of slice A / B | metres, e.g. `20` |
|
|
136
|
+
| `bsrcA`, `bsrcB` | Source of the band data | e.g. `FLEX` |
|
|
137
|
+
| `bsrcAutoA`, `bsrcAutoB` | Band source selected automatically | 1 = yes, 0 = no |
|
|
138
|
+
| `flexA`, `flexB` | FlexRadio nickname (FLEX mode) | text |
|
|
139
|
+
| `vac` | Mains voltage | V |
|
|
140
|
+
| `vdd` | Supply voltage | V; 0 when not transmitting |
|
|
141
|
+
| `id`, `peakid` | Drain current, and its peak | A; 0 when not transmitting |
|
|
142
|
+
| `fwd`, `peakfwd` | Forward power, and its peak | dBm; `fwd` is 30 (the meter minimum) when there is no RF, `peakfwd` keeps the last peak |
|
|
143
|
+
| `swr` | Return loss | dB (negative, e.g. -18; the FLEX `RL` meter); -60 when there is no RF |
|
|
144
|
+
| `temp` | PA temperature | °C |
|
|
145
|
+
| `hltemp` | Harmonic load temperature | °C |
|
|
146
|
+
| `cntfreq` | Frequency counted from the RF | kHz, e.g. 14098; 0 when there is no RF |
|
|
147
|
+
| `cat1freq`, `cat2freq` | Frequency from CAT port 1 / 2 (legacy radios with CAT or CI-V) | kHz; 0 in FLEX mode |
|
|
148
|
+
| `biasA`, `biasB` | Bias setting of input A / B, as `SOURCE_MODE` | e.g. `RADIO_AB`; others seen elsewhere: `AUTO_AAB`, `MANUAL_A` |
|
|
149
|
+
| `fanmode` | Fan mode | `STANDARD`, `CONTEST`, `BROADCAST` |
|
|
150
|
+
| `meffa` | MeFFA state | `OFF`, `ACTIVE`; may name a fault such as SWR, TEMP or CURRENT |
|
|
151
|
+
| `unkey` | Protection fault | 1 = active protection fault, 0 = normal operation |
|
|
152
|
+
| `antA` | Antenna selected on the antenna switch | Only on the 3-port antenna switch version; 0 on the SO2R version, which has no switch |
|
|
153
|
+
| `ants` | Antenna switch | 0 on the SO2R version (no antenna switch); values on the antenna switch version not seen yet |
|
|
154
|
+
|
|
155
|
+
Many status properties are only meaningful for some radio setups. With a FlexRadio (FLEX mode) the amplifier gets the
|
|
156
|
+
band and PTT from the radio over the network, and the properties for legacy radios using CAT or CI-V, such as
|
|
157
|
+
`cat1freq` and `cat2freq`, stay at 0. It is not known which of the remaining properties, for example `bsrcAutoA/B`,
|
|
158
|
+
belong to which mode, since the test amplifier is used with a FlexRadio.
|
|
159
|
+
|
|
160
|
+
Units are taken from the FLEX meter definitions in the API documentation and from observed values. There are two
|
|
161
|
+
hardware versions: SO2R, and one with a 3-port antenna switch. `antA` and `ants` were only seen on the SO2R version.
|
|
162
|
+
|
|
163
|
+
### Details
|
|
164
|
+
|
|
165
|
+
With *Only emit when the value changes* on, the first value after (re)connecting is always emitted.
|
|
166
|
+
The *Start delay* holds back all output for that many milliseconds after the flow is deployed, then emits
|
|
167
|
+
the latest known status. This gives downstream nodes such as dashboard widgets time to initialize.
|
|
168
|
+
The *Deadband* suppresses numeric changes smaller than the given amount, relative to the last emitted value,
|
|
169
|
+
which is useful for noisy values such as power and temperature.
|
|
170
|
+
</script>
|
package/power-genius-status.js
CHANGED
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
module.exports = (RED) => {
|
|
2
|
-
class PowerGeniusStatus {
|
|
3
|
-
constructor(config) {
|
|
4
|
-
RED.nodes.createNode(this, config);
|
|
5
|
-
this.server = RED.nodes.getNode(config.server);
|
|
6
|
-
|
|
7
|
-
if (this.server == null) {
|
|
8
|
-
this.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// "*" (or unset) emits the whole status object.
|
|
13
|
-
const property = config.property && config.property !== "*" ? config.property : null;
|
|
14
|
-
const onlyChange = config.onlyChange !== false && config.onlyChange !== "false";
|
|
15
|
-
const deadband = Math.max(parseFloat(config.deadband) || 0, 0);
|
|
16
|
-
const startDelay = Math.max(parseInt(config.startDelay, 10) || 0, 0);
|
|
17
|
-
let last;
|
|
18
|
-
let ready = startDelay === 0;
|
|
19
|
-
let startTimer = null;
|
|
20
|
-
|
|
21
|
-
const changed = (value) => {
|
|
22
|
-
if (last === undefined) return true;
|
|
23
|
-
if (deadband > 0 && typeof value === "number" && typeof last === "number") {
|
|
24
|
-
return Math.abs(value - last) >= deadband;
|
|
25
|
-
}
|
|
26
|
-
return value !== last;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const emit = (status, force) => {
|
|
30
|
-
if (property === null) {
|
|
31
|
-
const snapshot = JSON.stringify(status);
|
|
32
|
-
if (force || !onlyChange || snapshot !== last) {
|
|
33
|
-
last = snapshot;
|
|
34
|
-
this.send({ topic: "status", payload: status });
|
|
35
|
-
}
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
if (!(property in status)) return;
|
|
39
|
-
const value = status[property];
|
|
40
|
-
if (force || !onlyChange || changed(value)) {
|
|
41
|
-
const previous = last;
|
|
42
|
-
last = value;
|
|
43
|
-
this.send({ topic: property, payload: value, previous });
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const emitter = this.server.updatesEventEmitter;
|
|
48
|
-
|
|
49
|
-
const onConnected = () => {
|
|
50
|
-
this.status({ fill: "green", shape: "dot", text: this.server.info.name || "connected" });
|
|
51
|
-
};
|
|
52
|
-
const onClosed = () => {
|
|
53
|
-
last = undefined;
|
|
54
|
-
this.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
55
|
-
};
|
|
56
|
-
const onStatus = (status) => {
|
|
57
|
-
if (ready) emit(status, false);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// Hold back output after deploy so that downstream nodes (e.g. dashboard UI) can finish initializing,
|
|
61
|
-
// then emit the latest known status.
|
|
62
|
-
if (!ready) {
|
|
63
|
-
startTimer = setTimeout(() => {
|
|
64
|
-
startTimer = null;
|
|
65
|
-
ready = true;
|
|
66
|
-
if (Object.keys(this.server.status).length > 0) {
|
|
67
|
-
emit({ ...this.server.status }, false);
|
|
68
|
-
}
|
|
69
|
-
}, startDelay);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
emitter.on("connected", onConnected);
|
|
73
|
-
emitter.on("closed", onClosed);
|
|
74
|
-
emitter.on("status", onStatus);
|
|
75
|
-
|
|
76
|
-
// Any input emits the last known value regardless of the change filter, then refreshes from the device.
|
|
77
|
-
this.on("input", (msg, send, done) => {
|
|
78
|
-
if (Object.keys(this.server.status).length > 0) {
|
|
79
|
-
emit({ ...this.server.status }, true);
|
|
80
|
-
}
|
|
81
|
-
this.server.resendStatus();
|
|
82
|
-
if (done) done();
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
this.on("close", () => {
|
|
86
|
-
clearTimeout(startTimer);
|
|
87
|
-
emitter.removeListener("connected", onConnected);
|
|
88
|
-
emitter.removeListener("closed", onClosed);
|
|
89
|
-
emitter.removeListener("status", onStatus);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
this.server.connect();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
RED.nodes.registerType("power-genius-status", PowerGeniusStatus);
|
|
96
|
-
};
|
|
1
|
+
module.exports = (RED) => {
|
|
2
|
+
class PowerGeniusStatus {
|
|
3
|
+
constructor(config) {
|
|
4
|
+
RED.nodes.createNode(this, config);
|
|
5
|
+
this.server = RED.nodes.getNode(config.server);
|
|
6
|
+
|
|
7
|
+
if (this.server == null) {
|
|
8
|
+
this.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// "*" (or unset) emits the whole status object.
|
|
13
|
+
const property = config.property && config.property !== "*" ? config.property : null;
|
|
14
|
+
const onlyChange = config.onlyChange !== false && config.onlyChange !== "false";
|
|
15
|
+
const deadband = Math.max(parseFloat(config.deadband) || 0, 0);
|
|
16
|
+
const startDelay = Math.max(parseInt(config.startDelay, 10) || 0, 0);
|
|
17
|
+
let last;
|
|
18
|
+
let ready = startDelay === 0;
|
|
19
|
+
let startTimer = null;
|
|
20
|
+
|
|
21
|
+
const changed = (value) => {
|
|
22
|
+
if (last === undefined) return true;
|
|
23
|
+
if (deadband > 0 && typeof value === "number" && typeof last === "number") {
|
|
24
|
+
return Math.abs(value - last) >= deadband;
|
|
25
|
+
}
|
|
26
|
+
return value !== last;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const emit = (status, force) => {
|
|
30
|
+
if (property === null) {
|
|
31
|
+
const snapshot = JSON.stringify(status);
|
|
32
|
+
if (force || !onlyChange || snapshot !== last) {
|
|
33
|
+
last = snapshot;
|
|
34
|
+
this.send({ topic: "status", payload: status });
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!(property in status)) return;
|
|
39
|
+
const value = status[property];
|
|
40
|
+
if (force || !onlyChange || changed(value)) {
|
|
41
|
+
const previous = last;
|
|
42
|
+
last = value;
|
|
43
|
+
this.send({ topic: property, payload: value, previous });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const emitter = this.server.updatesEventEmitter;
|
|
48
|
+
|
|
49
|
+
const onConnected = () => {
|
|
50
|
+
this.status({ fill: "green", shape: "dot", text: this.server.info.name || "connected" });
|
|
51
|
+
};
|
|
52
|
+
const onClosed = () => {
|
|
53
|
+
last = undefined;
|
|
54
|
+
this.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
55
|
+
};
|
|
56
|
+
const onStatus = (status) => {
|
|
57
|
+
if (ready) emit(status, false);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Hold back output after deploy so that downstream nodes (e.g. dashboard UI) can finish initializing,
|
|
61
|
+
// then emit the latest known status.
|
|
62
|
+
if (!ready) {
|
|
63
|
+
startTimer = setTimeout(() => {
|
|
64
|
+
startTimer = null;
|
|
65
|
+
ready = true;
|
|
66
|
+
if (Object.keys(this.server.status).length > 0) {
|
|
67
|
+
emit({ ...this.server.status }, false);
|
|
68
|
+
}
|
|
69
|
+
}, startDelay);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
emitter.on("connected", onConnected);
|
|
73
|
+
emitter.on("closed", onClosed);
|
|
74
|
+
emitter.on("status", onStatus);
|
|
75
|
+
|
|
76
|
+
// Any input emits the last known value regardless of the change filter, then refreshes from the device.
|
|
77
|
+
this.on("input", (msg, send, done) => {
|
|
78
|
+
if (Object.keys(this.server.status).length > 0) {
|
|
79
|
+
emit({ ...this.server.status }, true);
|
|
80
|
+
}
|
|
81
|
+
this.server.resendStatus();
|
|
82
|
+
if (done) done();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
this.on("close", () => {
|
|
86
|
+
clearTimeout(startTimer);
|
|
87
|
+
emitter.removeListener("connected", onConnected);
|
|
88
|
+
emitter.removeListener("closed", onClosed);
|
|
89
|
+
emitter.removeListener("status", onStatus);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
this.server.connect();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
RED.nodes.registerType("power-genius-status", PowerGeniusStatus);
|
|
96
|
+
};
|