node-red-contrib-alice 2.2.3 → 2.2.5
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/.eslintrc.json +20 -0
- package/nodes/alice-device.html +6 -47
- package/nodes/alice-get.html +91 -0
- package/nodes/alice-get.js +10 -0
- package/nodes/alice-onoff.html +1 -1
- package/nodes/alice-onoff.js +2 -3
- package/nodes/alice-sensor.html +0 -2
- package/nodes/alice-sensor.js +1 -1
- package/nodes/alice.js +134 -122
- package/package.json +34 -3
- package/src/alice-get.html +91 -0
- package/src/alice-get.ts +18 -0
- package/src/alice.html +242 -0
- package/src/alice.ts +296 -0
- package/tsconfig.json +110 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es2021": true
|
|
5
|
+
},
|
|
6
|
+
"extends": [
|
|
7
|
+
"eslint:recommended",
|
|
8
|
+
"plugin:@typescript-eslint/recommended"
|
|
9
|
+
],
|
|
10
|
+
"parser": "@typescript-eslint/parser",
|
|
11
|
+
"parserOptions": {
|
|
12
|
+
"ecmaVersion": "latest",
|
|
13
|
+
"sourceType": "module"
|
|
14
|
+
},
|
|
15
|
+
"plugins": [
|
|
16
|
+
"@typescript-eslint"
|
|
17
|
+
],
|
|
18
|
+
"rules": {
|
|
19
|
+
}
|
|
20
|
+
}
|
package/nodes/alice-device.html
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
types: [
|
|
17
17
|
{
|
|
18
18
|
options: [
|
|
19
|
-
{ value: "devices.types.light", label: "Light" },
|
|
19
|
+
{ value: "devices.types.light", label: "Light" },
|
|
20
|
+
{ value: "devices.types.light.ceiling", label: "Light Сeiling" },
|
|
21
|
+
{ value: "devices.types.light.strip", label: "Light Strip" },
|
|
20
22
|
{ value: "devices.types.socket", label: "Socket" },
|
|
21
23
|
{ value: "devices.types.switch", label: "Switch" },
|
|
22
24
|
{ value: "devices.types.thermostat", label: "Thermostat" },
|
|
@@ -32,8 +34,11 @@
|
|
|
32
34
|
{ value: "devices.types.cooking.multicooker", label: "Multicooker" },
|
|
33
35
|
{ value: "devices.types.openable", label: "Door, gate, window, shutters" },
|
|
34
36
|
{ value: "devices.types.openable.curtain", label: "Curtains, blinds" },
|
|
37
|
+
{ value: "devices.types.openable.valve", label: "Valve (ball valve)" },
|
|
35
38
|
{ value: "devices.types.humidifier", label: "Humidifier" },
|
|
36
39
|
{ value: "devices.types.purifier", label: "Air purifier" },
|
|
40
|
+
{ value: "devices.types.ventilation", label: "Ventilation" },
|
|
41
|
+
{ value: "devices.types.ventilation.fan", label: "Fan" },
|
|
37
42
|
{ value: "devices.types.vacuum_cleaner", label: "Vacuum cleaner robot" },
|
|
38
43
|
{ value: "devices.types.washing_machine", label: "Washing machine" },
|
|
39
44
|
{ value: "devices.types.dishwasher", label: "Dishwasher" },
|
|
@@ -86,50 +91,4 @@
|
|
|
86
91
|
<label for="node-config-input-dtype">Type</label>
|
|
87
92
|
<input type="text" id="node-config-input-dtype">
|
|
88
93
|
</div>
|
|
89
|
-
<!-- <div class="form-row">
|
|
90
|
-
<label for="node-config-input-dtype">Type</label>
|
|
91
|
-
<select id="node-config-input-dtype" style="width: 70%;">
|
|
92
|
-
<option value="devices.types.light">Light</option>
|
|
93
|
-
<option value="devices.types.socket">Socket</option>
|
|
94
|
-
<option value="devices.types.switch" >Switch</option>
|
|
95
|
-
<option value="devices.types.thermostat">Thermostat</option>
|
|
96
|
-
<option value="devices.types.thermostat.ac">Air conditioning</option>
|
|
97
|
-
<option value="devices.types.media_device">Multimedia</option>
|
|
98
|
-
<option value="devices.types.media_device.tv">TV</option>
|
|
99
|
-
<option value="devices.types.media_device.tv_box">TV Box</option>
|
|
100
|
-
<option value="devices.types.media_device.receiver">AV Receiver</option>
|
|
101
|
-
<option value="devices.types.camera">Camera</option>
|
|
102
|
-
<option value="devices.types.cooking">Kitchen appliances</option>
|
|
103
|
-
<option value="devices.types.cooking.coffee_maker">Coffee machine</option>
|
|
104
|
-
<option value="devices.types.cooking.kettle">Smart kettle</option>
|
|
105
|
-
<option value="devices.types.cooking.multicooker">Multicooker</option>
|
|
106
|
-
<option value="devices.types.openable">Door, gate, window, shutters</option>
|
|
107
|
-
<option value="devices.types.openable.curtain">Curtains, blinds</option>
|
|
108
|
-
<option value="devices.types.humidifier">Humidifier</option>
|
|
109
|
-
<option value="devices.types.purifier">Air purifier</option>
|
|
110
|
-
<option value="devices.types.vacuum_cleaner">Vacuum cleaner robot</option>
|
|
111
|
-
<option value="devices.types.washing_machine">Washing machine</option>
|
|
112
|
-
<option value="devices.types.dishwasher">Dishwasher</option>
|
|
113
|
-
<option value="devices.types.iron">Iron, steam generator</option>
|
|
114
|
-
<option value="devices.types.sensor">Sensor</option>
|
|
115
|
-
<option value="devices.types.sensor.motion">Sensor motion</option>
|
|
116
|
-
<option value="devices.types.sensor.vibration">Sensor vibration</option>
|
|
117
|
-
<option value="devices.types.sensor.illumination">Sensor illumination</option>
|
|
118
|
-
<option value="devices.types.sensor.open">Sensor open</option>
|
|
119
|
-
<option value="devices.types.sensor.climate">Sensor climate</option>
|
|
120
|
-
<option value="devices.types.sensor.water_leak">Sensor water_leak</option>
|
|
121
|
-
<option value="devices.types.sensor.button">Sensor button</option>
|
|
122
|
-
<option value="devices.types.sensor.gas">Sensor gas</option>
|
|
123
|
-
<option value="devices.types.sensor.smoke">Sensor smoke</option>
|
|
124
|
-
<option value="devices.types.smart_meter">Counter</option>
|
|
125
|
-
<option value="devices.types.smart_meter.cold_water">Cold Water counter</option>
|
|
126
|
-
<option value="devices.types.smart_meter.hot_water">Hot Water counter</option>
|
|
127
|
-
<option value="devices.types.smart_meter.electricity">Electricity counter</option>
|
|
128
|
-
<option value="devices.types.smart_meter.gas">Gas counter</option>
|
|
129
|
-
<option value="devices.types.smart_meter.heat">Heat Water counter</option>
|
|
130
|
-
<option value="devices.types.pet_drinking_fountain">Pet drinking fountain</option>
|
|
131
|
-
<option value="devices.types.pet_feeder">Pet feeder</option>
|
|
132
|
-
<option value="devices.types.other">Other</option>
|
|
133
|
-
</select>
|
|
134
|
-
</div> -->
|
|
135
94
|
</script>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
let udyaconfig={};
|
|
3
|
+
RED.nodes.registerType('Alice-Get',{
|
|
4
|
+
category: 'alice',
|
|
5
|
+
inputs:1,
|
|
6
|
+
outputs:1,
|
|
7
|
+
icon: "alice.png",
|
|
8
|
+
color: "#D8BFD8",
|
|
9
|
+
defaults:{
|
|
10
|
+
service: {value:"", type:"alice-service"},
|
|
11
|
+
device: {value:undefined}
|
|
12
|
+
},
|
|
13
|
+
label: function(){
|
|
14
|
+
return this.name || "Alice-Get";
|
|
15
|
+
},
|
|
16
|
+
oneditprepare: ()=>{
|
|
17
|
+
$("#node-input-service").change(function(e){
|
|
18
|
+
if (this.value &&this.value!='_ADD_'){
|
|
19
|
+
$.ajax({
|
|
20
|
+
url: "/noderedhome/"+this.value+"/getfullconfig",
|
|
21
|
+
type:"GET"
|
|
22
|
+
})
|
|
23
|
+
.done(result=>{
|
|
24
|
+
// RED.notify("Full Alice SmartHome config successfully retrieved", {type:"success"});
|
|
25
|
+
console.log(result);
|
|
26
|
+
udyaconfig=result;
|
|
27
|
+
updateHouse(result.households);
|
|
28
|
+
})
|
|
29
|
+
.fail(error=>{
|
|
30
|
+
RED.notify("Error when retrieve Alice SmartHome config", {type:"error"});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
$('#node-input-home')
|
|
35
|
+
.prop('disabled', 'disabled')
|
|
36
|
+
.change((e)=>{
|
|
37
|
+
let val = $('#node-input-home').find(":selected").val();
|
|
38
|
+
console.log(val);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
$('#node-input-room').prop('disabled', 'disabled');
|
|
42
|
+
$('#node-input-device').prop('disabled', 'disabled');
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
function updateHouse(data){
|
|
47
|
+
$('#node-input-home')
|
|
48
|
+
.find('option')
|
|
49
|
+
.remove()
|
|
50
|
+
.end();
|
|
51
|
+
udyaconfig.households.forEach(h => {
|
|
52
|
+
$('#node-input-home')
|
|
53
|
+
.append('<option value="'+h.id+'">'+h.name+'</option>');
|
|
54
|
+
});
|
|
55
|
+
$('#node-input-home')
|
|
56
|
+
.prop('disabled', false);
|
|
57
|
+
};
|
|
58
|
+
function updaterooms(house){
|
|
59
|
+
$('#node-input-room')
|
|
60
|
+
.find('option')
|
|
61
|
+
.remove()
|
|
62
|
+
.end();
|
|
63
|
+
udyaconfig.households.forEach(h => {
|
|
64
|
+
if (h.household_id==house){
|
|
65
|
+
$('#node-input-room')
|
|
66
|
+
.append('<option value="'+h.id+'">'+h.name+'</option>');
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
$('#node-input-room').prop('disabled', false);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<script type="text/x-red" data-template-name="Alice-Get">
|
|
75
|
+
<div class="form-row">
|
|
76
|
+
<label for="node-input-service">Account</label>
|
|
77
|
+
<input id="node-input-service">
|
|
78
|
+
</div>
|
|
79
|
+
<div class="form-row">
|
|
80
|
+
<label for="node-input-home">Home</label>
|
|
81
|
+
<select id="node-input-home" style="width: 70%;"></select>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="form-row">
|
|
84
|
+
<label for="node-input-room">Room</label>
|
|
85
|
+
<select id="node-input-room" style="width: 70%;"></select>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="form-row">
|
|
88
|
+
<label for="node-input-device">Room</label>
|
|
89
|
+
<select id="node-input-device" style="width: 70%;"></select>
|
|
90
|
+
</div>
|
|
91
|
+
</script>
|
package/nodes/alice-onoff.html
CHANGED
package/nodes/alice-onoff.js
CHANGED
|
@@ -5,7 +5,6 @@ function AliceOnOff(config){
|
|
|
5
5
|
const device = RED.nodes.getNode(config.device);
|
|
6
6
|
device.setMaxListeners(device.getMaxListeners() + 1); // увеличиваем лимит для event
|
|
7
7
|
const id =JSON.parse(JSON.stringify(this.id));
|
|
8
|
-
const name = config.name;
|
|
9
8
|
const ctype = 'devices.capabilities.on_off';
|
|
10
9
|
const instance = 'on';
|
|
11
10
|
let response = config.response;
|
|
@@ -22,8 +21,8 @@ function AliceOnOff(config){
|
|
|
22
21
|
if (config.response === undefined){
|
|
23
22
|
response = true;
|
|
24
23
|
};
|
|
25
|
-
if (
|
|
26
|
-
split =
|
|
24
|
+
if (config.split === undefined){
|
|
25
|
+
split = false;
|
|
27
26
|
};
|
|
28
27
|
|
|
29
28
|
this.status({fill:"red",shape:"dot",text:"offline"});
|
package/nodes/alice-sensor.html
CHANGED
package/nodes/alice-sensor.js
CHANGED
|
@@ -64,7 +64,7 @@ function AliceSensor(config){
|
|
|
64
64
|
if (done) {done();}
|
|
65
65
|
return;
|
|
66
66
|
};
|
|
67
|
-
if (unit == 'unit.temperature.celsius'){
|
|
67
|
+
if (unit == 'unit.temperature.celsius' || unit == 'unit.ampere'){
|
|
68
68
|
msg.payload = +msg.payload.toFixed(1);
|
|
69
69
|
}else {
|
|
70
70
|
msg.payload = +msg.payload.toFixed(0);
|
package/nodes/alice.js
CHANGED
|
@@ -1,125 +1,137 @@
|
|
|
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
|
+
;
|
|
8
|
+
;
|
|
9
|
+
;
|
|
10
|
+
module.exports = (RED) => {
|
|
11
|
+
function AliceService(config) {
|
|
12
|
+
RED.nodes.createNode(this, config);
|
|
13
|
+
this.debug("Starting Alice service... ID: " + this.id);
|
|
14
|
+
const email = this.credentials.email;
|
|
15
|
+
const login = this.credentials.id;
|
|
16
|
+
const password = this.credentials.password;
|
|
17
|
+
const token = this.credentials.token;
|
|
18
|
+
const suburl = Buffer.from(email).toString('base64');
|
|
19
|
+
RED.httpAdmin.get("/noderedhome/" + suburl + "/clearalldevice", (req, res) => {
|
|
20
|
+
const option = {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
url: 'https://api.nodered-home.ru/gtw/device/clearallconfigs',
|
|
23
|
+
headers: {
|
|
24
|
+
'content-type': 'application/json',
|
|
25
|
+
'Authorization': "Bearer " + this.getToken()
|
|
26
|
+
},
|
|
27
|
+
data: {}
|
|
28
|
+
};
|
|
29
|
+
axios_1.default.request(option)
|
|
30
|
+
.then(result => {
|
|
31
|
+
this.trace("All devices configs deleted on gateway successfully");
|
|
32
|
+
res.sendStatus(200);
|
|
33
|
+
})
|
|
34
|
+
.catch(error => {
|
|
35
|
+
this.debug("Error when delete All devices configs deleted on gateway: " + error.message);
|
|
36
|
+
res.sendStatus(500);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
RED.httpAdmin.get("/noderedhome/" + this.id + "/getfullconfig", (req, res) => {
|
|
40
|
+
const option = {
|
|
41
|
+
method: 'GET',
|
|
42
|
+
url: 'https://api.iot.yandex.net/v1.0/user/info',
|
|
43
|
+
headers: {
|
|
44
|
+
'content-type': 'application/json',
|
|
45
|
+
'Authorization': "Bearer " + this.getToken()
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
axios_1.default.request(option)
|
|
49
|
+
.then(result => {
|
|
50
|
+
this.trace("Full Alice SmartHome config successfully retrieved");
|
|
51
|
+
res.json(result.data);
|
|
52
|
+
})
|
|
53
|
+
.catch(error => {
|
|
54
|
+
this.debug("Error when retrieve Alice SmartHome config: " + error.message);
|
|
55
|
+
res.sendStatus(500);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
this.isOnline = false;
|
|
59
|
+
if (!token) {
|
|
60
|
+
this.error("Authentication is required!!!");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
;
|
|
64
|
+
const mqttClient = mqtt_1.default.connect("mqtts://mqtt.cloud.yandex.net", {
|
|
65
|
+
port: 8883,
|
|
66
|
+
clientId: login,
|
|
67
|
+
rejectUnauthorized: false,
|
|
68
|
+
username: login,
|
|
69
|
+
password: password,
|
|
70
|
+
reconnectPeriod: 10000
|
|
71
|
+
});
|
|
72
|
+
mqttClient.on("message", (topic, payload) => {
|
|
73
|
+
const arrTopic = topic.split('/');
|
|
74
|
+
const data = JSON.parse(payload);
|
|
75
|
+
this.trace("Incoming:" + topic + " timestamp:" + new Date().getTime());
|
|
76
|
+
if (payload.length && typeof data === 'object') {
|
|
77
|
+
if (arrTopic[3] == 'message') {
|
|
78
|
+
this.warn(data.text);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.emit(arrTopic[3], data);
|
|
82
|
+
}
|
|
83
|
+
;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
mqttClient.on("connect", () => {
|
|
87
|
+
this.debug("Yandex IOT client connected. ");
|
|
88
|
+
this.emit('online');
|
|
89
|
+
mqttClient.subscribe("$me/device/commands/+", _ => {
|
|
90
|
+
this.debug("Yandex IOT client subscribed to the command");
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
mqttClient.on("offline", () => {
|
|
94
|
+
this.debug("Yandex IOT client offline. ");
|
|
95
|
+
this.emit('offline');
|
|
96
|
+
});
|
|
97
|
+
mqttClient.on("disconnect", () => {
|
|
98
|
+
this.debug("Yandex IOT client disconnect.");
|
|
99
|
+
this.emit('offline');
|
|
100
|
+
});
|
|
101
|
+
mqttClient.on("reconnect", () => {
|
|
102
|
+
this.debug("Yandex IOT client reconnecting ...");
|
|
103
|
+
});
|
|
104
|
+
mqttClient.on("error", (err) => {
|
|
105
|
+
this.error("Yandex IOT client Error: " + err.message);
|
|
106
|
+
this.emit('offline');
|
|
107
|
+
});
|
|
108
|
+
this.on('offline', () => {
|
|
109
|
+
this.isOnline = false;
|
|
110
|
+
});
|
|
111
|
+
this.on('online', () => {
|
|
112
|
+
this.isOnline = true;
|
|
113
|
+
});
|
|
114
|
+
this.on('close', (done) => {
|
|
115
|
+
this.emit('offline');
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
mqttClient.end(false, done);
|
|
118
|
+
}, 500);
|
|
119
|
+
});
|
|
120
|
+
this.send2gate = (path, data, retain) => {
|
|
121
|
+
this.trace("Outgoing: " + path);
|
|
122
|
+
mqttClient.publish(path, data, { qos: 0, retain: retain });
|
|
123
|
+
};
|
|
124
|
+
this.getToken = () => {
|
|
125
|
+
return JSON.parse(token).access_token;
|
|
60
126
|
};
|
|
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
127
|
}
|
|
121
|
-
|
|
128
|
+
;
|
|
129
|
+
RED.nodes.registerType("alice-service", AliceService, {
|
|
130
|
+
credentials: {
|
|
131
|
+
email: { type: "text" },
|
|
132
|
+
password: { type: "password" },
|
|
133
|
+
token: { type: "password" },
|
|
134
|
+
id: { type: "text" }
|
|
135
|
+
}
|
|
136
|
+
});
|
|
122
137
|
};
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-alice",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.5",
|
|
4
4
|
"description": "",
|
|
5
|
-
"main": "alice.js",
|
|
6
5
|
"scripts": {
|
|
7
|
-
"
|
|
6
|
+
"start": "npm run build && node-red",
|
|
7
|
+
"build": "tsc && npm run copy-html",
|
|
8
|
+
"copy-html": "cp ./src/*.html ./nodes/"
|
|
8
9
|
},
|
|
9
10
|
"repository": {
|
|
10
11
|
"type": "git",
|
|
@@ -44,5 +45,35 @@
|
|
|
44
45
|
"dependencies": {
|
|
45
46
|
"axios": "^1.4.0",
|
|
46
47
|
"mqtt": "^4.3.8"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/axios": "^0.14.0",
|
|
51
|
+
"@types/mqtt": "^2.5.0",
|
|
52
|
+
"@types/node": "^20.11.16",
|
|
53
|
+
"@types/node-red": "^1.3.4",
|
|
54
|
+
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
|
55
|
+
"@typescript-eslint/parser": "^6.20.0",
|
|
56
|
+
"eslint": "^8.56.0",
|
|
57
|
+
"nodemon": "^3.0.3",
|
|
58
|
+
"typescript": "^5.3.3"
|
|
59
|
+
},
|
|
60
|
+
"nodemonConfig": {
|
|
61
|
+
"ignoreRoot" : [".git", "test"],
|
|
62
|
+
"restartable": "rs",
|
|
63
|
+
"ignore": [
|
|
64
|
+
"node_modules/**/node_modules",
|
|
65
|
+
"node_modules/**/test",
|
|
66
|
+
"*.log"
|
|
67
|
+
],
|
|
68
|
+
"verbose": true,
|
|
69
|
+
"delay": "1000",
|
|
70
|
+
"events": {
|
|
71
|
+
"restart": "echo ------ restarted due to: $FILENAME ------"
|
|
72
|
+
},
|
|
73
|
+
"watch": [
|
|
74
|
+
"src/",
|
|
75
|
+
"node_modules/node-red-*"
|
|
76
|
+
],
|
|
77
|
+
"ext": "js json htm html css"
|
|
47
78
|
}
|
|
48
79
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
let udyaconfig={};
|
|
3
|
+
RED.nodes.registerType('Alice-Get',{
|
|
4
|
+
category: 'alice',
|
|
5
|
+
inputs:1,
|
|
6
|
+
outputs:1,
|
|
7
|
+
icon: "alice.png",
|
|
8
|
+
color: "#D8BFD8",
|
|
9
|
+
defaults:{
|
|
10
|
+
service: {value:"", type:"alice-service"},
|
|
11
|
+
device: {value:undefined}
|
|
12
|
+
},
|
|
13
|
+
label: function(){
|
|
14
|
+
return this.name || "Alice-Get";
|
|
15
|
+
},
|
|
16
|
+
oneditprepare: ()=>{
|
|
17
|
+
$("#node-input-service").change(function(e){
|
|
18
|
+
if (this.value &&this.value!='_ADD_'){
|
|
19
|
+
$.ajax({
|
|
20
|
+
url: "/noderedhome/"+this.value+"/getfullconfig",
|
|
21
|
+
type:"GET"
|
|
22
|
+
})
|
|
23
|
+
.done(result=>{
|
|
24
|
+
// RED.notify("Full Alice SmartHome config successfully retrieved", {type:"success"});
|
|
25
|
+
console.log(result);
|
|
26
|
+
udyaconfig=result;
|
|
27
|
+
updateHouse(result.households);
|
|
28
|
+
})
|
|
29
|
+
.fail(error=>{
|
|
30
|
+
RED.notify("Error when retrieve Alice SmartHome config", {type:"error"});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
$('#node-input-home')
|
|
35
|
+
.prop('disabled', 'disabled')
|
|
36
|
+
.change((e)=>{
|
|
37
|
+
let val = $('#node-input-home').find(":selected").val();
|
|
38
|
+
console.log(val);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
$('#node-input-room').prop('disabled', 'disabled');
|
|
42
|
+
$('#node-input-device').prop('disabled', 'disabled');
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
function updateHouse(data){
|
|
47
|
+
$('#node-input-home')
|
|
48
|
+
.find('option')
|
|
49
|
+
.remove()
|
|
50
|
+
.end();
|
|
51
|
+
udyaconfig.households.forEach(h => {
|
|
52
|
+
$('#node-input-home')
|
|
53
|
+
.append('<option value="'+h.id+'">'+h.name+'</option>');
|
|
54
|
+
});
|
|
55
|
+
$('#node-input-home')
|
|
56
|
+
.prop('disabled', false);
|
|
57
|
+
};
|
|
58
|
+
function updaterooms(house){
|
|
59
|
+
$('#node-input-room')
|
|
60
|
+
.find('option')
|
|
61
|
+
.remove()
|
|
62
|
+
.end();
|
|
63
|
+
udyaconfig.households.forEach(h => {
|
|
64
|
+
if (h.household_id==house){
|
|
65
|
+
$('#node-input-room')
|
|
66
|
+
.append('<option value="'+h.id+'">'+h.name+'</option>');
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
$('#node-input-room').prop('disabled', false);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<script type="text/x-red" data-template-name="Alice-Get">
|
|
75
|
+
<div class="form-row">
|
|
76
|
+
<label for="node-input-service">Account</label>
|
|
77
|
+
<input id="node-input-service">
|
|
78
|
+
</div>
|
|
79
|
+
<div class="form-row">
|
|
80
|
+
<label for="node-input-home">Home</label>
|
|
81
|
+
<select id="node-input-home" style="width: 70%;"></select>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="form-row">
|
|
84
|
+
<label for="node-input-room">Room</label>
|
|
85
|
+
<select id="node-input-room" style="width: 70%;"></select>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="form-row">
|
|
88
|
+
<label for="node-input-device">Room</label>
|
|
89
|
+
<select id="node-input-device" style="width: 70%;"></select>
|
|
90
|
+
</div>
|
|
91
|
+
</script>
|