homebridge-nest-accfactory 0.0.5 → 0.2.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/CHANGELOG.md +42 -4
- package/README.md +37 -19
- package/dist/HomeKitDevice.js +132 -109
- package/dist/camera.js +344 -262
- package/dist/doorbell.js +5 -3
- package/dist/floodlight.js +4 -4
- package/dist/nexustalk.js +84 -52
- package/dist/protect.js +2 -2
- package/dist/protobuf/googlehome/foyer.proto +216 -160
- package/dist/res/Nest_camera_connecting.h264 +0 -0
- package/dist/res/Nest_camera_off.h264 +0 -0
- package/dist/res/Nest_camera_offline.h264 +0 -0
- package/dist/res/Nest_camera_transfer.h264 +0 -0
- package/dist/streamer.js +100 -71
- package/dist/system.js +1321 -1263
- package/dist/thermostat.js +73 -27
- package/dist/webrtc.js +582 -0
- package/package.json +31 -29
package/dist/doorbell.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Nest Doorbell(s)
|
|
2
2
|
// Part of homebridge-nest-accfactory
|
|
3
3
|
//
|
|
4
|
-
// Code version
|
|
4
|
+
// Code version 27/9/2024
|
|
5
5
|
// Mark Hulskamp
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -41,7 +41,7 @@ export default class NestDoorbell extends NestCamera {
|
|
|
41
41
|
this.switchService.getCharacteristic(this.hap.Characteristic.On).onSet((value) => {
|
|
42
42
|
if (value !== this.deviceData.indoor_chime_enabled) {
|
|
43
43
|
// only change indoor chime status value if different than on-device
|
|
44
|
-
this.set({ indoor_chime_enabled: value });
|
|
44
|
+
this.set({ uuid: this.deviceData.nest_google_uuid, indoor_chime_enabled: value });
|
|
45
45
|
|
|
46
46
|
this?.log?.info && this.log.info('Indoor chime on "%s" was turned', this.deviceData.description, value === true ? 'on' : 'off');
|
|
47
47
|
}
|
|
@@ -66,7 +66,9 @@ export default class NestDoorbell extends NestCamera {
|
|
|
66
66
|
removeServices() {
|
|
67
67
|
super.removeServices();
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
clearTimeout(this.doorbellTimer);
|
|
70
|
+
this.doorbellTimer = undefined;
|
|
71
|
+
|
|
70
72
|
if (this.switchService !== undefined) {
|
|
71
73
|
this.accessory.removeService(this.switchService);
|
|
72
74
|
}
|
package/dist/floodlight.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Nest Cam with Floodlight
|
|
2
2
|
// Part of homebridge-nest-accfactory
|
|
3
3
|
//
|
|
4
|
-
// Code version
|
|
4
|
+
// Code version 27/9/2024
|
|
5
5
|
// Mark Hulskamp
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -38,7 +38,7 @@ export default class NestFloodlight extends NestCamera {
|
|
|
38
38
|
// Setup set callback for this light service
|
|
39
39
|
this.lightService.getCharacteristic(this.hap.Characteristic.On).onSet((value) => {
|
|
40
40
|
if (value !== this.deviceData.light_enabled) {
|
|
41
|
-
this.set({ light_enabled: value });
|
|
41
|
+
this.set({ uuid: this.deviceData.nest_google_uuid, light_enabled: value });
|
|
42
42
|
|
|
43
43
|
this?.log?.info && this.log.info('Floodlight on "%s" was turned', this.deviceData.description, value === true ? 'on' : 'off');
|
|
44
44
|
}
|
|
@@ -46,9 +46,9 @@ export default class NestFloodlight extends NestCamera {
|
|
|
46
46
|
|
|
47
47
|
this.lightService.getCharacteristic(this.hap.Characteristic.Brightness).onSet((value) => {
|
|
48
48
|
if (value !== this.deviceData.light_brightness) {
|
|
49
|
-
this.set({ light_brightness: value });
|
|
49
|
+
this.set({ uuid: this.deviceData.nest_google_uuid, light_brightness: value });
|
|
50
50
|
|
|
51
|
-
this?.log?.info && this.log.info('Floodlight brightness on "%s" was set to "%s %"', this.deviceData.description);
|
|
51
|
+
this?.log?.info && this.log.info('Floodlight brightness on "%s" was set to "%s %"', this.deviceData.description, value);
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
54
|
|
package/dist/nexustalk.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
//
|
|
6
6
|
// Credit to https://github.com/Brandawg93/homebridge-nest-cam for the work on the Nest Camera comms code on which this is based
|
|
7
7
|
//
|
|
8
|
-
// Code version
|
|
8
|
+
// Code version 29/9/2024
|
|
9
9
|
// Mark Hulskamp
|
|
10
10
|
'use strict';
|
|
11
11
|
|
|
@@ -55,15 +55,22 @@ const PacketType = {
|
|
|
55
55
|
AUTHORIZE_REQUEST: 212,
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
+
// Blank audio in AAC format, mono channel @48000
|
|
59
|
+
const AACMONO48000BLANK = Buffer.from([
|
|
60
|
+
0xff, 0xf1, 0x4c, 0x40, 0x03, 0x9f, 0xfc, 0xde, 0x02, 0x00, 0x4c, 0x61, 0x76, 0x63, 0x35, 0x39, 0x2e, 0x31, 0x38, 0x2e, 0x31, 0x30, 0x30,
|
|
61
|
+
0x00, 0x02, 0x30, 0x40, 0x0e,
|
|
62
|
+
]);
|
|
63
|
+
|
|
58
64
|
// nexusTalk object
|
|
59
65
|
export default class NexusTalk extends Streamer {
|
|
60
66
|
token = undefined;
|
|
61
67
|
tokenType = undefined;
|
|
62
|
-
id = undefined; // Session ID
|
|
63
68
|
pingTimer = undefined; // Timer object for ping interval
|
|
64
69
|
stalledTimer = undefined; // Timer object for no received data
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
host = ''; // Host to connect to or connected too
|
|
71
|
+
blankAudio = AACMONO48000BLANK;
|
|
72
|
+
video = {}; // Video stream details once connected
|
|
73
|
+
audio = {}; // Audio stream details once connected
|
|
67
74
|
|
|
68
75
|
// Internal data only for this class
|
|
69
76
|
#protobufNexusTalk = undefined; // Protobuf for NexusTalk
|
|
@@ -71,6 +78,7 @@ export default class NexusTalk extends Streamer {
|
|
|
71
78
|
#packets = []; // Incoming packets
|
|
72
79
|
#messages = []; // Incoming messages
|
|
73
80
|
#authorised = false; // Have we been authorised
|
|
81
|
+
#id = undefined; // Session ID
|
|
74
82
|
|
|
75
83
|
constructor(deviceData, options) {
|
|
76
84
|
super(deviceData, options);
|
|
@@ -86,8 +94,15 @@ export default class NexusTalk extends Streamer {
|
|
|
86
94
|
this.tokenType = deviceData?.apiAccess?.oauth2 !== undefined ? 'google' : 'nest';
|
|
87
95
|
this.host = deviceData?.streaming_host; // Host we'll connect to
|
|
88
96
|
|
|
97
|
+
// Set our streamer codec types
|
|
98
|
+
this.codecs = {
|
|
99
|
+
video: 'h264',
|
|
100
|
+
audio: 'aac',
|
|
101
|
+
talk: 'speex',
|
|
102
|
+
};
|
|
103
|
+
|
|
89
104
|
// If specified option to start buffering, kick off
|
|
90
|
-
if (
|
|
105
|
+
if (options?.buffer === true) {
|
|
91
106
|
this.startBuffering();
|
|
92
107
|
}
|
|
93
108
|
}
|
|
@@ -95,10 +110,11 @@ export default class NexusTalk extends Streamer {
|
|
|
95
110
|
// Class functions
|
|
96
111
|
connect(host) {
|
|
97
112
|
// Clear any timers we have running
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.
|
|
113
|
+
clearInterval(this.pingTimer);
|
|
114
|
+
clearTimeout(this.stalledTimer);
|
|
115
|
+
this.pingTimer = undefined;
|
|
116
|
+
this.stalledTimer = undefined;
|
|
117
|
+
this.#id = undefined; // No session ID yet
|
|
102
118
|
|
|
103
119
|
if (this.online === true && this.videoEnabled === true) {
|
|
104
120
|
if (typeof host === 'undefined' || host === null) {
|
|
@@ -106,7 +122,8 @@ export default class NexusTalk extends Streamer {
|
|
|
106
122
|
host = this.host;
|
|
107
123
|
}
|
|
108
124
|
|
|
109
|
-
this
|
|
125
|
+
this.connected = false; // Starting connection
|
|
126
|
+
this?.log?.debug && this.log.debug('Connection started to "%s"', host);
|
|
110
127
|
|
|
111
128
|
this.#socket = tls.connect({ host: host, port: 1443 }, () => {
|
|
112
129
|
// Opened connection to Nexus server, so now need to authenticate ourselves
|
|
@@ -129,12 +146,14 @@ export default class NexusTalk extends Streamer {
|
|
|
129
146
|
this.#socket.on('close', (hadError) => {
|
|
130
147
|
this?.log?.debug && this.log.debug('Connection closed to "%s"', host);
|
|
131
148
|
|
|
132
|
-
|
|
133
|
-
|
|
149
|
+
clearInterval(this.pingTimer);
|
|
150
|
+
clearTimeout(this.stalledTimer);
|
|
151
|
+
this.pingTimer = undefined;
|
|
152
|
+
this.stalledTimer = undefined;
|
|
134
153
|
this.#authorised = false; // Since connection close, we can't be authorised anymore
|
|
135
154
|
this.#socket = undefined; // Clear socket object
|
|
136
|
-
this.connected =
|
|
137
|
-
this
|
|
155
|
+
this.connected = undefined;
|
|
156
|
+
this.#id = undefined; // Not an active session anymore
|
|
138
157
|
|
|
139
158
|
if (hadError === true && this.haveOutputs() === true) {
|
|
140
159
|
// We still have either active buffering occuring or output streams running
|
|
@@ -147,7 +166,7 @@ export default class NexusTalk extends Streamer {
|
|
|
147
166
|
|
|
148
167
|
close(stopStreamFirst) {
|
|
149
168
|
// Close an authenicated socket stream gracefully
|
|
150
|
-
if (this.#socket !==
|
|
169
|
+
if (this.#socket !== undefined) {
|
|
151
170
|
if (stopStreamFirst === true) {
|
|
152
171
|
// Send a notifcation to nexus we're finished playback
|
|
153
172
|
this.#stopNexusData();
|
|
@@ -155,11 +174,13 @@ export default class NexusTalk extends Streamer {
|
|
|
155
174
|
this.#socket.destroy();
|
|
156
175
|
}
|
|
157
176
|
|
|
158
|
-
this.connected =
|
|
177
|
+
this.connected = undefined;
|
|
159
178
|
this.#socket = undefined;
|
|
160
|
-
this
|
|
179
|
+
this.#id = undefined; // Not an active session anymore
|
|
161
180
|
this.#packets = [];
|
|
162
181
|
this.#messages = [];
|
|
182
|
+
this.video = {};
|
|
183
|
+
this.audio = {};
|
|
163
184
|
}
|
|
164
185
|
|
|
165
186
|
update(deviceData) {
|
|
@@ -171,11 +192,16 @@ export default class NexusTalk extends Streamer {
|
|
|
171
192
|
// access token has changed so re-authorise
|
|
172
193
|
this.token = deviceData.apiAccess.token;
|
|
173
194
|
|
|
174
|
-
if (this.#socket !==
|
|
195
|
+
if (this.#socket !== undefined) {
|
|
175
196
|
this.#Authenticate(true); // Update authorisation only if connected
|
|
176
197
|
}
|
|
177
198
|
}
|
|
178
199
|
|
|
200
|
+
if (this.host !== deviceData.streaming_host) {
|
|
201
|
+
this.host = deviceData.streaming_host;
|
|
202
|
+
this?.log?.debug && this.log.debug('New host has been requested for connection. Host requested is "%s"', this.host);
|
|
203
|
+
}
|
|
204
|
+
|
|
179
205
|
// Let our parent handle the remaining updates
|
|
180
206
|
super.update(deviceData);
|
|
181
207
|
}
|
|
@@ -183,13 +209,13 @@ export default class NexusTalk extends Streamer {
|
|
|
183
209
|
talkingAudio(talkingData) {
|
|
184
210
|
// Encode audio packet for sending to camera
|
|
185
211
|
if (typeof talkingData === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
186
|
-
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.
|
|
212
|
+
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.AudioPayload');
|
|
187
213
|
if (TraitMap !== null) {
|
|
188
214
|
let encodedData = TraitMap.encode(
|
|
189
215
|
TraitMap.fromObject({
|
|
190
216
|
payload: talkingData,
|
|
191
|
-
sessionId: this
|
|
192
|
-
codec:
|
|
217
|
+
sessionId: this.#id,
|
|
218
|
+
codec: this.codecs.talk.toUpperCase(),
|
|
193
219
|
sampleRate: 16000,
|
|
194
220
|
}),
|
|
195
221
|
).finish();
|
|
@@ -227,12 +253,12 @@ export default class NexusTalk extends Streamer {
|
|
|
227
253
|
}
|
|
228
254
|
|
|
229
255
|
#stopNexusData() {
|
|
230
|
-
if (this
|
|
256
|
+
if (this.#id !== undefined && this.#protobufNexusTalk !== undefined) {
|
|
231
257
|
let TraitMap = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.StopPlayback');
|
|
232
258
|
if (TraitMap !== null) {
|
|
233
259
|
let encodedData = TraitMap.encode(
|
|
234
260
|
TraitMap.fromObject({
|
|
235
|
-
sessionId: this
|
|
261
|
+
sessionId: this.#id,
|
|
236
262
|
}),
|
|
237
263
|
).finish();
|
|
238
264
|
this.#sendMessage(PacketType.STOP_PLAYBACK, encodedData);
|
|
@@ -241,7 +267,7 @@ export default class NexusTalk extends Streamer {
|
|
|
241
267
|
}
|
|
242
268
|
|
|
243
269
|
#sendMessage(type, data) {
|
|
244
|
-
if (this.#socket
|
|
270
|
+
if (this.#socket?.readyState !== 'open' || (type !== PacketType.HELLO && this.#authorised === false)) {
|
|
245
271
|
// We're not connect and/or authorised yet, so 'cache' message for processing once this occurs
|
|
246
272
|
this.#messages.push({ type: type, data: data });
|
|
247
273
|
return;
|
|
@@ -339,30 +365,31 @@ export default class NexusTalk extends Streamer {
|
|
|
339
365
|
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.PlaybackBegin').decode(payload).toJSON();
|
|
340
366
|
decodedMessage.channels.forEach((stream) => {
|
|
341
367
|
// Find which channels match our video and audio streams
|
|
342
|
-
if (stream.codecType ===
|
|
368
|
+
if (stream.codecType === this.codecs.video.toUpperCase()) {
|
|
343
369
|
this.video = {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
370
|
+
id: stream.channelId,
|
|
371
|
+
startTime: Date.now() + stream.startTime,
|
|
372
|
+
sampleRate: stream.sampleRate,
|
|
373
|
+
timeStamp: 0,
|
|
348
374
|
};
|
|
349
375
|
}
|
|
350
|
-
if (stream.codecType ===
|
|
376
|
+
if (stream.codecType === this.codecs.audio.toUpperCase()) {
|
|
351
377
|
this.audio = {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
378
|
+
id: stream.channelId,
|
|
379
|
+
startTime: Date.now() + stream.startTime,
|
|
380
|
+
sampleRate: stream.sampleRate,
|
|
381
|
+
timeStamp: 0,
|
|
382
|
+
talking: false,
|
|
356
383
|
};
|
|
357
384
|
}
|
|
358
385
|
});
|
|
359
386
|
|
|
360
387
|
// Since this is the beginning of playback, clear any active buffers contents
|
|
361
|
-
this
|
|
388
|
+
this.#id = decodedMessage.sessionId;
|
|
362
389
|
this.#packets = [];
|
|
363
390
|
this.#messages = [];
|
|
364
391
|
|
|
365
|
-
this?.log?.debug && this.log.debug('Playback started from "%s" with session ID "%s"', this.host, this
|
|
392
|
+
this?.log?.debug && this.log.debug('Playback started from "%s" with session ID "%s"', this.host, this.#id);
|
|
366
393
|
}
|
|
367
394
|
}
|
|
368
395
|
|
|
@@ -374,28 +401,31 @@ export default class NexusTalk extends Streamer {
|
|
|
374
401
|
// Setup up a timeout to monitor for no packets recieved in a certain period
|
|
375
402
|
// If its trigger, we'll attempt to restart the stream and/or connection
|
|
376
403
|
// <-- testing to see how often this occurs first
|
|
377
|
-
|
|
404
|
+
clearTimeout(this.stalledTimer);
|
|
378
405
|
this.stalledTimer = setTimeout(() => {
|
|
379
|
-
this?.log?.debug &&
|
|
406
|
+
this?.log?.debug &&
|
|
407
|
+
this.log.debug(
|
|
408
|
+
'We have not received any data from nexus in the past "%s" seconds for uuid "%s". Attempting restart',
|
|
409
|
+
10,
|
|
410
|
+
this.uuid,
|
|
411
|
+
);
|
|
380
412
|
|
|
381
413
|
// Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
|
|
382
414
|
this.#socket &&
|
|
383
415
|
this.#socket.on('close', () => {
|
|
384
|
-
this.connect(
|
|
416
|
+
this.connect(); // try reconnection
|
|
385
417
|
});
|
|
386
418
|
this.close(false); // Close existing socket
|
|
387
419
|
}, 8000);
|
|
388
420
|
|
|
389
421
|
// Handle video packet
|
|
390
|
-
if (decodedMessage.channelId === this.video
|
|
391
|
-
this.video.
|
|
392
|
-
this.addToOutput('video', this.video.start_time + this.video.timestamp_delta, Buffer.from(decodedMessage.payload, 'base64'));
|
|
422
|
+
if (decodedMessage?.channelId !== undefined && decodedMessage.channelId === this.video?.id) {
|
|
423
|
+
this.addToOutput('video', Buffer.from(decodedMessage.payload, 'base64'));
|
|
393
424
|
}
|
|
394
425
|
|
|
395
426
|
// Handle audio packet
|
|
396
|
-
if (decodedMessage.channelId === this.audio
|
|
397
|
-
this.audio.
|
|
398
|
-
this.addToOutput('audio', this.audio.start_time + this.audio.timestamp_delta, Buffer.from(decodedMessage.payload, 'base64'));
|
|
427
|
+
if (decodedMessage?.channelId !== undefined && decodedMessage.channelId === this.audio?.id) {
|
|
428
|
+
this.addToOutput('audio', Buffer.from(decodedMessage.payload, 'base64'));
|
|
399
429
|
}
|
|
400
430
|
}
|
|
401
431
|
}
|
|
@@ -405,7 +435,7 @@ export default class NexusTalk extends Streamer {
|
|
|
405
435
|
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
406
436
|
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.PlaybackEnd').decode(payload).toJSON();
|
|
407
437
|
|
|
408
|
-
if (this
|
|
438
|
+
if (this.#id !== undefined && decodedMessage.reason === 'USER_ENDED_SESSION') {
|
|
409
439
|
// Normal playback ended ie: when we stopped playback
|
|
410
440
|
this?.log?.debug && this.log.debug('Playback ended on "%s"', this.host);
|
|
411
441
|
}
|
|
@@ -418,7 +448,7 @@ export default class NexusTalk extends Streamer {
|
|
|
418
448
|
// Setup listener for socket close event. Once socket is closed, we'll perform the re-connection
|
|
419
449
|
this.#socket &&
|
|
420
450
|
this.#socket.on('close', () => {
|
|
421
|
-
this.connect(
|
|
451
|
+
this.connect(); // try reconnection to existing host
|
|
422
452
|
});
|
|
423
453
|
this.close(false); // Close existing socket
|
|
424
454
|
}
|
|
@@ -442,16 +472,18 @@ export default class NexusTalk extends Streamer {
|
|
|
442
472
|
#handleTalkbackBegin(payload) {
|
|
443
473
|
// Decode talk begin packet
|
|
444
474
|
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
445
|
-
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackBegin').decode(payload).toJSON();
|
|
446
|
-
this
|
|
475
|
+
//let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackBegin').decode(payload).toJSON();
|
|
476
|
+
this.audio.talking = true;
|
|
477
|
+
this?.log?.debug && this.log.debug(Streamer.TALKINGSTART, this.uuid);
|
|
447
478
|
}
|
|
448
479
|
}
|
|
449
480
|
|
|
450
481
|
#handleTalkbackEnd(payload) {
|
|
451
482
|
// Decode talk end packet
|
|
452
483
|
if (typeof payload === 'object' && this.#protobufNexusTalk !== undefined) {
|
|
453
|
-
let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackEnd').decode(payload).toJSON();
|
|
454
|
-
this
|
|
484
|
+
//let decodedMessage = this.#protobufNexusTalk.lookup('nest.nexustalk.v1.TalkbackEnd').decode(payload).toJSON();
|
|
485
|
+
this.audio.talking = false;
|
|
486
|
+
this?.log?.debug && this.log.debug('Talking ended on uuid "%s"', this.uuid);
|
|
455
487
|
}
|
|
456
488
|
}
|
|
457
489
|
|
|
@@ -491,7 +523,7 @@ export default class NexusTalk extends Streamer {
|
|
|
491
523
|
}
|
|
492
524
|
|
|
493
525
|
// Periodically send PING message to keep stream alive
|
|
494
|
-
|
|
526
|
+
clearInterval(this.pingTimer);
|
|
495
527
|
this.pingTimer = setInterval(() => {
|
|
496
528
|
this.#sendMessage(PacketType.PING, Buffer.alloc(0));
|
|
497
529
|
}, PINGINTERVAL);
|
package/dist/protect.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Nest Protect
|
|
2
2
|
// Part of homebridge-nest-accfactory
|
|
3
3
|
//
|
|
4
|
-
// Code version
|
|
4
|
+
// Code version 27/9/2024
|
|
5
5
|
// Mark Hulskamp
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -233,7 +233,7 @@ export default class NestProtect extends HomeKitDevice {
|
|
|
233
233
|
//this.log.info('Eve Smoke Alarm test', (EveHomeSetData.alarmtest === true ? 'start' : 'stop'));
|
|
234
234
|
}
|
|
235
235
|
if (typeof EveHomeSetData?.statusled === 'boolean') {
|
|
236
|
-
this.set({ ntp_green_led_enable: EveHomeSetData.statusled });
|
|
236
|
+
this.set({ uuid: this.deviceData.nest_google_uuid, ntp_green_led_enable: EveHomeSetData.statusled });
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
}
|