@hurenkam/hue-services 0.6.5 → 0.6.6
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/.nyc_output/ccf277a0-5927-457e-9598-5bb4939612f5.json +1 -0
- package/.nyc_output/processinfo/ccf277a0-5927-457e-9598-5bb4939612f5.json +1 -0
- package/README.md +2 -0
- package/acquire_token_failed.log +14 -0
- package/bridge_v3_grouped_light.log +43 -0
- package/cross_room_onoff.log +42 -0
- package/package.json +1 -1
- package/select_fire_effect.log +59 -0
- package/src/RestApi.js +21 -5
- package/src/clip/Resource.js +1 -1
- package/src/nodes/BridgeConfigNode.js +1 -1
- package/src/nodes/ResourceNode.js +21 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"parent":null,"pid":232236,"argv":["/usr/bin/node","undefined"],"execArgv":["-e","\nconst pid = parseInt(process.argv[1], 10)\nprocess.title = 'node (foreground-child watchdog pid=' + pid + ')'\nif (!isNaN(pid)) {\n let barked = false\n // keepalive\n const interval = setInterval(() => {}, 60000)\n const bark = () => {\n clearInterval(interval)\n if (barked) return\n barked = true\n process.removeListener('SIGHUP', bark)\n setTimeout(() => {\n try {\n process.kill(pid, 'SIGKILL')\n setTimeout(() => process.exit(), 200)\n } catch (_) {}\n }, 500)\n })\n process.on('SIGHUP', bark)\n}\n"],"cwd":"/home/hurenkam/Workspace/node-red-hue-services","time":1766507688103,"ppid":1613,"coverageFilename":"/home/hurenkam/Workspace/node-red-hue-services/.nyc_output/ccf277a0-5927-457e-9598-5bb4939612f5.json","externalId":"","uuid":"ccf277a0-5927-457e-9598-5bb4939612f5","files":[]}
|
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ Unit tests are in place for the server side nodes.
|
|
|
15
15
|
Editor/UI functionality is currently not being tested apart from my own use in the editor, so your mileage may vary.
|
|
16
16
|
|
|
17
17
|
# Changelog
|
|
18
|
+
v0.6.6: Support bridge v3 acquire key; better error handling on put requests.
|
|
19
|
+
|
|
18
20
|
v0.6.5: Added nodes for camera and contact sensor. Improved generic service usability.
|
|
19
21
|
|
|
20
22
|
v0.6.4: Fix checkbox to work with Safari
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
info:hue /AcquireApplicationKey +4m
|
|
2
|
+
trace:hue { ip: '192.168.1.83' } +4m
|
|
3
|
+
info:BridgeConfigNode AcquireApplicationKey(192.168.1.83) +4m
|
|
4
|
+
trace:BridgeConfigNode AcquireApplicationKey(192.168.1.83) [
|
|
5
|
+
{
|
|
6
|
+
error: {
|
|
7
|
+
type: 4,
|
|
8
|
+
address: '/',
|
|
9
|
+
description: 'method, GET, not available for resource, /'
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
] +4m
|
|
13
|
+
error:hue /AcquireApplicationKey Error: undefined undefined +4m
|
|
14
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
2025-12-23T14:12:54.496Z trace:ClipApi:[Bridge v3a] constructor() found resource: {
|
|
2
|
+
id: '273c5261-178b-46ce-b339-b0dc5a99954e',
|
|
3
|
+
id_v1: '/groups/0',
|
|
4
|
+
owner: { rid: 'b832a485-c296-4e90-8efd-a3cbc84b690d', rtype: 'bridge_home' },
|
|
5
|
+
on: { on: true },
|
|
6
|
+
dimming: { brightness: 23.25333333333333 },
|
|
7
|
+
dimming_delta: {},
|
|
8
|
+
color_temperature: {},
|
|
9
|
+
color_temperature_delta: {},
|
|
10
|
+
color: {},
|
|
11
|
+
alert: { action_values: [ 'breathe' ] },
|
|
12
|
+
signaling: {
|
|
13
|
+
signal_values: [ 'alternating', 'no_signal', 'on_off', 'on_off_color' ]
|
|
14
|
+
},
|
|
15
|
+
dynamics: {},
|
|
16
|
+
type: 'grouped_light'
|
|
17
|
+
}
|
|
18
|
+
2025-12-23T14:12:54.496Z info:Resource:[grouped_light/273c5261-178b-46ce-b339-b0dc5a99954e] constructor()
|
|
19
|
+
2025-12-23T14:12:54.496Z trace:ClipApi:[Bridge v3a] #registerResource( grouped_light/273c5261-178b-46ce-b339-b0dc5a99954e )
|
|
20
|
+
2025-12-23T14:12:54.496Z trace:ClipApi:[Bridge v3a] constructor() found resource: {
|
|
21
|
+
id: '43892de0-48e4-4210-91b0-9015fa64361c',
|
|
22
|
+
id_v1: '/groups/83',
|
|
23
|
+
owner: {
|
|
24
|
+
rid: 'a4e51f59-52c4-4049-8b8e-aba53e4db3f2',
|
|
25
|
+
rtype: 'private_group'
|
|
26
|
+
},
|
|
27
|
+
on: { on: true },
|
|
28
|
+
dimming: { brightness: 6.586666666666667 },
|
|
29
|
+
dimming_delta: {},
|
|
30
|
+
color_temperature: {},
|
|
31
|
+
color_temperature_delta: {},
|
|
32
|
+
color: {},
|
|
33
|
+
alert: { action_values: [ 'breathe' ] },
|
|
34
|
+
signaling: {
|
|
35
|
+
signal_values: [ 'alternating', 'no_signal', 'on_off', 'on_off_color' ]
|
|
36
|
+
},
|
|
37
|
+
dynamics: {},
|
|
38
|
+
type: 'grouped_light'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
trace:BaseNode:[Living room v3a] onInput( {
|
|
2
|
+
_msgid: '0a227c9acf8aed5f',
|
|
3
|
+
payload: { on: { on: true } },
|
|
4
|
+
rtypes: [ 'light', 'grouped_light' ]
|
|
5
|
+
} ) +0ms
|
|
6
|
+
trace:Resource:[grouped_light/273c5261-178b-46ce-b339-b0dc5a99954e] put( { on: { on: true } } ) +0ms
|
|
7
|
+
trace:ClipApi:[Bridge v3a] put( grouped_light , 273c5261-178b-46ce-b339-b0dc5a99954e , { on: { on: true } } ) +9s
|
|
8
|
+
trace:RestApi:[Bridge v3a] put(/clip/v2/resource/grouped_light/273c5261-178b-46ce-b339-b0dc5a99954e) +9s
|
|
9
|
+
info:RestApi:[Bridge v3a] _handleRequest() pending: 1 +9s
|
|
10
|
+
info:RestApi:[Bridge v3a] _handleRequest() url: /clip/v2/resource/grouped_light/273c5261-178b-46ce-b339-b0dc5a99954e method: PUT data: [object Object] +0ms
|
|
11
|
+
info:RestApi:[Bridge v3a] _request(https://192.168.1.83/clip/v2/resource/grouped_light/273c5261-178b-46ce-b339-b0dc5a99954e, PUT, { on: { on: true } } ) +0ms
|
|
12
|
+
trace:LightNode:[Hue go table lamp black] onUpdate( {
|
|
13
|
+
id: '80f763f6-990f-4dad-af00-a7c9b4dc6ce9',
|
|
14
|
+
id_v1: '/lights/2',
|
|
15
|
+
on: { on: true },
|
|
16
|
+
owner: { rid: 'f71e85e3-3f4a-4fb4-99d0-65827b0d3031', rtype: 'device' },
|
|
17
|
+
service_id: 0,
|
|
18
|
+
type: 'light'
|
|
19
|
+
} ) +9s
|
|
20
|
+
trace:LightNode:[Hue go table lamp black] updateStatus() +0ms
|
|
21
|
+
trace:ResourceNode:[Hue go table lamp black] onUpdate() +0ms
|
|
22
|
+
trace:GroupedLightNode:[Living room v3a] onUpdate( {
|
|
23
|
+
dimming: { brightness: 23.25333333333333 },
|
|
24
|
+
id: '273c5261-178b-46ce-b339-b0dc5a99954e',
|
|
25
|
+
id_v1: '/groups/0',
|
|
26
|
+
on: { on: true },
|
|
27
|
+
owner: { rid: 'b832a485-c296-4e90-8efd-a3cbc84b690d', rtype: 'bridge_home' },
|
|
28
|
+
type: 'grouped_light'
|
|
29
|
+
} ) +11s
|
|
30
|
+
trace:GroupedLightNode:[Living room v3a] updateStatus() +1ms
|
|
31
|
+
trace:ResourceNode:[Living room v3a] onUpdate() +0ms
|
|
32
|
+
trace:GroupedLightNode:[Bedroom v3a] onUpdate( {
|
|
33
|
+
dimming: { brightness: 7.904000000000001 },
|
|
34
|
+
id: 'ab4bf27c-30ed-46ed-ae41-3d08ea119383',
|
|
35
|
+
id_v1: '/groups/82',
|
|
36
|
+
on: { on: true },
|
|
37
|
+
owner: { rid: '785bb0cc-0e26-45ac-8556-4c63f7a4f176', rtype: 'room' },
|
|
38
|
+
type: 'grouped_light'
|
|
39
|
+
} ) +11s
|
|
40
|
+
trace:GroupedLightNode:[Bedroom v3a] updateStatus() +0ms
|
|
41
|
+
trace:ResourceNode:[Bedroom v3a] onUpdate() +0ms
|
|
42
|
+
|
package/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
trace:ResourceNode:[Hue go table lamp black] onInput( { dimming: { brightness: 84.19 } } ) +3m
|
|
2
|
+
trace:Resource:[light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9 (Go table lamp 2)] put( { dimming: { brightness: 84.19 } } ) +3m
|
|
3
|
+
trace:ClipApi:[Bridge v3a] put( light , 80f763f6-990f-4dad-af00-a7c9b4dc6ce9 , { dimming: { brightness: 84.19 } } ) +3m
|
|
4
|
+
trace:RestApi:[Bridge v3a] put(/clip/v2/resource/light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9) +3m
|
|
5
|
+
trace:BaseNode:[Hue go table lamp black] onInput( {
|
|
6
|
+
payload: { dimming: { brightness: 84.19 } },
|
|
7
|
+
_msgid: '512053756ae9b1ae',
|
|
8
|
+
rtypes: [ 'light', 'grouped_light' ]
|
|
9
|
+
} ) +3m
|
|
10
|
+
trace:ResourceNode:[Hue go table lamp black] onInput( {
|
|
11
|
+
effects: { status: 'fire' },
|
|
12
|
+
effects_v2: { status: { effect: 'fire', parameters: [Object] } }
|
|
13
|
+
} ) +0ms
|
|
14
|
+
trace:Resource:[light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9 (Go table lamp 2)] put( {
|
|
15
|
+
effects: { status: 'fire' },
|
|
16
|
+
effects_v2: { status: { effect: 'fire', parameters: [Object] } }
|
|
17
|
+
} ) +0ms
|
|
18
|
+
trace:ClipApi:[Bridge v3a] put( light , 80f763f6-990f-4dad-af00-a7c9b4dc6ce9 , {
|
|
19
|
+
effects: { status: 'fire' },
|
|
20
|
+
effects_v2: { status: { effect: 'fire', parameters: [Object] } }
|
|
21
|
+
} ) +0ms
|
|
22
|
+
trace:RestApi:[Bridge v3a] put(/clip/v2/resource/light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9) +0ms
|
|
23
|
+
trace:BaseNode:[Hue go table lamp black] onInput( {
|
|
24
|
+
payload: { effects: { status: 'fire' }, effects_v2: { status: [Object] } },
|
|
25
|
+
_msgid: '75d3c53a12c48866',
|
|
26
|
+
rtypes: [ 'light', 'grouped_light' ]
|
|
27
|
+
} ) +0ms
|
|
28
|
+
trace:ResourceNode:[Hue go table lamp black] onInput( {
|
|
29
|
+
color: { xy: { x: 0.58, y: 0.38 } },
|
|
30
|
+
color_temperature: { mirek_valid: false }
|
|
31
|
+
} ) +1ms
|
|
32
|
+
trace:Resource:[light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9 (Go table lamp 2)] put( {
|
|
33
|
+
color: { xy: { x: 0.58, y: 0.38 } },
|
|
34
|
+
color_temperature: { mirek_valid: false }
|
|
35
|
+
} ) +1ms
|
|
36
|
+
trace:ClipApi:[Bridge v3a] put( light , 80f763f6-990f-4dad-af00-a7c9b4dc6ce9 , {
|
|
37
|
+
color: { xy: { x: 0.58, y: 0.38 } },
|
|
38
|
+
color_temperature: { mirek_valid: false }
|
|
39
|
+
} ) +1ms
|
|
40
|
+
trace:RestApi:[Bridge v3a] put(/clip/v2/resource/light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9) +1ms
|
|
41
|
+
trace:BaseNode:[Hue go table lamp black] onInput( {
|
|
42
|
+
payload: {
|
|
43
|
+
color: { xy: [Object] },
|
|
44
|
+
color_temperature: { mirek_valid: false }
|
|
45
|
+
},
|
|
46
|
+
_msgid: 'c7dd57e7101190f9',
|
|
47
|
+
rtypes: [ 'light', 'grouped_light' ]
|
|
48
|
+
} ) +1ms
|
|
49
|
+
info:RestApi:[Bridge v3a] _handleRequest() pending: 3 +3m
|
|
50
|
+
info:RestApi:[Bridge v3a] _handleRequest() url: /clip/v2/resource/light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9 method: PUT data: [object Object] +0ms
|
|
51
|
+
info:RestApi:[Bridge v3a] _request(https://192.168.1.83/clip/v2/resource/light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9, PUT, { dimming: { brightness: 84.19 } } ) +0ms
|
|
52
|
+
info:RestApi:[Bridge v3a] _handleRequest() pending: 2 +118ms
|
|
53
|
+
info:RestApi:[Bridge v3a] _handleRequest() url: /clip/v2/resource/light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9 method: PUT data: [object Object] +0ms
|
|
54
|
+
info:RestApi:[Bridge v3a] _request(https://192.168.1.83/clip/v2/resource/light/80f763f6-990f-4dad-af00-a7c9b4dc6ce9, PUT, {
|
|
55
|
+
effects: { status: 'fire' },
|
|
56
|
+
effects_v2: { status: { effect: 'fire', parameters: [Object] } }
|
|
57
|
+
} ) +0ms
|
|
58
|
+
|
|
59
|
+
|
package/src/RestApi.js
CHANGED
|
@@ -81,6 +81,7 @@ class RestApi {
|
|
|
81
81
|
var local = this;
|
|
82
82
|
|
|
83
83
|
var request = this.#requestQ.shift();
|
|
84
|
+
this.#info("_handleRequest() url: " + request.url + " method: " + request.method + " data: " + request.data);
|
|
84
85
|
this.#request(request.url, request.method, request.data)
|
|
85
86
|
.then(async (result) => {
|
|
86
87
|
await local.#limiter.removeTokens(1,()=>{});
|
|
@@ -90,7 +91,10 @@ class RestApi {
|
|
|
90
91
|
.catch((error) => {
|
|
91
92
|
this.#error("_handleRequest(" + request.url + ") error: ");
|
|
92
93
|
this.#error(error);
|
|
93
|
-
|
|
94
|
+
var info = {};
|
|
95
|
+
info.error = error;
|
|
96
|
+
info.request = request;
|
|
97
|
+
request.reject(info);
|
|
94
98
|
|
|
95
99
|
// back off for a few seconds, just in case we ran into a 429 error.
|
|
96
100
|
local.#timeout = setTimeout(local.#handleRequest.bind(local), 5000);
|
|
@@ -105,33 +109,45 @@ class RestApi {
|
|
|
105
109
|
get(url) {
|
|
106
110
|
this.#trace("get(" + url + ")");
|
|
107
111
|
var local = this;
|
|
108
|
-
|
|
112
|
+
|
|
113
|
+
let promise = new Promise((resolve, reject) => {
|
|
109
114
|
local.#requestQ.push({ url: url, method: "GET", data: null, resolve: resolve, reject: reject });
|
|
110
115
|
});
|
|
116
|
+
|
|
117
|
+
return promise;
|
|
111
118
|
}
|
|
112
119
|
|
|
113
120
|
put(url, data) {
|
|
114
121
|
this.#trace("put(" + url + ")");
|
|
115
122
|
var local = this;
|
|
116
|
-
|
|
123
|
+
|
|
124
|
+
let promise = new Promise((resolve, reject) => {
|
|
117
125
|
local.#requestQ.push({ url: url, method: "PUT", data: data, resolve: resolve, reject: reject });
|
|
118
126
|
});
|
|
127
|
+
|
|
128
|
+
return promise;
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
post(url, data) {
|
|
122
132
|
this.#trace(".post(" + url + ")");
|
|
123
133
|
var local = this;
|
|
124
|
-
|
|
134
|
+
|
|
135
|
+
let promise = new Promise((resolve, reject) => {
|
|
125
136
|
local.#requestQ.push({ url: url, method: "POST", data: data, resolve: resolve, reject: reject });
|
|
126
137
|
});
|
|
138
|
+
|
|
139
|
+
return promise;
|
|
127
140
|
}
|
|
128
141
|
|
|
129
142
|
delete(url, data) {
|
|
130
143
|
this.#trace(".delete(" + url + ")");
|
|
131
144
|
var local = this;
|
|
132
|
-
|
|
145
|
+
|
|
146
|
+
let promise = new Promise((resolve, reject) => {
|
|
133
147
|
local.#requestQ.push({ url: url, method: "DELETE", data: data, resolve: resolve, reject: reject });
|
|
134
148
|
});
|
|
149
|
+
|
|
150
|
+
return promise;
|
|
135
151
|
}
|
|
136
152
|
}
|
|
137
153
|
|
package/src/clip/Resource.js
CHANGED
|
@@ -119,7 +119,7 @@ class BridgeConfigNode extends BaseNode {
|
|
|
119
119
|
var id = "BridgeConfig (" + Math.floor((Math.random() * 100) + 1) + ")";
|
|
120
120
|
var request = {
|
|
121
121
|
"method": "POST",
|
|
122
|
-
"url": "
|
|
122
|
+
"url": "https://" + ip + "/api",
|
|
123
123
|
"headers": { "Content-Type": "application/json; charset=utf-8" },
|
|
124
124
|
"data": { "devicetype": id },
|
|
125
125
|
"httpsAgent": new https.Agent({ rejectUnauthorized: false })
|
|
@@ -82,26 +82,35 @@ class ResourceNode extends BaseNode {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
onInput(msg) {
|
|
85
|
+
super.onInput(msg);
|
|
86
|
+
|
|
85
87
|
var resource = this.resource();
|
|
86
88
|
if (!resource) {
|
|
87
89
|
this.#trace("onInput(): Resource not found",this.rid());
|
|
90
|
+
return;
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
if (msg.rtypes) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
if (msg.rtypes && msg.rtypes.includes(resource.rtype())) {
|
|
94
|
+
resource.put(msg.payload).then(result => {
|
|
95
|
+
return;
|
|
96
|
+
}, info => {
|
|
97
|
+
var error = info.error;
|
|
98
|
+
var request = info.request;
|
|
99
|
+
this.error("ResourceNode::onInput() request: "+JSON.stringify(request)+" error: " + error);
|
|
100
|
+
return;
|
|
101
|
+
});
|
|
95
102
|
}
|
|
96
103
|
|
|
97
|
-
if (msg.rids) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
if (msg.rids && msg.rids.includes(resource.rid())) {
|
|
105
|
+
resource.put(msg.payload).then(result => {
|
|
106
|
+
return;
|
|
107
|
+
}, info => {
|
|
108
|
+
var error = info.error;
|
|
109
|
+
var request = info.request;
|
|
110
|
+
this.error("ResourceNode::onInput() request: "+JSON.stringify(request)+" error: " + error);
|
|
111
|
+
return;
|
|
112
|
+
});
|
|
102
113
|
}
|
|
103
|
-
|
|
104
|
-
super.onInput(msg);
|
|
105
114
|
}
|
|
106
115
|
}
|
|
107
116
|
|