node-red-contrib-alice 2.2.5 → 2.3.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.
Potentially problematic release.
This version of node-red-contrib-alice might be problematic. Click here for more details.
- package/.claude/settings.local.json +11 -0
- package/CLAUDE.md +54 -0
- package/nodes/alice-color.js +208 -231
- package/nodes/alice-device.js +252 -286
- package/nodes/alice-event.js +110 -114
- package/nodes/alice-get.js +2 -3
- package/nodes/alice-mode.js +136 -145
- package/nodes/alice-onoff.js +126 -130
- package/nodes/alice-range.js +144 -150
- package/nodes/alice-sensor.js +101 -106
- package/nodes/alice-togle.js +118 -125
- package/nodes/alice-video.js +88 -132
- package/nodes/alice.js +11 -18
- package/nodes/types.js +3 -0
- package/package.json +2 -7
- package/src/alice-color.html +255 -0
- package/src/alice-color.ts +227 -0
- package/src/alice-device.html +94 -0
- package/src/alice-device.ts +301 -0
- package/src/alice-event.html +148 -0
- package/src/alice-event.ts +112 -0
- package/src/alice-get.ts +12 -15
- package/src/alice-mode.html +296 -0
- package/src/alice-mode.ts +139 -0
- package/src/alice-onoff.html +93 -0
- package/src/alice-onoff.ts +132 -0
- package/src/alice-range.html +293 -0
- package/src/alice-range.ts +144 -0
- package/src/alice-sensor.html +307 -0
- package/src/alice-sensor.ts +103 -0
- package/src/alice-togle.html +96 -0
- package/src/alice-togle.ts +122 -0
- package/src/alice-video.html +90 -0
- package/src/alice-video.ts +99 -0
- package/src/alice.ts +98 -248
- package/src/types.ts +157 -0
- package/tsconfig.json +13 -106
- package/.eslintrc.json +0 -20
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { NodeAPI, Node } from "node-red";
|
|
2
|
+
import { AliceModeConfig, AliceDeviceNode, CapabilityState } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export = (RED: NodeAPI): void => {
|
|
5
|
+
function AliceMode(this: Node, config: AliceModeConfig): void {
|
|
6
|
+
RED.nodes.createNode(this, config);
|
|
7
|
+
const device = RED.nodes.getNode(config.device) as AliceDeviceNode;
|
|
8
|
+
|
|
9
|
+
const ctype = 'devices.capabilities.mode';
|
|
10
|
+
const instance = config.instance || '';
|
|
11
|
+
const modes = config.modes;
|
|
12
|
+
let response = config.response;
|
|
13
|
+
let value: string | undefined;
|
|
14
|
+
|
|
15
|
+
if (config.response === undefined) {
|
|
16
|
+
response = true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const init = (): void => {
|
|
20
|
+
if (modes.length < 1) {
|
|
21
|
+
this.status({ fill: "red", shape: "dot", text: "error" });
|
|
22
|
+
this.error("In the list of supported commands, there must be at least one command");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!instance) {
|
|
26
|
+
this.status({ fill: "red", shape: "dot", text: "error" });
|
|
27
|
+
this.error("Mode type not selected");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const cfgModes = modes.map(v => ({ value: v }));
|
|
32
|
+
const capab = {
|
|
33
|
+
type: ctype,
|
|
34
|
+
retrievable: true,
|
|
35
|
+
reportable: true,
|
|
36
|
+
parameters: {
|
|
37
|
+
instance: instance,
|
|
38
|
+
modes: cfgModes
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
device.setCapability(this.id, capab)
|
|
43
|
+
.then(() => {
|
|
44
|
+
this.status({ fill: "green", shape: "dot", text: "online" });
|
|
45
|
+
})
|
|
46
|
+
.catch(err => {
|
|
47
|
+
this.error("Error on create capability: " + err.message);
|
|
48
|
+
this.status({ fill: "red", shape: "dot", text: "error" });
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if (device.initState) init();
|
|
53
|
+
|
|
54
|
+
device.on("online", () => {
|
|
55
|
+
init();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
device.on("offline", () => {
|
|
59
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
device.on(this.id, (val: string) => {
|
|
63
|
+
this.send({ payload: val });
|
|
64
|
+
const state: CapabilityState = {
|
|
65
|
+
type: ctype,
|
|
66
|
+
state: {
|
|
67
|
+
instance: instance,
|
|
68
|
+
value: val
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
if (response) {
|
|
72
|
+
device.updateCapabState(this.id, state)
|
|
73
|
+
.then(() => {
|
|
74
|
+
value = val;
|
|
75
|
+
this.status({ fill: "green", shape: "dot", text: "online" });
|
|
76
|
+
})
|
|
77
|
+
.catch(err => {
|
|
78
|
+
this.error("Error on update capability state: " + err.message);
|
|
79
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
this.on('input', (msg, _send, done) => {
|
|
85
|
+
const newValue = msg.payload;
|
|
86
|
+
if (typeof newValue != 'string') {
|
|
87
|
+
this.error("Wrong type! msg.payload must be String.");
|
|
88
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
89
|
+
if (done) { done(); }
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (modes.indexOf(newValue) < 0) {
|
|
93
|
+
this.error("Error! Unsupported command.");
|
|
94
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
95
|
+
if (done) { done(); }
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (newValue === value) {
|
|
99
|
+
this.debug("Value not changed. Cancel update");
|
|
100
|
+
if (done) { done(); }
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const state: CapabilityState = {
|
|
105
|
+
type: ctype,
|
|
106
|
+
state: {
|
|
107
|
+
instance: instance,
|
|
108
|
+
value: newValue
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
device.updateCapabState(this.id, state)
|
|
112
|
+
.then(() => {
|
|
113
|
+
value = newValue;
|
|
114
|
+
this.status({ fill: "green", shape: "dot", text: newValue });
|
|
115
|
+
if (done) { done(); }
|
|
116
|
+
})
|
|
117
|
+
.catch(err => {
|
|
118
|
+
this.error("Error on update capability state: " + err.message);
|
|
119
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
120
|
+
if (done) { done(); }
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
this.on('close', (removed: boolean, done: () => void) => {
|
|
125
|
+
if (removed) {
|
|
126
|
+
device.delCapability(this.id)
|
|
127
|
+
.then(() => { done(); })
|
|
128
|
+
.catch(err => {
|
|
129
|
+
this.error("Error on delete capability: " + err.message);
|
|
130
|
+
done();
|
|
131
|
+
});
|
|
132
|
+
} else {
|
|
133
|
+
done();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
RED.nodes.registerType("Mode", AliceMode);
|
|
139
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('On_Off',{
|
|
3
|
+
category: 'alice',
|
|
4
|
+
defaults:{
|
|
5
|
+
device: {value:"", type:"alice-device"},
|
|
6
|
+
name: {value:""},
|
|
7
|
+
// retrievable: {value:true},
|
|
8
|
+
response:{value:true},
|
|
9
|
+
split: {value:false}
|
|
10
|
+
},
|
|
11
|
+
inputs:1,
|
|
12
|
+
outputs:1,
|
|
13
|
+
icon: "alice.png",
|
|
14
|
+
color: "#D8BFD8",
|
|
15
|
+
label: function(){
|
|
16
|
+
return this.name + ":On/Off";
|
|
17
|
+
},
|
|
18
|
+
oneditprepare: function(){
|
|
19
|
+
if (this.response === undefined){
|
|
20
|
+
$( "#node-input-response").prop('checked', true);
|
|
21
|
+
};
|
|
22
|
+
if (this.retrievable === false){
|
|
23
|
+
$( "#node-input-split").prop('checked', true);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
oneditsave: function(){
|
|
27
|
+
deivcename = $('#node-input-device option:selected').text();
|
|
28
|
+
$('#node-input-name').val(deivcename);
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<script type="text/x-red" data-template-name="On_Off">
|
|
34
|
+
<input type="hidden" id="node-input-name">
|
|
35
|
+
<div class="form-row">
|
|
36
|
+
<label for="node-input-device">Device</label>
|
|
37
|
+
<input id="node-input-device">
|
|
38
|
+
</div>
|
|
39
|
+
<div class="form-row">
|
|
40
|
+
<label for="node-input-split"><i class="fa fa-power-off"></i> <span >Split button</span></label>
|
|
41
|
+
<label for="node-input-split" style="width:70%">
|
|
42
|
+
<input type="checkbox" id="node-input-split" style="display:inline-block; width:22px; vertical-align:baseline;" autocomplete="off"><span>Split On/Off button</span>
|
|
43
|
+
</label>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="form-row">
|
|
46
|
+
<label for="node-input-response"><i class="fa fa-refresh"></i> <span >Response</span></label>
|
|
47
|
+
<label for="node-input-response" style="width:70%">
|
|
48
|
+
<input type="checkbox" id="node-input-response" style="display:inline-block; width:22px; vertical-align:baseline;" autocomplete="off"><span>Always answer Alice with success</span>
|
|
49
|
+
</label>
|
|
50
|
+
</div>
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<script type="text/x-red" data-help-name="On_Off">
|
|
54
|
+
<p>Allows the device to turn on and off</p>
|
|
55
|
+
|
|
56
|
+
<h3>Property</h3>
|
|
57
|
+
<dl class="message-properties">
|
|
58
|
+
<dt>Device
|
|
59
|
+
<span class="property-type">Select</span>
|
|
60
|
+
</dt>
|
|
61
|
+
<dd> The device to which this feature is connected </dd>
|
|
62
|
+
<dt>Main button
|
|
63
|
+
<span class="property-type">checkbox</span>
|
|
64
|
+
</dt>
|
|
65
|
+
<dd>The main button blocks access to other controls if the device is turned off.
|
|
66
|
+
When unchecking this, the controls will be available, but you will not be able to find out whether the device is on or off</dd>
|
|
67
|
+
<dt>Response
|
|
68
|
+
<span class="property-type">checkbox</span>
|
|
69
|
+
</dt>
|
|
70
|
+
<dd> In order for the device to respond to Alice that the command was successful, the corresponding value should arrive at the input within 2.5 seconds.
|
|
71
|
+
If your device takes longer or doesn’t return a confirmation at all, just check this box. </dd>
|
|
72
|
+
</dl>
|
|
73
|
+
|
|
74
|
+
<h3>Inputs</h3>
|
|
75
|
+
<dl class="message-properties">
|
|
76
|
+
<dt>payload
|
|
77
|
+
<span class="property-type">boolean</span>
|
|
78
|
+
</dt>
|
|
79
|
+
<dd> true or false </dd>
|
|
80
|
+
</dl>
|
|
81
|
+
|
|
82
|
+
<h3>Outputs</h3>
|
|
83
|
+
<dl class="message-properties">
|
|
84
|
+
<dt>payload
|
|
85
|
+
<span class="property-type">boolean</span>
|
|
86
|
+
</dt>
|
|
87
|
+
<dd> true or false </dd>
|
|
88
|
+
</dl>
|
|
89
|
+
<h3>References</h3>
|
|
90
|
+
<ul>
|
|
91
|
+
<li><a href="https://yandex.ru/dev/dialogs/alice/doc/smart-home/concepts/capability-types-docpage/"> - Yandex documentation</a></li>
|
|
92
|
+
</ul>
|
|
93
|
+
</script>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { NodeAPI, Node } from "node-red";
|
|
2
|
+
import { AliceOnOffConfig, AliceDeviceNode, CapabilityState } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export = (RED: NodeAPI): void => {
|
|
5
|
+
function AliceOnOff(this: Node, config: AliceOnOffConfig): void {
|
|
6
|
+
RED.nodes.createNode(this, config);
|
|
7
|
+
const device = RED.nodes.getNode(config.device) as AliceDeviceNode;
|
|
8
|
+
device.setMaxListeners(device.getMaxListeners() + 1);
|
|
9
|
+
|
|
10
|
+
const id = JSON.parse(JSON.stringify(this.id));
|
|
11
|
+
const ctype = 'devices.capabilities.on_off';
|
|
12
|
+
const instance = 'on';
|
|
13
|
+
let response = config.response;
|
|
14
|
+
let split = config.split;
|
|
15
|
+
let initState = false;
|
|
16
|
+
|
|
17
|
+
const curentState: CapabilityState = {
|
|
18
|
+
type: ctype,
|
|
19
|
+
state: {
|
|
20
|
+
instance: instance,
|
|
21
|
+
value: false
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
if (config.response === undefined) {
|
|
26
|
+
response = true;
|
|
27
|
+
}
|
|
28
|
+
if (config.split === undefined) {
|
|
29
|
+
split = false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
33
|
+
|
|
34
|
+
const init = (): void => {
|
|
35
|
+
this.debug("Starting capability initilization ...");
|
|
36
|
+
const capab = {
|
|
37
|
+
type: ctype,
|
|
38
|
+
retrievable: true,
|
|
39
|
+
reportable: true,
|
|
40
|
+
parameters: {
|
|
41
|
+
instance: instance,
|
|
42
|
+
split: split
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
device.setCapability(id, capab)
|
|
47
|
+
.then(() => {
|
|
48
|
+
this.debug("Capability initilization - success!");
|
|
49
|
+
initState = true;
|
|
50
|
+
this.status({ fill: "green", shape: "dot", text: "online" });
|
|
51
|
+
})
|
|
52
|
+
.catch(err => {
|
|
53
|
+
this.error("Error on create capability: " + err.message);
|
|
54
|
+
this.status({ fill: "red", shape: "dot", text: "error" });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
device.updateCapabState(id, curentState)
|
|
58
|
+
.then(() => {
|
|
59
|
+
this.status({ fill: "green", shape: "dot", text: "online" });
|
|
60
|
+
})
|
|
61
|
+
.catch(err => {
|
|
62
|
+
this.error("Error on update capability state: " + err.message);
|
|
63
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
if (device.initState) init();
|
|
68
|
+
|
|
69
|
+
device.on("online", () => {
|
|
70
|
+
init();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
device.on("offline", () => {
|
|
74
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
device.on(id, (val: boolean) => {
|
|
78
|
+
this.send({ payload: val });
|
|
79
|
+
if (response) {
|
|
80
|
+
curentState.state.value = val;
|
|
81
|
+
device.updateCapabState(id, curentState)
|
|
82
|
+
.then(() => {
|
|
83
|
+
this.status({ fill: "green", shape: "dot", text: val.toString() });
|
|
84
|
+
})
|
|
85
|
+
.catch(err => {
|
|
86
|
+
this.error("Error on update capability state: " + err.message);
|
|
87
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
this.on('input', (msg, _send, done) => {
|
|
93
|
+
if (typeof msg.payload != 'boolean') {
|
|
94
|
+
this.error("Wrong type! msg.payload must be boolean.");
|
|
95
|
+
if (done) { done(); }
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (msg.payload === curentState.state.value) {
|
|
99
|
+
this.debug("Value not changed. Cancel update");
|
|
100
|
+
if (done) { done(); }
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
curentState.state.value = msg.payload;
|
|
104
|
+
device.updateCapabState(id, curentState)
|
|
105
|
+
.then(() => {
|
|
106
|
+
this.status({ fill: "green", shape: "dot", text: String(msg.payload) });
|
|
107
|
+
if (done) { done(); }
|
|
108
|
+
})
|
|
109
|
+
.catch(err => {
|
|
110
|
+
this.error("Error on update capability state: " + err.message);
|
|
111
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
112
|
+
if (done) { done(); }
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
this.on('close', (removed: boolean, done: () => void) => {
|
|
117
|
+
device.setMaxListeners(device.getMaxListeners() - 1);
|
|
118
|
+
if (removed) {
|
|
119
|
+
device.delCapability(id)
|
|
120
|
+
.then(() => { done(); })
|
|
121
|
+
.catch(err => {
|
|
122
|
+
this.error("Error on delete capability: " + err.message);
|
|
123
|
+
done();
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
done();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
RED.nodes.registerType("On_Off", AliceOnOff);
|
|
132
|
+
};
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('Range',{
|
|
3
|
+
category: 'alice',
|
|
4
|
+
defaults:{
|
|
5
|
+
device: {value:"", type:"alice-device"},
|
|
6
|
+
name: {value:""},
|
|
7
|
+
instance: {value:undefined, validate: (v)=>{
|
|
8
|
+
if (v){
|
|
9
|
+
return true;
|
|
10
|
+
}else{
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}},
|
|
14
|
+
unit: {value:""},
|
|
15
|
+
min:{value:1, validate: (v)=>{
|
|
16
|
+
if (v){
|
|
17
|
+
return true;
|
|
18
|
+
}else{
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}},
|
|
22
|
+
max:{value:100, validate: (v)=>{
|
|
23
|
+
if (v){
|
|
24
|
+
return true;
|
|
25
|
+
}else{
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}},
|
|
29
|
+
precision:{value: 1, validate: (v)=>{
|
|
30
|
+
if (v){
|
|
31
|
+
return true;
|
|
32
|
+
}else{
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}},
|
|
36
|
+
response:{value:true},
|
|
37
|
+
retrievable: {value: true}
|
|
38
|
+
},
|
|
39
|
+
inputs:1,
|
|
40
|
+
outputs:1,
|
|
41
|
+
icon: "alice.png",
|
|
42
|
+
color: "#D8BFD8",
|
|
43
|
+
label: function(){
|
|
44
|
+
return this.name + ":"+this.instance;
|
|
45
|
+
},
|
|
46
|
+
oneditsave: function(){
|
|
47
|
+
deivcename = $('#node-input-device option:selected').text();
|
|
48
|
+
$('#node-input-name').val(deivcename);
|
|
49
|
+
},
|
|
50
|
+
oneditprepare: function(){
|
|
51
|
+
var firstRun = true;
|
|
52
|
+
function instanceChange(inst){
|
|
53
|
+
var unit, min, max, precision;
|
|
54
|
+
// проверяем первый ли это запуск редактирования или он уже был настроен
|
|
55
|
+
if (firstRun && typeof inst !== "undefined"){
|
|
56
|
+
unit = $('#node-input-unit').find(":selected").val();
|
|
57
|
+
min = $('#node-input-min').val();
|
|
58
|
+
max = $('#node-input-max').val();
|
|
59
|
+
precision = $('#node-input-precision').val();
|
|
60
|
+
};
|
|
61
|
+
switch (inst) {
|
|
62
|
+
case 'brightness':
|
|
63
|
+
min = (typeof min !== "undefined") ? min : 0;
|
|
64
|
+
max = (typeof max !== "undefined") ? max : 100;
|
|
65
|
+
precision = (typeof precision !== "undefined") ? precision : 10;
|
|
66
|
+
$('#node-input-unit').replaceWith('<select id="node-input-unit" style="width: 70%;"></select>');
|
|
67
|
+
$('#node-input-unit').append('<option value="unit.percent">%</option>');
|
|
68
|
+
$('#node-input-unit select').val("unit.percent");
|
|
69
|
+
$('#node-input-unit').prop( "disabled", true );
|
|
70
|
+
$('#node-input-min').val(min);
|
|
71
|
+
$('#node-input-min').prop( "disabled", true );
|
|
72
|
+
$('#node-input-max').val(max);
|
|
73
|
+
$('#node-input-max').prop( "disabled", true );
|
|
74
|
+
$('#node-input-precision').val(precision);
|
|
75
|
+
$('#node-input-precision').prop( "disabled", false );
|
|
76
|
+
break;
|
|
77
|
+
case 'channel':
|
|
78
|
+
min = (typeof min !== "undefined") ? min : 1;
|
|
79
|
+
max = (typeof max !== "undefined") ? max : 1000;
|
|
80
|
+
precision = (typeof precision !== "undefined") ? precision : 1;
|
|
81
|
+
$('#node-input-unit').replaceWith('<select id="node-input-unit" style="width: 70%;"></select>');
|
|
82
|
+
$('#node-input-unit').append('<option value="unit.number">Number</option>');
|
|
83
|
+
$('#node-input-unit select').val("unit.number");
|
|
84
|
+
$('#node-input-unit').prop( "disabled", true );
|
|
85
|
+
$('#node-input-min').val(min);
|
|
86
|
+
$('#node-input-min').prop( "disabled", false );
|
|
87
|
+
$('#node-input-max').val(max);
|
|
88
|
+
$('#node-input-max').prop( "disabled", false );
|
|
89
|
+
$('#node-input-precision').val(precision);
|
|
90
|
+
$('#node-input-precision').prop( "disabled", false );
|
|
91
|
+
break;
|
|
92
|
+
case 'humidity':
|
|
93
|
+
min = (typeof min !== "undefined") ? min : 0;
|
|
94
|
+
max = (typeof max !== "undefined") ? max : 100;
|
|
95
|
+
precision = (typeof precision !== "undefined") ? precision : 10;
|
|
96
|
+
|
|
97
|
+
$('#node-input-unit').replaceWith('<select id="node-input-unit" style="width: 70%;"></select>');
|
|
98
|
+
$('#node-input-unit').append('<option value="unit.percent">%</option>');
|
|
99
|
+
$('#node-input-unit select').val("unit.percent");
|
|
100
|
+
$('#node-input-unit').prop( "disabled", true );
|
|
101
|
+
$('#node-input-min').val(min);
|
|
102
|
+
$('#node-input-min').prop( "disabled", true );
|
|
103
|
+
$('#node-input-max').val(max);
|
|
104
|
+
$('#node-input-max').prop( "disabled", true );
|
|
105
|
+
$('#node-input-precision').val(precision);
|
|
106
|
+
$('#node-input-precision').prop( "disabled", false );
|
|
107
|
+
break;
|
|
108
|
+
case 'open':
|
|
109
|
+
min = (typeof min !== "undefined") ? min : 0;
|
|
110
|
+
max = (typeof max !== "undefined") ? max : 100;
|
|
111
|
+
precision = (typeof precision !== "undefined") ? precision : 10;
|
|
112
|
+
|
|
113
|
+
$('#node-input-unit').replaceWith('<select id="node-input-unit" style="width: 70%;"></select>');
|
|
114
|
+
$('#node-input-unit').append('<option value="unit.percent">%</option>');
|
|
115
|
+
$('#node-input-unit select').val("unit.percent");
|
|
116
|
+
$('#node-input-unit').prop( "disabled", true );
|
|
117
|
+
$('#node-input-min').val(min);
|
|
118
|
+
$('#node-input-min').prop( "disabled", true );
|
|
119
|
+
$('#node-input-max').val(max);
|
|
120
|
+
$('#node-input-max').prop( "disabled", true );
|
|
121
|
+
$('#node-input-precision').val(precision);
|
|
122
|
+
$('#node-input-precision').prop( "disabled", false );
|
|
123
|
+
break;
|
|
124
|
+
case 'temperature':
|
|
125
|
+
unit = (typeof unit !== "unit") ? unit : "unit.temperature.celsius";
|
|
126
|
+
min = (typeof min !== "undefined") ? min : 0;
|
|
127
|
+
max = (typeof max !== "undefined") ? max : 100;
|
|
128
|
+
precision = (typeof precision !== "undefined") ? precision : 2;
|
|
129
|
+
|
|
130
|
+
$('#node-input-unit').replaceWith('<select id="node-input-unit" style="width: 70%;"></select>');
|
|
131
|
+
$('#node-input-unit').append('<option value="unit.temperature.celsius">Celsius (C)</option>');
|
|
132
|
+
$('#node-input-unit').append('<option value="unit.temperature.kelvin">Kelvin (K)</option>');
|
|
133
|
+
$('#node-input-unit select').val(unit);
|
|
134
|
+
$('#node-input-unit').prop( "disabled", false );
|
|
135
|
+
$('#node-input-min').val(min);
|
|
136
|
+
$('#node-input-min').prop( "disabled", false );
|
|
137
|
+
$('#node-input-max').val(max);
|
|
138
|
+
$('#node-input-max').prop( "disabled", false );
|
|
139
|
+
$('#node-input-precision').val(precision);
|
|
140
|
+
$('#node-input-precision').prop( "disabled", false );
|
|
141
|
+
break;
|
|
142
|
+
case 'volume':
|
|
143
|
+
min = (typeof min !== "undefined") ? min : 0;
|
|
144
|
+
max = (typeof max !== "undefined") ? max : 100;
|
|
145
|
+
precision = (typeof precision !== "undefined") ? precision : 10;
|
|
146
|
+
|
|
147
|
+
$('#node-input-unit').replaceWith('<select id="node-input-unit" style="width: 70%;"></select>');
|
|
148
|
+
$('#node-input-unit').append('<option value="unit.number">Number</option>');
|
|
149
|
+
$('#node-input-unit select').val("unit.number");
|
|
150
|
+
$('#node-input-unit').prop( "disabled", true );
|
|
151
|
+
$('#node-input-min').val(min);
|
|
152
|
+
$('#node-input-min').prop( "disabled", false );
|
|
153
|
+
$('#node-input-max').val(max);
|
|
154
|
+
$('#node-input-max').prop( "disabled", false );
|
|
155
|
+
$('#node-input-precision').val(precision);
|
|
156
|
+
$('#node-input-precision').prop( "disabled", false );
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
$('#node-input-unit').prop( "disabled", true );
|
|
160
|
+
$('#node-input-min').prop( "disabled", true );
|
|
161
|
+
$('#node-input-max').prop( "disabled", true );
|
|
162
|
+
$('#node-input-precision').prop( "disabled", true );
|
|
163
|
+
}
|
|
164
|
+
firstRun = false;
|
|
165
|
+
};
|
|
166
|
+
$('#node-input-instance').on('change',()=>{
|
|
167
|
+
var val = $('#node-input-instance').find(":selected").val();
|
|
168
|
+
instanceChange(val);
|
|
169
|
+
});
|
|
170
|
+
if (this.retrievable === undefined){
|
|
171
|
+
$( "#node-input-retrievable").prop('checked', true);
|
|
172
|
+
}
|
|
173
|
+
if (this.response === undefined){
|
|
174
|
+
$( "#node-input-response").prop('checked', true);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
</script>
|
|
179
|
+
|
|
180
|
+
<script type="text/x-red" data-template-name="Range">
|
|
181
|
+
<input type="hidden" id="node-input-name">
|
|
182
|
+
<div class="form-row">
|
|
183
|
+
<label for="node-input-device">Device</label>
|
|
184
|
+
<input id="node-input-device">
|
|
185
|
+
</div>
|
|
186
|
+
<div class="form-row">
|
|
187
|
+
<label for="node-input-instance">Range Type</label>
|
|
188
|
+
<select id="node-input-instance" style="width: 70%;">
|
|
189
|
+
<option value="brightness">Brightness</option>
|
|
190
|
+
<option value="channel">Channel</option>
|
|
191
|
+
<option value="humidity">Humidity</option>
|
|
192
|
+
<option value="open">Open</option>
|
|
193
|
+
<option value="temperature">Temperature</option>
|
|
194
|
+
<option value="volume">Volume</option>
|
|
195
|
+
</select>
|
|
196
|
+
</div>
|
|
197
|
+
<div class="form-row">
|
|
198
|
+
<label for="node-input-unit">Unit</label>
|
|
199
|
+
<select id="node-input-unit" style="width: 70%;">
|
|
200
|
+
<option value="unit.temperature.celsius">Celsius</option>
|
|
201
|
+
<option value="unit.temperature.kelvin">Kelvin</option>
|
|
202
|
+
<option value="unit.percent">Percent</option>
|
|
203
|
+
</select>
|
|
204
|
+
</div>
|
|
205
|
+
<div class="form-row">
|
|
206
|
+
<label for="node-input-min">Min</label>
|
|
207
|
+
<input type="number" id="node-input-min">
|
|
208
|
+
</div>
|
|
209
|
+
<div class="form-row">
|
|
210
|
+
<label for="node-input-max">Max</label>
|
|
211
|
+
<input type="number" id="node-input-max">
|
|
212
|
+
</div>
|
|
213
|
+
<div class="form-row">
|
|
214
|
+
<label for="node-input-precision">Step</label>
|
|
215
|
+
<input type="number" id="node-input-precision">
|
|
216
|
+
</div>
|
|
217
|
+
<div class="form-row">
|
|
218
|
+
<label for="node-input-retrievable"><i class="fa fa-sign-out"></i> <span >Output</span></label>
|
|
219
|
+
<label for="node-input-retrievable" style="width:70%">
|
|
220
|
+
<input type="checkbox" id="node-input-retrievable" style="display:inline-block; width:22px; vertical-align:baseline;" autocomplete="off"><span>full value/changes only</span>
|
|
221
|
+
</label>
|
|
222
|
+
</div>
|
|
223
|
+
<div class="form-row">
|
|
224
|
+
<label for="node-input-response"><i class="fa fa-refresh"></i> <span >Response</span></label>
|
|
225
|
+
<label for="node-input-response" style="width:70%">
|
|
226
|
+
<input type="checkbox" id="node-input-response" style="display:inline-block; width:22px; vertical-align:baseline;" autocomplete="off"><span>Always answer Alice with success</span>
|
|
227
|
+
</label>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
</script>
|
|
231
|
+
|
|
232
|
+
<script type="text/x-red" data-help-name="Range">
|
|
233
|
+
<p>Manage device settings that have a range. For example, lamp brightness, sound volume, heater temperature, etc.</p>
|
|
234
|
+
|
|
235
|
+
<h3>Property</h3>
|
|
236
|
+
<dl class="message-properties">
|
|
237
|
+
<dt>Device
|
|
238
|
+
<span class="property-type">Select</span>
|
|
239
|
+
</dt>
|
|
240
|
+
<dd> The device to which this feature is connected </dd>
|
|
241
|
+
<dt>Range Type
|
|
242
|
+
<span class="property-type">Select</span>
|
|
243
|
+
</dt>
|
|
244
|
+
<dd> Selection of the type of ranges (brightness, sound, channel, temperature, etc.) </dd>
|
|
245
|
+
<dt>Unit
|
|
246
|
+
<span class="property-type">Select</span>
|
|
247
|
+
</dt>
|
|
248
|
+
<dd> Unit of measure for the range </dd>
|
|
249
|
+
<dt>Min
|
|
250
|
+
<span class="property-type">Float</span>
|
|
251
|
+
</dt>
|
|
252
|
+
<dd> Minimum value </dd>
|
|
253
|
+
<dt>Max
|
|
254
|
+
<span class="property-type">Float</span>
|
|
255
|
+
</dt>
|
|
256
|
+
<dd> Maximum value </dd>
|
|
257
|
+
<dt>precision
|
|
258
|
+
<span class="property-type">Float</span>
|
|
259
|
+
</dt>
|
|
260
|
+
<dd> The minimum step of changing values within the range </dd>
|
|
261
|
+
<dt>Output
|
|
262
|
+
<span class="property-type">checkbox</span>
|
|
263
|
+
</dt>
|
|
264
|
+
<dd> Determines what kind of value will be output. The full value that the device should set or the delta of the value change.
|
|
265
|
+
When the checkbox is unchecked, the current device values are not stored in Yandex.. </dd>
|
|
266
|
+
<dt>Response
|
|
267
|
+
<span class="property-type">checkbox</span>
|
|
268
|
+
</dt>
|
|
269
|
+
<dd> In order for the device to respond to Alice that the command was successful, the corresponding value should arrive at the input within 2.5 seconds.
|
|
270
|
+
If your device takes longer or doesn’t return a confirmation at all, just check this box. </dd>
|
|
271
|
+
</dl>
|
|
272
|
+
</dl>
|
|
273
|
+
|
|
274
|
+
<h3>Inputs</h3>
|
|
275
|
+
<dl class="message-properties">
|
|
276
|
+
<dt>payload
|
|
277
|
+
<span class="property-type">Float</span>
|
|
278
|
+
</dt>
|
|
279
|
+
<dd> Value </dd>
|
|
280
|
+
</dl>
|
|
281
|
+
|
|
282
|
+
<h3>Outputs</h3>
|
|
283
|
+
<dl class="message-properties">
|
|
284
|
+
<dt>payload
|
|
285
|
+
<span class="property-type">Float</span>
|
|
286
|
+
</dt>
|
|
287
|
+
<dd> Value </dd>
|
|
288
|
+
</dl>
|
|
289
|
+
<h3>References</h3>
|
|
290
|
+
<ul>
|
|
291
|
+
<li><a href="https://yandex.ru/dev/dialogs/alice/doc/smart-home/concepts/range-docpage/"> Yandex documentation</a></li>
|
|
292
|
+
</ul>
|
|
293
|
+
</script>
|