node-red-contrib-alice 2.2.4 → 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.html +6 -1
- package/nodes/alice-device.js +252 -286
- package/nodes/alice-event.js +110 -114
- package/nodes/alice-get.html +91 -0
- package/nodes/alice-get.js +9 -0
- 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.html +0 -2
- 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 +127 -122
- package/nodes/types.js +3 -0
- package/package.json +22 -8
- 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.html +67 -6
- 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.html +242 -0
- package/src/alice.ts +146 -0
- package/src/types.ts +157 -0
- package/tsconfig.json +13 -106
- package/.eslintrc.json +0 -20
package/nodes/alice-video.js
CHANGED
|
@@ -1,132 +1,88 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function AliceVideo(config){
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// this.on('input', (msg, send, done)=>{
|
|
92
|
-
// if (typeof msg.payload != 'boolean'){
|
|
93
|
-
// this.error("Wrong type! msg.payload must be boolean.");
|
|
94
|
-
// if (done) {done();}
|
|
95
|
-
// return;
|
|
96
|
-
// };
|
|
97
|
-
// if (msg.payload === curentState.state.value){
|
|
98
|
-
// this.debug("Value not changed. Cancel update");
|
|
99
|
-
// if (done) {done();}
|
|
100
|
-
// return;
|
|
101
|
-
// };
|
|
102
|
-
// curentState.state.value = msg.payload;
|
|
103
|
-
// device.updateCapabState(id,curentState)
|
|
104
|
-
// .then(ref=>{
|
|
105
|
-
// this.status({fill:"green",shape:"dot",text:msg.payload.toString()});
|
|
106
|
-
// if (done) {done();}
|
|
107
|
-
// })
|
|
108
|
-
// .catch(err=>{
|
|
109
|
-
// this.error("Error on update capability state: " + err.message);
|
|
110
|
-
// this.status({fill:"red",shape:"dot",text:"Error"});
|
|
111
|
-
// if (done) {done();}
|
|
112
|
-
// })
|
|
113
|
-
// });
|
|
114
|
-
|
|
115
|
-
this.on('close', (removed, done)=>{
|
|
116
|
-
device.setMaxListeners(device.getMaxListeners() - 1);
|
|
117
|
-
if (removed) {
|
|
118
|
-
device.delCapability(id)
|
|
119
|
-
.then(res=>{
|
|
120
|
-
done()
|
|
121
|
-
})
|
|
122
|
-
.catch(err=>{
|
|
123
|
-
this.error("Error on delete capability: " + err.message);
|
|
124
|
-
done();
|
|
125
|
-
})
|
|
126
|
-
};
|
|
127
|
-
done();
|
|
128
|
-
return;
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
RED.nodes.registerType("Video",AliceVideo);
|
|
132
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
module.exports = (RED) => {
|
|
3
|
+
function AliceVideo(config) {
|
|
4
|
+
RED.nodes.createNode(this, config);
|
|
5
|
+
const device = RED.nodes.getNode(config.device);
|
|
6
|
+
device.setMaxListeners(device.getMaxListeners() + 1);
|
|
7
|
+
const id = this.id;
|
|
8
|
+
const ctype = 'devices.capabilities.video_stream';
|
|
9
|
+
const instance = 'get_stream';
|
|
10
|
+
const stream_url = config.stream_url;
|
|
11
|
+
const protocol = config.protocol;
|
|
12
|
+
const curentState = {
|
|
13
|
+
type: ctype,
|
|
14
|
+
state: {
|
|
15
|
+
instance: instance,
|
|
16
|
+
value: {
|
|
17
|
+
stream_url: stream_url,
|
|
18
|
+
protocol: protocol
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
23
|
+
const init = () => {
|
|
24
|
+
this.debug("Starting capability initilization ...");
|
|
25
|
+
const capab = {
|
|
26
|
+
type: ctype,
|
|
27
|
+
retrievable: false,
|
|
28
|
+
reportable: false,
|
|
29
|
+
parameters: {
|
|
30
|
+
instance: instance,
|
|
31
|
+
protocols: [protocol]
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
device.setCapability(id, capab)
|
|
35
|
+
.then(() => {
|
|
36
|
+
this.debug("Capability initilization - success!");
|
|
37
|
+
this.status({ fill: "green", shape: "dot", text: "online" });
|
|
38
|
+
})
|
|
39
|
+
.catch(err => {
|
|
40
|
+
this.error("Error on create capability: " + err.message);
|
|
41
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
42
|
+
});
|
|
43
|
+
device.updateCapabState(id, curentState)
|
|
44
|
+
.then(() => {
|
|
45
|
+
this.status({ fill: "green", shape: "dot", text: "online" });
|
|
46
|
+
})
|
|
47
|
+
.catch(err => {
|
|
48
|
+
this.error("Error on update capability state: " + err.message);
|
|
49
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
if (device.initState)
|
|
53
|
+
init();
|
|
54
|
+
device.on("online", () => {
|
|
55
|
+
init();
|
|
56
|
+
});
|
|
57
|
+
device.on("offline", () => {
|
|
58
|
+
this.status({ fill: "red", shape: "dot", text: "offline" });
|
|
59
|
+
});
|
|
60
|
+
device.on(id, () => {
|
|
61
|
+
device.updateCapabState(id, curentState)
|
|
62
|
+
.then(() => {
|
|
63
|
+
const str_url = stream_url.slice(0, 25) + "...";
|
|
64
|
+
this.status({ fill: "green", shape: "dot", text: str_url });
|
|
65
|
+
})
|
|
66
|
+
.catch(err => {
|
|
67
|
+
this.error("Error on update capability state: " + err.message);
|
|
68
|
+
this.status({ fill: "red", shape: "dot", text: "Error" });
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
this.on('close', (removed, done) => {
|
|
72
|
+
device.setMaxListeners(device.getMaxListeners() - 1);
|
|
73
|
+
if (removed) {
|
|
74
|
+
device.delCapability(id)
|
|
75
|
+
.then(() => { done(); })
|
|
76
|
+
.catch(err => {
|
|
77
|
+
this.error("Error on delete capability: " + err.message);
|
|
78
|
+
done();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
done();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
RED.nodes.registerType("Video", AliceVideo);
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=alice-video.js.map
|
package/nodes/alice.js
CHANGED
|
@@ -1,125 +1,130 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
const axios_1 = __importDefault(require("axios"));
|
|
6
|
+
const mqtt_1 = __importDefault(require("mqtt"));
|
|
7
|
+
module.exports = (RED) => {
|
|
8
|
+
function AliceService(config) {
|
|
9
|
+
RED.nodes.createNode(this, config);
|
|
10
|
+
this.debug("Starting Alice service... ID: " + this.id);
|
|
11
|
+
const email = this.credentials.email;
|
|
12
|
+
const login = this.credentials.id;
|
|
13
|
+
const password = this.credentials.password;
|
|
14
|
+
const token = this.credentials.token;
|
|
15
|
+
const suburl = Buffer.from(email).toString('base64');
|
|
16
|
+
RED.httpAdmin.get("/noderedhome/" + suburl + "/clearalldevice", (_req, res) => {
|
|
17
|
+
axios_1.default.request({
|
|
18
|
+
method: 'POST',
|
|
19
|
+
url: 'https://api.nodered-home.ru/gtw/device/clearallconfigs',
|
|
20
|
+
headers: {
|
|
21
|
+
'content-type': 'application/json',
|
|
22
|
+
'Authorization': "Bearer " + this.getToken()
|
|
23
|
+
},
|
|
24
|
+
data: {}
|
|
25
|
+
})
|
|
26
|
+
.then(() => {
|
|
27
|
+
this.trace("All devices configs deleted on gateway successfully");
|
|
28
|
+
res.sendStatus(200);
|
|
29
|
+
})
|
|
30
|
+
.catch(error => {
|
|
31
|
+
this.debug("Error when delete All devices configs deleted on gateway: " + error.message);
|
|
32
|
+
res.sendStatus(500);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
RED.httpAdmin.get("/noderedhome/" + this.id + "/getfullconfig", (_req, res) => {
|
|
36
|
+
axios_1.default.request({
|
|
37
|
+
method: 'GET',
|
|
38
|
+
url: 'https://api.iot.yandex.net/v1.0/user/info',
|
|
39
|
+
headers: {
|
|
40
|
+
'content-type': 'application/json',
|
|
41
|
+
'Authorization': "Bearer " + this.getToken()
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
.then(result => {
|
|
45
|
+
this.trace("Full Alice SmartHome config successfully retrieved");
|
|
46
|
+
res.json(result.data);
|
|
47
|
+
})
|
|
48
|
+
.catch(error => {
|
|
49
|
+
this.debug("Error when retrieve Alice SmartHome config: " + error.message);
|
|
50
|
+
res.sendStatus(500);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
this.isOnline = false;
|
|
54
|
+
if (!token) {
|
|
55
|
+
this.error("Authentication is required!!!");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const mqttClient = mqtt_1.default.connect("mqtts://mqtt.cloud.yandex.net", {
|
|
59
|
+
port: 8883,
|
|
60
|
+
clientId: login,
|
|
61
|
+
rejectUnauthorized: false,
|
|
62
|
+
username: login,
|
|
63
|
+
password: password,
|
|
64
|
+
reconnectPeriod: 10000
|
|
65
|
+
});
|
|
66
|
+
mqttClient.on("message", (topic, payload) => {
|
|
67
|
+
const arrTopic = topic.split('/');
|
|
68
|
+
const data = JSON.parse(payload.toString());
|
|
69
|
+
this.trace("Incoming:" + topic + " timestamp:" + new Date().getTime());
|
|
70
|
+
if (payload.length && typeof data === 'object') {
|
|
71
|
+
if (arrTopic[3] == 'message') {
|
|
72
|
+
this.warn(data.text);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
this.emit(arrTopic[3], data);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
mqttClient.on("connect", () => {
|
|
80
|
+
this.debug("Yandex IOT client connected. ");
|
|
81
|
+
this.emit('online');
|
|
82
|
+
mqttClient.subscribe("$me/device/commands/+", () => {
|
|
83
|
+
this.debug("Yandex IOT client subscribed to the command");
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
mqttClient.on("offline", () => {
|
|
87
|
+
this.debug("Yandex IOT client offline. ");
|
|
88
|
+
this.emit('offline');
|
|
89
|
+
});
|
|
90
|
+
mqttClient.on("disconnect", () => {
|
|
91
|
+
this.debug("Yandex IOT client disconnect.");
|
|
92
|
+
this.emit('offline');
|
|
93
|
+
});
|
|
94
|
+
mqttClient.on("reconnect", () => {
|
|
95
|
+
this.debug("Yandex IOT client reconnecting ...");
|
|
96
|
+
});
|
|
97
|
+
mqttClient.on("error", (err) => {
|
|
98
|
+
this.error("Yandex IOT client Error: " + err.message);
|
|
99
|
+
this.emit('offline');
|
|
100
|
+
});
|
|
101
|
+
this.on('offline', () => {
|
|
102
|
+
this.isOnline = false;
|
|
103
|
+
});
|
|
104
|
+
this.on('online', () => {
|
|
105
|
+
this.isOnline = true;
|
|
106
|
+
});
|
|
107
|
+
this.on('close', (done) => {
|
|
108
|
+
this.emit('offline');
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
mqttClient.end(false, {}, done);
|
|
111
|
+
}, 500);
|
|
112
|
+
});
|
|
113
|
+
this.send2gate = (path, data, retain) => {
|
|
114
|
+
this.trace("Outgoing: " + path);
|
|
115
|
+
mqttClient.publish(path, data, { qos: 0, retain: retain });
|
|
116
|
+
};
|
|
117
|
+
this.getToken = () => {
|
|
118
|
+
return JSON.parse(token).access_token;
|
|
60
119
|
};
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
mqttClient.on("connect",()=>{
|
|
64
|
-
this.debug("Yandex IOT client connected. ");
|
|
65
|
-
this.emit('online');
|
|
66
|
-
// Подписываемся на получение комманд
|
|
67
|
-
mqttClient.subscribe("$me/device/commands/+",_=>{
|
|
68
|
-
this.debug("Yandex IOT client subscribed to the command");
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
mqttClient.on("offline",()=>{
|
|
72
|
-
this.debug("Yandex IOT client offline. ");
|
|
73
|
-
this.emit('offline');
|
|
74
|
-
});
|
|
75
|
-
mqttClient.on("disconnect",()=>{
|
|
76
|
-
this.debug("Yandex IOT client disconnect.");
|
|
77
|
-
this.emit('offline');
|
|
78
|
-
});
|
|
79
|
-
mqttClient.on("reconnect",(err)=>{
|
|
80
|
-
this.debug("Yandex IOT client reconnecting ...");
|
|
81
|
-
});
|
|
82
|
-
mqttClient.on("error",(err)=>{
|
|
83
|
-
this.error("Yandex IOT client Error: "+ err.message);
|
|
84
|
-
this.emit('offline');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
this.on('offline', ()=>{
|
|
88
|
-
this.isOnline = false;
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
this.on('online', ()=>{
|
|
92
|
-
this.isOnline = true;
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
this.on('close',(done)=>{
|
|
96
|
-
this.emit('offline');
|
|
97
|
-
setTimeout(()=>{
|
|
98
|
-
mqttClient.end(false,done);
|
|
99
|
-
},500)
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
this.send2gate= (path,data,retain)=>{
|
|
103
|
-
// this.debug(path);
|
|
104
|
-
// this.debug(data);
|
|
105
|
-
this.trace("Outgoing: "+path);
|
|
106
|
-
mqttClient.publish(path, data ,{ qos: 0, retain: retain });
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
this.getToken = ()=>{
|
|
110
|
-
return JSON.parse(token).access_token;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
};
|
|
114
|
-
RED.nodes.registerType("alice-service",AliceService,{
|
|
115
|
-
credentials: {
|
|
116
|
-
email: {type: "text"},
|
|
117
|
-
password: {type: "password"},
|
|
118
|
-
token: {type: "password"},
|
|
119
|
-
id:{type:"text"}
|
|
120
120
|
}
|
|
121
|
-
|
|
121
|
+
RED.nodes.registerType("alice-service", AliceService, {
|
|
122
|
+
credentials: {
|
|
123
|
+
email: { type: "text" },
|
|
124
|
+
password: { type: "password" },
|
|
125
|
+
token: { type: "password" },
|
|
126
|
+
id: { type: "text" }
|
|
127
|
+
}
|
|
128
|
+
});
|
|
122
129
|
};
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
//# sourceMappingURL=alice.js.map
|
package/nodes/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-alice",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "",
|
|
5
|
-
"main": "alice.js",
|
|
6
5
|
"scripts": {
|
|
7
6
|
"start": "npm run build && node-red",
|
|
8
7
|
"build": "tsc && npm run copy-html",
|
|
9
|
-
"copy-html": "cp ./src/*.html ./nodes/"
|
|
10
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
"copy-html": "cp ./src/*.html ./nodes/"
|
|
11
9
|
},
|
|
12
10
|
"repository": {
|
|
13
11
|
"type": "git",
|
|
@@ -49,12 +47,28 @@
|
|
|
49
47
|
"mqtt": "^4.3.8"
|
|
50
48
|
},
|
|
51
49
|
"devDependencies": {
|
|
52
|
-
"@types/axios": "^0.14.0",
|
|
53
50
|
"@types/node": "^20.11.16",
|
|
54
51
|
"@types/node-red": "^1.3.4",
|
|
55
|
-
"
|
|
56
|
-
"@typescript-eslint/parser": "^6.20.0",
|
|
57
|
-
"eslint": "^8.56.0",
|
|
52
|
+
"nodemon": "^3.0.3",
|
|
58
53
|
"typescript": "^5.3.3"
|
|
54
|
+
},
|
|
55
|
+
"nodemonConfig": {
|
|
56
|
+
"ignoreRoot": [".git", "test"],
|
|
57
|
+
"restartable": "rs",
|
|
58
|
+
"ignore": [
|
|
59
|
+
"node_modules/**/node_modules",
|
|
60
|
+
"node_modules/**/test",
|
|
61
|
+
"*.log"
|
|
62
|
+
],
|
|
63
|
+
"verbose": true,
|
|
64
|
+
"delay": "1000",
|
|
65
|
+
"events": {
|
|
66
|
+
"restart": "echo ------ restarted due to: $FILENAME ------"
|
|
67
|
+
},
|
|
68
|
+
"watch": [
|
|
69
|
+
"src/",
|
|
70
|
+
"node_modules/node-red-*"
|
|
71
|
+
],
|
|
72
|
+
"ext": "js json htm html css"
|
|
59
73
|
}
|
|
60
74
|
}
|