@fastybird/smart-panel-backend 1.1.0-alpha.5 → 1.1.0-alpha.7

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.
Files changed (131) hide show
  1. package/dist/app.module.js +7 -0
  2. package/dist/app.module.js.map +1 -1
  3. package/dist/modules/devices/controllers/channels.properties.controller.js +16 -4
  4. package/dist/modules/devices/controllers/channels.properties.controller.js.map +1 -1
  5. package/dist/modules/devices/controllers/devices.channels.properties.controller.js +16 -4
  6. package/dist/modules/devices/controllers/devices.channels.properties.controller.js.map +1 -1
  7. package/dist/modules/devices/devices.module.js +12 -0
  8. package/dist/modules/devices/devices.module.js.map +1 -1
  9. package/dist/modules/devices/services/channels.properties.service.d.ts +27 -3
  10. package/dist/modules/devices/services/channels.properties.service.js +304 -28
  11. package/dist/modules/devices/services/channels.properties.service.js.map +1 -1
  12. package/dist/modules/devices/services/channels.service.js +42 -38
  13. package/dist/modules/devices/services/channels.service.js.map +1 -1
  14. package/dist/modules/devices/services/command-latency-trace-collector.service.d.ts +100 -0
  15. package/dist/modules/devices/services/command-latency-trace-collector.service.js +438 -0
  16. package/dist/modules/devices/services/command-latency-trace-collector.service.js.map +1 -0
  17. package/dist/modules/devices/services/device-structure-lock.service.d.ts +10 -2
  18. package/dist/modules/devices/services/device-structure-lock.service.js +86 -7
  19. package/dist/modules/devices/services/device-structure-lock.service.js.map +1 -1
  20. package/dist/modules/devices/services/devices.service.js +37 -33
  21. package/dist/modules/devices/services/devices.service.js.map +1 -1
  22. package/dist/modules/devices/services/module-reset.service.d.ts +3 -1
  23. package/dist/modules/devices/services/module-reset.service.js +21 -16
  24. package/dist/modules/devices/services/module-reset.service.js.map +1 -1
  25. package/dist/modules/devices/services/property-command-dispatch.service.d.ts +45 -0
  26. package/dist/modules/devices/services/property-command-dispatch.service.js +227 -0
  27. package/dist/modules/devices/services/property-command-dispatch.service.js.map +1 -0
  28. package/dist/modules/devices/services/property-command-window.service.d.ts +71 -0
  29. package/dist/modules/devices/services/property-command-window.service.js +204 -0
  30. package/dist/modules/devices/services/property-command-window.service.js.map +1 -0
  31. package/dist/modules/devices/services/property-command.service.d.ts +20 -3
  32. package/dist/modules/devices/services/property-command.service.js +56 -10
  33. package/dist/modules/devices/services/property-command.service.js.map +1 -1
  34. package/dist/modules/devices/services/property-state-coordinator.service.d.ts +4 -0
  35. package/dist/modules/devices/services/property-state-coordinator.service.js +35 -0
  36. package/dist/modules/devices/services/property-state-coordinator.service.js.map +1 -0
  37. package/dist/modules/devices/services/property-value.service.d.ts +1 -0
  38. package/dist/modules/devices/services/property-value.service.js +4 -0
  39. package/dist/modules/devices/services/property-value.service.js.map +1 -1
  40. package/dist/plugins/devices-home-assistant/services/home-assistant.ws.service.js +2 -1
  41. package/dist/plugins/devices-home-assistant/services/home-assistant.ws.service.js.map +1 -1
  42. package/dist/plugins/devices-home-assistant/services/state-changed.event.service.js +2 -3
  43. package/dist/plugins/devices-home-assistant/services/state-changed.event.service.js.map +1 -1
  44. package/dist/plugins/devices-homekit/listeners/homekit-event.listener.js +6 -1
  45. package/dist/plugins/devices-homekit/listeners/homekit-event.listener.js.map +1 -1
  46. package/dist/plugins/devices-homekit/mappers/base.mapper.js +27 -4
  47. package/dist/plugins/devices-homekit/mappers/base.mapper.js.map +1 -1
  48. package/dist/plugins/devices-homekit/mappers/homekit-mapper.interface.d.ts +8 -0
  49. package/dist/plugins/devices-homekit/mappers/thermostat-coordinator.d.ts +7 -0
  50. package/dist/plugins/devices-homekit/mappers/thermostat-coordinator.js +84 -73
  51. package/dist/plugins/devices-homekit/mappers/thermostat-coordinator.js.map +1 -1
  52. package/dist/plugins/devices-shelly-ng/delegates/delegates-manager.service.d.ts +16 -1
  53. package/dist/plugins/devices-shelly-ng/delegates/delegates-manager.service.js +194 -17
  54. package/dist/plugins/devices-shelly-ng/delegates/delegates-manager.service.js.map +1 -1
  55. package/dist/plugins/devices-shelly-ng/delegates/shelly-device.delegate.d.ts +9 -1
  56. package/dist/plugins/devices-shelly-ng/delegates/shelly-device.delegate.js +92 -10
  57. package/dist/plugins/devices-shelly-ng/delegates/shelly-device.delegate.js.map +1 -1
  58. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.d.ts +9 -1
  59. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.js +59 -24
  60. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.js.map +1 -1
  61. package/dist/plugins/devices-shelly-ng/services/shelly-ws-server.service.js +1 -3
  62. package/dist/plugins/devices-shelly-ng/services/shelly-ws-server.service.js.map +1 -1
  63. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.d.ts +17 -0
  64. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.js +147 -0
  65. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.js.map +1 -0
  66. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.d.ts +15 -0
  67. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.js +98 -0
  68. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.js.map +1 -0
  69. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.d.ts +9 -0
  70. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.js +94 -0
  71. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.js.map +1 -0
  72. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.d.ts +9 -0
  73. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.js +92 -0
  74. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.js.map +1 -0
  75. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.d.ts +7 -0
  76. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.js +48 -0
  77. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.js.map +1 -0
  78. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.d.ts +42 -0
  79. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.js +352 -0
  80. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.js.map +1 -0
  81. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.d.ts +24 -0
  82. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.js +27 -0
  83. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.js.map +1 -0
  84. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.d.ts +8 -0
  85. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.js +19 -0
  86. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.js.map +1 -0
  87. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.d.ts +4 -0
  88. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.js +20 -0
  89. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.js.map +1 -0
  90. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.d.ts +21 -0
  91. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.js +135 -0
  92. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.js.map +1 -0
  93. package/dist/plugins/remote-access-cloudflare-tunnel/scripts/cloudflared-setup.sh +185 -0
  94. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.d.ts +82 -0
  95. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.js +507 -0
  96. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.js.map +1 -0
  97. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.d.ts +10 -0
  98. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.js +37 -0
  99. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.js.map +1 -0
  100. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.d.ts +38 -0
  101. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.js +147 -0
  102. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.js.map +1 -0
  103. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.d.ts +15 -0
  104. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.js +67 -0
  105. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.js.map +1 -0
  106. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.d.ts +8 -0
  107. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.js +46 -0
  108. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.js.map +1 -0
  109. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.d.ts +27 -0
  110. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.js +139 -0
  111. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.js.map +1 -0
  112. package/dist/plugins/scenes-local/platforms/local-scene.platform.d.ts +3 -1
  113. package/dist/plugins/scenes-local/platforms/local-scene.platform.js +12 -7
  114. package/dist/plugins/scenes-local/platforms/local-scene.platform.js.map +1 -1
  115. package/dist/plugins/spaces-home-control/services/climate-intent.service.d.ts +3 -1
  116. package/dist/plugins/spaces-home-control/services/climate-intent.service.js +6 -3
  117. package/dist/plugins/spaces-home-control/services/climate-intent.service.js.map +1 -1
  118. package/dist/plugins/spaces-home-control/services/covers-intent.service.d.ts +3 -1
  119. package/dist/plugins/spaces-home-control/services/covers-intent.service.js +6 -3
  120. package/dist/plugins/spaces-home-control/services/covers-intent.service.js.map +1 -1
  121. package/dist/plugins/spaces-home-control/services/lighting-intent.service.d.ts +3 -1
  122. package/dist/plugins/spaces-home-control/services/lighting-intent.service.js +7 -4
  123. package/dist/plugins/spaces-home-control/services/lighting-intent.service.js.map +1 -1
  124. package/dist/plugins/spaces-home-control/services/space-media-activity.service.d.ts +3 -1
  125. package/dist/plugins/spaces-home-control/services/space-media-activity.service.js +11 -5
  126. package/dist/plugins/spaces-home-control/services/space-media-activity.service.js.map +1 -1
  127. package/dist/plugins/spaces-home-control/services/space-undo-history.service.d.ts +3 -1
  128. package/dist/plugins/spaces-home-control/services/space-undo-history.service.js +8 -5
  129. package/dist/plugins/spaces-home-control/services/space-undo-history.service.js.map +1 -1
  130. package/dist/tsconfig.build.tsbuildinfo +1 -1
  131. package/package.json +2 -2
@@ -8,16 +8,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
11
14
  var DelegatesManagerService_1;
12
15
  Object.defineProperty(exports, "__esModule", { value: true });
13
16
  exports.DelegatesManagerService = void 0;
14
- const class_transformer_1 = require("class-transformer");
15
17
  const common_1 = require("@nestjs/common");
16
18
  const logger_1 = require("../../../common/logger");
17
19
  const transform_utils_1 = require("../../../common/utils/transform.utils");
18
20
  const devices_constants_1 = require("../../../modules/devices/devices.constants");
19
21
  const channels_properties_service_1 = require("../../../modules/devices/services/channels.properties.service");
20
22
  const channels_service_1 = require("../../../modules/devices/services/channels.service");
23
+ const command_latency_trace_collector_service_1 = require("../../../modules/devices/services/command-latency-trace-collector.service");
21
24
  const device_connectivity_service_1 = require("../../../modules/devices/services/device-connectivity.service");
22
25
  const devices_service_1 = require("../../../modules/devices/services/devices.service");
23
26
  const devices_shelly_ng_constants_1 = require("../devices-shelly-ng.constants");
@@ -30,7 +33,7 @@ const device_manager_service_1 = require("../services/device-manager.service");
30
33
  const transform_utils_2 = require("../utils/transform.utils");
31
34
  const shelly_device_delegate_1 = require("./shelly-device.delegate");
32
35
  let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManagerService {
33
- constructor(devicesService, channelsService, channelsPropertiesService, deviceConnectivityService, deviceManagerService, deviceAddressService, propertyMappingStorage, transformerRegistry) {
36
+ constructor(devicesService, channelsService, channelsPropertiesService, deviceConnectivityService, deviceManagerService, deviceAddressService, propertyMappingStorage, transformerRegistry, commandLatencyTraceCollector = new command_latency_trace_collector_service_1.CommandLatencyTraceCollectorService()) {
34
37
  this.devicesService = devicesService;
35
38
  this.channelsService = channelsService;
36
39
  this.channelsPropertiesService = channelsPropertiesService;
@@ -39,6 +42,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
39
42
  this.deviceAddressService = deviceAddressService;
40
43
  this.propertyMappingStorage = propertyMappingStorage;
41
44
  this.transformerRegistry = transformerRegistry;
45
+ this.commandLatencyTraceCollector = commandLatencyTraceCollector;
42
46
  this.logger = (0, logger_1.createExtensionLogger)(devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_PLUGIN_NAME, 'DelegatesManagerService');
43
47
  this.delegates = new Map();
44
48
  this.delegateValueHandlers = new Map();
@@ -47,6 +51,10 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
47
51
  this.setChannelsHandlers = new Map();
48
52
  this.setPropertiesHandlers = new Map();
49
53
  this.pendingWrites = new Map();
54
+ this.pendingPollWrites = new Map();
55
+ this.activePollWrites = new Map();
56
+ this.delegatePollGenerations = new Map();
57
+ this.currentValueUpdateContext = null;
50
58
  this.propertiesMap = new Map();
51
59
  this.delegateDeviceIds = new Map();
52
60
  this.delegateToIdentifier = new Map();
@@ -75,6 +83,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
75
83
  }
76
84
  const generation = (this.insertGeneration.get(shelly.id) ?? 0) + 1;
77
85
  this.insertGeneration.set(shelly.id, generation);
86
+ this.delegatePollGenerations.set(shelly.id, (this.delegatePollGenerations.get(shelly.id) ?? 0) + 1);
78
87
  const delegate = new shelly_device_delegate_1.ShellyDeviceDelegate(shelly);
79
88
  this.delegates.set(shelly.id, delegate);
80
89
  const wifiIp = shelly.wifi?.sta_ip ?? null;
@@ -808,12 +817,13 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
808
817
  }
809
818
  if (this.insertGeneration.get(shelly.id) !== generation)
810
819
  return delegate;
811
- const valueHandler = (compKey, attr, val) => {
820
+ const valueHandler = (compKey, attr, val, origin = 'notify') => {
812
821
  const handler = this.changeHandlers.get(`${delegate.id}|${compKey}|${attr}`);
813
822
  if (!handler) {
814
823
  return;
815
824
  }
816
825
  try {
826
+ this.currentValueUpdateContext = { delegateId: delegate.id, deviceId: device.id, origin };
817
827
  handler(val);
818
828
  }
819
829
  catch (error) {
@@ -824,6 +834,9 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
824
834
  stack: err.stack,
825
835
  });
826
836
  }
837
+ finally {
838
+ this.currentValueUpdateContext = null;
839
+ }
827
840
  };
828
841
  delegate.on('value', valueHandler);
829
842
  this.delegateValueHandlers.set(delegate.id, valueHandler);
@@ -939,6 +952,8 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
939
952
  if (!delegate) {
940
953
  return;
941
954
  }
955
+ this.delegatePollGenerations.set(deviceId, (this.delegatePollGenerations.get(deviceId) ?? 0) + 1);
956
+ this.cancelPollWritesForDelegate(deviceId);
942
957
  const valueHandler = this.delegateValueHandlers.get(delegate.id);
943
958
  const connectionHandler = this.delegateConnectionHandlers.get(delegate.id);
944
959
  if (connectionHandler) {
@@ -1075,7 +1090,24 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1075
1090
  }
1076
1091
  }
1077
1092
  async handleChange(property, value, immediately = true) {
1093
+ const context = this.currentValueUpdateContext;
1094
+ if (context !== null) {
1095
+ this.commandLatencyTraceCollector.recordProviderReceipt(property.id, value, context.origin, {
1096
+ delegateId: context.delegateId,
1097
+ deviceId: context.deviceId,
1098
+ });
1099
+ }
1100
+ if (context?.origin === 'poll') {
1101
+ this.commandLatencyTraceCollector.recordPollActivity(property.id, 'poll-coalescer-admission', {
1102
+ delegateId: context.delegateId,
1103
+ deviceId: context.deviceId,
1104
+ });
1105
+ this.schedulePollWrite(context, property, value);
1106
+ return;
1107
+ }
1078
1108
  if (immediately) {
1109
+ this.cancelScheduledWrite(property.id);
1110
+ this.cancelPollWrite(property.id);
1079
1111
  await this.writeValueToProperty(property, value);
1080
1112
  }
1081
1113
  else {
@@ -1234,9 +1266,123 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1234
1266
  }, 250);
1235
1267
  this.pendingWrites.set(property.id, t);
1236
1268
  }
1269
+ schedulePollWrite(context, property, value) {
1270
+ let bucket = this.pendingPollWrites.get(context.deviceId);
1271
+ if (!bucket) {
1272
+ const values = new Map();
1273
+ const timer = setTimeout(() => {
1274
+ void this.flushPollWrites(context.deviceId);
1275
+ }, 250);
1276
+ bucket = { timer, values };
1277
+ this.pendingPollWrites.set(context.deviceId, bucket);
1278
+ }
1279
+ bucket.values.set(property.id, {
1280
+ delegateId: context.delegateId,
1281
+ delegateGeneration: this.delegatePollGenerations.get(context.delegateId) ?? 0,
1282
+ property,
1283
+ value,
1284
+ });
1285
+ }
1286
+ async flushPollWrites(deviceId) {
1287
+ const bucket = this.pendingPollWrites.get(deviceId);
1288
+ if (!bucket) {
1289
+ return;
1290
+ }
1291
+ this.pendingPollWrites.delete(deviceId);
1292
+ clearTimeout(bucket.timer);
1293
+ let activeBuckets = this.activePollWrites.get(deviceId);
1294
+ if (activeBuckets === undefined) {
1295
+ activeBuckets = new Set();
1296
+ this.activePollWrites.set(deviceId, activeBuckets);
1297
+ }
1298
+ activeBuckets.add(bucket);
1299
+ try {
1300
+ for (const [propertyId, pending] of [...bucket.values.entries()]) {
1301
+ if (bucket.values.get(propertyId) !== pending) {
1302
+ continue;
1303
+ }
1304
+ if (!this.delegates.has(pending.delegateId) ||
1305
+ (this.delegatePollGenerations.get(pending.delegateId) ?? 0) !== pending.delegateGeneration) {
1306
+ continue;
1307
+ }
1308
+ try {
1309
+ this.commandLatencyTraceCollector.recordPollActivity(pending.property.id, 'poll-drain', {
1310
+ delegateId: pending.delegateId,
1311
+ deviceId,
1312
+ });
1313
+ await this.writeValueToProperty(pending.property, pending.value);
1314
+ }
1315
+ catch (error) {
1316
+ const err = error;
1317
+ this.logger.error(`Failed to process poll write of value=${(0, transform_utils_1.safeToString)(pending.value)} to property=${pending.property.id}`, { message: err.message, stack: err.stack });
1318
+ }
1319
+ }
1320
+ }
1321
+ finally {
1322
+ activeBuckets.delete(bucket);
1323
+ if (activeBuckets.size === 0 && this.activePollWrites.get(deviceId) === activeBuckets) {
1324
+ this.activePollWrites.delete(deviceId);
1325
+ }
1326
+ }
1327
+ }
1328
+ cancelScheduledWrite(propertyId) {
1329
+ const timer = this.pendingWrites.get(propertyId);
1330
+ if (timer) {
1331
+ clearTimeout(timer);
1332
+ this.pendingWrites.delete(propertyId);
1333
+ }
1334
+ }
1335
+ cancelPollWrite(propertyId) {
1336
+ for (const [deviceId, bucket] of this.pendingPollWrites.entries()) {
1337
+ bucket.values.delete(propertyId);
1338
+ if (bucket.values.size === 0) {
1339
+ clearTimeout(bucket.timer);
1340
+ this.pendingPollWrites.delete(deviceId);
1341
+ }
1342
+ }
1343
+ for (const buckets of this.activePollWrites.values()) {
1344
+ for (const bucket of buckets) {
1345
+ bucket.values.delete(propertyId);
1346
+ }
1347
+ }
1348
+ }
1349
+ cancelPollWritesForDelegate(delegateId) {
1350
+ for (const [deviceId, bucket] of this.pendingPollWrites.entries()) {
1351
+ for (const [propertyId, pending] of bucket.values.entries()) {
1352
+ if (pending.delegateId === delegateId) {
1353
+ bucket.values.delete(propertyId);
1354
+ }
1355
+ }
1356
+ if (bucket.values.size === 0) {
1357
+ clearTimeout(bucket.timer);
1358
+ this.pendingPollWrites.delete(deviceId);
1359
+ }
1360
+ }
1361
+ for (const buckets of this.activePollWrites.values()) {
1362
+ for (const bucket of buckets) {
1363
+ for (const [propertyId, pending] of bucket.values.entries()) {
1364
+ if (pending.delegateId === delegateId) {
1365
+ bucket.values.delete(propertyId);
1366
+ }
1367
+ }
1368
+ }
1369
+ }
1370
+ }
1371
+ clearPollWrites() {
1372
+ for (const bucket of this.pendingPollWrites.values()) {
1373
+ clearTimeout(bucket.timer);
1374
+ }
1375
+ this.pendingPollWrites.clear();
1376
+ for (const buckets of this.activePollWrites.values()) {
1377
+ for (const bucket of buckets) {
1378
+ bucket.values.clear();
1379
+ }
1380
+ }
1381
+ this.activePollWrites.clear();
1382
+ }
1237
1383
  async writeValueToProperty(property, value) {
1238
1384
  return await this.channelsPropertiesService.update(property.id, (0, transform_utils_1.toInstance)(update_channel_property_dto_1.UpdateShellyNgChannelPropertyDto, {
1239
- ...(0, class_transformer_1.instanceToPlain)(property),
1385
+ type: devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE,
1240
1386
  value,
1241
1387
  }));
1242
1388
  }
@@ -1293,6 +1439,9 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1293
1439
  clearTimeout(pendingWrite);
1294
1440
  }
1295
1441
  this.pendingWrites.clear();
1442
+ this.clearPollWrites();
1443
+ this.delegatePollGenerations.clear();
1444
+ this.currentValueUpdateContext = null;
1296
1445
  this.deviceLocks.clear();
1297
1446
  this.canonicalMacLocks.clear();
1298
1447
  this.connectedDelegatesPerDevice.clear();
@@ -1336,20 +1485,46 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1336
1485
  await Promise.all(tasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
1337
1486
  }
1338
1487
  }
1339
- async pollAllDevices(timeoutMs = 10_000) {
1340
- const CONCURRENCY = 10;
1341
- const tasks = [];
1342
- for (const [id, delegate] of this.delegates.entries()) {
1343
- if (!delegate.connected) {
1344
- continue;
1345
- }
1346
- tasks.push(async () => {
1347
- const ok = await delegate.pollStatus(timeoutMs);
1348
- if (!ok) {
1349
- this.logger.warn(`Status poll failed for device=${id}`);
1350
- }
1488
+ getConnectedDelegateIds() {
1489
+ return Array.from(this.delegates.entries())
1490
+ .filter(([, delegate]) => delegate.connected)
1491
+ .map(([id]) => id)
1492
+ .sort();
1493
+ }
1494
+ invalidateStatusPolls() {
1495
+ for (const delegateId of this.delegates.keys()) {
1496
+ this.delegatePollGenerations.set(delegateId, (this.delegatePollGenerations.get(delegateId) ?? 0) + 1);
1497
+ }
1498
+ this.clearPollWrites();
1499
+ }
1500
+ async pollDevice(deviceId, timeoutMs = 10_000) {
1501
+ const delegate = this.delegates.get(deviceId);
1502
+ if (!delegate || !delegate.connected) {
1503
+ return;
1504
+ }
1505
+ const generation = this.delegatePollGenerations.get(deviceId) ?? 0;
1506
+ this.commandLatencyTraceCollector.recordPollRpc(deviceId, 'poll-rpc-start', { timeoutMs });
1507
+ let ok;
1508
+ try {
1509
+ ok = await delegate.pollStatus(timeoutMs, () => this.delegates.get(deviceId) === delegate &&
1510
+ delegate.connected &&
1511
+ this.delegatePollGenerations.get(deviceId) === generation);
1512
+ }
1513
+ catch (error) {
1514
+ this.commandLatencyTraceCollector.recordPollRpc(deviceId, 'poll-rpc-complete', {
1515
+ ok: false,
1516
+ error: error instanceof Error ? error.message : 'unknown failure',
1351
1517
  });
1518
+ throw error;
1352
1519
  }
1520
+ this.commandLatencyTraceCollector.recordPollRpc(deviceId, 'poll-rpc-complete', { ok });
1521
+ if (!ok && this.delegates.get(deviceId) === delegate && this.delegatePollGenerations.get(deviceId) === generation) {
1522
+ this.logger.warn(`Status poll failed for device=${deviceId}`);
1523
+ }
1524
+ }
1525
+ async pollAllDevices(timeoutMs = 10_000) {
1526
+ const CONCURRENCY = 10;
1527
+ const tasks = this.getConnectedDelegateIds().map((id) => () => this.pollDevice(id, timeoutMs));
1353
1528
  for (let i = 0; i < tasks.length; i += CONCURRENCY) {
1354
1529
  await Promise.all(tasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
1355
1530
  }
@@ -1398,6 +1573,7 @@ exports.DelegatesManagerService = DelegatesManagerService;
1398
1573
  DelegatesManagerService.DISCONNECT_GRACE_MS = 15_000;
1399
1574
  exports.DelegatesManagerService = DelegatesManagerService = DelegatesManagerService_1 = __decorate([
1400
1575
  (0, common_1.Injectable)(),
1576
+ __param(8, (0, common_1.Optional)()),
1401
1577
  __metadata("design:paramtypes", [devices_service_1.DevicesService,
1402
1578
  channels_service_1.ChannelsService,
1403
1579
  channels_properties_service_1.ChannelsPropertiesService,
@@ -1405,6 +1581,7 @@ exports.DelegatesManagerService = DelegatesManagerService = DelegatesManagerServ
1405
1581
  device_manager_service_1.DeviceManagerService,
1406
1582
  device_address_service_1.DeviceAddressService,
1407
1583
  mappings_1.PropertyMappingStorageService,
1408
- mappings_1.TransformerRegistry])
1584
+ mappings_1.TransformerRegistry,
1585
+ command_latency_trace_collector_service_1.CommandLatencyTraceCollectorService])
1409
1586
  ], DelegatesManagerService);
1410
1587
  //# sourceMappingURL=delegates-manager.service.js.map