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

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 (214) 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 +20 -1
  86. package/dist/plugins/devices-shelly-ng/delegates/delegates-manager.service.js +361 -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/devices-shelly-ng.plugin.js +2 -0
  94. package/dist/plugins/devices-shelly-ng/devices-shelly-ng.plugin.js.map +1 -1
  95. package/dist/plugins/devices-shelly-ng/mappings/mapping-loader.service.js +4 -0
  96. package/dist/plugins/devices-shelly-ng/mappings/mapping-loader.service.js.map +1 -1
  97. package/dist/plugins/devices-shelly-ng/services/device-manager.service.js +5 -0
  98. package/dist/plugins/devices-shelly-ng/services/device-manager.service.js.map +1 -1
  99. package/dist/plugins/devices-shelly-ng/services/poll-placement-diagnostics.service.d.ts +29 -0
  100. package/dist/plugins/devices-shelly-ng/services/poll-placement-diagnostics.service.js +233 -0
  101. package/dist/plugins/devices-shelly-ng/services/poll-placement-diagnostics.service.js.map +1 -0
  102. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.d.ts +12 -2
  103. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.js +81 -27
  104. package/dist/plugins/devices-shelly-ng/services/shelly-ng.service.js.map +1 -1
  105. package/dist/plugins/devices-shelly-ng/services/shelly-ws-server.service.d.ts +0 -1
  106. package/dist/plugins/devices-shelly-ng/services/shelly-ws-server.service.js +5 -12
  107. package/dist/plugins/devices-shelly-ng/services/shelly-ws-server.service.js.map +1 -1
  108. package/dist/plugins/devices-shelly-ng/utils/transform.utils.d.ts +2 -0
  109. package/dist/plugins/devices-shelly-ng/utils/transform.utils.js +14 -1
  110. package/dist/plugins/devices-shelly-ng/utils/transform.utils.js.map +1 -1
  111. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.d.ts +17 -0
  112. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.js +147 -0
  113. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/setup.controller.js.map +1 -0
  114. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.d.ts +15 -0
  115. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.js +98 -0
  116. package/dist/plugins/remote-access-cloudflare-tunnel/controllers/status.controller.js.map +1 -0
  117. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.d.ts +9 -0
  118. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.js +94 -0
  119. package/dist/plugins/remote-access-cloudflare-tunnel/dto/update-config.dto.js.map +1 -0
  120. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.d.ts +9 -0
  121. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.js +92 -0
  122. package/dist/plugins/remote-access-cloudflare-tunnel/models/config.model.js.map +1 -0
  123. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.d.ts +7 -0
  124. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.js +48 -0
  125. package/dist/plugins/remote-access-cloudflare-tunnel/models/install.model.js.map +1 -0
  126. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.d.ts +42 -0
  127. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.js +352 -0
  128. package/dist/plugins/remote-access-cloudflare-tunnel/models/status.model.js.map +1 -0
  129. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.d.ts +24 -0
  130. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.js +27 -0
  131. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.constants.js.map +1 -0
  132. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.d.ts +8 -0
  133. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.js +19 -0
  134. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.exceptions.js.map +1 -0
  135. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.d.ts +4 -0
  136. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.js +20 -0
  137. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.openapi.js.map +1 -0
  138. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.d.ts +21 -0
  139. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.js +135 -0
  140. package/dist/plugins/remote-access-cloudflare-tunnel/remote-access-cloudflare-tunnel.plugin.js.map +1 -0
  141. package/dist/plugins/remote-access-cloudflare-tunnel/scripts/cloudflared-setup.sh +185 -0
  142. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.d.ts +82 -0
  143. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.js +507 -0
  144. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-managed.service.js.map +1 -0
  145. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.d.ts +10 -0
  146. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.js +37 -0
  147. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-provider.service.js.map +1 -0
  148. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.d.ts +38 -0
  149. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.js +147 -0
  150. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflare-tunnel-setup.service.js.map +1 -0
  151. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.d.ts +15 -0
  152. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.js +67 -0
  153. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-cli.service.js.map +1 -0
  154. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.d.ts +8 -0
  155. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.js +46 -0
  156. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-metrics.service.js.map +1 -0
  157. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.d.ts +27 -0
  158. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.js +139 -0
  159. package/dist/plugins/remote-access-cloudflare-tunnel/services/cloudflared-process.service.js.map +1 -0
  160. package/dist/plugins/remote-access-tailscale/controllers/setup.controller.d.ts +1 -0
  161. package/dist/plugins/remote-access-tailscale/controllers/setup.controller.js +26 -10
  162. package/dist/plugins/remote-access-tailscale/controllers/setup.controller.js.map +1 -1
  163. package/dist/plugins/remote-access-tailscale/controllers/status.controller.d.ts +6 -1
  164. package/dist/plugins/remote-access-tailscale/controllers/status.controller.js +28 -3
  165. package/dist/plugins/remote-access-tailscale/controllers/status.controller.js.map +1 -1
  166. package/dist/plugins/remote-access-tailscale/models/status.model.d.ts +19 -0
  167. package/dist/plugins/remote-access-tailscale/models/status.model.js +158 -1
  168. package/dist/plugins/remote-access-tailscale/models/status.model.js.map +1 -1
  169. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.constants.d.ts +2 -0
  170. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.constants.js +3 -1
  171. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.constants.js.map +1 -1
  172. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.exceptions.d.ts +13 -0
  173. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.exceptions.js +27 -0
  174. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.exceptions.js.map +1 -0
  175. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.openapi.d.ts +2 -2
  176. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.openapi.js +2 -0
  177. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.openapi.js.map +1 -1
  178. package/dist/plugins/remote-access-tailscale/remote-access-tailscale.plugin.js +1 -1
  179. package/dist/plugins/remote-access-tailscale/scripts/tailscale-setup.sh +61 -0
  180. package/dist/plugins/remote-access-tailscale/services/tailscale-cli.service.d.ts +9 -0
  181. package/dist/plugins/remote-access-tailscale/services/tailscale-cli.service.js +12 -0
  182. package/dist/plugins/remote-access-tailscale/services/tailscale-cli.service.js.map +1 -1
  183. package/dist/plugins/remote-access-tailscale/services/tailscale-login.service.d.ts +1 -0
  184. package/dist/plugins/remote-access-tailscale/services/tailscale-login.service.js +27 -2
  185. package/dist/plugins/remote-access-tailscale/services/tailscale-login.service.js.map +1 -1
  186. package/dist/plugins/remote-access-tailscale/services/tailscale-node-managed.service.d.ts +30 -1
  187. package/dist/plugins/remote-access-tailscale/services/tailscale-node-managed.service.js +300 -30
  188. package/dist/plugins/remote-access-tailscale/services/tailscale-node-managed.service.js.map +1 -1
  189. package/dist/plugins/remote-access-tailscale/services/tailscale-serve.service.d.ts +8 -3
  190. package/dist/plugins/remote-access-tailscale/services/tailscale-serve.service.js +39 -12
  191. package/dist/plugins/remote-access-tailscale/services/tailscale-serve.service.js.map +1 -1
  192. package/dist/plugins/remote-access-tailscale/services/tailscale-setup.service.d.ts +14 -5
  193. package/dist/plugins/remote-access-tailscale/services/tailscale-setup.service.js +51 -16
  194. package/dist/plugins/remote-access-tailscale/services/tailscale-setup.service.js.map +1 -1
  195. package/dist/plugins/scenes-local/platforms/local-scene.platform.d.ts +3 -1
  196. package/dist/plugins/scenes-local/platforms/local-scene.platform.js +12 -7
  197. package/dist/plugins/scenes-local/platforms/local-scene.platform.js.map +1 -1
  198. package/dist/plugins/spaces-home-control/services/climate-intent.service.d.ts +3 -1
  199. package/dist/plugins/spaces-home-control/services/climate-intent.service.js +6 -3
  200. package/dist/plugins/spaces-home-control/services/climate-intent.service.js.map +1 -1
  201. package/dist/plugins/spaces-home-control/services/covers-intent.service.d.ts +3 -1
  202. package/dist/plugins/spaces-home-control/services/covers-intent.service.js +6 -3
  203. package/dist/plugins/spaces-home-control/services/covers-intent.service.js.map +1 -1
  204. package/dist/plugins/spaces-home-control/services/lighting-intent.service.d.ts +3 -1
  205. package/dist/plugins/spaces-home-control/services/lighting-intent.service.js +7 -4
  206. package/dist/plugins/spaces-home-control/services/lighting-intent.service.js.map +1 -1
  207. package/dist/plugins/spaces-home-control/services/space-media-activity.service.d.ts +3 -1
  208. package/dist/plugins/spaces-home-control/services/space-media-activity.service.js +11 -5
  209. package/dist/plugins/spaces-home-control/services/space-media-activity.service.js.map +1 -1
  210. package/dist/plugins/spaces-home-control/services/space-undo-history.service.d.ts +3 -1
  211. package/dist/plugins/spaces-home-control/services/space-undo-history.service.js +8 -5
  212. package/dist/plugins/spaces-home-control/services/space-undo-history.service.js.map +1 -1
  213. package/dist/tsconfig.build.tsbuildinfo +1 -1
  214. 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");
@@ -27,10 +30,11 @@ const mappings_1 = require("../mappings");
27
30
  const transformers_1 = require("../mappings/transformers/transformers");
28
31
  const device_address_service_1 = require("../services/device-address.service");
29
32
  const device_manager_service_1 = require("../services/device-manager.service");
33
+ const poll_placement_diagnostics_service_1 = require("../services/poll-placement-diagnostics.service");
30
34
  const transform_utils_2 = require("../utils/transform.utils");
31
35
  const shelly_device_delegate_1 = require("./shelly-device.delegate");
32
36
  let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManagerService {
33
- constructor(devicesService, channelsService, channelsPropertiesService, deviceConnectivityService, deviceManagerService, deviceAddressService, propertyMappingStorage, transformerRegistry) {
37
+ constructor(devicesService, channelsService, channelsPropertiesService, deviceConnectivityService, deviceManagerService, deviceAddressService, propertyMappingStorage, transformerRegistry, commandLatencyTraceCollector = new command_latency_trace_collector_service_1.CommandLatencyTraceCollectorService(), pollPlacementDiagnostics = new poll_placement_diagnostics_service_1.PollPlacementDiagnosticsService()) {
34
38
  this.devicesService = devicesService;
35
39
  this.channelsService = channelsService;
36
40
  this.channelsPropertiesService = channelsPropertiesService;
@@ -39,6 +43,8 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
39
43
  this.deviceAddressService = deviceAddressService;
40
44
  this.propertyMappingStorage = propertyMappingStorage;
41
45
  this.transformerRegistry = transformerRegistry;
46
+ this.commandLatencyTraceCollector = commandLatencyTraceCollector;
47
+ this.pollPlacementDiagnostics = pollPlacementDiagnostics;
42
48
  this.logger = (0, logger_1.createExtensionLogger)(devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_PLUGIN_NAME, 'DelegatesManagerService');
43
49
  this.delegates = new Map();
44
50
  this.delegateValueHandlers = new Map();
@@ -47,6 +53,10 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
47
53
  this.setChannelsHandlers = new Map();
48
54
  this.setPropertiesHandlers = new Map();
49
55
  this.pendingWrites = new Map();
56
+ this.pendingPollWrites = new Map();
57
+ this.activePollWrites = new Map();
58
+ this.delegatePollGenerations = new Map();
59
+ this.currentValueUpdateContext = null;
50
60
  this.propertiesMap = new Map();
51
61
  this.delegateDeviceIds = new Map();
52
62
  this.delegateToIdentifier = new Map();
@@ -75,6 +85,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
75
85
  }
76
86
  const generation = (this.insertGeneration.get(shelly.id) ?? 0) + 1;
77
87
  this.insertGeneration.set(shelly.id, generation);
88
+ this.delegatePollGenerations.set(shelly.id, (this.delegatePollGenerations.get(shelly.id) ?? 0) + 1);
78
89
  const delegate = new shelly_device_delegate_1.ShellyDeviceDelegate(shelly);
79
90
  this.delegates.set(shelly.id, delegate);
80
91
  const wifiIp = shelly.wifi?.sta_ip ?? null;
@@ -120,6 +131,12 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
120
131
  let device = resolvedDevice;
121
132
  this.delegateDeviceIds.set(delegate.id, device.id);
122
133
  this.delegateToIdentifier.set(delegate.id, device.identifier);
134
+ this.pollPlacementDiagnostics.observeDelegate({
135
+ delegateId: delegate.id,
136
+ sourceDeviceId: device.id,
137
+ connected: delegate.connected,
138
+ generation,
139
+ });
123
140
  const delegateSet = this.identifierToDelegates.get(device.identifier) ?? new Set();
124
141
  delegateSet.add(delegate.id);
125
142
  this.identifierToDelegates.set(device.identifier, delegateSet);
@@ -199,60 +216,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
199
216
  await comp.set(val);
200
217
  return true;
201
218
  });
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
- }
219
+ await this.wireElectricalChannels(delegate, device, comp);
256
220
  }
257
221
  if (this.insertGeneration.get(shelly.id) !== generation)
258
222
  return delegate;
@@ -314,6 +278,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
314
278
  await comp.stop();
315
279
  return true;
316
280
  });
281
+ await this.wireElectricalChannels(delegate, device, comp);
317
282
  }
318
283
  if (this.insertGeneration.get(shelly.id) !== generation)
319
284
  return delegate;
@@ -362,6 +327,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
362
327
  return true;
363
328
  });
364
329
  }
330
+ await this.wireElectricalChannels(delegate, device, comp);
365
331
  }
366
332
  if (this.insertGeneration.get(shelly.id) !== generation)
367
333
  return delegate;
@@ -495,6 +461,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
495
461
  ]);
496
462
  return true;
497
463
  });
464
+ await this.wireElectricalChannels(delegate, device, comp);
498
465
  }
499
466
  if (this.insertGeneration.get(shelly.id) !== generation)
500
467
  return delegate;
@@ -653,6 +620,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
653
620
  ], Math.round((0, transform_utils_1.clampNumber)(whiteValue, 0, 255)));
654
621
  return true;
655
622
  });
623
+ await this.wireElectricalChannels(delegate, device, comp);
656
624
  }
657
625
  if (this.insertGeneration.get(shelly.id) !== generation)
658
626
  return delegate;
@@ -746,6 +714,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
746
714
  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
715
  return true;
748
716
  });
717
+ await this.wireElectricalChannels(delegate, device, comp);
749
718
  }
750
719
  if (this.insertGeneration.get(shelly.id) !== generation)
751
720
  return delegate;
@@ -800,63 +769,69 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
800
769
  if (this.insertGeneration.get(shelly.id) !== generation)
801
770
  return delegate;
802
771
  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
- }
772
+ await this.wireElectricalChannels(delegate, device, comp);
773
+ }
774
+ if (this.insertGeneration.get(shelly.id) !== generation)
775
+ return delegate;
776
+ for (const comp of delegate.em.values()) {
777
+ const phases = [
778
+ { id: 'a', power: comp.a_act_power, voltage: comp.a_voltage, current: comp.a_current, freq: comp.a_freq },
779
+ { id: 'b', power: comp.b_act_power, voltage: comp.b_voltage, current: comp.b_current, freq: comp.b_freq },
780
+ { id: 'c', power: comp.c_act_power, voltage: comp.c_voltage, current: comp.c_current, freq: comp.c_freq },
781
+ ];
782
+ for (const phase of phases) {
783
+ const channelIdentifier = `power:${comp.id}:${phase.id}`;
784
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_act_power`, `${phase.id}_act_power`, phase.power, true);
785
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_voltage`, `${phase.id}_voltage`, phase.voltage, true);
786
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_current`, `${phase.id}_current`, phase.current, true);
787
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_freq`, `${phase.id}_freq`, phase.freq, true);
788
+ }
789
+ const totalChannelIdentifier = `power:${comp.id}:total`;
790
+ await this.wireMeterProperty(delegate, device, comp.key, totalChannelIdentifier, 'total_act_power', 'total_act_power', comp.total_act_power, true);
791
+ await this.wireMeterProperty(delegate, device, comp.key, totalChannelIdentifier, 'total_current', 'total_current', comp.total_current, true);
792
+ }
793
+ if (this.insertGeneration.get(shelly.id) !== generation)
794
+ return delegate;
795
+ for (const comp of delegate.emData.values()) {
796
+ const phases = [
797
+ { id: 'a', energy: comp.a_total_act_energy, returned: comp.a_total_act_ret_energy },
798
+ { id: 'b', energy: comp.b_total_act_energy, returned: comp.b_total_act_ret_energy },
799
+ { id: 'c', energy: comp.c_total_act_energy, returned: comp.c_total_act_ret_energy },
800
+ ];
801
+ for (const phase of phases) {
802
+ const channelIdentifier = `energy:${comp.id}:${phase.id}`;
803
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_total_act_energy`, `${phase.id}_total_act_energy`, phase.energy, false);
804
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, `${phase.id}_total_act_ret_energy`, `${phase.id}_total_act_ret_energy`, phase.returned, false);
805
+ }
806
+ const totalChannelIdentifier = `energy:${comp.id}:total`;
807
+ await this.wireMeterProperty(delegate, device, comp.key, totalChannelIdentifier, 'total_act', 'total_act', comp.total_act, false);
808
+ await this.wireMeterProperty(delegate, device, comp.key, totalChannelIdentifier, 'total_act_ret', 'total_act_ret', comp.total_act_ret, false);
851
809
  }
852
810
  if (this.insertGeneration.get(shelly.id) !== generation)
853
811
  return delegate;
854
- const valueHandler = (compKey, attr, val) => {
812
+ for (const comp of delegate.em1.values()) {
813
+ const channelIdentifier = `power:${comp.id}`;
814
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'act_power', 'act_power', comp.act_power, true);
815
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'voltage', 'voltage', comp.voltage, true);
816
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'current', 'current', comp.current, true);
817
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'freq', 'freq', comp.freq, true);
818
+ }
819
+ if (this.insertGeneration.get(shelly.id) !== generation)
820
+ return delegate;
821
+ for (const comp of delegate.em1Data.values()) {
822
+ const channelIdentifier = `energy:${comp.id}`;
823
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'total_act_energy', 'total_act_energy', comp.total_act_energy, false);
824
+ await this.wireMeterProperty(delegate, device, comp.key, channelIdentifier, 'total_act_ret_energy', 'total_act_ret_energy', comp.total_act_ret_energy, false);
825
+ }
826
+ if (this.insertGeneration.get(shelly.id) !== generation)
827
+ return delegate;
828
+ const valueHandler = (compKey, attr, val, origin = 'notify') => {
855
829
  const handler = this.changeHandlers.get(`${delegate.id}|${compKey}|${attr}`);
856
830
  if (!handler) {
857
831
  return;
858
832
  }
859
833
  try {
834
+ this.currentValueUpdateContext = { delegateId: delegate.id, deviceId: device.id, origin };
860
835
  handler(val);
861
836
  }
862
837
  catch (error) {
@@ -867,6 +842,9 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
867
842
  stack: err.stack,
868
843
  });
869
844
  }
845
+ finally {
846
+ this.currentValueUpdateContext = null;
847
+ }
870
848
  };
871
849
  delegate.on('value', valueHandler);
872
850
  this.delegateValueHandlers.set(delegate.id, valueHandler);
@@ -877,6 +855,12 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
877
855
  if (wasConnected)
878
856
  return;
879
857
  this.delegateConnectedState.set(delegate.id, true);
858
+ this.pollPlacementDiagnostics.observeDelegate({
859
+ delegateId: delegate.id,
860
+ sourceDeviceId: device.id,
861
+ connected: true,
862
+ generation,
863
+ });
880
864
  const pendingTimer = this.disconnectTimers.get(deviceDbId);
881
865
  if (pendingTimer) {
882
866
  clearTimeout(pendingTimer);
@@ -898,6 +882,12 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
898
882
  if (!wasConnected)
899
883
  return;
900
884
  this.delegateConnectedState.set(delegate.id, false);
885
+ this.pollPlacementDiagnostics.observeDelegate({
886
+ delegateId: delegate.id,
887
+ sourceDeviceId: device.id,
888
+ connected: false,
889
+ generation,
890
+ });
901
891
  const count = Math.max(0, (this.connectedDelegatesPerDevice.get(deviceDbId) ?? 1) - 1);
902
892
  this.connectedDelegatesPerDevice.set(deviceDbId, count);
903
893
  if (count === 0) {
@@ -982,6 +972,8 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
982
972
  if (!delegate) {
983
973
  return;
984
974
  }
975
+ this.delegatePollGenerations.set(deviceId, (this.delegatePollGenerations.get(deviceId) ?? 0) + 1);
976
+ this.cancelPollWritesForDelegate(deviceId);
985
977
  const valueHandler = this.delegateValueHandlers.get(delegate.id);
986
978
  const connectionHandler = this.delegateConnectionHandlers.get(delegate.id);
987
979
  if (connectionHandler) {
@@ -1052,6 +1044,7 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1052
1044
  }
1053
1045
  this.delegateDeviceIds.delete(deviceId);
1054
1046
  this.delegateToIdentifier.delete(deviceId);
1047
+ this.pollPlacementDiagnostics.invalidate('delegate-detached-or-remapped');
1055
1048
  this.insertGeneration.delete(deviceId);
1056
1049
  this.delegates.delete(deviceId);
1057
1050
  this.logger.log(`Detached Shelly device=${deviceId}`, { resource: deviceId });
@@ -1118,7 +1111,24 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1118
1111
  }
1119
1112
  }
1120
1113
  async handleChange(property, value, immediately = true) {
1114
+ const context = this.currentValueUpdateContext;
1115
+ if (context !== null) {
1116
+ this.commandLatencyTraceCollector.recordProviderReceipt(property.id, value, context.origin, {
1117
+ delegateId: context.delegateId,
1118
+ deviceId: context.deviceId,
1119
+ });
1120
+ }
1121
+ if (context?.origin === 'poll') {
1122
+ this.commandLatencyTraceCollector.recordPollActivity(property.id, 'poll-coalescer-admission', {
1123
+ delegateId: context.delegateId,
1124
+ deviceId: context.deviceId,
1125
+ });
1126
+ this.schedulePollWrite(context, property, value);
1127
+ return;
1128
+ }
1121
1129
  if (immediately) {
1130
+ this.cancelScheduledWrite(property.id);
1131
+ this.cancelPollWrite(property.id);
1122
1132
  await this.writeValueToProperty(property, value);
1123
1133
  }
1124
1134
  else {
@@ -1142,6 +1152,87 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1142
1152
  }
1143
1153
  set.add(property.id);
1144
1154
  }
1155
+ async wireElectricalChannels(delegate, device, comp) {
1156
+ if (typeof comp.aenergy !== 'undefined') {
1157
+ const electricalEnergy = await this.channelsService.findOneBy('identifier', `energy:${comp.id}`, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
1158
+ if (electricalEnergy === null) {
1159
+ }
1160
+ else {
1161
+ const consumption = await this.channelsPropertiesService.findOneBy('identifier', 'aenergy', electricalEnergy.id);
1162
+ if (consumption === null) {
1163
+ }
1164
+ else {
1165
+ await this.setDefaultPropertyValue(device.id, consumption, (0, transform_utils_2.toEnergy)(comp.aenergy));
1166
+ this.changeHandlers.set(`${delegate.id}|${comp.key}|aenergy.total`, (val) => {
1167
+ this.handleNumericChange(comp.key, 'aenergy.total', consumption.id, val, (n) => this.handleChange(consumption, (0, transform_utils_2.toEnergy)(n), false));
1168
+ });
1169
+ }
1170
+ }
1171
+ }
1172
+ if (typeof comp.apower !== 'undefined' ||
1173
+ typeof comp.voltage !== 'undefined' ||
1174
+ typeof comp.current !== 'undefined') {
1175
+ const electricalPower = await this.channelsService.findOneBy('identifier', `power:${comp.id}`, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
1176
+ if (electricalPower === null) {
1177
+ }
1178
+ else {
1179
+ if (typeof comp.apower !== 'undefined') {
1180
+ const power = await this.channelsPropertiesService.findOneBy('identifier', 'apower', electricalPower.id);
1181
+ if (power === null) {
1182
+ }
1183
+ else {
1184
+ await this.setDefaultPropertyValue(device.id, power, Math.max(0, comp.apower));
1185
+ this.changeHandlers.set(`${delegate.id}|${comp.key}|apower`, (val) => {
1186
+ this.handleNumericChange(comp.key, 'apower', power.id, val, (n) => this.handleChange(power, Math.max(0, n), false));
1187
+ });
1188
+ }
1189
+ }
1190
+ if (typeof comp.voltage !== 'undefined') {
1191
+ const voltage = await this.channelsPropertiesService.findOneBy('identifier', 'voltage', electricalPower.id);
1192
+ if (voltage === null) {
1193
+ }
1194
+ else {
1195
+ await this.setDefaultPropertyValue(device.id, voltage, comp.voltage);
1196
+ this.changeHandlers.set(`${delegate.id}|${comp.key}|voltage`, (val) => {
1197
+ this.handleNumericChange(comp.key, 'voltage', voltage.id, val, (n) => this.handleChange(voltage, n, false));
1198
+ });
1199
+ }
1200
+ }
1201
+ if (typeof comp.current !== 'undefined') {
1202
+ const current = await this.channelsPropertiesService.findOneBy('identifier', 'current', electricalPower.id);
1203
+ if (current === null) {
1204
+ }
1205
+ else {
1206
+ await this.setDefaultPropertyValue(device.id, current, comp.current);
1207
+ this.changeHandlers.set(`${delegate.id}|${comp.key}|current`, (val) => {
1208
+ this.handleNumericChange(comp.key, 'current', current.id, val, (n) => this.handleChange(current, n, false));
1209
+ });
1210
+ }
1211
+ }
1212
+ }
1213
+ }
1214
+ }
1215
+ async wireMeterProperty(delegate, device, compKey, channelIdentifier, attr, propertyIdentifier, value, allowNull) {
1216
+ if (typeof value === 'undefined') {
1217
+ return;
1218
+ }
1219
+ const channel = await this.channelsService.findOneBy('identifier', channelIdentifier, device.id, devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE);
1220
+ if (channel === null) {
1221
+ return;
1222
+ }
1223
+ const property = await this.channelsPropertiesService.findOneBy('identifier', propertyIdentifier, channel.id);
1224
+ if (property === null) {
1225
+ return;
1226
+ }
1227
+ if (value !== null) {
1228
+ await this.setDefaultPropertyValue(device.id, property, value);
1229
+ }
1230
+ this.changeHandlers.set(`${delegate.id}|${compKey}|${attr}`, (val) => {
1231
+ this.handleNumericChange(compKey, attr, property.id, val, (n) => this.handleChange(property, n, false), {
1232
+ allowNull,
1233
+ });
1234
+ });
1235
+ }
1145
1236
  determineCategory(delegate) {
1146
1237
  if (delegate.descriptor && delegate.descriptor.categories.length > 0) {
1147
1238
  return delegate.descriptor.categories[0];
@@ -1164,6 +1255,9 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1164
1255
  return devices_constants_1.DeviceCategory.GENERIC;
1165
1256
  }
1166
1257
  handleNumericChange(compKey, attr, propertyId, val, write, opts) {
1258
+ if (val === null && opts?.allowNull) {
1259
+ return;
1260
+ }
1167
1261
  const n = (0, transform_utils_1.coerceNumberSafe)(val, opts);
1168
1262
  if (n === null || Number.isNaN(n)) {
1169
1263
  this.logger.warn(`Dropping invalid numeric update for ${compKey}.${attr} -> ${(0, transform_utils_1.safeToString)(val)} (property=${propertyId})`);
@@ -1193,9 +1287,123 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1193
1287
  }, 250);
1194
1288
  this.pendingWrites.set(property.id, t);
1195
1289
  }
1290
+ schedulePollWrite(context, property, value) {
1291
+ let bucket = this.pendingPollWrites.get(context.deviceId);
1292
+ if (!bucket) {
1293
+ const values = new Map();
1294
+ const timer = setTimeout(() => {
1295
+ void this.flushPollWrites(context.deviceId);
1296
+ }, 250);
1297
+ bucket = { timer, values };
1298
+ this.pendingPollWrites.set(context.deviceId, bucket);
1299
+ }
1300
+ bucket.values.set(property.id, {
1301
+ delegateId: context.delegateId,
1302
+ delegateGeneration: this.delegatePollGenerations.get(context.delegateId) ?? 0,
1303
+ property,
1304
+ value,
1305
+ });
1306
+ }
1307
+ async flushPollWrites(deviceId) {
1308
+ const bucket = this.pendingPollWrites.get(deviceId);
1309
+ if (!bucket) {
1310
+ return;
1311
+ }
1312
+ this.pendingPollWrites.delete(deviceId);
1313
+ clearTimeout(bucket.timer);
1314
+ let activeBuckets = this.activePollWrites.get(deviceId);
1315
+ if (activeBuckets === undefined) {
1316
+ activeBuckets = new Set();
1317
+ this.activePollWrites.set(deviceId, activeBuckets);
1318
+ }
1319
+ activeBuckets.add(bucket);
1320
+ try {
1321
+ for (const [propertyId, pending] of [...bucket.values.entries()]) {
1322
+ if (bucket.values.get(propertyId) !== pending) {
1323
+ continue;
1324
+ }
1325
+ if (!this.delegates.has(pending.delegateId) ||
1326
+ (this.delegatePollGenerations.get(pending.delegateId) ?? 0) !== pending.delegateGeneration) {
1327
+ continue;
1328
+ }
1329
+ try {
1330
+ this.commandLatencyTraceCollector.recordPollActivity(pending.property.id, 'poll-drain', {
1331
+ delegateId: pending.delegateId,
1332
+ deviceId,
1333
+ });
1334
+ await this.writeValueToProperty(pending.property, pending.value);
1335
+ }
1336
+ catch (error) {
1337
+ const err = error;
1338
+ 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 });
1339
+ }
1340
+ }
1341
+ }
1342
+ finally {
1343
+ activeBuckets.delete(bucket);
1344
+ if (activeBuckets.size === 0 && this.activePollWrites.get(deviceId) === activeBuckets) {
1345
+ this.activePollWrites.delete(deviceId);
1346
+ }
1347
+ }
1348
+ }
1349
+ cancelScheduledWrite(propertyId) {
1350
+ const timer = this.pendingWrites.get(propertyId);
1351
+ if (timer) {
1352
+ clearTimeout(timer);
1353
+ this.pendingWrites.delete(propertyId);
1354
+ }
1355
+ }
1356
+ cancelPollWrite(propertyId) {
1357
+ for (const [deviceId, bucket] of this.pendingPollWrites.entries()) {
1358
+ bucket.values.delete(propertyId);
1359
+ if (bucket.values.size === 0) {
1360
+ clearTimeout(bucket.timer);
1361
+ this.pendingPollWrites.delete(deviceId);
1362
+ }
1363
+ }
1364
+ for (const buckets of this.activePollWrites.values()) {
1365
+ for (const bucket of buckets) {
1366
+ bucket.values.delete(propertyId);
1367
+ }
1368
+ }
1369
+ }
1370
+ cancelPollWritesForDelegate(delegateId) {
1371
+ for (const [deviceId, bucket] of this.pendingPollWrites.entries()) {
1372
+ for (const [propertyId, pending] of bucket.values.entries()) {
1373
+ if (pending.delegateId === delegateId) {
1374
+ bucket.values.delete(propertyId);
1375
+ }
1376
+ }
1377
+ if (bucket.values.size === 0) {
1378
+ clearTimeout(bucket.timer);
1379
+ this.pendingPollWrites.delete(deviceId);
1380
+ }
1381
+ }
1382
+ for (const buckets of this.activePollWrites.values()) {
1383
+ for (const bucket of buckets) {
1384
+ for (const [propertyId, pending] of bucket.values.entries()) {
1385
+ if (pending.delegateId === delegateId) {
1386
+ bucket.values.delete(propertyId);
1387
+ }
1388
+ }
1389
+ }
1390
+ }
1391
+ }
1392
+ clearPollWrites() {
1393
+ for (const bucket of this.pendingPollWrites.values()) {
1394
+ clearTimeout(bucket.timer);
1395
+ }
1396
+ this.pendingPollWrites.clear();
1397
+ for (const buckets of this.activePollWrites.values()) {
1398
+ for (const bucket of buckets) {
1399
+ bucket.values.clear();
1400
+ }
1401
+ }
1402
+ this.activePollWrites.clear();
1403
+ }
1196
1404
  async writeValueToProperty(property, value) {
1197
1405
  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),
1406
+ type: devices_shelly_ng_constants_1.DEVICES_SHELLY_NG_TYPE,
1199
1407
  value,
1200
1408
  }));
1201
1409
  }
@@ -1252,6 +1460,9 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1252
1460
  clearTimeout(pendingWrite);
1253
1461
  }
1254
1462
  this.pendingWrites.clear();
1463
+ this.clearPollWrites();
1464
+ this.delegatePollGenerations.clear();
1465
+ this.currentValueUpdateContext = null;
1255
1466
  this.deviceLocks.clear();
1256
1467
  this.canonicalMacLocks.clear();
1257
1468
  this.connectedDelegatesPerDevice.clear();
@@ -1295,20 +1506,47 @@ let DelegatesManagerService = DelegatesManagerService_1 = class DelegatesManager
1295
1506
  await Promise.all(tasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
1296
1507
  }
1297
1508
  }
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
- }
1509
+ getConnectedDelegateIds() {
1510
+ return Array.from(this.delegates.entries())
1511
+ .filter(([, delegate]) => delegate.connected)
1512
+ .map(([id]) => id)
1513
+ .sort();
1514
+ }
1515
+ invalidateStatusPolls() {
1516
+ for (const delegateId of this.delegates.keys()) {
1517
+ this.delegatePollGenerations.set(delegateId, (this.delegatePollGenerations.get(delegateId) ?? 0) + 1);
1518
+ }
1519
+ this.clearPollWrites();
1520
+ }
1521
+ async pollDevice(deviceId, timeoutMs = 10_000) {
1522
+ const delegate = this.delegates.get(deviceId);
1523
+ if (!delegate || !delegate.connected) {
1524
+ return;
1525
+ }
1526
+ const generation = this.delegatePollGenerations.get(deviceId) ?? 0;
1527
+ const traceDeviceId = this.delegateDeviceIds.get(deviceId) ?? deviceId;
1528
+ this.commandLatencyTraceCollector.recordPollRpc(traceDeviceId, 'poll-rpc-start', { timeoutMs });
1529
+ let ok;
1530
+ try {
1531
+ ok = await delegate.pollStatus(timeoutMs, () => this.delegates.get(deviceId) === delegate &&
1532
+ delegate.connected &&
1533
+ this.delegatePollGenerations.get(deviceId) === generation);
1534
+ }
1535
+ catch (error) {
1536
+ this.commandLatencyTraceCollector.recordPollRpc(traceDeviceId, 'poll-rpc-complete', {
1537
+ ok: false,
1538
+ error: error instanceof Error ? error.message : 'unknown failure',
1310
1539
  });
1540
+ throw error;
1541
+ }
1542
+ this.commandLatencyTraceCollector.recordPollRpc(traceDeviceId, 'poll-rpc-complete', { ok });
1543
+ if (!ok && this.delegates.get(deviceId) === delegate && this.delegatePollGenerations.get(deviceId) === generation) {
1544
+ this.logger.warn(`Status poll failed for device=${deviceId}`);
1311
1545
  }
1546
+ }
1547
+ async pollAllDevices(timeoutMs = 10_000) {
1548
+ const CONCURRENCY = 10;
1549
+ const tasks = this.getConnectedDelegateIds().map((id) => () => this.pollDevice(id, timeoutMs));
1312
1550
  for (let i = 0; i < tasks.length; i += CONCURRENCY) {
1313
1551
  await Promise.all(tasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
1314
1552
  }
@@ -1357,6 +1595,8 @@ exports.DelegatesManagerService = DelegatesManagerService;
1357
1595
  DelegatesManagerService.DISCONNECT_GRACE_MS = 15_000;
1358
1596
  exports.DelegatesManagerService = DelegatesManagerService = DelegatesManagerService_1 = __decorate([
1359
1597
  (0, common_1.Injectable)(),
1598
+ __param(8, (0, common_1.Optional)()),
1599
+ __param(9, (0, common_1.Optional)()),
1360
1600
  __metadata("design:paramtypes", [devices_service_1.DevicesService,
1361
1601
  channels_service_1.ChannelsService,
1362
1602
  channels_properties_service_1.ChannelsPropertiesService,
@@ -1364,6 +1604,8 @@ exports.DelegatesManagerService = DelegatesManagerService = DelegatesManagerServ
1364
1604
  device_manager_service_1.DeviceManagerService,
1365
1605
  device_address_service_1.DeviceAddressService,
1366
1606
  mappings_1.PropertyMappingStorageService,
1367
- mappings_1.TransformerRegistry])
1607
+ mappings_1.TransformerRegistry,
1608
+ command_latency_trace_collector_service_1.CommandLatencyTraceCollectorService,
1609
+ poll_placement_diagnostics_service_1.PollPlacementDiagnosticsService])
1368
1610
  ], DelegatesManagerService);
1369
1611
  //# sourceMappingURL=delegates-manager.service.js.map