@fastybird/smart-panel-backend 1.1.0-alpha.1 → 1.1.0-alpha.10

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 (209) hide show
  1. package/dist/app.module.js +7 -0
  2. package/dist/app.module.js.map +1 -1
  3. package/dist/common/filters/conflict-exception.filter.d.ts +6 -0
  4. package/dist/common/filters/conflict-exception.filter.js +59 -0
  5. package/dist/common/filters/conflict-exception.filter.js.map +1 -0
  6. package/dist/common/filters/global-error.filter.js +1 -4
  7. package/dist/common/filters/global-error.filter.js.map +1 -1
  8. package/dist/common/filters/global-filters.d.ts +3 -0
  9. package/dist/common/filters/global-filters.js +22 -0
  10. package/dist/common/filters/global-filters.js.map +1 -0
  11. package/dist/common/filters/unprocessable-entity-exception.filter.d.ts +1 -0
  12. package/dist/common/filters/unprocessable-entity-exception.filter.js +15 -3
  13. package/dist/common/filters/unprocessable-entity-exception.filter.js.map +1 -1
  14. package/dist/common/utils/transform.utils.js +3 -0
  15. package/dist/common/utils/transform.utils.js.map +1 -1
  16. package/dist/main.js +2 -7
  17. package/dist/main.js.map +1 -1
  18. package/dist/modules/devices/controllers/channels.properties.controller.js +16 -4
  19. package/dist/modules/devices/controllers/channels.properties.controller.js.map +1 -1
  20. package/dist/modules/devices/controllers/devices.channels.properties.controller.js +16 -4
  21. package/dist/modules/devices/controllers/devices.channels.properties.controller.js.map +1 -1
  22. package/dist/modules/devices/devices.module.js +12 -0
  23. package/dist/modules/devices/devices.module.js.map +1 -1
  24. package/dist/modules/devices/services/channels.properties.service.d.ts +27 -3
  25. package/dist/modules/devices/services/channels.properties.service.js +304 -28
  26. package/dist/modules/devices/services/channels.properties.service.js.map +1 -1
  27. package/dist/modules/devices/services/channels.service.js +42 -38
  28. package/dist/modules/devices/services/channels.service.js.map +1 -1
  29. package/dist/modules/devices/services/command-latency-trace-collector.service.d.ts +101 -0
  30. package/dist/modules/devices/services/command-latency-trace-collector.service.js +451 -0
  31. package/dist/modules/devices/services/command-latency-trace-collector.service.js.map +1 -0
  32. package/dist/modules/devices/services/device-structure-lock.service.d.ts +10 -2
  33. package/dist/modules/devices/services/device-structure-lock.service.js +86 -7
  34. package/dist/modules/devices/services/device-structure-lock.service.js.map +1 -1
  35. package/dist/modules/devices/services/devices.service.js +37 -33
  36. package/dist/modules/devices/services/devices.service.js.map +1 -1
  37. package/dist/modules/devices/services/module-reset.service.d.ts +3 -1
  38. package/dist/modules/devices/services/module-reset.service.js +21 -16
  39. package/dist/modules/devices/services/module-reset.service.js.map +1 -1
  40. package/dist/modules/devices/services/property-command-dispatch.service.d.ts +45 -0
  41. package/dist/modules/devices/services/property-command-dispatch.service.js +227 -0
  42. package/dist/modules/devices/services/property-command-dispatch.service.js.map +1 -0
  43. package/dist/modules/devices/services/property-command-window.service.d.ts +71 -0
  44. package/dist/modules/devices/services/property-command-window.service.js +204 -0
  45. package/dist/modules/devices/services/property-command-window.service.js.map +1 -0
  46. package/dist/modules/devices/services/property-command.service.d.ts +20 -3
  47. package/dist/modules/devices/services/property-command.service.js +56 -10
  48. package/dist/modules/devices/services/property-command.service.js.map +1 -1
  49. package/dist/modules/devices/services/property-state-coordinator.service.d.ts +4 -0
  50. package/dist/modules/devices/services/property-state-coordinator.service.js +35 -0
  51. package/dist/modules/devices/services/property-state-coordinator.service.js.map +1 -0
  52. package/dist/modules/devices/services/property-value.service.d.ts +1 -0
  53. package/dist/modules/devices/services/property-value.service.js +4 -0
  54. package/dist/modules/devices/services/property-value.service.js.map +1 -1
  55. package/dist/modules/platform/services/platform.service.d.ts +13 -4
  56. package/dist/modules/platform/services/platform.service.js +57 -35
  57. package/dist/modules/platform/services/platform.service.js.map +1 -1
  58. package/dist/modules/remote-access/dto/update-config.dto.js +5 -0
  59. package/dist/modules/remote-access/dto/update-config.dto.js.map +1 -1
  60. package/dist/modules/remote-access/validators/is-remote-access-url.validator.js +5 -2
  61. package/dist/modules/remote-access/validators/is-remote-access-url.validator.js.map +1 -1
  62. package/dist/modules/system/services/privileged-worker.service.d.ts +10 -0
  63. package/dist/modules/system/services/privileged-worker.service.js +137 -11
  64. package/dist/modules/system/services/privileged-worker.service.js.map +1 -1
  65. package/dist/modules/websocket/gateway/websocket.gateway.d.ts +4 -1
  66. package/dist/modules/websocket/gateway/websocket.gateway.js +28 -5
  67. package/dist/modules/websocket/gateway/websocket.gateway.js.map +1 -1
  68. package/dist/modules/websocket/services/command-acknowledgement-trace.service.d.ts +143 -0
  69. package/dist/modules/websocket/services/command-acknowledgement-trace.service.js +523 -0
  70. package/dist/modules/websocket/services/command-acknowledgement-trace.service.js.map +1 -0
  71. package/dist/modules/websocket/websocket.module.js +9 -1
  72. package/dist/modules/websocket/websocket.module.js.map +1 -1
  73. package/dist/plugins/devices-home-assistant/services/home-assistant.ws.service.js +2 -1
  74. package/dist/plugins/devices-home-assistant/services/home-assistant.ws.service.js.map +1 -1
  75. package/dist/plugins/devices-home-assistant/services/state-changed.event.service.js +2 -3
  76. package/dist/plugins/devices-home-assistant/services/state-changed.event.service.js.map +1 -1
  77. package/dist/plugins/devices-homekit/listeners/homekit-event.listener.js +6 -1
  78. package/dist/plugins/devices-homekit/listeners/homekit-event.listener.js.map +1 -1
  79. package/dist/plugins/devices-homekit/mappers/base.mapper.js +27 -4
  80. package/dist/plugins/devices-homekit/mappers/base.mapper.js.map +1 -1
  81. package/dist/plugins/devices-homekit/mappers/homekit-mapper.interface.d.ts +8 -0
  82. package/dist/plugins/devices-homekit/mappers/thermostat-coordinator.d.ts +7 -0
  83. package/dist/plugins/devices-homekit/mappers/thermostat-coordinator.js +84 -73
  84. package/dist/plugins/devices-homekit/mappers/thermostat-coordinator.js.map +1 -1
  85. package/dist/plugins/devices-shelly-ng/delegates/delegates-manager.service.d.ts +18 -1
  86. package/dist/plugins/devices-shelly-ng/delegates/delegates-manager.service.js +338 -119
  87. package/dist/plugins/devices-shelly-ng/delegates/delegates-manager.service.js.map +1 -1
  88. package/dist/plugins/devices-shelly-ng/delegates/shelly-device.delegate.d.ts +13 -1
  89. package/dist/plugins/devices-shelly-ng/delegates/shelly-device.delegate.js +109 -10
  90. package/dist/plugins/devices-shelly-ng/delegates/shelly-device.delegate.js.map +1 -1
  91. package/dist/plugins/devices-shelly-ng/devices-shelly-ng.constants.js +8 -11
  92. package/dist/plugins/devices-shelly-ng/devices-shelly-ng.constants.js.map +1 -1
  93. package/dist/plugins/devices-shelly-ng/mappings/mapping-loader.service.js +4 -0
  94. package/dist/plugins/devices-shelly-ng/mappings/mapping-loader.service.js.map +1 -1
  95. package/dist/plugins/devices-shelly-ng/services/device-manager.service.js +5 -0
  96. package/dist/plugins/devices-shelly-ng/services/device-manager.service.js.map +1 -1
  97. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.d.ts +9 -1
  98. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.js +59 -24
  99. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.js.map +1 -1
  100. package/dist/plugins/devices-shelly-ng/services/shelly-ws-server.service.d.ts +0 -1
  101. package/dist/plugins/devices-shelly-ng/services/shelly-ws-server.service.js +5 -12
  102. package/dist/plugins/devices-shelly-ng/services/shelly-ws-server.service.js.map +1 -1
  103. package/dist/plugins/devices-shelly-ng/utils/transform.utils.d.ts +2 -0
  104. package/dist/plugins/devices-shelly-ng/utils/transform.utils.js +14 -1
  105. package/dist/plugins/devices-shelly-ng/utils/transform.utils.js.map +1 -1
  106. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.d.ts +17 -0
  107. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.js +147 -0
  108. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.js.map +1 -0
  109. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.d.ts +15 -0
  110. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.js +98 -0
  111. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.js.map +1 -0
  112. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.d.ts +9 -0
  113. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.js +94 -0
  114. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.js.map +1 -0
  115. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.d.ts +9 -0
  116. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.js +92 -0
  117. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.js.map +1 -0
  118. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.d.ts +7 -0
  119. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.js +48 -0
  120. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.js.map +1 -0
  121. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.d.ts +42 -0
  122. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.js +352 -0
  123. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.js.map +1 -0
  124. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.d.ts +24 -0
  125. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.js +27 -0
  126. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.js.map +1 -0
  127. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.d.ts +8 -0
  128. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.js +19 -0
  129. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.js.map +1 -0
  130. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.d.ts +4 -0
  131. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.js +20 -0
  132. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.js.map +1 -0
  133. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.d.ts +21 -0
  134. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.js +135 -0
  135. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.js.map +1 -0
  136. package/dist/plugins/remote-access-cloudflare-tunnel/scripts/cloudflared-setup.sh +185 -0
  137. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.d.ts +82 -0
  138. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.js +507 -0
  139. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.js.map +1 -0
  140. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.d.ts +10 -0
  141. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.js +37 -0
  142. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.js.map +1 -0
  143. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.d.ts +38 -0
  144. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.js +147 -0
  145. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.js.map +1 -0
  146. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.d.ts +15 -0
  147. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.js +67 -0
  148. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.js.map +1 -0
  149. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.d.ts +8 -0
  150. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.js +46 -0
  151. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.js.map +1 -0
  152. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.d.ts +27 -0
  153. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.js +139 -0
  154. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.js.map +1 -0
  155. package/dist/plugins/remote-access-tailscale/controllers/setup.controller.d.ts +1 -0
  156. package/dist/plugins/remote-access-tailscale/controllers/setup.controller.js +26 -10
  157. package/dist/plugins/remote-access-tailscale/controllers/setup.controller.js.map +1 -1
  158. package/dist/plugins/remote-access-tailscale/controllers/status.controller.d.ts +6 -1
  159. package/dist/plugins/remote-access-tailscale/controllers/status.controller.js +28 -3
  160. package/dist/plugins/remote-access-tailscale/controllers/status.controller.js.map +1 -1
  161. package/dist/plugins/remote-access-tailscale/models/status.model.d.ts +19 -0
  162. package/dist/plugins/remote-access-tailscale/models/status.model.js +158 -1
  163. package/dist/plugins/remote-access-tailscale/models/status.model.js.map +1 -1
  164. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.constants.d.ts +2 -0
  165. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.constants.js +3 -1
  166. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.constants.js.map +1 -1
  167. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.exceptions.d.ts +13 -0
  168. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.exceptions.js +27 -0
  169. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.exceptions.js.map +1 -0
  170. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.openapi.d.ts +2 -2
  171. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.openapi.js +2 -0
  172. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.openapi.js.map +1 -1
  173. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.plugin.js +1 -1
  174. package/dist/plugins/remote-access-tailscale/scripts/tailscale-setup.sh +61 -0
  175. package/dist/plugins/remote-access-tailscale/services/tailscale-cli.service.d.ts +9 -0
  176. package/dist/plugins/remote-access-tailscale/services/tailscale-cli.service.js +12 -0
  177. package/dist/plugins/remote-access-tailscale/services/tailscale-cli.service.js.map +1 -1
  178. package/dist/plugins/remote-access-tailscale/services/tailscale-login.service.d.ts +1 -0
  179. package/dist/plugins/remote-access-tailscale/services/tailscale-login.service.js +27 -2
  180. package/dist/plugins/remote-access-tailscale/services/tailscale-login.service.js.map +1 -1
  181. package/dist/plugins/remote-access-tailscale/services/tailscale-node-managed.service.d.ts +30 -1
  182. package/dist/plugins/remote-access-tailscale/services/tailscale-node-managed.service.js +300 -30
  183. package/dist/plugins/remote-access-tailscale/services/tailscale-node-managed.service.js.map +1 -1
  184. package/dist/plugins/remote-access-tailscale/services/tailscale-serve.service.d.ts +8 -3
  185. package/dist/plugins/remote-access-tailscale/services/tailscale-serve.service.js +39 -12
  186. package/dist/plugins/remote-access-tailscale/services/tailscale-serve.service.js.map +1 -1
  187. package/dist/plugins/remote-access-tailscale/services/tailscale-setup.service.d.ts +14 -5
  188. package/dist/plugins/remote-access-tailscale/services/tailscale-setup.service.js +51 -16
  189. package/dist/plugins/remote-access-tailscale/services/tailscale-setup.service.js.map +1 -1
  190. package/dist/plugins/scenes-local/platforms/local-scene.platform.d.ts +3 -1
  191. package/dist/plugins/scenes-local/platforms/local-scene.platform.js +12 -7
  192. package/dist/plugins/scenes-local/platforms/local-scene.platform.js.map +1 -1
  193. package/dist/plugins/spaces-home-control/services/climate-intent.service.d.ts +3 -1
  194. package/dist/plugins/spaces-home-control/services/climate-intent.service.js +6 -3
  195. package/dist/plugins/spaces-home-control/services/climate-intent.service.js.map +1 -1
  196. package/dist/plugins/spaces-home-control/services/covers-intent.service.d.ts +3 -1
  197. package/dist/plugins/spaces-home-control/services/covers-intent.service.js +6 -3
  198. package/dist/plugins/spaces-home-control/services/covers-intent.service.js.map +1 -1
  199. package/dist/plugins/spaces-home-control/services/lighting-intent.service.d.ts +3 -1
  200. package/dist/plugins/spaces-home-control/services/lighting-intent.service.js +7 -4
  201. package/dist/plugins/spaces-home-control/services/lighting-intent.service.js.map +1 -1
  202. package/dist/plugins/spaces-home-control/services/space-media-activity.service.d.ts +3 -1
  203. package/dist/plugins/spaces-home-control/services/space-media-activity.service.js +11 -5
  204. package/dist/plugins/spaces-home-control/services/space-media-activity.service.js.map +1 -1
  205. package/dist/plugins/spaces-home-control/services/space-undo-history.service.d.ts +3 -1
  206. package/dist/plugins/spaces-home-control/services/space-undo-history.service.js +8 -5
  207. package/dist/plugins/spaces-home-control/services/space-undo-history.service.js.map +1 -1
  208. package/dist/tsconfig.build.tsbuildinfo +1 -1
  209. 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;
@@ -199,60 +208,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
199
208
  await comp.set(val);
200
209
  return true;
201
210
  });
202
- if (typeof comp.aenergy !== 'undefined') {
203
- const electricalEnergy = await this.channelsService.findOneBy('identifier', `energy:${comp.id}`, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
204
- if (electricalEnergy === null) {
205
- }
206
- else {
207
- const consumption = await this.channelsPropertiesService.findOneBy('identifier', 'aenergy', electricalEnergy.id);
208
- if (consumption === null) {
209
- }
210
- else {
211
- await this.setDefaultPropertyValue(device.id, consumption, (0, transform_utils_2.toEnergy)(comp.aenergy));
212
- this.changeHandlers.set(`${delegate.id}|${comp.key}|aenergy`, (val) => {
213
- this.handleNumericChange(comp.key, 'aenergy', consumption.id, val, (n) => this.handleChange(consumption, (0, transform_utils_2.toEnergy)(n), false));
214
- });
215
- }
216
- }
217
- }
218
- if (typeof comp.apower !== 'undefined') {
219
- const electricalPower = await this.channelsService.findOneBy('identifier', `power:${comp.id}`, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
220
- if (electricalPower === null) {
221
- }
222
- else {
223
- const power = await this.channelsPropertiesService.findOneBy('identifier', 'apower', electricalPower.id);
224
- if (power === null) {
225
- }
226
- else {
227
- await this.setDefaultPropertyValue(device.id, power, Math.max(0, comp.apower));
228
- this.changeHandlers.set(`${delegate.id}|${comp.key}|apower`, (val) => {
229
- this.handleNumericChange(comp.key, 'apower', power.id, val, (n) => this.handleChange(power, Math.max(0, n), false));
230
- });
231
- if (typeof comp.voltage !== 'undefined') {
232
- const voltage = await this.channelsPropertiesService.findOneBy('identifier', 'voltage', electricalPower.id);
233
- if (voltage === null) {
234
- }
235
- else {
236
- await this.setDefaultPropertyValue(device.id, voltage, comp.voltage);
237
- this.changeHandlers.set(`${delegate.id}|${comp.key}|voltage`, (val) => {
238
- this.handleNumericChange(comp.key, 'voltage', voltage.id, val, (n) => this.handleChange(voltage, n, false));
239
- });
240
- }
241
- }
242
- if (typeof comp.current !== 'undefined') {
243
- const current = await this.channelsPropertiesService.findOneBy('identifier', 'current', electricalPower.id);
244
- if (current === null) {
245
- }
246
- else {
247
- await this.setDefaultPropertyValue(device.id, current, comp.current);
248
- this.changeHandlers.set(`${delegate.id}|${comp.key}|current`, (val) => {
249
- this.handleNumericChange(comp.key, 'current', current.id, val, (n) => this.handleChange(current, n, false));
250
- });
251
- }
252
- }
253
- }
254
- }
255
- }
211
+ await this.wireElectricalChannels(delegate, device, comp);
256
212
  }
257
213
  if (this.insertGeneration.get(shelly.id) !== generation)
258
214
  return delegate;
@@ -314,6 +270,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
314
270
  await comp.stop();
315
271
  return true;
316
272
  });
273
+ await this.wireElectricalChannels(delegate, device, comp);
317
274
  }
318
275
  if (this.insertGeneration.get(shelly.id) !== generation)
319
276
  return delegate;
@@ -362,6 +319,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
362
319
  return true;
363
320
  });
364
321
  }
322
+ await this.wireElectricalChannels(delegate, device, comp);
365
323
  }
366
324
  if (this.insertGeneration.get(shelly.id) !== generation)
367
325
  return delegate;
@@ -495,6 +453,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
495
453
  ]);
496
454
  return true;
497
455
  });
456
+ await this.wireElectricalChannels(delegate, device, comp);
498
457
  }
499
458
  if (this.insertGeneration.get(shelly.id) !== generation)
500
459
  return delegate;
@@ -653,6 +612,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
653
612
  ], Math.round((0, transform_utils_1.clampNumber)(whiteValue, 0, 255)));
654
613
  return true;
655
614
  });
615
+ await this.wireElectricalChannels(delegate, device, comp);
656
616
  }
657
617
  if (this.insertGeneration.get(shelly.id) !== generation)
658
618
  return delegate;
@@ -746,6 +706,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
746
706
  await comp.set(outputValue, Math.round((0, transform_utils_1.clampNumber)(brightnessValue, 0, 100)), Math.round((0, transform_utils_1.clampNumber)(ctValue, 2_700, 6_500)));
747
707
  return true;
748
708
  });
709
+ await this.wireElectricalChannels(delegate, device, comp);
749
710
  }
750
711
  if (this.insertGeneration.get(shelly.id) !== generation)
751
712
  return delegate;
@@ -800,63 +761,69 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
800
761
  if (this.insertGeneration.get(shelly.id) !== generation)
801
762
  return delegate;
802
763
  for (const comp of delegate.pm1.values()) {
803
- const electricalPower = await this.channelsService.findOneBy('identifier', `power:${comp.id}`, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
804
- if (electricalPower === null) {
805
- continue;
806
- }
807
- const power = await this.channelsPropertiesService.findOneBy('identifier', 'apower', electricalPower.id);
808
- if (power === null) {
809
- throw new devices_shelly_ng_exceptions_1.DevicesShellyNgNotFoundException('Failed to load electrical power channel property');
810
- }
811
- await this.setDefaultPropertyValue(device.id, power, Math.max(0, comp.apower));
812
- this.changeHandlers.set(`${delegate.id}|${comp.key}|apower`, (val) => {
813
- this.handleNumericChange(comp.key, 'apower', power.id, val, (n) => this.handleChange(power, Math.max(0, n), false));
814
- });
815
- if (typeof comp.voltage !== 'undefined') {
816
- const voltage = await this.channelsPropertiesService.findOneBy('identifier', 'voltage', electricalPower.id);
817
- if (voltage === null) {
818
- throw new devices_shelly_ng_exceptions_1.DevicesShellyNgNotFoundException('Failed to load electrical power voltage channel property');
819
- }
820
- await this.setDefaultPropertyValue(device.id, voltage, comp.voltage);
821
- this.changeHandlers.set(`${delegate.id}|${comp.key}|voltage`, (val) => {
822
- this.handleNumericChange(comp.key, 'voltage', voltage.id, val, (n) => this.handleChange(voltage, n, false));
823
- });
824
- }
825
- if (typeof comp.current !== 'undefined') {
826
- const current = await this.channelsPropertiesService.findOneBy('identifier', 'current', electricalPower.id);
827
- if (current === null) {
828
- throw new devices_shelly_ng_exceptions_1.DevicesShellyNgNotFoundException('Failed to load electrical power current channel property');
829
- }
830
- await this.setDefaultPropertyValue(device.id, current, comp.current);
831
- this.changeHandlers.set(`${delegate.id}|${comp.key}|current`, (val) => {
832
- this.handleNumericChange(comp.key, 'current', current.id, val, (n) => this.handleChange(current, n, false));
833
- });
834
- }
835
- if (typeof comp.aenergy !== 'undefined') {
836
- const electricalEnergy = await this.channelsService.findOneBy('identifier', `energy:${comp.id}`, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
837
- if (electricalEnergy === null) {
838
- }
839
- else {
840
- const consumption = await this.channelsPropertiesService.findOneBy('identifier', 'aenergy', electricalEnergy.id);
841
- if (consumption === null) {
842
- }
843
- else {
844
- await this.setDefaultPropertyValue(device.id, consumption, (0, transform_utils_2.toEnergy)(comp.aenergy));
845
- this.changeHandlers.set(`${delegate.id}|${comp.key}|aenergy`, (val) => {
846
- this.handleNumericChange(comp.key, 'aenergy', consumption.id, val, (n) => this.handleChange(consumption, (0, transform_utils_2.toEnergy)(n), false));
847
- });
848
- }
849
- }
850
- }
764
+ await this.wireElectricalChannels(delegate, device, comp);
765
+ }
766
+ if (this.insertGeneration.get(shelly.id) !== generation)
767
+ return delegate;
768
+ for (const comp of delegate.em.values()) {
769
+ const phases = [
770
+ { id: 'a', power: comp.a_act_power, voltage: comp.a_voltage, current: comp.a_current, freq: comp.a_freq },
771
+ { id: 'b', power: comp.b_act_power, voltage: comp.b_voltage, current: comp.b_current, freq: comp.b_freq },
772
+ { id: 'c', power: comp.c_act_power, voltage: comp.c_voltage, current: comp.c_current, freq: comp.c_freq },
773
+ ];
774
+ for (const phase of phases) {
775
+ const channelIdentifier = `power:${comp.id}:${phase.id}`;
776
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_act_power`, `${phase.id}_act_power`, phase.power, true);
777
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_voltage`, `${phase.id}_voltage`, phase.voltage, true);
778
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_current`, `${phase.id}_current`, phase.current, true);
779
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_freq`, `${phase.id}_freq`, phase.freq, true);
780
+ }
781
+ const totalChannelIdentifier = `power:${comp.id}:total`;
782
+ await this.wireMeterProperty(delegate, device, comp.key, totalChannelIdentifier, 'total_act_power', 'total_act_power', comp.total_act_power, true);
783
+ await this.wireMeterProperty(delegate, device, comp.key, totalChannelIdentifier, 'total_current', 'total_current', comp.total_current, true);
784
+ }
785
+ if (this.insertGeneration.get(shelly.id) !== generation)
786
+ return delegate;
787
+ for (const comp of delegate.emData.values()) {
788
+ const phases = [
789
+ { id: 'a', energy: comp.a_total_act_energy, returned: comp.a_total_act_ret_energy },
790
+ { id: 'b', energy: comp.b_total_act_energy, returned: comp.b_total_act_ret_energy },
791
+ { id: 'c', energy: comp.c_total_act_energy, returned: comp.c_total_act_ret_energy },
792
+ ];
793
+ for (const phase of phases) {
794
+ const channelIdentifier = `energy:${comp.id}:${phase.id}`;
795
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_total_act_energy`, `${phase.id}_total_act_energy`, phase.energy, false);
796
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_total_act_ret_energy`, `${phase.id}_total_act_ret_energy`, phase.returned, false);
797
+ }
798
+ const totalChannelIdentifier = `energy:${comp.id}:total`;
799
+ await this.wireMeterProperty(delegate, device, comp.key, totalChannelIdentifier, 'total_act', 'total_act', comp.total_act, false);
800
+ await this.wireMeterProperty(delegate, device, comp.key, totalChannelIdentifier, 'total_act_ret', 'total_act_ret', comp.total_act_ret, false);
851
801
  }
852
802
  if (this.insertGeneration.get(shelly.id) !== generation)
853
803
  return delegate;
854
- const valueHandler = (compKey, attr, val) => {
804
+ for (const comp of delegate.em1.values()) {
805
+ const channelIdentifier = `power:${comp.id}`;
806
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'act_power', 'act_power', comp.act_power, true);
807
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'voltage', 'voltage', comp.voltage, true);
808
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'current', 'current', comp.current, true);
809
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'freq', 'freq', comp.freq, true);
810
+ }
811
+ if (this.insertGeneration.get(shelly.id) !== generation)
812
+ return delegate;
813
+ for (const comp of delegate.em1Data.values()) {
814
+ const channelIdentifier = `energy:${comp.id}`;
815
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'total_act_energy', 'total_act_energy', comp.total_act_energy, false);
816
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'total_act_ret_energy', 'total_act_ret_energy', comp.total_act_ret_energy, false);
817
+ }
818
+ if (this.insertGeneration.get(shelly.id) !== generation)
819
+ return delegate;
820
+ const valueHandler = (compKey, attr, val, origin = 'notify') => {
855
821
  const handler = this.changeHandlers.get(`${delegate.id}|${compKey}|${attr}`);
856
822
  if (!handler) {
857
823
  return;
858
824
  }
859
825
  try {
826
+ this.currentValueUpdateContext = { delegateId: delegate.id, deviceId: device.id, origin };
860
827
  handler(val);
861
828
  }
862
829
  catch (error) {
@@ -867,6 +834,9 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
867
834
  stack: err.stack,
868
835
  });
869
836
  }
837
+ finally {
838
+ this.currentValueUpdateContext = null;
839
+ }
870
840
  };
871
841
  delegate.on('value', valueHandler);
872
842
  this.delegateValueHandlers.set(delegate.id, valueHandler);
@@ -982,6 +952,8 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
982
952
  if (!delegate) {
983
953
  return;
984
954
  }
955
+ this.delegatePollGenerations.set(deviceId, (this.delegatePollGenerations.get(deviceId) ?? 0) + 1);
956
+ this.cancelPollWritesForDelegate(deviceId);
985
957
  const valueHandler = this.delegateValueHandlers.get(delegate.id);
986
958
  const connectionHandler = this.delegateConnectionHandlers.get(delegate.id);
987
959
  if (connectionHandler) {
@@ -1118,7 +1090,24 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1118
1090
  }
1119
1091
  }
1120
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
+ }
1121
1108
  if (immediately) {
1109
+ this.cancelScheduledWrite(property.id);
1110
+ this.cancelPollWrite(property.id);
1122
1111
  await this.writeValueToProperty(property, value);
1123
1112
  }
1124
1113
  else {
@@ -1142,6 +1131,87 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1142
1131
  }
1143
1132
  set.add(property.id);
1144
1133
  }
1134
+ async wireElectricalChannels(delegate, device, comp) {
1135
+ if (typeof comp.aenergy !== 'undefined') {
1136
+ const electricalEnergy = await this.channelsService.findOneBy('identifier', `energy:${comp.id}`, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
1137
+ if (electricalEnergy === null) {
1138
+ }
1139
+ else {
1140
+ const consumption = await this.channelsPropertiesService.findOneBy('identifier', 'aenergy', electricalEnergy.id);
1141
+ if (consumption === null) {
1142
+ }
1143
+ else {
1144
+ await this.setDefaultPropertyValue(device.id, consumption, (0, transform_utils_2.toEnergy)(comp.aenergy));
1145
+ this.changeHandlers.set(`${delegate.id}|${comp.key}|aenergy.total`, (val) => {
1146
+ this.handleNumericChange(comp.key, 'aenergy.total', consumption.id, val, (n) => this.handleChange(consumption, (0, transform_utils_2.toEnergy)(n), false));
1147
+ });
1148
+ }
1149
+ }
1150
+ }
1151
+ if (typeof comp.apower !== 'undefined' ||
1152
+ typeof comp.voltage !== 'undefined' ||
1153
+ typeof comp.current !== 'undefined') {
1154
+ const electricalPower = await this.channelsService.findOneBy('identifier', `power:${comp.id}`, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
1155
+ if (electricalPower === null) {
1156
+ }
1157
+ else {
1158
+ if (typeof comp.apower !== 'undefined') {
1159
+ const power = await this.channelsPropertiesService.findOneBy('identifier', 'apower', electricalPower.id);
1160
+ if (power === null) {
1161
+ }
1162
+ else {
1163
+ await this.setDefaultPropertyValue(device.id, power, Math.max(0, comp.apower));
1164
+ this.changeHandlers.set(`${delegate.id}|${comp.key}|apower`, (val) => {
1165
+ this.handleNumericChange(comp.key, 'apower', power.id, val, (n) => this.handleChange(power, Math.max(0, n), false));
1166
+ });
1167
+ }
1168
+ }
1169
+ if (typeof comp.voltage !== 'undefined') {
1170
+ const voltage = await this.channelsPropertiesService.findOneBy('identifier', 'voltage', electricalPower.id);
1171
+ if (voltage === null) {
1172
+ }
1173
+ else {
1174
+ await this.setDefaultPropertyValue(device.id, voltage, comp.voltage);
1175
+ this.changeHandlers.set(`${delegate.id}|${comp.key}|voltage`, (val) => {
1176
+ this.handleNumericChange(comp.key, 'voltage', voltage.id, val, (n) => this.handleChange(voltage, n, false));
1177
+ });
1178
+ }
1179
+ }
1180
+ if (typeof comp.current !== 'undefined') {
1181
+ const current = await this.channelsPropertiesService.findOneBy('identifier', 'current', electricalPower.id);
1182
+ if (current === null) {
1183
+ }
1184
+ else {
1185
+ await this.setDefaultPropertyValue(device.id, current, comp.current);
1186
+ this.changeHandlers.set(`${delegate.id}|${comp.key}|current`, (val) => {
1187
+ this.handleNumericChange(comp.key, 'current', current.id, val, (n) => this.handleChange(current, n, false));
1188
+ });
1189
+ }
1190
+ }
1191
+ }
1192
+ }
1193
+ }
1194
+ async wireMeterProperty(delegate, device, compKey, channelIdentifier, attr, propertyIdentifier, value, allowNull) {
1195
+ if (typeof value === 'undefined') {
1196
+ return;
1197
+ }
1198
+ const channel = await this.channelsService.findOneBy('identifier', channelIdentifier, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
1199
+ if (channel === null) {
1200
+ return;
1201
+ }
1202
+ const property = await this.channelsPropertiesService.findOneBy('identifier', propertyIdentifier, channel.id);
1203
+ if (property === null) {
1204
+ return;
1205
+ }
1206
+ if (value !== null) {
1207
+ await this.setDefaultPropertyValue(device.id, property, value);
1208
+ }
1209
+ this.changeHandlers.set(`${delegate.id}|${compKey}|${attr}`, (val) => {
1210
+ this.handleNumericChange(compKey, attr, property.id, val, (n) => this.handleChange(property, n, false), {
1211
+ allowNull,
1212
+ });
1213
+ });
1214
+ }
1145
1215
  determineCategory(delegate) {
1146
1216
  if (delegate.descriptor && delegate.descriptor.categories.length > 0) {
1147
1217
  return delegate.descriptor.categories[0];
@@ -1164,6 +1234,9 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1164
1234
  return devices_constants_1.DeviceCategory.GENERIC;
1165
1235
  }
1166
1236
  handleNumericChange(compKey, attr, propertyId, val, write, opts) {
1237
+ if (val === null && opts?.allowNull) {
1238
+ return;
1239
+ }
1167
1240
  const n = (0, transform_utils_1.coerceNumberSafe)(val, opts);
1168
1241
  if (n === null || Number.isNaN(n)) {
1169
1242
  this.logger.warn(`Dropping invalid numeric update for ${compKey}.${attr} -> ${(0, transform_utils_1.safeToString)(val)} (property=${propertyId})`);
@@ -1193,9 +1266,123 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1193
1266
  }, 250);
1194
1267
  this.pendingWrites.set(property.id, t);
1195
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
+ }
1196
1383
  async writeValueToProperty(property, value) {
1197
1384
  return await this.channelsPropertiesService.update(property.id, (0, transform_utils_1.toInstance)(update_channel_property_dto_1.UpdateShellyNgChannelPropertyDto, {
1198
- ...(0, class_transformer_1.instanceToPlain)(property),
1385
+ type: devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE,
1199
1386
  value,
1200
1387
  }));
1201
1388
  }
@@ -1252,6 +1439,9 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1252
1439
  clearTimeout(pendingWrite);
1253
1440
  }
1254
1441
  this.pendingWrites.clear();
1442
+ this.clearPollWrites();
1443
+ this.delegatePollGenerations.clear();
1444
+ this.currentValueUpdateContext = null;
1255
1445
  this.deviceLocks.clear();
1256
1446
  this.canonicalMacLocks.clear();
1257
1447
  this.connectedDelegatesPerDevice.clear();
@@ -1295,20 +1485,47 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1295
1485
  await Promise.all(tasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
1296
1486
  }
1297
1487
  }
1298
- async pollAllDevices(timeoutMs = 10_000) {
1299
- const CONCURRENCY = 10;
1300
- const tasks = [];
1301
- for (const [id, delegate] of this.delegates.entries()) {
1302
- if (!delegate.connected) {
1303
- continue;
1304
- }
1305
- tasks.push(async () => {
1306
- const ok = await delegate.pollStatus(timeoutMs);
1307
- if (!ok) {
1308
- this.logger.warn(`Status poll failed for device=${id}`);
1309
- }
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
+ const traceDeviceId = this.delegateDeviceIds.get(deviceId) ?? deviceId;
1507
+ this.commandLatencyTraceCollector.recordPollRpc(traceDeviceId, 'poll-rpc-start', { timeoutMs });
1508
+ let ok;
1509
+ try {
1510
+ ok = await delegate.pollStatus(timeoutMs, () => this.delegates.get(deviceId) === delegate &&
1511
+ delegate.connected &&
1512
+ this.delegatePollGenerations.get(deviceId) === generation);
1513
+ }
1514
+ catch (error) {
1515
+ this.commandLatencyTraceCollector.recordPollRpc(traceDeviceId, 'poll-rpc-complete', {
1516
+ ok: false,
1517
+ error: error instanceof Error ? error.message : 'unknown failure',
1310
1518
  });
1519
+ throw error;
1520
+ }
1521
+ this.commandLatencyTraceCollector.recordPollRpc(traceDeviceId, 'poll-rpc-complete', { ok });
1522
+ if (!ok && this.delegates.get(deviceId) === delegate && this.delegatePollGenerations.get(deviceId) === generation) {
1523
+ this.logger.warn(`Status poll failed for device=${deviceId}`);
1311
1524
  }
1525
+ }
1526
+ async pollAllDevices(timeoutMs = 10_000) {
1527
+ const CONCURRENCY = 10;
1528
+ const tasks = this.getConnectedDelegateIds().map((id) => () => this.pollDevice(id, timeoutMs));
1312
1529
  for (let i = 0; i < tasks.length; i += CONCURRENCY) {
1313
1530
  await Promise.all(tasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
1314
1531
  }
@@ -1357,6 +1574,7 @@ exports.DelegatesManagerService = DelegatesManagerService;
1357
1574
  DelegatesManagerService.DISCONNECT_GRACE_MS = 15_000;
1358
1575
  exports.DelegatesManagerService = DelegatesManagerService = DelegatesManagerService_1 = __decorate([
1359
1576
  (0, common_1.Injectable)(),
1577
+ __param(8, (0, common_1.Optional)()),
1360
1578
  __metadata("design:paramtypes", [devices_service_1.DevicesService,
1361
1579
  channels_service_1.ChannelsService,
1362
1580
  channels_properties_service_1.ChannelsPropertiesService,
@@ -1364,6 +1582,7 @@ exports.DelegatesManagerService = DelegatesManagerService = DelegatesManagerServ
1364
1582
  device_manager_service_1.DeviceManagerService,
1365
1583
  device_address_service_1.DeviceAddressService,
1366
1584
  mappings_1.PropertyMappingStorageService,
1367
- mappings_1.TransformerRegistry])
1585
+ mappings_1.TransformerRegistry,
1586
+ command_latency_trace_collector_service_1.CommandLatencyTraceCollectorService])
1368
1587
  ], DelegatesManagerService);
1369
1588
  //# sourceMappingURL=delegates-manager.service.js.map