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
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
RED.nodes.registerType("power-genius-control", {
|
|
3
|
-
category: "Power Genius",
|
|
4
|
-
color: "#a6bbcf",
|
|
5
|
-
defaults: {
|
|
6
|
-
name: { value: "" },
|
|
7
|
-
server: { type: "power-genius-server", required: true },
|
|
8
|
-
action: { value: "" },
|
|
9
|
-
},
|
|
10
|
-
inputs: 1,
|
|
11
|
-
outputs: 1,
|
|
12
|
-
icon: "bridge.svg",
|
|
13
|
-
label: function () {
|
|
14
|
-
return this.name || "pg control";
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
</script>
|
|
18
|
-
|
|
19
|
-
<script type="text/html" data-template-name="power-genius-control">
|
|
20
|
-
<div class="form-row">
|
|
21
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
22
|
-
<input type="text" id="node-input-name" />
|
|
23
|
-
</div>
|
|
24
|
-
<div class="form-row">
|
|
25
|
-
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
|
26
|
-
<input type="text" id="node-input-server" />
|
|
27
|
-
</div>
|
|
28
|
-
<div class="form-row">
|
|
29
|
-
<label for="node-input-action"><i class="fa fa-cog"></i> Action</label>
|
|
30
|
-
<select id="node-input-action">
|
|
31
|
-
<option value="">msg.topic</option>
|
|
32
|
-
<option value="operate">operate</option>
|
|
33
|
-
<option value="antenna">antenna</option>
|
|
34
|
-
<option value="fanmode">fanmode</option>
|
|
35
|
-
<option value="command">command</option>
|
|
36
|
-
</select>
|
|
37
|
-
</div>
|
|
38
|
-
</script>
|
|
39
|
-
|
|
40
|
-
<script type="text/markdown" data-help-name="power-genius-control">
|
|
41
|
-
Controls the Power Genius XL.
|
|
42
|
-
|
|
43
|
-
### Input
|
|
44
|
-
|
|
45
|
-
: topic (string) : `operate`, `antenna`, `fanmode` or `command`. Only used when the node's Action is set to `msg.topic`; a fixed action in the node always takes precedence.
|
|
46
|
-
|
|
47
|
-
: payload (boolean|number|string) : Depends on the action:
|
|
48
|
-
|
|
49
|
-
| Action | Payload | Command sent |
|
|
50
|
-
|---|---|---|
|
|
51
|
-
| `operate` | `true`, `1`, `"1"` or `"on"` for operate, `false`, `0`, `"0"` or `"off"` for standby. Anything else is an error and nothing is sent. | `operate=<1\|0>` |
|
|
52
|
-
| `antenna` | The antenna number, 1-3. Only for amplifiers with the antenna switch; the SO2R version answers with an error | `antenna=<n>` |
|
|
53
|
-
| `fanmode` | `STANDARD`, `CONTEST` or `BROADCAST` (any case). Shows up as `fanmode` in the status | `setup fanmode=<mode>` |
|
|
54
|
-
| `command` | The command, on a single line, for example `setup read` or `ping` | The payload as it is |
|
|
55
|
-
|
|
56
|
-
### Output
|
|
57
|
-
|
|
58
|
-
: topic (string) : The action.
|
|
59
|
-
: payload (string) : The reply message from the amplifier, for example `key=value key=value ...`. Empty when the command has no reply message.
|
|
60
|
-
|
|
61
|
-
A failed command is reported as an error on the node, with the result code from the amplifier. For example
|
|
62
|
-
`0x50000015` means that the amplifier does not know the command, and `0x50000013` that the hardware has no antenna switch.
|
|
63
|
-
|
|
64
|
-
### Details
|
|
65
|
-
|
|
66
|
-
`command` is for trying out commands that the API documentation does not cover. Commands that change the
|
|
67
|
-
configuration, such as `ifconf`, `catradio` and `flexradio`, take effect after `save`, which reboots the amplifier. Use with care.
|
|
68
|
-
The effect of `operate` shows up in the status `state` (`STANDBY`, or `IDLE` when operating).
|
|
69
|
-
</script>
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType("power-genius-control", {
|
|
3
|
+
category: "Power Genius",
|
|
4
|
+
color: "#a6bbcf",
|
|
5
|
+
defaults: {
|
|
6
|
+
name: { value: "" },
|
|
7
|
+
server: { type: "power-genius-server", required: true },
|
|
8
|
+
action: { value: "" },
|
|
9
|
+
},
|
|
10
|
+
inputs: 1,
|
|
11
|
+
outputs: 1,
|
|
12
|
+
icon: "bridge.svg",
|
|
13
|
+
label: function () {
|
|
14
|
+
return this.name || "pg control";
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script type="text/html" data-template-name="power-genius-control">
|
|
20
|
+
<div class="form-row">
|
|
21
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
22
|
+
<input type="text" id="node-input-name" />
|
|
23
|
+
</div>
|
|
24
|
+
<div class="form-row">
|
|
25
|
+
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
|
26
|
+
<input type="text" id="node-input-server" />
|
|
27
|
+
</div>
|
|
28
|
+
<div class="form-row">
|
|
29
|
+
<label for="node-input-action"><i class="fa fa-cog"></i> Action</label>
|
|
30
|
+
<select id="node-input-action">
|
|
31
|
+
<option value="">msg.topic</option>
|
|
32
|
+
<option value="operate">operate</option>
|
|
33
|
+
<option value="antenna">antenna</option>
|
|
34
|
+
<option value="fanmode">fanmode</option>
|
|
35
|
+
<option value="command">command</option>
|
|
36
|
+
</select>
|
|
37
|
+
</div>
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<script type="text/markdown" data-help-name="power-genius-control">
|
|
41
|
+
Controls the Power Genius XL.
|
|
42
|
+
|
|
43
|
+
### Input
|
|
44
|
+
|
|
45
|
+
: topic (string) : `operate`, `antenna`, `fanmode` or `command`. Only used when the node's Action is set to `msg.topic`; a fixed action in the node always takes precedence.
|
|
46
|
+
|
|
47
|
+
: payload (boolean|number|string) : Depends on the action:
|
|
48
|
+
|
|
49
|
+
| Action | Payload | Command sent |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `operate` | `true`, `1`, `"1"` or `"on"` for operate, `false`, `0`, `"0"` or `"off"` for standby. Anything else is an error and nothing is sent. | `operate=<1\|0>` |
|
|
52
|
+
| `antenna` | The antenna number, 1-3. Only for amplifiers with the antenna switch; the SO2R version answers with an error | `antenna=<n>` |
|
|
53
|
+
| `fanmode` | `STANDARD`, `CONTEST` or `BROADCAST` (any case). Shows up as `fanmode` in the status | `setup fanmode=<mode>` |
|
|
54
|
+
| `command` | The command, on a single line, for example `setup read` or `ping` | The payload as it is |
|
|
55
|
+
|
|
56
|
+
### Output
|
|
57
|
+
|
|
58
|
+
: topic (string) : The action.
|
|
59
|
+
: payload (string) : The reply message from the amplifier, for example `key=value key=value ...`. Empty when the command has no reply message.
|
|
60
|
+
|
|
61
|
+
A failed command is reported as an error on the node, with the result code from the amplifier. For example
|
|
62
|
+
`0x50000015` means that the amplifier does not know the command, and `0x50000013` that the hardware has no antenna switch.
|
|
63
|
+
|
|
64
|
+
### Details
|
|
65
|
+
|
|
66
|
+
`command` is for trying out commands that the API documentation does not cover. Commands that change the
|
|
67
|
+
configuration, such as `ifconf`, `catradio` and `flexradio`, take effect after `save`, which reboots the amplifier. Use with care.
|
|
68
|
+
The effect of `operate` shows up in the status `state` (`STANDBY`, or `IDLE` when operating).
|
|
69
|
+
</script>
|
package/power-genius-control.js
CHANGED
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
const FAN_MODES = ["STANDARD", "CONTEST", "BROADCAST"];
|
|
2
|
-
|
|
3
|
-
// Builds the command to send from the payload. "command" sends the payload as it is, to try commands that
|
|
4
|
-
// are not documented; the amplifier answers an unknown one with an error.
|
|
5
|
-
const COMMANDS = {
|
|
6
|
-
operate: (payload) => `operate=${parseSwitch(payload)}`,
|
|
7
|
-
fanmode: (payload) => {
|
|
8
|
-
const mode = String(payload === undefined || payload === null ? "" : payload).trim().toUpperCase();
|
|
9
|
-
if (!FAN_MODES.includes(mode)) {
|
|
10
|
-
throw new Error(`payload must be one of: ${FAN_MODES.join(", ")}`);
|
|
11
|
-
}
|
|
12
|
-
return `setup fanmode=${mode}`;
|
|
13
|
-
},
|
|
14
|
-
antenna: (payload) => {
|
|
15
|
-
const n = Number(payload);
|
|
16
|
-
if (payload === "" || payload === null || !Number.isInteger(n) || n < 1 || n > 3) {
|
|
17
|
-
throw new Error("payload must be the antenna number, 1-3");
|
|
18
|
-
}
|
|
19
|
-
return `antenna=${n}`;
|
|
20
|
-
},
|
|
21
|
-
command: (payload) => {
|
|
22
|
-
const cmd = String(payload === undefined || payload === null ? "" : payload).trim();
|
|
23
|
-
if (!cmd) throw new Error("payload must be the command to send");
|
|
24
|
-
if (/[\r\n]/.test(cmd)) throw new Error("payload must be a single line");
|
|
25
|
-
return cmd;
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
const ACTIONS = Object.keys(COMMANDS);
|
|
29
|
-
|
|
30
|
-
// true/false, 1/0, "1"/"0" and "on"/"off" (any case). Anything else is rejected, so that a stray payload
|
|
31
|
-
// can never switch the amplifier by accident.
|
|
32
|
-
const parseSwitch = (payload) => {
|
|
33
|
-
if (payload === true || payload === 1) return 1;
|
|
34
|
-
if (payload === false || payload === 0) return 0;
|
|
35
|
-
switch (String(payload).trim().toLowerCase()) {
|
|
36
|
-
case "1":
|
|
37
|
-
case "on":
|
|
38
|
-
case "true":
|
|
39
|
-
return 1;
|
|
40
|
-
case "0":
|
|
41
|
-
case "off":
|
|
42
|
-
case "false":
|
|
43
|
-
return 0;
|
|
44
|
-
default:
|
|
45
|
-
throw new Error("payload must be true/false, 1/0 or on/off");
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
module.exports = (RED) => {
|
|
50
|
-
class PowerGeniusControl {
|
|
51
|
-
constructor(config) {
|
|
52
|
-
RED.nodes.createNode(this, config);
|
|
53
|
-
this.server = RED.nodes.getNode(config.server);
|
|
54
|
-
|
|
55
|
-
if (this.server == null) {
|
|
56
|
-
this.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const emitter = this.server.updatesEventEmitter;
|
|
61
|
-
const onConnected = () => {
|
|
62
|
-
this.status({ fill: "green", shape: "dot", text: this.server.info.name || "connected" });
|
|
63
|
-
};
|
|
64
|
-
const onClosed = () => {
|
|
65
|
-
this.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
66
|
-
};
|
|
67
|
-
emitter.on("connected", onConnected);
|
|
68
|
-
emitter.on("closed", onClosed);
|
|
69
|
-
|
|
70
|
-
this.on("close", () => {
|
|
71
|
-
emitter.removeListener("connected", onConnected);
|
|
72
|
-
emitter.removeListener("closed", onClosed);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
this.on("input", async (msg, send, done) => {
|
|
76
|
-
const action = String(config.action || msg.topic || "").toLowerCase();
|
|
77
|
-
try {
|
|
78
|
-
if (!ACTIONS.includes(action)) {
|
|
79
|
-
throw new Error(`topic must be one of: ${ACTIONS.join(", ")}`);
|
|
80
|
-
}
|
|
81
|
-
const reply = await this.server.command(COMMANDS[action](msg.payload));
|
|
82
|
-
send({ ...msg, topic: action, payload: reply });
|
|
83
|
-
if (done) done();
|
|
84
|
-
} catch (err) {
|
|
85
|
-
this.status({ fill: "red", shape: "ring", text: err.message });
|
|
86
|
-
if (done) done(err); else this.error(err, msg);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
this.server.connect();
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
RED.nodes.registerType("power-genius-control", PowerGeniusControl);
|
|
94
|
-
};
|
|
1
|
+
const FAN_MODES = ["STANDARD", "CONTEST", "BROADCAST"];
|
|
2
|
+
|
|
3
|
+
// Builds the command to send from the payload. "command" sends the payload as it is, to try commands that
|
|
4
|
+
// are not documented; the amplifier answers an unknown one with an error.
|
|
5
|
+
const COMMANDS = {
|
|
6
|
+
operate: (payload) => `operate=${parseSwitch(payload)}`,
|
|
7
|
+
fanmode: (payload) => {
|
|
8
|
+
const mode = String(payload === undefined || payload === null ? "" : payload).trim().toUpperCase();
|
|
9
|
+
if (!FAN_MODES.includes(mode)) {
|
|
10
|
+
throw new Error(`payload must be one of: ${FAN_MODES.join(", ")}`);
|
|
11
|
+
}
|
|
12
|
+
return `setup fanmode=${mode}`;
|
|
13
|
+
},
|
|
14
|
+
antenna: (payload) => {
|
|
15
|
+
const n = Number(payload);
|
|
16
|
+
if (payload === "" || payload === null || !Number.isInteger(n) || n < 1 || n > 3) {
|
|
17
|
+
throw new Error("payload must be the antenna number, 1-3");
|
|
18
|
+
}
|
|
19
|
+
return `antenna=${n}`;
|
|
20
|
+
},
|
|
21
|
+
command: (payload) => {
|
|
22
|
+
const cmd = String(payload === undefined || payload === null ? "" : payload).trim();
|
|
23
|
+
if (!cmd) throw new Error("payload must be the command to send");
|
|
24
|
+
if (/[\r\n]/.test(cmd)) throw new Error("payload must be a single line");
|
|
25
|
+
return cmd;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
const ACTIONS = Object.keys(COMMANDS);
|
|
29
|
+
|
|
30
|
+
// true/false, 1/0, "1"/"0" and "on"/"off" (any case). Anything else is rejected, so that a stray payload
|
|
31
|
+
// can never switch the amplifier by accident.
|
|
32
|
+
const parseSwitch = (payload) => {
|
|
33
|
+
if (payload === true || payload === 1) return 1;
|
|
34
|
+
if (payload === false || payload === 0) return 0;
|
|
35
|
+
switch (String(payload).trim().toLowerCase()) {
|
|
36
|
+
case "1":
|
|
37
|
+
case "on":
|
|
38
|
+
case "true":
|
|
39
|
+
return 1;
|
|
40
|
+
case "0":
|
|
41
|
+
case "off":
|
|
42
|
+
case "false":
|
|
43
|
+
return 0;
|
|
44
|
+
default:
|
|
45
|
+
throw new Error("payload must be true/false, 1/0 or on/off");
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
module.exports = (RED) => {
|
|
50
|
+
class PowerGeniusControl {
|
|
51
|
+
constructor(config) {
|
|
52
|
+
RED.nodes.createNode(this, config);
|
|
53
|
+
this.server = RED.nodes.getNode(config.server);
|
|
54
|
+
|
|
55
|
+
if (this.server == null) {
|
|
56
|
+
this.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const emitter = this.server.updatesEventEmitter;
|
|
61
|
+
const onConnected = () => {
|
|
62
|
+
this.status({ fill: "green", shape: "dot", text: this.server.info.name || "connected" });
|
|
63
|
+
};
|
|
64
|
+
const onClosed = () => {
|
|
65
|
+
this.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
66
|
+
};
|
|
67
|
+
emitter.on("connected", onConnected);
|
|
68
|
+
emitter.on("closed", onClosed);
|
|
69
|
+
|
|
70
|
+
this.on("close", () => {
|
|
71
|
+
emitter.removeListener("connected", onConnected);
|
|
72
|
+
emitter.removeListener("closed", onClosed);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
this.on("input", async (msg, send, done) => {
|
|
76
|
+
const action = String(config.action || msg.topic || "").toLowerCase();
|
|
77
|
+
try {
|
|
78
|
+
if (!ACTIONS.includes(action)) {
|
|
79
|
+
throw new Error(`topic must be one of: ${ACTIONS.join(", ")}`);
|
|
80
|
+
}
|
|
81
|
+
const reply = await this.server.command(COMMANDS[action](msg.payload));
|
|
82
|
+
send({ ...msg, topic: action, payload: reply });
|
|
83
|
+
if (done) done();
|
|
84
|
+
} catch (err) {
|
|
85
|
+
this.status({ fill: "red", shape: "ring", text: err.message });
|
|
86
|
+
if (done) done(err); else this.error(err, msg);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
this.server.connect();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
RED.nodes.registerType("power-genius-control", PowerGeniusControl);
|
|
94
|
+
};
|
package/power-genius-info.html
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
RED.nodes.registerType("power-genius-info", {
|
|
3
|
-
category: "Power Genius",
|
|
4
|
-
color: "#a6bbcf",
|
|
5
|
-
defaults: {
|
|
6
|
-
name: { value: "" },
|
|
7
|
-
server: { type: "power-genius-server", required: true },
|
|
8
|
-
property: { value: "*" },
|
|
9
|
-
startDelay: { value: 1000, validate: function (v) { return v === "" || v === undefined || (!isNaN(v) && Number(v) >= 0); } },
|
|
10
|
-
},
|
|
11
|
-
inputs: 1,
|
|
12
|
-
outputs: 1,
|
|
13
|
-
icon: "bridge.svg",
|
|
14
|
-
label: function () {
|
|
15
|
-
if (this.name) return this.name;
|
|
16
|
-
return this.property && this.property !== "*" ? "pg " + this.property : "pg info";
|
|
17
|
-
},
|
|
18
|
-
oneditprepare: function () {
|
|
19
|
-
const select = $("#node-input-property-select");
|
|
20
|
-
const input = $("#node-input-property");
|
|
21
|
-
const known = select.find("option").map(function () { return this.value; }).get();
|
|
22
|
-
const current = input.val() || "*";
|
|
23
|
-
select.val(known.includes(current) ? current : "__custom__");
|
|
24
|
-
const sync = () => {
|
|
25
|
-
if (select.val() !== "__custom__") input.val(select.val());
|
|
26
|
-
input.toggle(select.val() === "__custom__");
|
|
27
|
-
};
|
|
28
|
-
select.on("change", sync);
|
|
29
|
-
sync();
|
|
30
|
-
},
|
|
31
|
-
oneditsave: function () {
|
|
32
|
-
if (!$("#node-input-property").val().trim()) $("#node-input-property").val("*");
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
</script>
|
|
36
|
-
|
|
37
|
-
<script type="text/html" data-template-name="power-genius-info">
|
|
38
|
-
<div class="form-row">
|
|
39
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
40
|
-
<input type="text" id="node-input-name" />
|
|
41
|
-
</div>
|
|
42
|
-
<div class="form-row">
|
|
43
|
-
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
|
44
|
-
<input type="text" id="node-input-server" />
|
|
45
|
-
</div>
|
|
46
|
-
<div class="form-row">
|
|
47
|
-
<label for="node-input-property-select"><i class="fa fa-filter"></i> Property</label>
|
|
48
|
-
<select id="node-input-property-select" style="width:70%">
|
|
49
|
-
<option value="*">(all, as an object)</option>
|
|
50
|
-
<option value="name">name</option>
|
|
51
|
-
<option value="nickname">nickname</option>
|
|
52
|
-
<option value="firmware">firmware</option>
|
|
53
|
-
<option value="authRequired">authRequired</option>
|
|
54
|
-
<option value="ifconf">ifconf</option>
|
|
55
|
-
<option value="catradioA">catradioA</option>
|
|
56
|
-
<option value="catradioB">catradioB</option>
|
|
57
|
-
<option value="flexradioA">flexradioA</option>
|
|
58
|
-
<option value="flexradioB">flexradioB</option>
|
|
59
|
-
<option value="__custom__">other (type the name)...</option>
|
|
60
|
-
</select>
|
|
61
|
-
<input type="text" id="node-input-property" style="display:none; margin-top:5px; width:70%; margin-left:105px" />
|
|
62
|
-
</div>
|
|
63
|
-
<div class="form-row">
|
|
64
|
-
<label for="node-input-startDelay"><i class="fa fa-hourglass-start"></i> Start delay</label>
|
|
65
|
-
<input type="number" id="node-input-startDelay" min="0" step="100" style="width:100px" />
|
|
66
|
-
<span style="margin-left:5px">ms before the first output after deploy</span>
|
|
67
|
-
</div>
|
|
68
|
-
</script>
|
|
69
|
-
|
|
70
|
-
<script type="text/markdown" data-help-name="power-genius-info">
|
|
71
|
-
Emits the Power Genius XL device information and configuration, or a single item of it.
|
|
72
|
-
|
|
73
|
-
### Input
|
|
74
|
-
|
|
75
|
-
Any message re-reads the info from the device and emits it.
|
|
76
|
-
|
|
77
|
-
### Output
|
|
78
|
-
|
|
79
|
-
: payload (string | number | boolean | object) : The selected item, or the whole info object when `*` is selected.
|
|
80
|
-
: topic (string) : The property name, or `info` when `*` is selected.
|
|
81
|
-
|
|
82
|
-
### Details
|
|
83
|
-
|
|
84
|
-
The info is collected with the read-only commands `setup read`, `ifconf read`, `catradio read=A|B` and
|
|
85
|
-
`flexradio read=A|B`; each reply is parsed as `key=value` pairs. Use `*` to get everything.
|
|
86
|
-
|
|
87
|
-
| Item | Meaning |
|
|
88
|
-
|---|---|
|
|
89
|
-
| `name` | Device name (the `nickname`, with `_` replaced by a space) |
|
|
90
|
-
| `nickname` | Device name as reported |
|
|
91
|
-
| `firmware` | Firmware version, from the banner the device sends on connect |
|
|
92
|
-
| `authRequired` | `true` when the device asked for authentication (only outside the local network; not supported yet) |
|
|
93
|
-
| `ledintens` | LED intensity |
|
|
94
|
-
| `txdelay` | TX delay |
|
|
95
|
-
| `inactivity-timeout` | Inactivity timeout, 0 = off |
|
|
96
|
-
| `authcode` | Authentication code for WAN access. Treat it as a secret: it is part of the whole info object |
|
|
97
|
-
| `ants`, `ant1name`..`ant3name` | Antenna switch setup: `ants` (0 on the SO2R version, which has no switch) and the names of antennas 1-3 (empty when not set) |
|
|
98
|
-
| `ifconf` | Object with the network configuration: `address`, `netmask`, `gateway`, `dhcp`, `dhcpstatus` and the active `address-status`, `netmask-status`, `gateway-status` |
|
|
99
|
-
| `catradioA`, `catradioB` | Objects with the CAT radio configuration of slice A / B, used with legacy radios (CAT or CI-V): `type`, `baud`, `parity`, `stopbits`, `civ`, `active` |
|
|
100
|
-
| `flexradioA`, `flexradioB` | Objects with the FlexRadio configuration of slice A / B: `serial`, `txant`, `ptt`, `active` |
|
|
101
|
-
|
|
102
|
-
The info is emitted once after the connection is established, and again after every reconnect.
|
|
103
|
-
The *Start delay* holds back output for that many milliseconds after the flow is deployed,
|
|
104
|
-
giving downstream nodes such as dashboard widgets time to initialize.
|
|
105
|
-
</script>
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType("power-genius-info", {
|
|
3
|
+
category: "Power Genius",
|
|
4
|
+
color: "#a6bbcf",
|
|
5
|
+
defaults: {
|
|
6
|
+
name: { value: "" },
|
|
7
|
+
server: { type: "power-genius-server", required: true },
|
|
8
|
+
property: { value: "*" },
|
|
9
|
+
startDelay: { value: 1000, validate: function (v) { return v === "" || v === undefined || (!isNaN(v) && Number(v) >= 0); } },
|
|
10
|
+
},
|
|
11
|
+
inputs: 1,
|
|
12
|
+
outputs: 1,
|
|
13
|
+
icon: "bridge.svg",
|
|
14
|
+
label: function () {
|
|
15
|
+
if (this.name) return this.name;
|
|
16
|
+
return this.property && this.property !== "*" ? "pg " + this.property : "pg info";
|
|
17
|
+
},
|
|
18
|
+
oneditprepare: function () {
|
|
19
|
+
const select = $("#node-input-property-select");
|
|
20
|
+
const input = $("#node-input-property");
|
|
21
|
+
const known = select.find("option").map(function () { return this.value; }).get();
|
|
22
|
+
const current = input.val() || "*";
|
|
23
|
+
select.val(known.includes(current) ? current : "__custom__");
|
|
24
|
+
const sync = () => {
|
|
25
|
+
if (select.val() !== "__custom__") input.val(select.val());
|
|
26
|
+
input.toggle(select.val() === "__custom__");
|
|
27
|
+
};
|
|
28
|
+
select.on("change", sync);
|
|
29
|
+
sync();
|
|
30
|
+
},
|
|
31
|
+
oneditsave: function () {
|
|
32
|
+
if (!$("#node-input-property").val().trim()) $("#node-input-property").val("*");
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<script type="text/html" data-template-name="power-genius-info">
|
|
38
|
+
<div class="form-row">
|
|
39
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
40
|
+
<input type="text" id="node-input-name" />
|
|
41
|
+
</div>
|
|
42
|
+
<div class="form-row">
|
|
43
|
+
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
|
44
|
+
<input type="text" id="node-input-server" />
|
|
45
|
+
</div>
|
|
46
|
+
<div class="form-row">
|
|
47
|
+
<label for="node-input-property-select"><i class="fa fa-filter"></i> Property</label>
|
|
48
|
+
<select id="node-input-property-select" style="width:70%">
|
|
49
|
+
<option value="*">(all, as an object)</option>
|
|
50
|
+
<option value="name">name</option>
|
|
51
|
+
<option value="nickname">nickname</option>
|
|
52
|
+
<option value="firmware">firmware</option>
|
|
53
|
+
<option value="authRequired">authRequired</option>
|
|
54
|
+
<option value="ifconf">ifconf</option>
|
|
55
|
+
<option value="catradioA">catradioA</option>
|
|
56
|
+
<option value="catradioB">catradioB</option>
|
|
57
|
+
<option value="flexradioA">flexradioA</option>
|
|
58
|
+
<option value="flexradioB">flexradioB</option>
|
|
59
|
+
<option value="__custom__">other (type the name)...</option>
|
|
60
|
+
</select>
|
|
61
|
+
<input type="text" id="node-input-property" style="display:none; margin-top:5px; width:70%; margin-left:105px" />
|
|
62
|
+
</div>
|
|
63
|
+
<div class="form-row">
|
|
64
|
+
<label for="node-input-startDelay"><i class="fa fa-hourglass-start"></i> Start delay</label>
|
|
65
|
+
<input type="number" id="node-input-startDelay" min="0" step="100" style="width:100px" />
|
|
66
|
+
<span style="margin-left:5px">ms before the first output after deploy</span>
|
|
67
|
+
</div>
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<script type="text/markdown" data-help-name="power-genius-info">
|
|
71
|
+
Emits the Power Genius XL device information and configuration, or a single item of it.
|
|
72
|
+
|
|
73
|
+
### Input
|
|
74
|
+
|
|
75
|
+
Any message re-reads the info from the device and emits it.
|
|
76
|
+
|
|
77
|
+
### Output
|
|
78
|
+
|
|
79
|
+
: payload (string | number | boolean | object) : The selected item, or the whole info object when `*` is selected.
|
|
80
|
+
: topic (string) : The property name, or `info` when `*` is selected.
|
|
81
|
+
|
|
82
|
+
### Details
|
|
83
|
+
|
|
84
|
+
The info is collected with the read-only commands `setup read`, `ifconf read`, `catradio read=A|B` and
|
|
85
|
+
`flexradio read=A|B`; each reply is parsed as `key=value` pairs. Use `*` to get everything.
|
|
86
|
+
|
|
87
|
+
| Item | Meaning |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `name` | Device name (the `nickname`, with `_` replaced by a space) |
|
|
90
|
+
| `nickname` | Device name as reported |
|
|
91
|
+
| `firmware` | Firmware version, from the banner the device sends on connect |
|
|
92
|
+
| `authRequired` | `true` when the device asked for authentication (only outside the local network; not supported yet) |
|
|
93
|
+
| `ledintens` | LED intensity |
|
|
94
|
+
| `txdelay` | TX delay |
|
|
95
|
+
| `inactivity-timeout` | Inactivity timeout, 0 = off |
|
|
96
|
+
| `authcode` | Authentication code for WAN access. Treat it as a secret: it is part of the whole info object |
|
|
97
|
+
| `ants`, `ant1name`..`ant3name` | Antenna switch setup: `ants` (0 on the SO2R version, which has no switch) and the names of antennas 1-3 (empty when not set) |
|
|
98
|
+
| `ifconf` | Object with the network configuration: `address`, `netmask`, `gateway`, `dhcp`, `dhcpstatus` and the active `address-status`, `netmask-status`, `gateway-status` |
|
|
99
|
+
| `catradioA`, `catradioB` | Objects with the CAT radio configuration of slice A / B, used with legacy radios (CAT or CI-V): `type`, `baud`, `parity`, `stopbits`, `civ`, `active` |
|
|
100
|
+
| `flexradioA`, `flexradioB` | Objects with the FlexRadio configuration of slice A / B: `serial`, `txant`, `ptt`, `active` |
|
|
101
|
+
|
|
102
|
+
The info is emitted once after the connection is established, and again after every reconnect.
|
|
103
|
+
The *Start delay* holds back output for that many milliseconds after the flow is deployed,
|
|
104
|
+
giving downstream nodes such as dashboard widgets time to initialize.
|
|
105
|
+
</script>
|