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,122 @@
|
|
|
1
|
+
import { NodeAPI, Node } from "node-red";
|
|
2
|
+
import { AliceCapabilityConfig, AliceDeviceNode, CapabilityState } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export = (RED: NodeAPI): void => {
|
|
5
|
+
function AliceToggle(this: Node, config: AliceCapabilityConfig): 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 ctype = 'devices.capabilities.toggle';
|
|
11
|
+
const instance = config.instance || '';
|
|
12
|
+
let response = config.response;
|
|
13
|
+
let value = false;
|
|
14
|
+
|
|
15
|
+
if (config.response === undefined) {
|
|
16
|
+
response = true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
20
|
+
|
|
21
|
+
const init = (): void => {
|
|
22
|
+
this.debug("Starting capability initilization ...");
|
|
23
|
+
const capab = {
|
|
24
|
+
type: ctype,
|
|
25
|
+
retrievable: true,
|
|
26
|
+
reportable: true,
|
|
27
|
+
parameters: {
|
|
28
|
+
instance: instance,
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
device.setCapability(this.id, capab)
|
|
32
|
+
.then(() => {
|
|
33
|
+
this.debug("Capability initilization - success!");
|
|
34
|
+
this.status({ fill: "green", shape: "dot", text: "online" });
|
|
35
|
+
})
|
|
36
|
+
.catch(err => {
|
|
37
|
+
this.error("Error on create capability: " + err.message);
|
|
38
|
+
this.status({ fill: "red", shape: "dot", text: "error" });
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (device.initState) init();
|
|
43
|
+
|
|
44
|
+
device.on("online", () => {
|
|
45
|
+
init();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
device.on("offline", () => {
|
|
49
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
device.on(this.id, (val: boolean) => {
|
|
53
|
+
this.debug("Received a new value from Yandex...");
|
|
54
|
+
this.send({ payload: val });
|
|
55
|
+
const state: CapabilityState = {
|
|
56
|
+
type: ctype,
|
|
57
|
+
state: {
|
|
58
|
+
instance: instance,
|
|
59
|
+
value: val
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
if (response) {
|
|
63
|
+
this.debug("Automatic confirmation is true, sending confirmation to Yandex ...");
|
|
64
|
+
device.updateCapabState(this.id, state)
|
|
65
|
+
.then(() => {
|
|
66
|
+
value = val;
|
|
67
|
+
this.status({ fill: "green", shape: "dot", text: String(val) });
|
|
68
|
+
})
|
|
69
|
+
.catch(err => {
|
|
70
|
+
this.error("Error on update capability state: " + err.message);
|
|
71
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.on('input', (msg, _send, done) => {
|
|
77
|
+
if (typeof msg.payload != 'boolean') {
|
|
78
|
+
this.error("Wrong type! msg.payload must be boolean.");
|
|
79
|
+
if (done) { done(); }
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (msg.payload === value) {
|
|
83
|
+
this.debug("Value not changed. Cancel update");
|
|
84
|
+
if (done) { done(); }
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const state: CapabilityState = {
|
|
88
|
+
type: ctype,
|
|
89
|
+
state: {
|
|
90
|
+
instance: instance,
|
|
91
|
+
value: msg.payload
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
device.updateCapabState(this.id, state)
|
|
95
|
+
.then(() => {
|
|
96
|
+
value = msg.payload as boolean;
|
|
97
|
+
this.status({ fill: "green", shape: "dot", text: String(msg.payload) });
|
|
98
|
+
if (done) { done(); }
|
|
99
|
+
})
|
|
100
|
+
.catch(err => {
|
|
101
|
+
this.error("Error on update capability state: " + err.message);
|
|
102
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
103
|
+
if (done) { done(); }
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
this.on('close', (removed: boolean, done: () => void) => {
|
|
108
|
+
if (removed) {
|
|
109
|
+
device.delCapability(this.id)
|
|
110
|
+
.then(() => { done(); })
|
|
111
|
+
.catch(err => {
|
|
112
|
+
this.error("Error on delete capability: " + err.message);
|
|
113
|
+
done();
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
done();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
RED.nodes.registerType("Toggle", AliceToggle);
|
|
122
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('Video',{
|
|
3
|
+
category: 'alice',
|
|
4
|
+
defaults:{
|
|
5
|
+
device: {value:"", type:"alice-device"},
|
|
6
|
+
name: {value:""},
|
|
7
|
+
protocol: { value:"hls" },
|
|
8
|
+
stream_url:{ value:"", required: true }
|
|
9
|
+
},
|
|
10
|
+
inputs:0,
|
|
11
|
+
outputs:0,
|
|
12
|
+
icon: "alice.png",
|
|
13
|
+
color: "#D8BFD8",
|
|
14
|
+
label: function(){
|
|
15
|
+
return this.name + ":video";
|
|
16
|
+
},
|
|
17
|
+
// oneditprepare: function(){
|
|
18
|
+
// $("#node-input-protocol").typedInput({
|
|
19
|
+
// types: [
|
|
20
|
+
// {
|
|
21
|
+
// value: "protocol",
|
|
22
|
+
// options: [
|
|
23
|
+
// { value: "hls", label: "HLS"},
|
|
24
|
+
// { value: "progressive_mp4", label: "Progressive mp4"},
|
|
25
|
+
// ]
|
|
26
|
+
// }
|
|
27
|
+
// ]
|
|
28
|
+
// });
|
|
29
|
+
// },
|
|
30
|
+
oneditsave: function(){
|
|
31
|
+
deivcename = $('#node-input-device option:selected').text();
|
|
32
|
+
$('#node-input-name').val(deivcename);
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<script type="text/x-red" data-template-name="Video">
|
|
38
|
+
<input type="hidden" id="node-input-name">
|
|
39
|
+
<div class="form-row">
|
|
40
|
+
<label for="node-input-device">Device</label>
|
|
41
|
+
<input id="node-input-device">
|
|
42
|
+
</div>
|
|
43
|
+
<div class="form-row">
|
|
44
|
+
<label for="node-input-protocol">Protocol</label>
|
|
45
|
+
<input type="text" id="node-input-protocol" disabled>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="form-row">
|
|
48
|
+
<label for="node-input-stream_url">URL</label>
|
|
49
|
+
<input type="text" id="node-input-stream_url">
|
|
50
|
+
</div>
|
|
51
|
+
<div class="form-tips" id="node-tip">
|
|
52
|
+
<span>Currently only supports the HLS stream protocol.<br>
|
|
53
|
+
Supported video codecs: H264.<br>
|
|
54
|
+
Maximum video resolution: 1920 x 1080.<br>
|
|
55
|
+
Supported audio codecs: AAC.
|
|
56
|
+
</span>
|
|
57
|
+
</div>
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<script type="text/x-red" data-help-name="Video">
|
|
61
|
+
<p>Getting a video stream from a camera.</p>
|
|
62
|
+
|
|
63
|
+
<h3>Property</h3>
|
|
64
|
+
<dl class="message-properties">
|
|
65
|
+
<dt>Device
|
|
66
|
+
<span class="property-type">Select</span>
|
|
67
|
+
</dt>
|
|
68
|
+
<dd> The device to which this feature is connected </dd>
|
|
69
|
+
<dt>Protocol
|
|
70
|
+
<span class="property-type">disabled</span>
|
|
71
|
+
</dt>
|
|
72
|
+
<dd>Currently only supports the HLS stream protocol.<br>
|
|
73
|
+
Supported video codecs: H264.<br>
|
|
74
|
+
Maximum video resolution: 1920 x 1080.<br>
|
|
75
|
+
Supported audio codecs: AAC.</dd>
|
|
76
|
+
<dt>URL
|
|
77
|
+
<span class="property-type">string</span>
|
|
78
|
+
</dt>
|
|
79
|
+
<dd>Stream URL with parameters.<br>
|
|
80
|
+
The URL must be accessible from the Internet<br>
|
|
81
|
+
In response to a request for a stream using this link, you need to pass headers:<br>
|
|
82
|
+
Content-type: application/vnd.apple.mpegurl<br>
|
|
83
|
+
Access-Control-Allow-Origin: https://yastatic.net</dd>
|
|
84
|
+
</dl>
|
|
85
|
+
|
|
86
|
+
<h3>References</h3>
|
|
87
|
+
<ul>
|
|
88
|
+
<li><a href="https://yandex.ru/dev/dialogs/smart-home/doc/concepts/video_stream.html"> - Yandex documentation</a></li>
|
|
89
|
+
</ul>
|
|
90
|
+
</script>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { NodeAPI, Node } from "node-red";
|
|
2
|
+
import { AliceVideoConfig, AliceDeviceNode, CapabilityState } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export = (RED: NodeAPI): void => {
|
|
5
|
+
function AliceVideo(this: Node, config: AliceVideoConfig): 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 = this.id;
|
|
11
|
+
const ctype = 'devices.capabilities.video_stream';
|
|
12
|
+
const instance = 'get_stream';
|
|
13
|
+
const stream_url = config.stream_url;
|
|
14
|
+
const protocol = config.protocol;
|
|
15
|
+
|
|
16
|
+
const curentState: CapabilityState = {
|
|
17
|
+
type: ctype,
|
|
18
|
+
state: {
|
|
19
|
+
instance: instance,
|
|
20
|
+
value: {
|
|
21
|
+
stream_url: stream_url,
|
|
22
|
+
protocol: protocol
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
28
|
+
|
|
29
|
+
const init = (): void => {
|
|
30
|
+
this.debug("Starting capability initilization ...");
|
|
31
|
+
const capab = {
|
|
32
|
+
type: ctype,
|
|
33
|
+
retrievable: false,
|
|
34
|
+
reportable: false,
|
|
35
|
+
parameters: {
|
|
36
|
+
instance: instance,
|
|
37
|
+
protocols: [protocol]
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
device.setCapability(id, capab)
|
|
42
|
+
.then(() => {
|
|
43
|
+
this.debug("Capability initilization - success!");
|
|
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
|
+
device.updateCapabState(id, curentState)
|
|
52
|
+
.then(() => {
|
|
53
|
+
this.status({ fill: "green", shape: "dot", text: "online" });
|
|
54
|
+
})
|
|
55
|
+
.catch(err => {
|
|
56
|
+
this.error("Error on update capability state: " + err.message);
|
|
57
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (device.initState) init();
|
|
62
|
+
|
|
63
|
+
device.on("online", () => {
|
|
64
|
+
init();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
device.on("offline", () => {
|
|
68
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
device.on(id, () => {
|
|
72
|
+
device.updateCapabState(id, curentState)
|
|
73
|
+
.then(() => {
|
|
74
|
+
const str_url = stream_url.slice(0, 25) + "...";
|
|
75
|
+
this.status({ fill: "green", shape: "dot", text: str_url });
|
|
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
|
+
this.on('close', (removed: boolean, done: () => void) => {
|
|
84
|
+
device.setMaxListeners(device.getMaxListeners() - 1);
|
|
85
|
+
if (removed) {
|
|
86
|
+
device.delCapability(id)
|
|
87
|
+
.then(() => { done(); })
|
|
88
|
+
.catch(err => {
|
|
89
|
+
this.error("Error on delete capability: " + err.message);
|
|
90
|
+
done();
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
done();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
RED.nodes.registerType("Video", AliceVideo);
|
|
99
|
+
};
|