iobroker.mg-saic 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -36,13 +36,19 @@ For manufacturer information, see [MG Motor](https://www.mgmotor.eu/) and [SAIC
36
36
 
37
37
  ## Installation
38
38
 
39
- The adapter is published on npm but has not yet been added to the ioBroker adapter catalog.
39
+ The adapter is published on npm and available from ioBroker's Latest adapter repository.
40
40
 
41
41
  ## Support
42
42
 
43
43
  [![Donate](https://camo.githubusercontent.com/ef8c60305542390406855547e32850909812a73c4abada236de22a6dc88b313f/68747470733a2f2f7777772e70617970616c6f626a656374732e636f6d2f64655f44452f44452f692f62746e2f62746e5f646f6e61746543435f4c472e676966)](https://www.paypal.com/donate/?hosted_button_id=3RJQGSJNRSHUJ)
44
44
 
45
45
  ## Changelog
46
+ ### 0.1.2 (2026-11-08)
47
+
48
+ - (Voodoo2man) Prevented unsafe or case-colliding API fields and vehicle IDs from creating duplicate datapoints, kept status IDs stable across field-casing changes, scheduled polling after each completed cycle while honoring queued manual refreshes, and removed an unused cloud-backend translation.
49
+ - (Voodoo2man) Replaced untrusted cloud error text with English code-based diagnostics and standardized the product title as MG/SAIC across locales.
50
+ - (Voodoo2man) Reused dynamic charging datapoints across field-name casing changes and normalized known status fields.
51
+
46
52
  ### 0.1.1 (2026-11-07)
47
53
 
48
54
  - (Voodoo2man) Lowered the minimum Node.js requirement to 22.22.2.
@@ -69,10 +75,6 @@ The adapter is published on npm but has not yet been added to the ioBroker adapt
69
75
 
70
76
  Older changelog entries are available in [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
71
77
 
72
- ### 0.0.2 (2026-10-20)
73
-
74
- - (Voodoo2man) Added regional iSmart account setup, vehicle status, and supported remote controls.
75
-
76
78
  ## License
77
79
 
78
80
  MIT License
@@ -7,7 +7,6 @@
7
7
  "Region": "Region",
8
8
  "European Union": "Europäische Union",
9
9
  "Rest of World": "Rest der Welt",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "Die Cloud-Anbindung ist noch nicht implementiert. Dieser Wert wählt kein funktionsfähiges Backend aus.",
11
10
  "Login type": "Anmeldetyp",
12
11
  "Email": "E-Mail",
13
12
  "Phone number": "Telefonnummer",
@@ -7,7 +7,6 @@
7
7
  "Region": "Region",
8
8
  "European Union": "European Union",
9
9
  "Rest of World": "Rest of World",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "Cloud connectivity is not implemented yet. This value does not select a working backend.",
11
10
  "Login type": "Login type",
12
11
  "Email": "Email",
13
12
  "Phone number": "Phone number",
@@ -7,7 +7,6 @@
7
7
  "Region": "Región",
8
8
  "European Union": "Unión Europea",
9
9
  "Rest of World": "Resto del mundo",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "La conexión a la nube aún no está implementada. Este valor no selecciona un servicio operativo.",
11
10
  "Login type": "Tipo de inicio de sesión",
12
11
  "Email": "Correo electrónico",
13
12
  "Phone number": "Número de teléfono",
@@ -7,7 +7,6 @@
7
7
  "Region": "Région",
8
8
  "European Union": "Union européenne",
9
9
  "Rest of World": "Reste du monde",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "La connexion au cloud n'est pas encore implémentée. Cette valeur ne sélectionne pas de service fonctionnel.",
11
10
  "Login type": "Type de connexion",
12
11
  "Email": "E-mail",
13
12
  "Phone number": "Numéro de téléphone",
@@ -7,7 +7,6 @@
7
7
  "Region": "Regione",
8
8
  "European Union": "Unione europea",
9
9
  "Rest of World": "Resto del mondo",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "La connessione cloud non è ancora implementata. Questo valore non seleziona un servizio funzionante.",
11
10
  "Login type": "Tipo di accesso",
12
11
  "Email": "E-mail",
13
12
  "Phone number": "Numero di telefono",
@@ -7,7 +7,6 @@
7
7
  "Region": "Regio",
8
8
  "European Union": "Europese Unie",
9
9
  "Rest of World": "Rest van de wereld",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "Cloudverbinding is nog niet geïmplementeerd. Deze waarde selecteert geen werkende backend.",
11
10
  "Login type": "Aanmeldtype",
12
11
  "Email": "E-mailadres",
13
12
  "Phone number": "Telefoonnummer",
@@ -7,7 +7,6 @@
7
7
  "Region": "Region",
8
8
  "European Union": "Unia Europejska",
9
9
  "Rest of World": "Reszta świata",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "Połączenie z chmurą nie jest jeszcze zaimplementowane. Ta wartość nie wybiera działającej usługi.",
11
10
  "Login type": "Typ logowania",
12
11
  "Email": "E-mail",
13
12
  "Phone number": "Numer telefonu",
@@ -7,7 +7,6 @@
7
7
  "Region": "Região",
8
8
  "European Union": "União Europeia",
9
9
  "Rest of World": "Resto do mundo",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "A ligação à nuvem ainda não está implementada. Este valor não seleciona um serviço funcional.",
11
10
  "Login type": "Tipo de início de sessão",
12
11
  "Email": "E-mail",
13
12
  "Phone number": "Número de telefone",
@@ -7,7 +7,6 @@
7
7
  "Region": "Регион",
8
8
  "European Union": "Европейский союз",
9
9
  "Rest of World": "Остальной мир",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "Подключение к облаку пока не реализовано. Это значение не выбирает работающий сервер.",
11
10
  "Login type": "Тип входа",
12
11
  "Email": "Электронная почта",
13
12
  "Phone number": "Номер телефона",
@@ -7,7 +7,6 @@
7
7
  "Region": "Регіон",
8
8
  "European Union": "Європейський Союз",
9
9
  "Rest of World": "Решта світу",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "Підключення до хмари ще не реалізовано. Це значення не вибирає робочий сервер.",
11
10
  "Login type": "Тип входу",
12
11
  "Email": "Електронна пошта",
13
12
  "Phone number": "Номер телефону",
@@ -7,7 +7,6 @@
7
7
  "Region": "地区",
8
8
  "European Union": "欧盟",
9
9
  "Rest of World": "其他地区",
10
- "Cloud connectivity is not implemented yet. This value does not select a working backend.": "云连接尚未实现。此选项不会选择可用的后端服务。",
11
10
  "Login type": "登录类型",
12
11
  "Email": "电子邮箱",
13
12
  "Phone number": "电话号码",
package/build/main.js CHANGED
@@ -28,6 +28,8 @@ var import_config = require("./config");
28
28
  var import_saic_client = require("./saic-client");
29
29
  var import_regions = require("./regions");
30
30
  var import_refresh_command = require("./refresh-command");
31
+ var import_refresh_poll_queue = require("./refresh-poll-queue");
32
+ var import_refresh_poll_timer = require("./refresh-poll-timer");
31
33
  var import_pending_setting_edits = require("./pending-setting-edits");
32
34
  var import_status_metadata = require("./status-metadata");
33
35
  var import_runtime_translations = require("./runtime-translations");
@@ -114,13 +116,17 @@ class MgSaic extends utils.Adapter {
114
116
  ...options,
115
117
  name: "mg-saic"
116
118
  });
119
+ this.pollTimer = new import_refresh_poll_timer.RefreshPollTimer(
120
+ (callback, milliseconds) => this.setTimeout(callback, milliseconds),
121
+ (timer) => this.clearTimeout(timer)
122
+ );
117
123
  this.on("ready", this.onReady.bind(this));
118
124
  this.on("stateChange", this.onStateChange.bind(this));
119
125
  this.on("unload", this.onUnload.bind(this));
120
126
  }
121
127
  pollTimer;
122
- pollInProgress = false;
123
- refreshQueued = false;
128
+ pollIntervalMilliseconds;
129
+ refreshPollQueue = new import_refresh_poll_queue.RefreshPollQueue();
124
130
  stopping = false;
125
131
  unloadCallbackCalled = false;
126
132
  abortController = new AbortController();
@@ -129,6 +135,7 @@ class MgSaic extends utils.Adapter {
129
135
  accessToken;
130
136
  accessTokenExpiresAt = 0;
131
137
  vehicles = [];
138
+ vehicleStatusFieldIds = /* @__PURE__ */ new Map();
132
139
  lastStatusTimes = /* @__PURE__ */ new Map();
133
140
  lastCanonicalStatusTimes = /* @__PURE__ */ new Map();
134
141
  vehicleCommandsInProgress = /* @__PURE__ */ new Set();
@@ -262,11 +269,9 @@ class MgSaic extends utils.Adapter {
262
269
  this.log.warn("No vehicles are linked to this SAIC account.");
263
270
  return;
264
271
  }
265
- await this.refreshVehicleStatuses();
266
272
  const intervalSeconds = (_e = config.pollIntervalSeconds) != null ? _e : import_config.DEFAULT_POLL_INTERVAL_SECONDS;
267
- if (!this.stopping) {
268
- this.pollTimer = this.setInterval(() => this.triggerRefresh(), intervalSeconds * 1e3);
269
- }
273
+ this.pollIntervalMilliseconds = intervalSeconds * 1e3;
274
+ await this.refreshVehicleStatuses();
270
275
  } catch (error) {
271
276
  if (this.stopping) {
272
277
  return;
@@ -289,26 +294,31 @@ class MgSaic extends utils.Adapter {
289
294
  await this.setState("info.connection", true, true);
290
295
  }
291
296
  triggerRefresh() {
297
+ this.pollTimer.clear();
292
298
  void this.refreshVehicleStatuses().catch((error) => {
293
299
  const details = error instanceof Error ? error.message : "Unknown refresh error";
294
300
  this.log.error(`Vehicle status refresh failed: ${details}`);
295
301
  });
296
302
  }
303
+ scheduleNextPoll() {
304
+ if (this.stopping || this.pollIntervalMilliseconds === void 0) {
305
+ return;
306
+ }
307
+ this.pollTimer.schedule(() => this.triggerRefresh(), this.pollIntervalMilliseconds);
308
+ }
297
309
  async refreshVehicleStatuses() {
298
310
  var _a;
299
311
  if (this.stopping || !this.client || !this.loginOptions || !this.accessToken) {
300
312
  return;
301
313
  }
302
- if (this.pollInProgress) {
303
- this.refreshQueued = true;
314
+ if (!this.refreshPollQueue.request()) {
304
315
  return;
305
316
  }
306
- this.pollInProgress = true;
307
317
  const statusErrors = [];
308
318
  let followUpUsed = false;
309
319
  try {
310
320
  do {
311
- this.refreshQueued = false;
321
+ this.refreshPollQueue.clearQueuedRefresh();
312
322
  for (const vehicle of this.vehicles) {
313
323
  if (this.stopping) {
314
324
  break;
@@ -375,7 +385,7 @@ class MgSaic extends utils.Adapter {
375
385
  }
376
386
  } else {
377
387
  const details = error instanceof Error ? error.message : "Unknown error";
378
- const diagnostic = error instanceof import_saic_client.SaicRemoteInstructionError ? `SAIC/MG returned remote instruction code 4 for ${vehicle.vin}; this is a response from the MG/SAIC service or vehicle, not an adapter parsing/processing error. SAIC message: ${details}` : details;
388
+ const diagnostic = error instanceof import_saic_client.SaicRemoteInstructionError ? `SAIC/MG returned remote instruction code 4 for ${vehicle.vin}; this is a response from the MG/SAIC service or vehicle, not an adapter parsing/processing error. Diagnostic: ${details}` : details;
379
389
  statusErrors.push(`Vehicle status request failed for ${vehicle.vin}: ${diagnostic}`);
380
390
  this.log.warn(
381
391
  `Could not retrieve current status for vehicle ${vehicle.vin}: ${diagnostic}`
@@ -478,17 +488,21 @@ class MgSaic extends utils.Adapter {
478
488
  this.log.error(`Could not write live status for ${vehicle.vin}: ${details}`);
479
489
  }
480
490
  }
481
- if (this.refreshQueued && followUpUsed) {
482
- this.refreshQueued = false;
483
- } else if (this.refreshQueued) {
491
+ if (this.refreshPollQueue.hasQueuedRefresh && followUpUsed) {
492
+ this.refreshPollQueue.clearQueuedRefresh();
493
+ } else if (this.refreshPollQueue.hasQueuedRefresh) {
484
494
  followUpUsed = true;
485
495
  }
486
- } while (this.refreshQueued && !this.stopping);
496
+ } while (this.refreshPollQueue.hasQueuedRefresh && !this.stopping);
487
497
  if (!this.stopping) {
488
498
  await this.setState("info.lastError", statusErrors.join("; "), true);
489
499
  }
490
500
  } finally {
491
- this.pollInProgress = false;
501
+ this.refreshPollQueue.finish(
502
+ this.stopping,
503
+ () => this.triggerRefresh(),
504
+ () => this.scheduleNextPoll()
505
+ );
492
506
  }
493
507
  }
494
508
  onStateChange(id, state) {
@@ -801,6 +815,21 @@ class MgSaic extends utils.Adapter {
801
815
  this.vehicleCommandsInProgress.delete(vin);
802
816
  }
803
817
  }
818
+ async getVehicleStatusFieldIds(channelId) {
819
+ const cachedIds = this.vehicleStatusFieldIds.get(channelId);
820
+ if (cachedIds) {
821
+ return cachedIds;
822
+ }
823
+ const objectIdPrefix = `${this.namespace}.${channelId}.`;
824
+ const objects = await this.getObjectListAsync({
825
+ startkey: objectIdPrefix,
826
+ endkey: `${objectIdPrefix}\u9999`
827
+ });
828
+ const stateIds = objects.rows.filter((row) => row.value.type === "state" && row.id.startsWith(`${this.namespace}.`)).map((row) => row.id.slice(this.namespace.length + 1));
829
+ const fieldIds = (0, import_status_metadata.indexVehicleStatusFieldIds)(stateIds, channelId);
830
+ this.vehicleStatusFieldIds.set(channelId, fieldIds);
831
+ return fieldIds;
832
+ }
804
833
  async createVehicleStatusObjects(vin, status, channel = "status", channelName = "currentStatus") {
805
834
  if (this.stopping) {
806
835
  return;
@@ -809,10 +838,6 @@ class MgSaic extends utils.Adapter {
809
838
  return;
810
839
  }
811
840
  const statusId = `vehicles.${vin}.${channel}`;
812
- for (const key of import_status_metadata.excludedVehicleStatusFields) {
813
- const stateId = `${statusId}.${(0, import_status_metadata.getVehicleStatusGroup)(key)}.${key}`;
814
- await this.delObjectAsync(stateId);
815
- }
816
841
  await this.setObjectNotExistsAsync(statusId, {
817
842
  type: "channel",
818
843
  common: { name: (0, import_runtime_translations.getRuntimeName)(channelName) },
@@ -822,6 +847,11 @@ class MgSaic extends utils.Adapter {
822
847
  if (this.stopping) {
823
848
  return;
824
849
  }
850
+ const fieldIds = await this.getVehicleStatusFieldIds(statusId);
851
+ for (const key of import_status_metadata.excludedVehicleStatusFields) {
852
+ const stateId = (0, import_status_metadata.resolveVehicleStatusFieldId)(fieldIds, statusId, (0, import_status_metadata.getVehicleStatusGroup)(key), key);
853
+ await this.delObjectAsync(stateId);
854
+ }
825
855
  const values = { ...status.basicVehicleStatus };
826
856
  if (status.statusTime !== void 0) {
827
857
  values.statusTime = status.statusTime;
@@ -834,15 +864,17 @@ class MgSaic extends utils.Adapter {
834
864
  if (this.stopping) {
835
865
  return;
836
866
  }
837
- if (import_status_metadata.excludedVehicleStatusFields.some((excludedKey) => excludedKey === key)) {
838
- await this.delObjectAsync(`${statusId}.${(0, import_status_metadata.getVehicleStatusGroup)(key)}.${key}`);
867
+ const stateId = (0, import_status_metadata.resolveVehicleStatusFieldId)(fieldIds, statusId, (0, import_status_metadata.getVehicleStatusGroup)(key), key);
868
+ const separator = stateId.lastIndexOf(".");
869
+ const fieldName = stateId.slice(separator + 1);
870
+ const groupId = stateId.slice(0, separator);
871
+ const group = groupId.slice(statusId.length + 1);
872
+ if (import_status_metadata.excludedVehicleStatusFields.some((excludedKey) => excludedKey.toLowerCase() === fieldName.toLowerCase())) {
873
+ await this.delObjectAsync(stateId);
839
874
  continue;
840
875
  }
841
- const group = (0, import_status_metadata.getVehicleStatusGroup)(key);
842
- const groupId = `${statusId}.${group}`;
843
- const stateId = `${groupId}.${key}`;
844
876
  if (value === void 0) {
845
- if ((0, import_status_metadata.shouldDeleteUnavailableStatusValue)(key)) {
877
+ if ((0, import_status_metadata.shouldDeleteUnavailableStatusValue)(fieldName)) {
846
878
  await this.delObjectAsync(stateId);
847
879
  } else {
848
880
  const previousState = await this.getStateAsync(stateId);
@@ -852,7 +884,7 @@ class MgSaic extends utils.Adapter {
852
884
  }
853
885
  continue;
854
886
  }
855
- const normalizedValue = (0, import_status_metadata.normalizeVehicleStatusValue)(key, value);
887
+ const normalizedValue = (0, import_status_metadata.normalizeVehicleStatusValue)(fieldName, value);
856
888
  if (normalizedValue === void 0) {
857
889
  await this.delObjectAsync(stateId);
858
890
  continue;
@@ -866,7 +898,7 @@ class MgSaic extends utils.Adapter {
866
898
  if (this.stopping) {
867
899
  return;
868
900
  }
869
- const metadata = (0, import_status_metadata.getVehicleStatusMetadata)(key);
901
+ const metadata = (0, import_status_metadata.getVehicleStatusMetadata)(fieldName);
870
902
  const common = {
871
903
  name: metadata.name,
872
904
  type: metadata.type,
@@ -895,7 +927,7 @@ class MgSaic extends utils.Adapter {
895
927
  if (this.stopping) {
896
928
  return;
897
929
  }
898
- const seatSetting = key === "frontLeftSeatHeatLevel" ? "driverSeatHeatLevel" : key === "frontRightSeatHeatLevel" ? "passengerSeatHeatLevel" : void 0;
930
+ const seatSetting = fieldName === "frontLeftSeatHeatLevel" ? "driverSeatHeatLevel" : fieldName === "frontRightSeatHeatLevel" ? "passengerSeatHeatLevel" : void 0;
899
931
  if (seatSetting && Number.isInteger(value) && value >= 0 && value <= 3) {
900
932
  const settingId = vehicleCommandPath(vin, seatSetting);
901
933
  const settingState = await this.getStateAsync(settingId);
@@ -903,12 +935,32 @@ class MgSaic extends utils.Adapter {
903
935
  await this.setStateAsync(settingId, { val: value, ack: true });
904
936
  }
905
937
  }
906
- await this.delObjectAsync(`${statusId}.${key}`);
938
+ await this.delObjectAsync(`${statusId}.${fieldName}`);
907
939
  }
908
940
  }
909
941
  async createVehicleChargingObjects(vin, charging, series) {
942
+ var _a, _b;
910
943
  await this.ensureVehicleChargingGroups(vin);
911
944
  const rootId = `vehicles.${vin}.status.charging`;
945
+ const existingObjects = await this.getObjectListAsync({
946
+ startkey: `${this.namespace}.${rootId}.`,
947
+ endkey: `${this.namespace}.${rootId}.\u9999`
948
+ });
949
+ const existingFieldIds = new Map(chargingGroups.map(({ id }) => [id, []]));
950
+ for (const { id: objectId, value: object } of existingObjects.rows) {
951
+ if (object.type !== "state") {
952
+ continue;
953
+ }
954
+ const group = chargingGroups.find(({ id }) => objectId.startsWith(`${this.namespace}.${rootId}.${id}.`));
955
+ if (!group) {
956
+ continue;
957
+ }
958
+ const prefix = `${this.namespace}.${rootId}.${group.id}.`;
959
+ const fieldId = objectId.slice(prefix.length);
960
+ if (fieldId && !fieldId.includes(".")) {
961
+ (_a = existingFieldIds.get(group.id)) == null ? void 0 : _a.push(fieldId);
962
+ }
963
+ }
912
964
  for (const { source, id } of chargingGroups) {
913
965
  const groupId = `${rootId}.${id}`;
914
966
  const excludedFields = id === "session" ? import_status_metadata.excludedChargingSessionFields : import_status_metadata.excludedChargingStatisticsFields;
@@ -916,27 +968,34 @@ class MgSaic extends utils.Adapter {
916
968
  for (const field of excludedFields) {
917
969
  await this.delObjectAsync(`${groupId}.${field}`);
918
970
  }
919
- for (const [field, value] of fields) {
971
+ const valuesByField = new Map(fields);
972
+ const resolvedFieldIds = (0, import_status_metadata.resolveChargingFieldIds)(
973
+ fields.map(([field]) => field),
974
+ (_b = existingFieldIds.get(id)) != null ? _b : []
975
+ );
976
+ for (const [responseField, field] of resolvedFieldIds) {
920
977
  if (this.stopping) {
921
978
  return;
922
979
  }
923
- if (excludedFields.some((excludedField) => excludedField === field)) {
980
+ const value = valuesByField.get(responseField);
981
+ const canonicalField = (0, import_status_metadata.resolveChargingFieldName)(field);
982
+ if (excludedFields.some((excludedField) => excludedField === canonicalField)) {
924
983
  await this.delObjectAsync(`${groupId}.${field}`);
925
984
  continue;
926
985
  }
927
986
  const stateId = `${groupId}.${field}`;
928
- if (value === void 0 && field !== "realtimePower" && field !== "batteryAvailableEnergy") {
987
+ if (value === void 0 && canonicalField !== "realtimePower" && canonicalField !== "batteryAvailableEnergy") {
929
988
  await this.delObjectAsync(stateId);
930
989
  continue;
931
990
  }
932
- const normalizedValue = field === "realtimePower" ? (0, import_status_metadata.calculateRealtimePower)(charging.chrgMgmtData.bmsPackCrnt, charging.chrgMgmtData.bmsPackVol) : value === void 0 ? void 0 : (0, import_status_metadata.normalizeChargingValue)(field, value, series);
933
- if (normalizedValue === void 0 && field !== "batteryAvailableEnergy") {
991
+ const normalizedValue = canonicalField === "realtimePower" ? (0, import_status_metadata.calculateRealtimePower)(charging.chrgMgmtData.bmsPackCrnt, charging.chrgMgmtData.bmsPackVol) : value === void 0 ? void 0 : (0, import_status_metadata.normalizeChargingValue)(canonicalField, value, series);
992
+ if (normalizedValue === void 0 && canonicalField !== "batteryAvailableEnergy") {
934
993
  await this.delObjectAsync(stateId);
935
994
  continue;
936
995
  }
937
- const metadata = (0, import_status_metadata.getChargingFieldMetadata)(field, series);
996
+ const metadata = (0, import_status_metadata.getChargingFieldMetadata)(canonicalField, series);
938
997
  const common = {
939
- name: (0, import_runtime_translations.getChargingFieldName)(field),
998
+ name: (0, import_runtime_translations.getChargingFieldName)(canonicalField),
940
999
  type: metadata.type === "boolean" ? "boolean" : typeof normalizedValue === "string" ? "string" : "number",
941
1000
  role: typeof normalizedValue === "string" ? "text" : metadata.role,
942
1001
  read: true,
@@ -1314,10 +1373,8 @@ class MgSaic extends utils.Adapter {
1314
1373
  this.unloadCallbackCalled = true;
1315
1374
  this.stopping = true;
1316
1375
  this.abortController.abort(new DOMException("Adapter is stopping", "AbortError"));
1317
- this.refreshQueued = false;
1318
- if (this.pollTimer) {
1319
- this.clearInterval(this.pollTimer);
1320
- }
1376
+ this.refreshPollQueue.clearQueuedRefresh();
1377
+ this.pollTimer.clear();
1321
1378
  callback();
1322
1379
  }
1323
1380
  }