@hurenkam/hue-services 0.6.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/.github/workflows/node.js.yml +31 -0
- package/.nyc_output/ecb1b16f-015c-458b-96d5-32cb9569c1e8.json +1 -0
- package/.nyc_output/processinfo/ecb1b16f-015c-458b-96d5-32cb9569c1e8.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/.vscode/settings.json +15 -0
- package/.vscode/sftp.json +11 -0
- package/LICENSE +201 -0
- package/README.md +340 -0
- package/Todo.txt +18 -0
- package/coverage/BaseNode.js.html +379 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +101 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +161 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/src/RestApi.js.html +499 -0
- package/coverage/lcov-report/src/all.js.html +208 -0
- package/coverage/lcov-report/src/clip/ClipApi.js.html +1096 -0
- package/coverage/lcov-report/src/clip/Resource.js.html +481 -0
- package/coverage/lcov-report/src/clip/index.html +131 -0
- package/coverage/lcov-report/src/debug.js.html +253 -0
- package/coverage/lcov-report/src/files.js.html +118 -0
- package/coverage/lcov-report/src/index.html +161 -0
- package/coverage/lcov-report/src/nodes/BaseNode.js.html +381 -0
- package/coverage/lcov-report/src/nodes/BridgeConfigNode.js.html +817 -0
- package/coverage/lcov-report/src/nodes/ButtonNode.js.html +241 -0
- package/coverage/lcov-report/src/nodes/DevicePowerNode.js.html +199 -0
- package/coverage/lcov-report/src/nodes/GroupedLightNode.js.html +226 -0
- package/coverage/lcov-report/src/nodes/LightLevelNode.js.html +205 -0
- package/coverage/lcov-report/src/nodes/LightNode.js.html +226 -0
- package/coverage/lcov-report/src/nodes/MotionNode.js.html +205 -0
- package/coverage/lcov-report/src/nodes/RelativeRotaryNode.js.html +253 -0
- package/coverage/lcov-report/src/nodes/ResourceNode.js.html +388 -0
- package/coverage/lcov-report/src/nodes/SceneNode.js.html +124 -0
- package/coverage/lcov-report/src/nodes/ServiceNode.js.html +124 -0
- package/coverage/lcov-report/src/nodes/TemperatureNode.js.html +205 -0
- package/coverage/lcov-report/src/nodes/ZigbeeConnectivityNode.js.html +199 -0
- package/coverage/lcov-report/src/nodes/index.html +311 -0
- package/coverage/lcov-report/src/ui/BaseUI.js.html +484 -0
- package/coverage/lcov-report/src/ui/BridgeConfigUI.js.html +475 -0
- package/coverage/lcov-report/src/ui/ButtonUI.js.html +166 -0
- package/coverage/lcov-report/src/ui/DevicePowerUI.js.html +166 -0
- package/coverage/lcov-report/src/ui/GroupedLightUI.js.html +178 -0
- package/coverage/lcov-report/src/ui/LightLevelUI.js.html +166 -0
- package/coverage/lcov-report/src/ui/LightUI.js.html +178 -0
- package/coverage/lcov-report/src/ui/MotionUI.js.html +166 -0
- package/coverage/lcov-report/src/ui/RelativeRotaryUI.js.html +166 -0
- package/coverage/lcov-report/src/ui/ResourceUI.js.html +511 -0
- package/coverage/lcov-report/src/ui/SceneUI.js.html +160 -0
- package/coverage/lcov-report/src/ui/ServiceUI.js.html +868 -0
- package/coverage/lcov-report/src/ui/TemperatureUI.js.html +166 -0
- package/coverage/lcov-report/src/ui/ZigbeeConnectivityUI.js.html +166 -0
- package/coverage/lcov-report/src/ui/index.html +311 -0
- package/coverage/lcov.info +2217 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/coverage/src/RestApi.js.html +499 -0
- package/coverage/src/all.js.html +208 -0
- package/coverage/src/clip/ClipApi.js.html +1183 -0
- package/coverage/src/clip/Resource.js.html +481 -0
- package/coverage/src/clip/index.html +131 -0
- package/coverage/src/debug.js.html +253 -0
- package/coverage/src/files.js.html +118 -0
- package/coverage/src/index.html +116 -0
- package/coverage/src/nodes/BaseNode.js.html +379 -0
- package/coverage/src/nodes/BridgeConfigNode.js.html +517 -0
- package/coverage/src/nodes/ButtonNode.js.html +238 -0
- package/coverage/src/nodes/DevicePowerNode.js.html +196 -0
- package/coverage/src/nodes/GroupedLightNode.js.html +223 -0
- package/coverage/src/nodes/LightLevelNode.js.html +202 -0
- package/coverage/src/nodes/LightNode.js.html +223 -0
- package/coverage/src/nodes/MotionNode.js.html +202 -0
- package/coverage/src/nodes/RelativeRotaryNode.js.html +250 -0
- package/coverage/src/nodes/ResourceNode.js.html +373 -0
- package/coverage/src/nodes/SceneNode.js.html +124 -0
- package/coverage/src/nodes/ServiceNode.js.html +124 -0
- package/coverage/src/nodes/TemperatureNode.js.html +202 -0
- package/coverage/src/nodes/ZigbeeConnectivityNode.js.html +199 -0
- package/coverage/src/nodes/index.html +311 -0
- package/coverage/src/ui/BaseUI.js.html +484 -0
- package/coverage/src/ui/BridgeConfigUI.js.html +475 -0
- package/coverage/src/ui/ButtonUI.js.html +166 -0
- package/coverage/src/ui/DevicePowerUI.js.html +166 -0
- package/coverage/src/ui/GroupedLightUI.js.html +178 -0
- package/coverage/src/ui/LightLevelUI.js.html +166 -0
- package/coverage/src/ui/LightUI.js.html +178 -0
- package/coverage/src/ui/MotionUI.js.html +166 -0
- package/coverage/src/ui/RelativeRotaryUI.js.html +166 -0
- package/coverage/src/ui/ResourceUI.js.html +511 -0
- package/coverage/src/ui/SceneUI.js.html +160 -0
- package/coverage/src/ui/ServiceUI.js.html +868 -0
- package/coverage/src/ui/TemperatureUI.js.html +166 -0
- package/coverage/src/ui/ZigbeeConnectivityUI.js.html +166 -0
- package/coverage/src/ui/index.html +311 -0
- package/examples/flows.json +959 -0
- package/package.json +53 -0
- package/screenshots/Screenshot from 2022-11-29 00-29-23.png +0 -0
- package/screenshots/Screenshot from 2022-11-29 00-30-16.png +0 -0
- package/screenshots/Screenshot from 2022-11-29 00-30-58.png +0 -0
- package/screenshots/Screenshot from 2022-11-29 00-31-29.png +0 -0
- package/src/RestApi.js +138 -0
- package/src/all.html +52 -0
- package/src/all.js +42 -0
- package/src/clip/ClipApi.js +367 -0
- package/src/clip/Resource.js +132 -0
- package/src/debug.js +56 -0
- package/src/files.js +12 -0
- package/src/hue.js +98 -0
- package/src/nodes/BaseNode.js +98 -0
- package/src/nodes/BridgeConfigNode.js +144 -0
- package/src/nodes/ButtonNode.js +51 -0
- package/src/nodes/DevicePowerNode.js +37 -0
- package/src/nodes/GroupedLightNode.js +46 -0
- package/src/nodes/LightLevelNode.js +39 -0
- package/src/nodes/LightNode.js +46 -0
- package/src/nodes/MotionNode.js +39 -0
- package/src/nodes/RelativeRotaryNode.js +55 -0
- package/src/nodes/ResourceNode.js +95 -0
- package/src/nodes/SceneNode.js +13 -0
- package/src/nodes/ServiceNode.js +13 -0
- package/src/nodes/TemperatureNode.js +39 -0
- package/src/nodes/ZigbeeConnectivityNode.js +38 -0
- package/src/ui/BaseUI.js +133 -0
- package/src/ui/BridgeConfigUI.js +130 -0
- package/src/ui/ButtonUI.js +27 -0
- package/src/ui/DevicePowerUI.js +27 -0
- package/src/ui/GroupedLightUI.js +31 -0
- package/src/ui/LightLevelUI.js +27 -0
- package/src/ui/LightUI.js +31 -0
- package/src/ui/MotionUI.js +27 -0
- package/src/ui/RelativeRotaryUI.js +27 -0
- package/src/ui/ResourceUI.js +142 -0
- package/src/ui/SceneUI.js +25 -0
- package/src/ui/ServiceUI.js +261 -0
- package/src/ui/TemperatureUI.js +27 -0
- package/src/ui/ZigbeeConnectivityUI.js +27 -0
- package/test/BaseNode_spec.js +246 -0
- package/test/BaseUI_spec.js +17 -0
- package/test/BridgeConfigNode_spec.js +184 -0
- package/test/ButtonNode_spec.js +178 -0
- package/test/ClipApi_spec.js +769 -0
- package/test/DevicePowerNode_spec.js +186 -0
- package/test/GroupedLightNode_spec.js +218 -0
- package/test/LightLevelNode_spec.js +154 -0
- package/test/LightNode_spec.js +218 -0
- package/test/MotionNode_spec.js +186 -0
- package/test/RelativeRotataryNode_spec.js +325 -0
- package/test/ResourceNode_spec.js +308 -0
- package/test/Resource_spec.js +392 -0
- package/test/SceneNode_spec.js +33 -0
- package/test/ServiceNode_spec.js +33 -0
- package/test/TemperatureNode_spec.js +153 -0
- package/test/ZigbeeConnectivityNode_spec.js +186 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ServiceUI } from "./ServiceUI.js"
|
|
2
|
+
|
|
3
|
+
export class DevicePowerUI extends ServiceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Device Power","hue services","device_power");
|
|
6
|
+
console.log("DevicePowerUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#B0E0FF";
|
|
9
|
+
this.config.icon = "font-awesome/fa-battery-three-quarters";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
buildHelp() {
|
|
13
|
+
var help = super.buildHelp();
|
|
14
|
+
help["Outputs"] += "\
|
|
15
|
+
The Device Power node only has one output. It will listen to events for the specified service \
|
|
16
|
+
and forward them to the output as `msg.payload` which contains the device_power events in a \
|
|
17
|
+
JSON format conform the clip v2 specification.\n\n\
|
|
18
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
19
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
20
|
+
return help;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
onEditPrepare(config) {
|
|
24
|
+
super.onEditPrepare(config);
|
|
25
|
+
$('#node-container-rtype').hide();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ServiceUI } from "./ServiceUI.js"
|
|
2
|
+
|
|
3
|
+
export class GroupedLightUI extends ServiceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Grouped Light","hue services","grouped_light");
|
|
6
|
+
console.log("GroupedLightUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#FFFFA8";
|
|
9
|
+
this.config.icon = "light.svg";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
buildHelp() {
|
|
13
|
+
var help = super.buildHelp();
|
|
14
|
+
help["Inputs"] += "\
|
|
15
|
+
The Grouped Light node accepts input. The `msg.payload` content (in JSON format) will be send as a put request to the associated Clip v2 resource url.\n\n\
|
|
16
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
17
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
18
|
+
help["Outputs"] += "\
|
|
19
|
+
The Grouped Light node only has one output. It will listen to Clip v2 events for this service \
|
|
20
|
+
and forward them to the output as `msg.payload` which contains the grouped_light events in a \
|
|
21
|
+
JSON format conform the clip v2 specification.\n\n\
|
|
22
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
23
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
24
|
+
return help;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
onEditPrepare(config) {
|
|
28
|
+
super.onEditPrepare(config);
|
|
29
|
+
$('#node-container-rtype').hide();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ServiceUI } from "./ServiceUI.js"
|
|
2
|
+
|
|
3
|
+
export class LightLevelUI extends ServiceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Light Level","hue services","light_level");
|
|
6
|
+
console.log("LightLevelUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#FFFFFF";
|
|
9
|
+
this.config.icon = "font-awesome/fa-sun-o";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
buildHelp() {
|
|
13
|
+
var help = super.buildHelp();
|
|
14
|
+
help["Outputs"] += "\
|
|
15
|
+
The Light Level node only has one output. It will listen to events for the specified service \
|
|
16
|
+
and forward them to the output as `msg.payload` which contains the light_level events in a \
|
|
17
|
+
JSON format conform the clip v2 specification.\n\n\
|
|
18
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
19
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
20
|
+
return help;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
onEditPrepare(config) {
|
|
24
|
+
super.onEditPrepare(config);
|
|
25
|
+
$('#node-container-rtype').hide();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ServiceUI } from "./ServiceUI.js"
|
|
2
|
+
|
|
3
|
+
export class LightUI extends ServiceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Light","hue services","light");
|
|
6
|
+
console.log("LightUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#FFFFD8";
|
|
9
|
+
this.config.icon = "light.svg";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
buildHelp() {
|
|
13
|
+
var help = super.buildHelp();
|
|
14
|
+
help["Inputs"] += "\
|
|
15
|
+
The Light node accepts input. The `msg.payload` content (in JSON format) will be send as a put request to the associated Clip v2 resource url.\n\n\
|
|
16
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
17
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
18
|
+
help["Outputs"] += "\
|
|
19
|
+
The Light node only has one output. It will listen to Clip v2 events for this service \
|
|
20
|
+
and forward them to the output as `msg.payload` which contains the light events in a \
|
|
21
|
+
JSON format conform the clip v2 specification.\n\n\
|
|
22
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
23
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
24
|
+
return help;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
onEditPrepare(config) {
|
|
28
|
+
super.onEditPrepare(config);
|
|
29
|
+
$('#node-container-rtype').hide();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ServiceUI } from "./ServiceUI.js"
|
|
2
|
+
|
|
3
|
+
export class MotionUI extends ServiceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Motion","hue services","motion");
|
|
6
|
+
console.log("MotionUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#FFC0FF";
|
|
9
|
+
this.config.icon = "font-awesome/fa-rss";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
buildHelp() {
|
|
13
|
+
var help = super.buildHelp();
|
|
14
|
+
help["Outputs"] += "\
|
|
15
|
+
The Motion node only has one output. It will listen to events for the specified service \
|
|
16
|
+
and forward them to the output as `msg.payload` which contains the motion events in a \
|
|
17
|
+
JSON format conform the clip v2 specification.\n\n\
|
|
18
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
19
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
20
|
+
return help;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
onEditPrepare(config) {
|
|
24
|
+
super.onEditPrepare(config);
|
|
25
|
+
$('#node-container-rtype').hide();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ServiceUI } from "./ServiceUI.js"
|
|
2
|
+
|
|
3
|
+
export class RelativeRotaryUI extends ServiceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Relative Rotary","hue services","relative_rotary");
|
|
6
|
+
console.log("RelativeRotaryUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#E0FFB0";
|
|
9
|
+
this.config.icon = "font-awesome/fa-circle-o-notch";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
buildHelp() {
|
|
13
|
+
var help = super.buildHelp();
|
|
14
|
+
help["Outputs"] += "\
|
|
15
|
+
The Relative Rotary node only has one output. It will listen to events for the specified service \
|
|
16
|
+
and forward them to the output as `msg.payload` which contains the relative_rotary events in a \
|
|
17
|
+
JSON format conform the clip v2 specification.\n\n\
|
|
18
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
19
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
20
|
+
return help;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
onEditPrepare(config) {
|
|
24
|
+
super.onEditPrepare(config);
|
|
25
|
+
$('#node-container-rtype').hide();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { BaseUI } from "./BaseUI.js";
|
|
2
|
+
|
|
3
|
+
export class ResourceUI extends BaseUI {
|
|
4
|
+
#rtype;
|
|
5
|
+
#models;
|
|
6
|
+
|
|
7
|
+
constructor(label="Resource",category="hue services",rtype=null,models=null) {
|
|
8
|
+
super(label,category);
|
|
9
|
+
console.log("ResourceUI.constructor()");
|
|
10
|
+
|
|
11
|
+
this.config.defaults.name = { value:"" };
|
|
12
|
+
this.config.defaults.bridge = { type: "BridgeConfigNode", required: true };
|
|
13
|
+
this.config.defaults.uuid = { value:"", required: true };
|
|
14
|
+
|
|
15
|
+
this.config.inputs = 1;
|
|
16
|
+
this.config.color = "#EEEEEE";
|
|
17
|
+
this.config.icon = "font-awesome/fa-gears";
|
|
18
|
+
|
|
19
|
+
this.#rtype = rtype;
|
|
20
|
+
this.#models = models;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
buildHelp() {
|
|
24
|
+
var help = super.buildHelp();
|
|
25
|
+
help["Settings"] += "\
|
|
26
|
+
#### Bridge\n\
|
|
27
|
+
Select the hue bridge for your device or resource.\n\n\
|
|
28
|
+
#### UUID\n\
|
|
29
|
+
Select the device or service by UUID, you can toggle between search \
|
|
30
|
+
and manual input. The search will query the bridge for suitable devices \
|
|
31
|
+
and present them as a selection list.\n\n\
|
|
32
|
+
";
|
|
33
|
+
return help;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
ui(){
|
|
37
|
+
var text = super.ui();
|
|
38
|
+
console.log("ResourceUI.ui()");
|
|
39
|
+
text += this.uiTextInput("bridge","Bridge");
|
|
40
|
+
text += this.uiSelectInput("uuid","UUID");
|
|
41
|
+
return text;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
selectText(id) {
|
|
45
|
+
console.log("ResourceUI.selectText()");
|
|
46
|
+
|
|
47
|
+
var current = $('#node-input-'+id).val();
|
|
48
|
+
$('#input-select-'+id).empty();
|
|
49
|
+
$('#input-select-'+id).append('<input type="text" id="node-input-'+id+'" style="width: 100%" value="'+current+'" />');
|
|
50
|
+
|
|
51
|
+
var button = $("#input-select-"+id+"-search");
|
|
52
|
+
var icon = button.find("i");
|
|
53
|
+
icon.removeClass("fa-pencil");
|
|
54
|
+
icon.addClass("fa-search");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
selectOption(id,url,data) {
|
|
58
|
+
console.log("ResourceUI.selectOption()");
|
|
59
|
+
var current = $('#node-input-'+id).val();
|
|
60
|
+
var notification = RED.notify("Searching for options...", {
|
|
61
|
+
type: "compact", modal: true, fixed: true
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
$.get(url, data)
|
|
65
|
+
.done( function(data) {
|
|
66
|
+
var options = JSON.parse(data);
|
|
67
|
+
|
|
68
|
+
if(options.length <= 0)
|
|
69
|
+
{
|
|
70
|
+
notification.close();
|
|
71
|
+
RED.notify("No options found.", { type: "error" });
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
$("#node-input-"+id).typedInput({
|
|
76
|
+
types: [
|
|
77
|
+
{
|
|
78
|
+
value: current,
|
|
79
|
+
options: options
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
var button = $("#input-select-"+id+"-search");
|
|
85
|
+
var icon = button.find("i");
|
|
86
|
+
icon.removeClass("fa-search");
|
|
87
|
+
icon.addClass("fa-pencil");
|
|
88
|
+
|
|
89
|
+
// Remove the notification
|
|
90
|
+
notification.close();
|
|
91
|
+
})
|
|
92
|
+
.fail(function()
|
|
93
|
+
{
|
|
94
|
+
console.log("ResourceUI.selectOption(): failed");
|
|
95
|
+
|
|
96
|
+
// Remove the notification
|
|
97
|
+
notification.close();
|
|
98
|
+
RED.notify("unknown error", "error");
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
selectResource() {
|
|
103
|
+
console.log("ResourceUI.selectResource()");
|
|
104
|
+
var bridge_id = $('#node-input-bridge').val();
|
|
105
|
+
if(!bridge_id) {
|
|
106
|
+
console.log("ResourceUI.selectResource() invalid bridge_id:", bridge_id);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
var bridge = RED.nodes.node(bridge_id);
|
|
111
|
+
if(!bridge) {
|
|
112
|
+
console.log("ResourceUI.selectResource(): invalid bridge:", bridge);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.selectOption(
|
|
117
|
+
"uuid",
|
|
118
|
+
"BridgeConfigNode/GetSortedResourceOptions",
|
|
119
|
+
{
|
|
120
|
+
type: this.#rtype,
|
|
121
|
+
bridge_id: bridge.id,
|
|
122
|
+
models: this.#models
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
onEditPrepare(config) {
|
|
128
|
+
super.onEditPrepare(config);
|
|
129
|
+
console.log("ResourceUI.onEditPrepare()");
|
|
130
|
+
var instance = this;
|
|
131
|
+
|
|
132
|
+
$('#input-select-uuid-search').click(function()
|
|
133
|
+
{
|
|
134
|
+
if($('#input-select-uuid').find(".red-ui-typedInput-container").length > 0) {
|
|
135
|
+
instance.selectText("uuid");
|
|
136
|
+
} else {
|
|
137
|
+
instance.selectResource();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
instance.selectResource();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ResourceUI } from "./ResourceUI.js"
|
|
2
|
+
|
|
3
|
+
export class SceneUI extends ResourceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Scene","hue services","scene");
|
|
6
|
+
console.log("SceneUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#FFCCCC";
|
|
9
|
+
this.config.inputs = 1;
|
|
10
|
+
this.config.outputs = 1;
|
|
11
|
+
this.config.icon = "font-awesome/fa-tachometer";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
buildHelp() {
|
|
15
|
+
var help = super.buildHelp();
|
|
16
|
+
help["Input"] = "\
|
|
17
|
+
If you wish to send input to the scene, you need to address the scene specifically either by \
|
|
18
|
+
adding its resource id to the `msg.rids` list (formatted as JSON), or adding the 'scene' type \
|
|
19
|
+
to the `msg.rtypes` list (formatted as JSON).\n\
|
|
20
|
+
The content of `msg.payload` will then be forwarded as a 'put' request to the clip v2 url \
|
|
21
|
+
for the scene.\n\n\
|
|
22
|
+
";
|
|
23
|
+
return help;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { BaseUI } from "./BaseUI.js";
|
|
2
|
+
|
|
3
|
+
export class ServiceUI extends BaseUI {
|
|
4
|
+
constructor(label="Service",category="hue services",rtype="") {
|
|
5
|
+
super(label,category);
|
|
6
|
+
console.log("ServiceUI.constructor(",label,category,rtype,")");
|
|
7
|
+
|
|
8
|
+
this.config.defaults.name = { value:"" };
|
|
9
|
+
this.config.defaults.bridge = { type: "BridgeConfigNode", required: true };
|
|
10
|
+
this.config.defaults.rtype = { value:rtype, required: true };
|
|
11
|
+
this.config.defaults.owner = { value:"", required: true };
|
|
12
|
+
this.config.defaults.uuid = { value:"", required: true };
|
|
13
|
+
|
|
14
|
+
this.config.inputs = 1;
|
|
15
|
+
this.config.color = "#EEEEEE";
|
|
16
|
+
this.config.icon = "font-awesome/fa-gears";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
buildHelp() {
|
|
20
|
+
var help = super.buildHelp();
|
|
21
|
+
help["Settings"] += "\
|
|
22
|
+
#### Bridge\n\
|
|
23
|
+
Select the hue bridge for your device or resource.\n\n\
|
|
24
|
+
#### Type\n\
|
|
25
|
+
If the node works for multiple types, then you can select a type here. Otherwise \
|
|
26
|
+
the field is hidden. \
|
|
27
|
+
\n\n\
|
|
28
|
+
#### Owner\n\
|
|
29
|
+
Here you can either fill in the UUID of the device that offers the service \
|
|
30
|
+
or alternately you can select the owner from the available list of devices.\
|
|
31
|
+
\n\n\
|
|
32
|
+
#### UUID\n\
|
|
33
|
+
If the selected owner offers only one service of the (pre)selected type, then \
|
|
34
|
+
this field is hidden, and the one choice is automatically selected. \n\n\
|
|
35
|
+
If not, then it offers you a choice of either filling in the UUID of the service \
|
|
36
|
+
to be selected, or you can select one from the list which is offered. \
|
|
37
|
+
\n\n\
|
|
38
|
+
";
|
|
39
|
+
return help;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ui() {
|
|
43
|
+
var text = super.ui();
|
|
44
|
+
console.log("ServiceUI.ui()");
|
|
45
|
+
|
|
46
|
+
text += this.uiTextInput("bridge","Bridge");
|
|
47
|
+
text += this.uiSelectInput("rtype","Type");
|
|
48
|
+
text += this.uiSelectInput("owner","Owner");
|
|
49
|
+
text += this.uiSelectInput("uuid","UUID");
|
|
50
|
+
return text;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
selectText(id) {
|
|
54
|
+
console.log("ServiceUI.selectText()");
|
|
55
|
+
|
|
56
|
+
var current = $('#node-input-'+id).val();
|
|
57
|
+
$('#input-select-'+id).empty();
|
|
58
|
+
$('#input-select-'+id).append('<input type="text" id="node-input-'+id+'" style="width: 100%" value="'+current+'" />');
|
|
59
|
+
|
|
60
|
+
var button = $("#input-select-"+id+"-search");
|
|
61
|
+
var icon = button.find("i");
|
|
62
|
+
icon.removeClass("fa-pencil");
|
|
63
|
+
icon.addClass("fa-search");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
selectOption(id,url,data) {
|
|
67
|
+
console.log("ServiceUI.selectOption()");
|
|
68
|
+
var current = $('#node-input-'+id).val();
|
|
69
|
+
var notification = RED.notify("Searching for options...", {
|
|
70
|
+
type: "compact", modal: true, fixed: true
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
$.get(url, data)
|
|
74
|
+
.done( function(data) {
|
|
75
|
+
var options = JSON.parse(data);
|
|
76
|
+
|
|
77
|
+
if(options.length <= 0)
|
|
78
|
+
{
|
|
79
|
+
notification.close();
|
|
80
|
+
RED.notify("No options found.", { type: "error" });
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
$("#node-input-"+id).typedInput({
|
|
85
|
+
types: [
|
|
86
|
+
{
|
|
87
|
+
value: current,
|
|
88
|
+
options: options
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
var button = $("#input-select-"+id+"-search");
|
|
94
|
+
var icon = button.find("i");
|
|
95
|
+
icon.removeClass("fa-search");
|
|
96
|
+
icon.addClass("fa-pencil");
|
|
97
|
+
|
|
98
|
+
// Remove the notification
|
|
99
|
+
notification.close();
|
|
100
|
+
})
|
|
101
|
+
.fail(function()
|
|
102
|
+
{
|
|
103
|
+
console.log("ServiceUI.selectOption(): failed");
|
|
104
|
+
|
|
105
|
+
// Remove the notification
|
|
106
|
+
notification.close();
|
|
107
|
+
RED.notify("unknown error", "error");
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
selectType() {
|
|
112
|
+
console.log("ServiceUI.selectType()");
|
|
113
|
+
var bridge_id = $('#node-input-bridge').val();
|
|
114
|
+
var bridge = (bridge_id)? RED.nodes.node(bridge_id): null;
|
|
115
|
+
|
|
116
|
+
if ((!bridge_id) || (!bridge)) {
|
|
117
|
+
console.log("ResourceUI.selectResource(): invalid bridge:", bridge_id);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.selectOption(
|
|
122
|
+
"rtype",
|
|
123
|
+
"BridgeConfigNode/GetSortedTypeOptions",
|
|
124
|
+
{
|
|
125
|
+
bridge_id: bridge.id,
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
selectOwner() {
|
|
131
|
+
console.log("ServiceUI.selectOwner()");
|
|
132
|
+
var bridge_id = $('#node-input-bridge').val();
|
|
133
|
+
var bridge = (bridge_id)? RED.nodes.node(bridge_id): null;
|
|
134
|
+
|
|
135
|
+
if ((!bridge_id) || (!bridge)) {
|
|
136
|
+
console.log("ServiceUI.selectOwner(): invalid bridge:", bridge_id);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
var rtype = $('#node-input-rtype').val();
|
|
141
|
+
if (!rtype) {
|
|
142
|
+
console.log("ServiceUI.selectOwner(): invalid rtype:", rtype);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log("ServiceUI.selectOwner()",bridge.id,rtype);
|
|
147
|
+
this.selectOption(
|
|
148
|
+
"owner",
|
|
149
|
+
"BridgeConfigNode/GetSortedOwnerOptions",
|
|
150
|
+
{
|
|
151
|
+
bridge_id: bridge.id,
|
|
152
|
+
rtype: rtype
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
selectService() {
|
|
158
|
+
console.log("ServiceUI.selectService()");
|
|
159
|
+
|
|
160
|
+
console.log("ServiceUI.selectService()");
|
|
161
|
+
var bridge_id = $('#node-input-bridge').val();
|
|
162
|
+
var bridge = (bridge_id)? RED.nodes.node(bridge_id): null;
|
|
163
|
+
|
|
164
|
+
if ((!bridge_id) || (!bridge)) {
|
|
165
|
+
console.log("ServiceUI.selectService(): invalid bridge:", bridge_id);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
var rtype = $('#node-input-rtype').val();
|
|
170
|
+
if (!rtype) {
|
|
171
|
+
console.log("ServiceUI.selectService(): invalid rtype:", rtype);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
var owner = $('#node-input-owner').val();
|
|
176
|
+
if (!owner) {
|
|
177
|
+
console.log("ServiceUI.selectService(): invalid owner:", owner);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
this.selectOption(
|
|
182
|
+
"uuid",
|
|
183
|
+
"BridgeConfigNode/GetSortedServiceOptions",
|
|
184
|
+
{
|
|
185
|
+
bridge_id: bridge.id,
|
|
186
|
+
rtype: rtype,
|
|
187
|
+
owner: owner
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
showServiceSelectionIfThereIsChoice() {
|
|
193
|
+
console.log("TemperatureUI[].showServiceSelectionIfThereIsChoice()");
|
|
194
|
+
|
|
195
|
+
var bridge = $('#node-input-bridge').val();
|
|
196
|
+
var owner = $('#node-input-owner').val();
|
|
197
|
+
var rtype = $('#node-input-rtype').val();
|
|
198
|
+
|
|
199
|
+
if ((!bridge) || (!owner) || (owner=="") || (!rtype) || (rtype=="")) return;
|
|
200
|
+
|
|
201
|
+
$.get("BridgeConfigNode/GetSortedServiceOptions", {
|
|
202
|
+
bridge_id: bridge,
|
|
203
|
+
rtype: rtype,
|
|
204
|
+
owner: owner
|
|
205
|
+
})
|
|
206
|
+
.done(function(data) {
|
|
207
|
+
var options = JSON.parse(data);
|
|
208
|
+
console.log("Options:",options);
|
|
209
|
+
if (options.length == 1) {
|
|
210
|
+
$('#node-input-uuid').val(options[0].value);
|
|
211
|
+
$('#node-container-uuid').hide();
|
|
212
|
+
} else if (options.length > 1) {
|
|
213
|
+
$('#node-container-uuid').show();
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
onEditPrepare(config) {
|
|
219
|
+
super.onEditPrepare(config);
|
|
220
|
+
console.log("ServiceUI.onEditPrepare()",config);
|
|
221
|
+
var instance = this;
|
|
222
|
+
|
|
223
|
+
$('#input-select-rtype-search').click(function()
|
|
224
|
+
{
|
|
225
|
+
if($('#input-select-rtype').find(".red-ui-typedInput-container").length > 0) {
|
|
226
|
+
instance.selectText("rtype");
|
|
227
|
+
} else {
|
|
228
|
+
instance.selectType();
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
$('#input-select-owner-search').click(function()
|
|
233
|
+
{
|
|
234
|
+
if($('#input-select-owner').find(".red-ui-typedInput-container").length > 0) {
|
|
235
|
+
instance.selectText("owner");
|
|
236
|
+
} else {
|
|
237
|
+
instance.selectOwner();
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
$('#input-select-uuid-search').click(function()
|
|
242
|
+
{
|
|
243
|
+
if($('#input-select-uuid').find(".red-ui-typedInput-container").length > 0) {
|
|
244
|
+
instance.selectText("uuid");
|
|
245
|
+
} else {
|
|
246
|
+
instance.selectService();
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
$('#node-input-owner').change(function() {
|
|
251
|
+
console.log("TemperatureUI[].onEditPrepare().on('change')");
|
|
252
|
+
instance.showServiceSelectionIfThereIsChoice();
|
|
253
|
+
instance.selectText("uuid");
|
|
254
|
+
instance.selectService();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
$('#node-container-uuid').hide();
|
|
258
|
+
|
|
259
|
+
this.showServiceSelectionIfThereIsChoice();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ServiceUI } from "./ServiceUI.js"
|
|
2
|
+
|
|
3
|
+
export class TemperatureUI extends ServiceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Temperature","hue services","temperature");
|
|
6
|
+
console.log("TemperatureUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#A8FFFF";
|
|
9
|
+
this.config.icon = "font-awesome/fa-thermometer-half";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
buildHelp() {
|
|
13
|
+
var help = super.buildHelp();
|
|
14
|
+
help["Outputs"] += "\
|
|
15
|
+
The Temperature node only has one output. It will listen to events for the specified service \
|
|
16
|
+
and forward them to the output as `msg.payload` which contains the temperature events in a \
|
|
17
|
+
JSON format conform the clip v2 specification.\n\n\
|
|
18
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
19
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
20
|
+
return help;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
onEditPrepare(config) {
|
|
24
|
+
super.onEditPrepare(config);
|
|
25
|
+
$('#node-container-rtype').hide();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ServiceUI } from "./ServiceUI.js"
|
|
2
|
+
|
|
3
|
+
export class ZigbeeConnectivityUI extends ServiceUI {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Zigbee Connectivity","hue services","zigbee_connectivity");
|
|
6
|
+
console.log("ZigbeeConnectivityUI.constructor()");
|
|
7
|
+
|
|
8
|
+
this.config.color = "#E0B0FF";
|
|
9
|
+
this.config.icon = "font-awesome/fa-sitemap";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
buildHelp() {
|
|
13
|
+
var help = super.buildHelp();
|
|
14
|
+
help["Outputs"] += "\
|
|
15
|
+
The Zigbee Connectivity node only has one output. It will listen to events for the specified service \
|
|
16
|
+
and forward them to the output as `msg.payload` which contains the zigbee_connectivity events in a \
|
|
17
|
+
JSON format conform the clip v2 specification.\n\n\
|
|
18
|
+
Please see the Hue CLIP API documentation: \n\n\
|
|
19
|
+
https://developers.meethue.com/develop/hue-api-v2";
|
|
20
|
+
return help;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
onEditPrepare(config) {
|
|
24
|
+
super.onEditPrepare(config);
|
|
25
|
+
$('#node-container-rtype').hide();
|
|
26
|
+
}
|
|
27
|
+
}
|