homebridge-nest-accfactory 0.3.0 → 0.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.
package/dist/system.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Nest System communications
2
2
  // Part of homebridge-nest-accfactory
3
3
  //
4
- // Code version 2025.06.13
4
+ // Code version 2025.06.15
5
5
  // Mark Hulskamp
6
6
  'use strict';
7
7
 
@@ -19,19 +19,19 @@ import { fileURLToPath } from 'node:url';
19
19
 
20
20
  // Import our modules
21
21
  import HomeKitDevice from './HomeKitDevice.js';
22
- import { DeviceType, loadDeviceModules, getDeviceHKCategory } from './devices.js';
23
- import { AccountType, processConfig, buildConnections } from './config.js';
22
+ import { DEVICE_TYPE, loadDeviceModules, getDeviceHKCategory } from './devices.js';
23
+ import { ACCOUNT_TYPE, processConfig, buildConnections } from './config.js';
24
24
 
25
25
  // Define constants
26
- const CAMERAALERTPOLLING = 2000; // Camera alerts polling timer
27
- const CAMERAZONEPOLLING = 30000; // Camera zones changes polling timer
28
- const WEATHERPOLLING = 300000; // Weather data polling timer
29
- const NESTAPITIMEOUT = 10000; // Nest API timeout
30
- const USERAGENT = 'Nest/5.78.0 (iOScom.nestlabs.jasper.release) os=18.0'; // User Agent string
26
+ const CAMERA_ALERT_POLLING = 2000; // Camera alerts polling timer
27
+ const CAMERA_ZONE_POLLING = 30000; // Camera zones changes polling timer
28
+ const WEATHER_POLLING = 300000; // Weather data polling timer
29
+ const NEST_API_TIMEOUT = 10000; // Nest API timeout
30
+ const USER_AGENT = 'Nest/5.78.0 (iOScom.nestlabs.jasper.release) os=18.0'; // User Agent string
31
31
  const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Make a defined for JS __dirname
32
32
  const DATASOURCE = {
33
- NestAPI: 'Nest', // From the Nest API
34
- ProtobufAPI: 'Protobuf', // From the Protobuf API
33
+ NEST_API: 'Nest', // From the Nest API
34
+ PROTOBUF_API: 'Protobuf', // From the Protobuf API
35
35
  };
36
36
 
37
37
  // We handle the connections to Nest/Google
@@ -143,7 +143,7 @@ export default class NestAccfactory {
143
143
  this.#connections[uuid].name,
144
144
  this.#connections[uuid].fieldTest === true ? 'using field test endpoints' : '',
145
145
  );
146
- if (this.#connections[uuid].type === AccountType.Google) {
146
+ if (this.#connections[uuid].type === ACCOUNT_TYPE.GOOGLE) {
147
147
  // Google cookie method as refresh token method no longer supported by Google since October 2022
148
148
  // Instructions from homebridge_nest or homebridge_nest_cam to obtain this
149
149
  this?.log?.debug?.('Performing authorisation using Google account for connection uuid "%s"', uuid);
@@ -151,7 +151,7 @@ export default class NestAccfactory {
151
151
  await fetchWrapper('get', this.#connections[uuid].issuetoken, {
152
152
  headers: {
153
153
  referer: 'https://accounts.google.com/o/oauth2/iframe',
154
- 'User-Agent': USERAGENT,
154
+ 'User-Agent': USER_AGENT,
155
155
  cookie: this.#connections[uuid].cookie,
156
156
  'Sec-Fetch-Mode': 'cors',
157
157
  'X-Requested-With': 'XmlHttpRequest',
@@ -167,7 +167,7 @@ export default class NestAccfactory {
167
167
  {
168
168
  headers: {
169
169
  referer: 'https://' + this.#connections[uuid].referer,
170
- 'User-Agent': USERAGENT,
170
+ 'User-Agent': USER_AGENT,
171
171
  Authorization: data.token_type + ' ' + data.access_token,
172
172
  'Content-Type': 'application/x-www-form-urlencoded',
173
173
  },
@@ -184,7 +184,7 @@ export default class NestAccfactory {
184
184
  await fetchWrapper('get', 'https://' + this.#connections[uuid].restAPIHost + '/session', {
185
185
  headers: {
186
186
  referer: 'https://' + this.#connections[uuid].referer,
187
- 'User-Agent': USERAGENT,
187
+ 'User-Agent': USER_AGENT,
188
188
  Authorization: 'Basic ' + googleToken,
189
189
  },
190
190
  })
@@ -227,7 +227,7 @@ export default class NestAccfactory {
227
227
  });
228
228
  }
229
229
 
230
- if (this.#connections[uuid].type === AccountType.Nest) {
230
+ if (this.#connections[uuid].type === ACCOUNT_TYPE.NEST) {
231
231
  // Nest access token method. Get WEBSITE2 cookie for use with camera API calls if needed later
232
232
  this?.log?.debug?.('Performing authorisation using Nest account for connection uuid "%s"', uuid);
233
233
 
@@ -238,7 +238,7 @@ export default class NestAccfactory {
238
238
  withCredentials: true,
239
239
  headers: {
240
240
  referer: 'https://' + this.#connections[uuid].referer,
241
- 'User-Agent': USERAGENT,
241
+ 'User-Agent': USER_AGENT,
242
242
  'Content-Type': 'application/x-www-form-urlencoded',
243
243
  },
244
244
  },
@@ -255,7 +255,7 @@ export default class NestAccfactory {
255
255
  await fetchWrapper('get', 'https://' + this.#connections[uuid].restAPIHost + '/session', {
256
256
  headers: {
257
257
  referer: 'https://' + this.#connections[uuid].referer,
258
- 'User-Agent': USERAGENT,
258
+ 'User-Agent': USER_AGENT,
259
259
  Authorization: 'Basic ' + this.#connections[uuid].access_token,
260
260
  },
261
261
  })
@@ -336,7 +336,7 @@ export default class NestAccfactory {
336
336
  subscribeJSONData = { objects: [] };
337
337
  Object.entries(this.#rawData)
338
338
  // eslint-disable-next-line no-unused-vars
339
- .filter(([object_key, object]) => object.source === DATASOURCE.NestAPI && object.connection === uuid)
339
+ .filter(([object_key, object]) => object.source === DATASOURCE.NEST_API && object.connection === uuid)
340
340
  .forEach(([object_key, object]) => {
341
341
  subscribeJSONData.objects.push({
342
342
  object_key: object_key,
@@ -356,7 +356,7 @@ export default class NestAccfactory {
356
356
  {
357
357
  headers: {
358
358
  referer: 'https://' + this.#connections[uuid].referer,
359
- 'User-Agent': USERAGENT,
359
+ 'User-Agent': USER_AGENT,
360
360
  Authorization: 'Basic ' + this.#connections[uuid].token,
361
361
  },
362
362
  keepalive: true,
@@ -421,11 +421,11 @@ export default class NestAccfactory {
421
421
  {
422
422
  headers: {
423
423
  referer: 'https://' + this.#connections[uuid].referer,
424
- 'User-Agent': USERAGENT,
424
+ 'User-Agent': USER_AGENT,
425
425
  [this.#connections[uuid].cameraAPI.key]:
426
426
  this.#connections[uuid].cameraAPI.value + this.#connections[uuid].cameraAPI.token,
427
427
  },
428
- timeout: NESTAPITIMEOUT,
428
+ timeout: NEST_API_TIMEOUT,
429
429
  },
430
430
  );
431
431
  let data = await response.json();
@@ -451,11 +451,11 @@ export default class NestAccfactory {
451
451
  {
452
452
  headers: {
453
453
  referer: 'https://' + this.#connections[uuid].referer,
454
- 'User-Agent': USERAGENT,
454
+ 'User-Agent': USER_AGENT,
455
455
  [this.#connections[uuid].cameraAPI.key]:
456
456
  this.#connections[uuid].cameraAPI.value + this.#connections[uuid].cameraAPI.token,
457
457
  },
458
- timeout: NESTAPITIMEOUT,
458
+ timeout: NEST_API_TIMEOUT,
459
459
  },
460
460
  );
461
461
  let data = await response.json();
@@ -463,7 +463,7 @@ export default class NestAccfactory {
463
463
  .filter((zone) => zone?.type?.toUpperCase() === 'ACTIVITY' || zone?.type?.toUpperCase() === 'REGION')
464
464
  .map((zone) => ({
465
465
  id: zone.id === 0 ? 1 : zone.id,
466
- name: makeHomeKitName(zone.label),
466
+ name: HomeKitDevice.makeHomeKitName(zone.label),
467
467
  hidden: zone.hidden === true,
468
468
  uri: zone.nexusapi_image_uri,
469
469
  }));
@@ -533,7 +533,7 @@ export default class NestAccfactory {
533
533
  this.#rawData[value.object_key].object_revision = value.object_revision;
534
534
  this.#rawData[value.object_key].object_timestamp = value.object_timestamp;
535
535
  this.#rawData[value.object_key].connection = uuid;
536
- this.#rawData[value.object_key].source = DATASOURCE.NestAPI;
536
+ this.#rawData[value.object_key].source = DATASOURCE.NEST_API;
537
537
  this.#rawData[value.object_key].value = {};
538
538
  }
539
539
 
@@ -629,11 +629,11 @@ export default class NestAccfactory {
629
629
  // This also depends on the account type we connected with
630
630
  // Nest accounts cannot observe camera/doorbell product traits
631
631
  if (
632
- (this.#connections[uuid].type === AccountType.Nest &&
632
+ (this.#connections[uuid].type === ACCOUNT_TYPE.NEST &&
633
633
  type.fullName.startsWith('.nest.trait.product.camera') === false &&
634
634
  type.fullName.startsWith('.nest.trait.product.doorbell') === false &&
635
635
  (type.fullName.startsWith('.nest.trait') === true || type.fullName.startsWith('.weave.') === true)) ||
636
- (this.#connections[uuid].type === AccountType.Google &&
636
+ (this.#connections[uuid].type === ACCOUNT_TYPE.GOOGLE &&
637
637
  (type.fullName.startsWith('.nest.trait') === true ||
638
638
  type.fullName.startsWith('.weave.') === true ||
639
639
  type.fullName.startsWith('.google.trait.product.camera') === true))
@@ -654,7 +654,7 @@ export default class NestAccfactory {
654
654
  {
655
655
  headers: {
656
656
  referer: 'https://' + this.#connections[uuid].referer,
657
- 'User-Agent': USERAGENT,
657
+ 'User-Agent': USER_AGENT,
658
658
  Authorization: 'Basic ' + this.#connections[uuid].token,
659
659
  'Content-Type': 'application/x-protobuf',
660
660
  'X-Accept-Content-Transfer-Encoding': 'binary',
@@ -745,7 +745,7 @@ export default class NestAccfactory {
745
745
  if (typeof this.#rawData[trait.traitId.resourceId] === 'undefined') {
746
746
  this.#rawData[trait.traitId.resourceId] = {};
747
747
  this.#rawData[trait.traitId.resourceId].connection = uuid;
748
- this.#rawData[trait.traitId.resourceId].source = DATASOURCE.ProtobufAPI;
748
+ this.#rawData[trait.traitId.resourceId].source = DATASOURCE.PROTOBUF_API;
749
749
  this.#rawData[trait.traitId.resourceId].value = {};
750
750
  }
751
751
  this.#rawData[trait.traitId.resourceId]['value'][trait.traitId.traitLabel] =
@@ -849,9 +849,9 @@ export default class NestAccfactory {
849
849
 
850
850
  // Optional things for each device type
851
851
  if (
852
- deviceClass.TYPE === DeviceType.CAMERA ||
853
- deviceClass.TYPE === DeviceType.DOORBELL ||
854
- deviceClass.TYPE === DeviceType.FLOODLIGHT
852
+ deviceClass.TYPE === DEVICE_TYPE.CAMERA ||
853
+ deviceClass.TYPE === DEVICE_TYPE.DOORBELL ||
854
+ deviceClass.TYPE === DEVICE_TYPE.FLOODLIGHT
855
855
  ) {
856
856
  // Setup polling loop for camera/doorbell zone data
857
857
  // This is only required for Nest API data sources as these details are present in Protobuf API
@@ -860,7 +860,7 @@ export default class NestAccfactory {
860
860
  let nest_google_uuid = this.#trackedDevices?.[deviceData?.serialNumber]?.rawDataUuid;
861
861
  if (
862
862
  this.#rawData?.[nest_google_uuid]?.value !== undefined &&
863
- this.#trackedDevices?.[deviceData?.serialNumber]?.source === DATASOURCE.NestAPI
863
+ this.#trackedDevices?.[deviceData?.serialNumber]?.source === DATASOURCE.NEST_API
864
864
  ) {
865
865
  try {
866
866
  let response = await fetchWrapper(
@@ -871,12 +871,12 @@ export default class NestAccfactory {
871
871
  {
872
872
  headers: {
873
873
  referer: 'https://' + this.#connections[this.#rawData[nest_google_uuid].connection].referer,
874
- 'User-Agent': USERAGENT,
874
+ 'User-Agent': USER_AGENT,
875
875
  [this.#connections[this.#rawData[nest_google_uuid].connection].cameraAPI.key]:
876
876
  this.#connections[this.#rawData[nest_google_uuid].connection].cameraAPI.value +
877
877
  this.#connections[this.#rawData[nest_google_uuid].connection].cameraAPI.token,
878
878
  },
879
- timeout: CAMERAZONEPOLLING,
879
+ timeout: CAMERA_ZONE_POLLING,
880
880
  },
881
881
  );
882
882
  let data = await response.json();
@@ -888,7 +888,7 @@ export default class NestAccfactory {
888
888
  .filter((zone) => zone.type.toUpperCase() === 'ACTIVITY' || zone.type.toUpperCase() === 'REGION')
889
889
  .map((zone) => ({
890
890
  id: zone.id === 0 ? 1 : zone.id,
891
- name: makeHomeKitName(zone.label),
891
+ name: HomeKitDevice.makeHomeKitName(zone.label),
892
892
  hidden: zone.hidden === true,
893
893
  uri: zone.nexusapi_image_uri,
894
894
  }))
@@ -916,7 +916,7 @@ export default class NestAccfactory {
916
916
  }
917
917
  }
918
918
  }
919
- }, CAMERAZONEPOLLING);
919
+ }, CAMERA_ZONE_POLLING);
920
920
 
921
921
  // Setup polling loop for camera/doorbell alert data, clearing any existing polling loop
922
922
  clearInterval(this.#trackedDevices?.[deviceData.serialNumber]?.timers?.alerts);
@@ -925,7 +925,7 @@ export default class NestAccfactory {
925
925
  let nest_google_uuid = this.#trackedDevices?.[deviceData?.serialNumber]?.rawDataUuid;
926
926
  if (
927
927
  this.#rawData?.[nest_google_uuid]?.value !== undefined &&
928
- this.#trackedDevices?.[deviceData?.serialNumber]?.source === DATASOURCE.ProtobufAPI
928
+ this.#trackedDevices?.[deviceData?.serialNumber]?.source === DATASOURCE.PROTOBUF_API
929
929
  ) {
930
930
  let commandResponse = await this.#protobufCommand(
931
931
  this.#rawData[nest_google_uuid].connection,
@@ -991,7 +991,7 @@ export default class NestAccfactory {
991
991
 
992
992
  if (
993
993
  this.#rawData?.[nest_google_uuid]?.value !== undefined &&
994
- this.#trackedDevices?.[deviceData?.serialNumber]?.source === DATASOURCE.NestAPI
994
+ this.#trackedDevices?.[deviceData?.serialNumber]?.source === DATASOURCE.NEST_API
995
995
  ) {
996
996
  try {
997
997
  let response = await fetchWrapper(
@@ -1004,12 +1004,12 @@ export default class NestAccfactory {
1004
1004
  {
1005
1005
  headers: {
1006
1006
  referer: 'https://' + this.#connections[this.#rawData[nest_google_uuid].connection].referer,
1007
- 'User-Agent': USERAGENT,
1007
+ 'User-Agent': USER_AGENT,
1008
1008
  [this.#connections[this.#rawData[nest_google_uuid].connection].cameraAPI.key]:
1009
1009
  this.#connections[this.#rawData[nest_google_uuid].connection].cameraAPI.value +
1010
1010
  this.#connections[this.#rawData[nest_google_uuid].connection].cameraAPI.token,
1011
1011
  },
1012
- timeout: CAMERAALERTPOLLING,
1012
+ timeout: CAMERA_ALERT_POLLING,
1013
1013
  retry: 3,
1014
1014
  },
1015
1015
  );
@@ -1055,10 +1055,10 @@ export default class NestAccfactory {
1055
1055
  this.#trackedDevices?.[deviceData?.serialNumber]?.uuid &&
1056
1056
  this.#eventEmitter?.emit?.(this.#trackedDevices[deviceData.serialNumber].uuid, HomeKitDevice.UPDATE, { alerts: alerts });
1057
1057
  }
1058
- }, CAMERAALERTPOLLING);
1058
+ }, CAMERA_ALERT_POLLING);
1059
1059
  }
1060
1060
 
1061
- if (deviceClass.TYPE === DeviceType.WEATHER) {
1061
+ if (deviceClass.TYPE === DEVICE_TYPE.WEATHER) {
1062
1062
  // Setup polling loop for weather data, clearing any existing polling loop
1063
1063
  clearInterval(this.#trackedDevices?.[deviceData.serialNumber]?.timers?.weather);
1064
1064
  this.#trackedDevices[deviceData.serialNumber].timers.weather = setInterval(async () => {
@@ -1077,7 +1077,7 @@ export default class NestAccfactory {
1077
1077
  this.#processData(this.#trackedDevices[deviceData.serialNumber].rawDataUuid)?.[deviceData.serialNumber],
1078
1078
  );
1079
1079
  }
1080
- }, WEATHERPOLLING);
1080
+ }, WEATHER_POLLING);
1081
1081
  }
1082
1082
  }
1083
1083
  }
@@ -1199,7 +1199,7 @@ export default class NestAccfactory {
1199
1199
  if (description === '' && location === '') {
1200
1200
  description = 'unknown description';
1201
1201
  }
1202
- data.description = makeHomeKitName(location === '' ? description : description + ' - ' + location);
1202
+ data.description = HomeKitDevice.makeHomeKitName(location === '' ? description : description + ' - ' + location);
1203
1203
  delete data.location;
1204
1204
 
1205
1205
  // Insert HomeKit pairing code for when using HAP-NodeJS library rather than Homebridge
@@ -1240,7 +1240,7 @@ export default class NestAccfactory {
1240
1240
  let processed = {};
1241
1241
  try {
1242
1242
  // Fix up data we need to
1243
- data.device_type = DeviceType.THERMOSTAT; // Nest Thermostat
1243
+ data.device_type = DEVICE_TYPE.THERMOSTAT; // Nest Thermostat
1244
1244
 
1245
1245
  // If we have hot water control, it should be a 'UK/EU' model, so add that after the 'gen' tag in the model name
1246
1246
  data.model = data.has_hot_water_control === true ? data.model.replace(/\bgen\)/, 'gen, EU)') : data.model;
@@ -1283,7 +1283,7 @@ export default class NestAccfactory {
1283
1283
  let tempDevice = {};
1284
1284
  try {
1285
1285
  if (
1286
- value?.source === DATASOURCE.ProtobufAPI &&
1286
+ value?.source === DATASOURCE.PROTOBUF_API &&
1287
1287
  this.config.options?.useGoogleAPI === true &&
1288
1288
  value.value?.configuration_done?.deviceReady === true
1289
1289
  ) {
@@ -1515,7 +1515,7 @@ export default class NestAccfactory {
1515
1515
  tempDevice = process_thermostat_data(object_key, RESTTypeData);
1516
1516
  }
1517
1517
 
1518
- if (value?.source === DATASOURCE.NestAPI && this.config.options?.useNestAPI === true && value.value?.where_id !== undefined) {
1518
+ if (value?.source === DATASOURCE.NEST_API && this.config.options?.useNestAPI === true && value.value?.where_id !== undefined) {
1519
1519
  let RESTTypeData = {};
1520
1520
  RESTTypeData.serialNumber = value.value.serial_number;
1521
1521
  RESTTypeData.softwareVersion = value.value.current_version;
@@ -1566,7 +1566,7 @@ export default class NestAccfactory {
1566
1566
 
1567
1567
  RESTTypeData.description =
1568
1568
  this.#rawData?.['shared.' + value.value.serial_number]?.value?.name !== undefined
1569
- ? makeHomeKitName(this.#rawData['shared.' + value.value.serial_number].value.name)
1569
+ ? HomeKitDevice.makeHomeKitName(this.#rawData['shared.' + value.value.serial_number].value.name)
1570
1570
  : '';
1571
1571
  RESTTypeData.location = get_location_name(
1572
1572
  this.#rawData?.['link.' + value.value.serial_number].value.structure.split('.')[1],
@@ -1763,7 +1763,7 @@ export default class NestAccfactory {
1763
1763
  let processed = {};
1764
1764
  try {
1765
1765
  // Fix up data we need to
1766
- data.device_type = DeviceType.TEMPSENSOR; // Nest Temperature sensor
1766
+ data.device_type = DEVICE_TYPE.TEMPSENSOR; // Nest Temperature sensor
1767
1767
  data.model = 'Temperature Sensor';
1768
1768
  data.softwareVersion = '1.0.0';
1769
1769
  data = process_common_data(object_key, data);
@@ -1787,7 +1787,7 @@ export default class NestAccfactory {
1787
1787
  let tempDevice = {};
1788
1788
  try {
1789
1789
  if (
1790
- value?.source === DATASOURCE.ProtobufAPI &&
1790
+ value?.source === DATASOURCE.PROTOBUF_API &&
1791
1791
  this.config.options?.useGoogleAPI === true &&
1792
1792
  value.value?.configuration_done?.deviceReady === true &&
1793
1793
  typeof value?.value?.associated_thermostat === 'string' &&
@@ -1813,7 +1813,7 @@ export default class NestAccfactory {
1813
1813
  tempDevice = process_kryptonite_data(object_key, RESTTypeData);
1814
1814
  }
1815
1815
  if (
1816
- value?.source === DATASOURCE.NestAPI &&
1816
+ value?.source === DATASOURCE.NEST_API &&
1817
1817
  this.config.options?.useNestAPI === true &&
1818
1818
  value.value?.where_id !== undefined &&
1819
1819
  value.value?.structure_id !== undefined &&
@@ -1852,7 +1852,7 @@ export default class NestAccfactory {
1852
1852
  let processed = {};
1853
1853
  try {
1854
1854
  // Fix up data we need to
1855
- data.device_type = DeviceType.HEATLINK;
1855
+ data.device_type = DEVICE_TYPE.HEATLINK;
1856
1856
  data = process_common_data(object_key, data);
1857
1857
  data.current_temperature = adjustTemperature(data.current_temperature, 'C', 'C', true);
1858
1858
  processed = data;
@@ -1874,7 +1874,7 @@ export default class NestAccfactory {
1874
1874
  let tempDevice = {};
1875
1875
  try {
1876
1876
  if (
1877
- value?.source === DATASOURCE.ProtobufAPI &&
1877
+ value?.source === DATASOURCE.PROTOBUF_API &&
1878
1878
  this.config.options?.useGoogleAPI === true &&
1879
1879
  value.value?.configuration_done?.deviceReady === true
1880
1880
  ) {
@@ -1915,7 +1915,7 @@ export default class NestAccfactory {
1915
1915
  let processed = {};
1916
1916
  try {
1917
1917
  // Fix up data we need to
1918
- data.device_type = DeviceType.SMOKESENSOR; // Nest Protect
1918
+ data.device_type = DEVICE_TYPE.SMOKESENSOR; // Nest Protect
1919
1919
  data = process_common_data(object_key, data);
1920
1920
  processed = data;
1921
1921
  // eslint-disable-next-line no-unused-vars
@@ -1943,7 +1943,7 @@ export default class NestAccfactory {
1943
1943
  let tempDevice = {};
1944
1944
  try {
1945
1945
  if (
1946
- value?.source === DATASOURCE.ProtobufAPI &&
1946
+ value?.source === DATASOURCE.PROTOBUF_API &&
1947
1947
  this.config.options?.useGoogleAPI === true &&
1948
1948
  value.value?.configuration_done?.deviceReady === true
1949
1949
  ) {
@@ -2012,7 +2012,7 @@ export default class NestAccfactory {
2012
2012
  tempDevice = process_protect_data(object_key, RESTTypeData);
2013
2013
  }
2014
2014
  if (
2015
- value?.source === DATASOURCE.NestAPI &&
2015
+ value?.source === DATASOURCE.NEST_API &&
2016
2016
  this.config.options?.useNestAPI === true &&
2017
2017
  value.value?.where_id !== undefined &&
2018
2018
  value.value?.structure_id !== undefined
@@ -2081,12 +2081,12 @@ export default class NestAccfactory {
2081
2081
  let processed = {};
2082
2082
  try {
2083
2083
  // Fix up data we need to
2084
- data.device_type = DeviceType.CAMERA;
2084
+ data.device_type = DEVICE_TYPE.CAMERA;
2085
2085
  if (data.model.toUpperCase().includes('DOORBELL') === true) {
2086
- data.device_type = DeviceType.DOORBELL;
2086
+ data.device_type = DEVICE_TYPE.DOORBELL;
2087
2087
  }
2088
2088
  if (data.model.toUpperCase().includes('FLOODLIGHT') === true) {
2089
- data.device_type = DeviceType.FLOODLIGHT;
2089
+ data.device_type = DEVICE_TYPE.FLOODLIGHT;
2090
2090
  }
2091
2091
  data = process_common_data(object_key, data);
2092
2092
  processed = data;
@@ -2120,7 +2120,7 @@ export default class NestAccfactory {
2120
2120
  let tempDevice = {};
2121
2121
  try {
2122
2122
  if (
2123
- value?.source === DATASOURCE.ProtobufAPI &&
2123
+ value?.source === DATASOURCE.PROTOBUF_API &&
2124
2124
  this.config.options?.useGoogleAPI === true &&
2125
2125
  Array.isArray(value.value?.streaming_protocol?.supportedProtocols) === true &&
2126
2126
  value.value.streaming_protocol.supportedProtocols.includes('PROTOCOL_WEBRTC') === true &&
@@ -2192,7 +2192,7 @@ export default class NestAccfactory {
2192
2192
  value.value.activity_zone_settings.activityZones.forEach((zone) => {
2193
2193
  RESTTypeData.activity_zones.push({
2194
2194
  id: zone.zoneProperties?.zoneId !== undefined ? zone.zoneProperties.zoneId : zone.zoneProperties.internalIndex,
2195
- name: makeHomeKitName(zone.zoneProperties?.name !== undefined ? zone.zoneProperties.name : ''),
2195
+ name: HomeKitDevice.makeHomeKitName(zone.zoneProperties?.name !== undefined ? zone.zoneProperties.name : ''),
2196
2196
  hidden: false,
2197
2197
  uri: '',
2198
2198
  });
@@ -2230,7 +2230,7 @@ export default class NestAccfactory {
2230
2230
  }
2231
2231
 
2232
2232
  if (
2233
- value?.source === DATASOURCE.NestAPI &&
2233
+ value?.source === DATASOURCE.NEST_API &&
2234
2234
  this.config.options?.useNestAPI === true &&
2235
2235
  value.value?.where_id !== undefined &&
2236
2236
  value.value?.structure_id !== undefined &&
@@ -2314,7 +2314,7 @@ export default class NestAccfactory {
2314
2314
  let processed = {};
2315
2315
  try {
2316
2316
  // Fix up data we need to
2317
- data.device_type = DeviceType.WEATHER;
2317
+ data.device_type = DEVICE_TYPE.WEATHER;
2318
2318
  data.model = 'Weather';
2319
2319
  data.softwareVersion = '1.0.0';
2320
2320
  data = process_common_data(object_key, data);
@@ -2346,7 +2346,7 @@ export default class NestAccfactory {
2346
2346
  let tempDevice = {};
2347
2347
  try {
2348
2348
  if (
2349
- value?.source === DATASOURCE.ProtobufAPI &&
2349
+ value?.source === DATASOURCE.PROTOBUF_API &&
2350
2350
  this.config.options?.useGoogleAPI === true &&
2351
2351
  value.value?.structure_location?.geoCoordinate?.latitude !== undefined &&
2352
2352
  value.value?.structure_location?.geoCoordinate?.longitude !== undefined
@@ -2371,7 +2371,7 @@ export default class NestAccfactory {
2371
2371
  }
2372
2372
 
2373
2373
  if (
2374
- value?.source === DATASOURCE.NestAPI &&
2374
+ value?.source === DATASOURCE.NEST_API &&
2375
2375
  this.config.options?.useNestAPI === true &&
2376
2376
  value.value?.latitude !== undefined &&
2377
2377
  value.value?.longitude !== undefined
@@ -2424,7 +2424,7 @@ export default class NestAccfactory {
2424
2424
  let nest_google_uuid = values.uuid; // Nest/Google structure uuid for this get request
2425
2425
  let uuid = this.#rawData[values.uuid].connection; // Connection uuid for this device
2426
2426
 
2427
- if (this.#protobufRoot !== null && this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.ProtobufAPI) {
2427
+ if (this.#protobufRoot !== null && this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.PROTOBUF_API) {
2428
2428
  let updatedTraits = [];
2429
2429
  let protobufElement = {
2430
2430
  traitRequest: {
@@ -2736,7 +2736,7 @@ export default class NestAccfactory {
2736
2736
  }
2737
2737
  }
2738
2738
 
2739
- if (this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.NestAPI && nest_google_uuid.startsWith('quartz.') === true) {
2739
+ if (this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.NEST_API && nest_google_uuid.startsWith('quartz.') === true) {
2740
2740
  // Set value on Nest Camera/Doorbell
2741
2741
  await Promise.all(
2742
2742
  Object.entries(values)
@@ -2758,12 +2758,12 @@ export default class NestAccfactory {
2758
2758
  {
2759
2759
  headers: {
2760
2760
  referer: 'https://' + this.#connections[uuid].referer,
2761
- 'User-Agent': USERAGENT,
2761
+ 'User-Agent': USER_AGENT,
2762
2762
  'Content-Type': 'application/x-www-form-urlencoded',
2763
2763
  [this.#connections[uuid].cameraAPI.key]:
2764
2764
  this.#connections[uuid].cameraAPI.value + this.#connections[uuid].cameraAPI.token,
2765
2765
  },
2766
- timeout: NESTAPITIMEOUT,
2766
+ timeout: NEST_API_TIMEOUT,
2767
2767
  },
2768
2768
  mappedKey + '=' + value + '&uuid=' + nest_google_uuid.split('.')[1],
2769
2769
  );
@@ -2781,7 +2781,7 @@ export default class NestAccfactory {
2781
2781
  );
2782
2782
  }
2783
2783
 
2784
- if (this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.NestAPI && nest_google_uuid.startsWith('quartz.') === false) {
2784
+ if (this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.NEST_API && nest_google_uuid.startsWith('quartz.') === false) {
2785
2785
  // set values on other Nest devices besides cameras/doorbells
2786
2786
  await Promise.all(
2787
2787
  Object.entries(values)
@@ -2858,7 +2858,7 @@ export default class NestAccfactory {
2858
2858
  {
2859
2859
  referer: 'https://' + this.#connections[uuid].referer,
2860
2860
  headers: {
2861
- 'User-Agent': USERAGENT,
2861
+ 'User-Agent': USER_AGENT,
2862
2862
  Authorization: 'Basic ' + this.#connections[uuid].token,
2863
2863
  },
2864
2864
  },
@@ -2897,7 +2897,7 @@ export default class NestAccfactory {
2897
2897
  values[key] = undefined;
2898
2898
 
2899
2899
  if (
2900
- this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.NestAPI &&
2900
+ this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.NEST_API &&
2901
2901
  key === 'camera_snapshot' &&
2902
2902
  nest_google_uuid.startsWith('quartz.') === true &&
2903
2903
  typeof this.#rawData?.[nest_google_uuid]?.value?.nexus_api_http_server_url === 'string' &&
@@ -2911,7 +2911,7 @@ export default class NestAccfactory {
2911
2911
  {
2912
2912
  headers: {
2913
2913
  referer: 'https://' + this.#connections[uuid].referer,
2914
- 'User-Agent': USERAGENT,
2914
+ 'User-Agent': USER_AGENT,
2915
2915
  [this.#connections[uuid].cameraAPI.key]:
2916
2916
  this.#connections[uuid].cameraAPI.value + this.#connections[uuid].cameraAPI.token,
2917
2917
  },
@@ -2931,7 +2931,7 @@ export default class NestAccfactory {
2931
2931
  }
2932
2932
 
2933
2933
  if (
2934
- this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.ProtobufAPI &&
2934
+ this.#rawData?.[nest_google_uuid]?.source === DATASOURCE.PROTOBUF_API &&
2935
2935
  this.#protobufRoot !== null &&
2936
2936
  this.#rawData[nest_google_uuid]?.value?.device_identity?.vendorProductId !== undefined &&
2937
2937
  key === 'camera_snapshot'
@@ -2964,7 +2964,7 @@ export default class NestAccfactory {
2964
2964
  let response = await fetchWrapper('get', this.#rawData[nest_google_uuid].value.upload_live_image.liveImageUrl, {
2965
2965
  referer: 'https://' + this.#connections[uuid].referer,
2966
2966
  headers: {
2967
- 'User-Agent': USERAGENT,
2967
+ 'User-Agent': USER_AGENT,
2968
2968
  Authorization: 'Basic ' + this.#connections[uuid].token,
2969
2969
  },
2970
2970
  timeout: 3000,
@@ -2997,9 +2997,9 @@ export default class NestAccfactory {
2997
2997
  let response = await fetchWrapper('get', this.#connections[uuid].weather_url + location, {
2998
2998
  referer: 'https://' + this.#connections[uuid].referer,
2999
2999
  headers: {
3000
- 'User-Agent': USERAGENT,
3000
+ 'User-Agent': USER_AGENT,
3001
3001
  },
3002
- timeout: NESTAPITIMEOUT,
3002
+ timeout: NEST_API_TIMEOUT,
3003
3003
  });
3004
3004
 
3005
3005
  let data = await response.json();
@@ -3087,7 +3087,7 @@ export default class NestAccfactory {
3087
3087
  {
3088
3088
  headers: {
3089
3089
  referer: 'https://' + this.#connections[uuid].referer,
3090
- 'User-Agent': USERAGENT,
3090
+ 'User-Agent': USER_AGENT,
3091
3091
  Authorization: 'Basic ' + this.#connections[uuid].token,
3092
3092
  'Content-Type': 'application/x-protobuf',
3093
3093
  'X-Accept-Content-Transfer-Encoding': 'binary',
@@ -3129,20 +3129,6 @@ function adjustTemperature(temperature, currentTemperatureUnit, targetTemperatur
3129
3129
  return temperature;
3130
3130
  }
3131
3131
 
3132
- function makeHomeKitName(nameToMakeValid) {
3133
- // Strip invalid characters to meet HomeKit naming requirements
3134
- // Ensure only letters or numbers are at the beginning AND/OR end of string
3135
- // Matches against uni-code characters
3136
- let validHomeKitName = nameToMakeValid;
3137
- if (typeof nameToMakeValid === 'string') {
3138
- validHomeKitName = nameToMakeValid
3139
- .replace(/[^\p{L}\p{N}\p{Z}\u2019 '.,-]/gu, '') // Remove disallowed characters
3140
- .replace(/^[^\p{L}\p{N}]*/gu, '') // Trim invalid prefix
3141
- .replace(/[^\p{L}\p{N}]+$/gu, ''); // Trim invalid suffix
3142
- }
3143
- return validHomeKitName;
3144
- }
3145
-
3146
3132
  function crc24(valueToHash) {
3147
3133
  const crc24HashTable = [
3148
3134
  0x000000, 0x864cfb, 0x8ad50d, 0x0c99f6, 0x93e6e1, 0x15aa1a, 0x1933ec, 0x9f7f17, 0xa18139, 0x27cdc2, 0x2b5434, 0xad18cf, 0x3267d8,