@espressif/rainmaker-neo-base-sdk 1.0.0 → 1.2.0

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 (117) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +40 -4
  3. package/dist/cjs/ESPDevice.js +6 -0
  4. package/dist/cjs/ESPDevice.js.map +1 -1
  5. package/dist/cjs/ESPRMNeoBase.js +1 -1
  6. package/dist/cjs/ESPRMNeoNode.js +33 -14
  7. package/dist/cjs/ESPRMNeoNode.js.map +1 -1
  8. package/dist/cjs/index.js +14 -0
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/methods/ESPDevice/Provision.js +7 -0
  11. package/dist/cjs/methods/ESPDevice/Provision.js.map +1 -1
  12. package/dist/cjs/methods/ESPDevice/ResetWifiStatus.js +26 -0
  13. package/dist/cjs/methods/ESPDevice/ResetWifiStatus.js.map +1 -0
  14. package/dist/cjs/methods/ESPDevice/RetryNetworkCredentials.js +46 -0
  15. package/dist/cjs/methods/ESPDevice/RetryNetworkCredentials.js.map +1 -0
  16. package/dist/cjs/methods/ESPRMNeoNode/Sync.js +4 -1
  17. package/dist/cjs/methods/ESPRMNeoNode/Sync.js.map +1 -1
  18. package/dist/cjs/methods/ESPRMNeoUser/MQTT/AssumeRole.js +8 -9
  19. package/dist/cjs/methods/ESPRMNeoUser/MQTT/AssumeRole.js.map +1 -1
  20. package/dist/cjs/proto/esp_rmaker_chal_resp.js +5 -0
  21. package/dist/cjs/proto/esp_rmaker_chal_resp.js.map +1 -1
  22. package/dist/cjs/proto/rmaker_local_ctrl.js +273 -0
  23. package/dist/cjs/proto/rmaker_local_ctrl.js.map +1 -0
  24. package/dist/cjs/services/ESPRMNeoMqtt/ESPRMNeoMqtt.js +13 -0
  25. package/dist/cjs/services/ESPRMNeoMqtt/ESPRMNeoMqtt.js.map +1 -1
  26. package/dist/cjs/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js +5 -4
  27. package/dist/cjs/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js.map +1 -1
  28. package/dist/cjs/services/ESPTransport/ESPLocalControlTransport.js +183 -116
  29. package/dist/cjs/services/ESPTransport/ESPLocalControlTransport.js.map +1 -1
  30. package/dist/cjs/services/ESPTransport/LocalControlSession.js +62 -0
  31. package/dist/cjs/services/ESPTransport/LocalControlSession.js.map +1 -0
  32. package/dist/cjs/services/NodeMQTTOrchestrator.js +2 -5
  33. package/dist/cjs/services/NodeMQTTOrchestrator.js.map +1 -1
  34. package/dist/cjs/types/transport.js +24 -0
  35. package/dist/cjs/types/transport.js.map +1 -1
  36. package/dist/cjs/utils/constants.js +80 -4
  37. package/dist/cjs/utils/constants.js.map +1 -1
  38. package/dist/cjs/utils/eventSubscriptionUtils.js +48 -4
  39. package/dist/cjs/utils/eventSubscriptionUtils.js.map +1 -1
  40. package/dist/cjs/utils/nodeUtils.js +12 -1
  41. package/dist/cjs/utils/nodeUtils.js.map +1 -1
  42. package/dist/cjs/utils/waitForNodeOnline.js +7 -6
  43. package/dist/cjs/utils/waitForNodeOnline.js.map +1 -1
  44. package/dist/esm/ESPDevice.js +6 -0
  45. package/dist/esm/ESPDevice.js.map +1 -1
  46. package/dist/esm/ESPRMNeoBase.js +1 -1
  47. package/dist/esm/ESPRMNeoNode.js +33 -14
  48. package/dist/esm/ESPRMNeoNode.js.map +1 -1
  49. package/dist/esm/index.js +4 -2
  50. package/dist/esm/index.js.map +1 -1
  51. package/dist/esm/methods/ESPDevice/Provision.js +7 -0
  52. package/dist/esm/methods/ESPDevice/Provision.js.map +1 -1
  53. package/dist/esm/methods/ESPDevice/ResetWifiStatus.js +24 -0
  54. package/dist/esm/methods/ESPDevice/ResetWifiStatus.js.map +1 -0
  55. package/dist/esm/methods/ESPDevice/RetryNetworkCredentials.js +44 -0
  56. package/dist/esm/methods/ESPDevice/RetryNetworkCredentials.js.map +1 -0
  57. package/dist/esm/methods/ESPRMNeoNode/Sync.js +4 -1
  58. package/dist/esm/methods/ESPRMNeoNode/Sync.js.map +1 -1
  59. package/dist/esm/methods/ESPRMNeoUser/MQTT/AssumeRole.js +9 -10
  60. package/dist/esm/methods/ESPRMNeoUser/MQTT/AssumeRole.js.map +1 -1
  61. package/dist/esm/proto/esp_rmaker_chal_resp.js +5 -0
  62. package/dist/esm/proto/esp_rmaker_chal_resp.js.map +1 -1
  63. package/dist/esm/proto/rmaker_local_ctrl.js +271 -0
  64. package/dist/esm/proto/rmaker_local_ctrl.js.map +1 -0
  65. package/dist/esm/services/ESPRMNeoMqtt/ESPRMNeoMqtt.js +13 -0
  66. package/dist/esm/services/ESPRMNeoMqtt/ESPRMNeoMqtt.js.map +1 -1
  67. package/dist/esm/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js +5 -4
  68. package/dist/esm/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js.map +1 -1
  69. package/dist/esm/services/ESPTransport/ESPLocalControlTransport.js +184 -117
  70. package/dist/esm/services/ESPTransport/ESPLocalControlTransport.js.map +1 -1
  71. package/dist/esm/services/ESPTransport/LocalControlSession.js +59 -0
  72. package/dist/esm/services/ESPTransport/LocalControlSession.js.map +1 -0
  73. package/dist/esm/services/NodeMQTTOrchestrator.js +2 -5
  74. package/dist/esm/services/NodeMQTTOrchestrator.js.map +1 -1
  75. package/dist/esm/types/transport.js +24 -1
  76. package/dist/esm/types/transport.js.map +1 -1
  77. package/dist/esm/utils/constants.js +74 -5
  78. package/dist/esm/utils/constants.js.map +1 -1
  79. package/dist/esm/utils/eventSubscriptionUtils.js +49 -5
  80. package/dist/esm/utils/eventSubscriptionUtils.js.map +1 -1
  81. package/dist/esm/utils/nodeUtils.js +12 -1
  82. package/dist/esm/utils/nodeUtils.js.map +1 -1
  83. package/dist/esm/utils/waitForNodeOnline.js +7 -6
  84. package/dist/esm/utils/waitForNodeOnline.js.map +1 -1
  85. package/dist/types/ESPDevice.d.ts +10 -0
  86. package/dist/types/ESPRMNeoBase.d.ts +1 -1
  87. package/dist/types/ESPRMNeoNode.d.ts +17 -5
  88. package/dist/types/methods/ESPDevice/ResetWifiStatus.d.ts +18 -0
  89. package/dist/types/methods/ESPDevice/RetryNetworkCredentials.d.ts +22 -0
  90. package/dist/types/methods/ESPDevice/index.d.ts +2 -0
  91. package/dist/types/methods/ESPRMNeoUser/MQTT/AssumeRole.d.ts +25 -15
  92. package/dist/types/proto/rmaker_local_ctrl.d.ts +137 -0
  93. package/dist/types/services/ESPRMNeoMqtt/ESPRMNeoMqtt.d.ts +10 -0
  94. package/dist/types/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.d.ts +4 -3
  95. package/dist/types/services/ESPTransport/ESPLocalControlTransport.d.ts +70 -23
  96. package/dist/types/services/ESPTransport/LocalControlSession.d.ts +24 -0
  97. package/dist/types/services/NodeMQTTOrchestrator.d.ts +2 -2
  98. package/dist/types/services/interfaces/MQTTTransport.d.ts +10 -0
  99. package/dist/types/types/discovery.d.ts +1 -1
  100. package/dist/types/types/localControl.d.ts +26 -1
  101. package/dist/types/types/provision.d.ts +10 -0
  102. package/dist/types/types/transport.d.ts +24 -2
  103. package/dist/types/utils/baseUtils.d.ts +1 -1
  104. package/dist/types/utils/constants.d.ts +74 -5
  105. package/dist/types/utils/eventSubscriptionUtils.d.ts +19 -3
  106. package/dist/types/utils/waitForNodeOnline.d.ts +9 -3
  107. package/package.json +1 -1
  108. package/dist/cjs/proto/constants.js +0 -24
  109. package/dist/cjs/proto/constants.js.map +0 -1
  110. package/dist/cjs/proto/esp_local_ctrl.js +0 -787
  111. package/dist/cjs/proto/esp_local_ctrl.js.map +0 -1
  112. package/dist/esm/proto/constants.js +0 -24
  113. package/dist/esm/proto/constants.js.map +0 -1
  114. package/dist/esm/proto/esp_local_ctrl.js +0 -758
  115. package/dist/esm/proto/esp_local_ctrl.js.map +0 -1
  116. package/dist/types/proto/constants.d.ts +0 -15
  117. package/dist/types/proto/esp_local_ctrl.d.ts +0 -283
@@ -1 +1 @@
1
- {"version":3,"file":"ESPLocalControlTransport.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"ESPLocalControlTransport.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ var ESPRMNeoBase = require('../../ESPRMNeoBase.js');
4
+
5
+ /*
6
+ * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
7
+ *
8
+ * SPDX-License-Identifier: Apache-2.0
9
+ */
10
+ /** Attempts made before a local-control handshake is reported as failed. */
11
+ const DEFAULT_CONNECT_RETRIES = 3;
12
+ /**
13
+ * Returns the app-supplied local control adapter.
14
+ *
15
+ * @throws {Error} When no adapter was registered on {@link ESPRMNeoBase}.
16
+ */
17
+ function getLocalControlAdapter() {
18
+ const adapter = ESPRMNeoBase.ESPRMNeoBase.getLocalControlAdapter();
19
+ if (!adapter) {
20
+ throw new Error("Local control adapter is not configured");
21
+ }
22
+ return adapter;
23
+ }
24
+ /**
25
+ * Ensures a usable local-control session for `nodeId`, connecting (with
26
+ * retries) when the adapter reports none.
27
+ *
28
+ * The adapter resolves on a successful handshake and rejects otherwise, so a
29
+ * resolved `connect` is treated as connected.
30
+ *
31
+ * @param adapter - Adapter to drive.
32
+ * @param nodeId - Node to connect to.
33
+ * @param metadata - Local transport metadata (`baseUrl`, `securityType`, `pop`,
34
+ * `username`).
35
+ * @param options - Session endpoints for the protocol in use; omitted for the
36
+ * adapter's built-in default paths.
37
+ * @param maxRetries - Connection attempts before failing.
38
+ * @throws {Error} When every connection attempt fails.
39
+ */
40
+ async function ensureLocalControlSession(adapter, nodeId, metadata, options, maxRetries = DEFAULT_CONNECT_RETRIES) {
41
+ if (await adapter.isConnected(nodeId)) {
42
+ return;
43
+ }
44
+ let attempt = 0;
45
+ let lastError;
46
+ while (attempt < maxRetries) {
47
+ try {
48
+ await adapter.connect(nodeId, metadata.baseUrl, metadata.securityType ?? 0, metadata.pop, metadata.username, options);
49
+ return;
50
+ }
51
+ catch (error) {
52
+ lastError = error;
53
+ attempt += 1;
54
+ }
55
+ }
56
+ const message = lastError instanceof Error ? lastError.message : String(lastError);
57
+ throw new Error(`Failed to connect after ${maxRetries} attempts: ${message}`);
58
+ }
59
+
60
+ exports.ensureLocalControlSession = ensureLocalControlSession;
61
+ exports.getLocalControlAdapter = getLocalControlAdapter;
62
+ //# sourceMappingURL=LocalControlSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalControlSession.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -141,8 +141,8 @@ class NodeMQTTOrchestrator {
141
141
  /**
142
142
  * Registers a node with the orchestrator.
143
143
  * Must be called before subscribeToNode, getParams, getShadow, etc.
144
- * On shadow rename: clears the old binding; ignores shorter/incomplete names.
145
- * Shrink membership via {@link unregisterNode} first.
144
+ * On shadow rename: clears the old binding, then installs the new name
145
+ * (including shrinks to a shorter membership shadow).
146
146
  *
147
147
  * @param nodeId - The device/node identifier.
148
148
  * @param shadowName - The named shadow (e.g. `params-groupId-subgroupId`).
@@ -151,9 +151,6 @@ class NodeMQTTOrchestrator {
151
151
  const instance = NodeMQTTOrchestrator.getInstance();
152
152
  const existing = instance.nodeMap.get(nodeId);
153
153
  if (existing && existing.shadowName !== shadowName) {
154
- if (shadowName.split("-").length < existing.shadowName.split("-").length) {
155
- return;
156
- }
157
154
  NodeMQTTOrchestrator.unregisterNode(nodeId);
158
155
  }
159
156
  instance.nodeMap.set(nodeId, { shadowName });
@@ -1 +1 @@
1
- {"version":3,"file":"NodeMQTTOrchestrator.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"NodeMQTTOrchestrator.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -19,6 +19,29 @@ exports.ESPTransportMode = void 0;
19
19
  /** Communication is routed through MQTT (RainMaker Neo cloud: AWS shadow). */
20
20
  ESPTransportMode["mqtt"] = "mqtt";
21
21
  })(exports.ESPTransportMode || (exports.ESPTransportMode = {}));
22
+ /**
23
+ * Wire protocol spoken by the `local` transport. Both protocols run over a
24
+ * protocomm session on the node's LAN HTTP server; they differ in endpoint
25
+ * names and message encoding.
26
+ *
27
+ * Carried on the local transport config's `metadata.protocol`, set by local
28
+ * discovery from the mDNS service type that produced the hit.
29
+ */
30
+ exports.ESPLocalControlProtocol = void 0;
31
+ (function (ESPLocalControlProtocol) {
32
+ /**
33
+ * RainMaker Neo protocol (`rmaker_local_ctrl/*` session plus
34
+ * `get_params`/`set_params`/`get_config`), advertised as
35
+ * `_esp_rmaker_ctrl._tcp`. Default for this SDK.
36
+ */
37
+ ESPLocalControlProtocol["rmakerLocalCtrl"] = "rmaker_local_ctrl";
38
+ })(exports.ESPLocalControlProtocol || (exports.ESPLocalControlProtocol = {}));
39
+ /**
40
+ * Protocol assumed when a local transport config carries no explicit
41
+ * `metadata.protocol` — for example a LAN transport restored from a client-side
42
+ * registry rather than a fresh discovery hit.
43
+ */
44
+ const DEFAULT_LOCAL_CONTROL_PROTOCOL = exports.ESPLocalControlProtocol.rmakerLocalCtrl;
22
45
  /**
23
46
  * Default transport priority order used when neither the node nor the SDK base
24
47
  * has an explicit order configured: local control first, MQTT (cloud) fallback.
@@ -28,5 +51,6 @@ const DEFAULT_TRANSPORT_ORDER = [
28
51
  exports.ESPTransportMode.mqtt,
29
52
  ];
30
53
 
54
+ exports.DEFAULT_LOCAL_CONTROL_PROTOCOL = DEFAULT_LOCAL_CONTROL_PROTOCOL;
31
55
  exports.DEFAULT_TRANSPORT_ORDER = DEFAULT_TRANSPORT_ORDER;
32
56
  //# sourceMappingURL=transport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"transport.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -393,6 +393,15 @@ const TriggerErrorMessages = {
393
393
  /** Logged when retrieving triggers for a node fails. */
394
394
  GET_FAILED: "getTriggers failed",
395
395
  };
396
+ /**
397
+ * Error messages for assumeRole (POST /v1/assumed-roles).
398
+ */
399
+ const AssumeRoleErrorMessages = {
400
+ /** Thrown when `services` is provided without a `nodeId`. */
401
+ NODE_ID_REQUIRED: "assumeRole: nodeId is required when services is provided",
402
+ /** Thrown when the assume-role response is missing required credential fields. */
403
+ INVALID_RESPONSE: "Invalid assume role response: missing required credential fields",
404
+ };
396
405
  /**
397
406
  * Error / log messages for temporary AWS credentials (POST /v1/user/credentials).
398
407
  */
@@ -466,8 +475,6 @@ const ProvisionType = {
466
475
  * An object containing endpoint paths.
467
476
  */
468
477
  const Endpoint = {
469
- /** The endpoint for local control. */
470
- LOCAL_CTRL: "esp_local_ctrl/control",
471
478
  /** The endpoint for cloud user association. */
472
479
  CLOUD_USER_ASSOCIATION: "cloud_user_assoc",
473
480
  /** The endpoint for challenge-response and get-node-id protocol with the device. */
@@ -475,6 +482,64 @@ const Endpoint = {
475
482
  /** The endpoint for assisted claiming. */
476
483
  RM_CLAIM: "rmaker_claim",
477
484
  };
485
+ /**
486
+ * Endpoint paths of the `rmaker_local_ctrl` protocol served by RainMaker Neo
487
+ * firmware (see the firmware's local-control endpoint protocol spec).
488
+ *
489
+ * All data endpoints inherit the security of the session established on
490
+ * {@link RMakerLocalCtrlEndpoint.SESSION}.
491
+ */
492
+ const RMakerLocalCtrlEndpoint = {
493
+ /** Protocomm session-security endpoint (SEC1 with/without PoP, or SEC2). */
494
+ SESSION: "rmaker_local_ctrl/session",
495
+ /** POST any payload; responds with the service info JSON (`sec_ver`, `cap`, …). */
496
+ VERSION: "rmaker_local_ctrl/version",
497
+ /** Reads the params JSON — protobuf `CmdGetData`, fragmented response. */
498
+ GET_PARAMS: "get_params",
499
+ /** Reads the node config JSON — protobuf `CmdGetData`, fragmented response. */
500
+ GET_CONFIG: "get_config",
501
+ /** Writes params — raw JSON request and response (no protobuf). */
502
+ SET_PARAMS: "set_params",
503
+ };
504
+ /**
505
+ * Root key of the JSON served by {@link RMakerLocalCtrlEndpoint.VERSION}, i.e.
506
+ * `{"rmaker_local_ctrl": {"ver": …, "sec_ver": …, "cap": [...]}}`. Passed to the
507
+ * local-control adapter so the native layer probes the right scheme version.
508
+ */
509
+ const RMAKER_LOCAL_CTRL_VERSION_KEY = "rmaker_local_ctrl";
510
+ /**
511
+ * Maximum fragment size (bytes) the firmware serves per `RespGetData`. Reads
512
+ * loop with `Offset += Payload.length` until `TotalLen` is reached; this value
513
+ * is informational (the device dictates the actual fragment length).
514
+ */
515
+ const RMAKER_LOCAL_CTRL_FRAGMENT_SIZE = 200;
516
+ /**
517
+ * `status` values in a `set_params` raw-JSON response.
518
+ */
519
+ const RMakerLocalCtrlSetParamsStatus = {
520
+ SUCCESS: "success",
521
+ FAIL: "fail",
522
+ };
523
+ /**
524
+ * mDNS TXT record keys advertised by the `_esp_rmaker_ctrl._tcp` service.
525
+ */
526
+ const RMakerLocalCtrlTxtKey = {
527
+ /** Node ID (also the service instance name and hostname). */
528
+ NODE_ID: "node_id",
529
+ /** Comma-separated active capabilities — see {@link RMakerLocalCtrlCapability}. */
530
+ CAP: "cap",
531
+ };
532
+ /**
533
+ * Capability tokens found in the `cap` TXT record. A node advertising only
534
+ * `ch_resp` is reachable for on-network user-node association but *not* for
535
+ * param control, so it must not be registered as a local control transport.
536
+ */
537
+ const RMakerLocalCtrlCapability = {
538
+ /** Params/config endpoints are registered. */
539
+ LOCAL_CTRL: "local_ctrl",
540
+ /** Challenge-response (on-network user-node association) is registered. */
541
+ CH_RESP: "ch_resp",
542
+ };
478
543
  /**
479
544
  * Assisted-claiming REST paths, on the deployment's main API and SigV4-signed
480
545
  * like every other `/v1/*` route.
@@ -632,8 +697,12 @@ const ProvErrorCodes = {
632
697
  * @enum {string}
633
698
  */
634
699
  const ServiceType = {
635
- /** Represents the ESP local control TCP service type. */
636
- ESP_LOCAL_CTRL_TCP: "_esp_local_ctrl._tcp.",
700
+ /**
701
+ * Service type advertised by RainMaker Neo firmware. A single instance serves
702
+ * the `rmaker_local_ctrl` endpoints; the `cap` TXT record says which endpoint
703
+ * sets are active. This is the default for local discovery in this SDK.
704
+ */
705
+ ESP_RMAKER_LOCAL_CTRL_TCP: "_esp_rmaker_ctrl._tcp.",
637
706
  };
638
707
  /**
639
708
  * An object containing protocol types.
@@ -847,6 +916,7 @@ exports.APIEndpoints = APIEndpoints;
847
916
  exports.APIOperations = APIOperations;
848
917
  exports.APIPathV1 = APIPathV1;
849
918
  exports.AWSCredentialsErrorMessages = AWSCredentialsErrorMessages;
919
+ exports.AssumeRoleErrorMessages = AssumeRoleErrorMessages;
850
920
  exports.AuthErrorCodes = AuthErrorCodes;
851
921
  exports.AuthSuccessMessages = AuthSuccessMessages;
852
922
  exports.AutomationStatusValues = AutomationStatusValues;
@@ -877,6 +947,12 @@ exports.NodeWarnMessages = NodeWarnMessages;
877
947
  exports.ProtocolType = ProtocolType;
878
948
  exports.ProvErrorCodes = ProvErrorCodes;
879
949
  exports.ProvisionType = ProvisionType;
950
+ exports.RMAKER_LOCAL_CTRL_FRAGMENT_SIZE = RMAKER_LOCAL_CTRL_FRAGMENT_SIZE;
951
+ exports.RMAKER_LOCAL_CTRL_VERSION_KEY = RMAKER_LOCAL_CTRL_VERSION_KEY;
952
+ exports.RMakerLocalCtrlCapability = RMakerLocalCtrlCapability;
953
+ exports.RMakerLocalCtrlEndpoint = RMakerLocalCtrlEndpoint;
954
+ exports.RMakerLocalCtrlSetParamsStatus = RMakerLocalCtrlSetParamsStatus;
955
+ exports.RMakerLocalCtrlTxtKey = RMakerLocalCtrlTxtKey;
880
956
  exports.SDK_VERSION = SDK_VERSION;
881
957
  exports.ScheduleErrorMessages = ScheduleErrorMessages;
882
958
  exports.ScheduleSuccessMessages = ScheduleSuccessMessages;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"constants.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -3,26 +3,70 @@
3
3
  var ESPDiscoveryManager = require('../services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js');
4
4
  var NodeUpdatesBus = require('../services/NodeUpdatesBus.js');
5
5
  var transport = require('../types/transport.js');
6
+ var constants = require('./constants.js');
6
7
 
7
8
  /*
8
9
  * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
9
10
  *
10
11
  * SPDX-License-Identifier: Apache-2.0
11
12
  */
12
- /** Maps a default local-discovery hit into the client-facing payload shape. */
13
+ /**
14
+ * Splits the mDNS `cap` TXT record (`"local_ctrl,ch_resp"`) into tokens.
15
+ * Returns `undefined` when the record is absent, which older firmware omits.
16
+ */
17
+ function parseCapabilities(txt) {
18
+ const raw = txt?.[constants.RMakerLocalCtrlTxtKey.CAP];
19
+ if (typeof raw !== "string")
20
+ return undefined;
21
+ const capabilities = raw
22
+ .split(",")
23
+ .map((capability) => capability.trim())
24
+ .filter(Boolean);
25
+ return capabilities.length ? capabilities : undefined;
26
+ }
27
+ /**
28
+ * Maps a default local-discovery hit into the client-facing payload shape.
29
+ *
30
+ * The `_esp_rmaker_ctrl._tcp` instance is also advertised by nodes that
31
+ * only serve challenge-response (on-network user-node association). Those are
32
+ * not reachable for param control, so a hit whose `cap` TXT record excludes
33
+ * `local_ctrl` maps to `undefined` and is dropped rather than registered as a
34
+ * local transport. A hit with no `cap` record is treated as control-capable.
35
+ *
36
+ * @param info - Raw adapter result (`nodeId`, `baseUrl`, and `txt` when the
37
+ * platform resolved TXT records).
38
+ * @returns The payload to deliver, or `undefined` to skip this hit.
39
+ */
13
40
  function toDiscoveredNodeData(info) {
41
+ const capabilities = parseCapabilities(info.txt);
42
+ if (capabilities &&
43
+ !capabilities.includes(constants.RMakerLocalCtrlCapability.LOCAL_CTRL)) {
44
+ return undefined;
45
+ }
14
46
  return {
15
47
  nodeId: info.nodeId,
16
48
  transportDetails: {
17
49
  type: transport.ESPTransportMode.local,
18
- metadata: { baseUrl: info.baseUrl },
50
+ metadata: {
51
+ baseUrl: info.baseUrl,
52
+ protocol: transport.ESPLocalControlProtocol.rmakerLocalCtrl,
53
+ ...(capabilities && { capabilities }),
54
+ },
19
55
  },
20
56
  };
21
57
  }
22
- /** Starts LAN discovery; each hit is mapped then passed to `onDiscovered`. */
58
+ /**
59
+ * Starts LAN discovery; each hit is mapped then passed to `onDiscovered`.
60
+ * Hits that are not control-capable (see {@link toDiscoveredNodeData}) are
61
+ * skipped.
62
+ */
23
63
  function startLocalDiscovery(onDiscovered) {
24
64
  const manager = new ESPDiscoveryManager.ESPDiscoveryManager();
25
- manager.startDiscovery((info) => onDiscovered(toDiscoveredNodeData(info)));
65
+ manager.startDiscovery((info) => {
66
+ const data = toDiscoveredNodeData(info);
67
+ if (data)
68
+ onDiscovered(data);
69
+ });
26
70
  return { stop: () => manager.stopDiscovery() };
27
71
  }
28
72
  /** Forwards process-wide node param updates to `onUpdate`. */
@@ -1 +1 @@
1
- {"version":3,"file":"eventSubscriptionUtils.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"eventSubscriptionUtils.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -28,7 +28,18 @@ async function readLocalNodeConfig(nodeId) {
28
28
  /** Best-effort persist of node config to local storage. */
29
29
  async function writeLocalNodeConfig(nodeId, config) {
30
30
  try {
31
- await ESPRMNeoStorage.ESPRMNeoStorage.setNodeConfig(nodeId, config);
31
+ let toStore = config;
32
+ // Cloud config omits connectivity — keep the last cached status when writing.
33
+ if (!config.connectivity_status) {
34
+ const prev = await ESPRMNeoStorage.ESPRMNeoStorage.getNodeConfig(nodeId);
35
+ if (prev?.connectivity_status) {
36
+ toStore = {
37
+ ...config,
38
+ connectivity_status: prev.connectivity_status,
39
+ };
40
+ }
41
+ }
42
+ await ESPRMNeoStorage.ESPRMNeoStorage.setNodeConfig(nodeId, toStore);
32
43
  }
33
44
  catch (error) {
34
45
  logger.warn(`Cache write failed for ${nodeId}`, error);
@@ -1 +1 @@
1
- {"version":3,"file":"nodeUtils.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"nodeUtils.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -65,11 +65,12 @@ function isNodeOnlineFromShadowPayload(payload) {
65
65
  * @throws {ESPProvError} If `timeoutMs` elapses without the node reporting online.
66
66
  * @throws {Error} If MQTT connection or subscription fails.
67
67
  */
68
- async function waitForNodeOnline({ nodeId, groupId, user, timeoutMs = DEFAULT_NODE_ONLINE_TIMEOUT_MS, pollIntervalMs = DEFAULT_NODE_ONLINE_POLL_INTERVAL_MS, }) {
69
- const shadowName = shadowUtils.constructShadowName(groupId);
68
+ async function waitForNodeOnline({ nodeId, groupId, subgroupIds, user, timeoutMs = DEFAULT_NODE_ONLINE_TIMEOUT_MS, pollIntervalMs = DEFAULT_NODE_ONLINE_POLL_INTERVAL_MS, }) {
69
+ const shadowName = shadowUtils.constructShadowName(groupId, subgroupIds ?? []);
70
70
  logger.info("Waiting for node to come online", {
71
71
  nodeId,
72
72
  groupId,
73
+ subgroupIds: subgroupIds ?? [],
73
74
  shadowName,
74
75
  timeoutMs,
75
76
  pollIntervalMs,
@@ -149,10 +150,10 @@ async function waitForNodeOnline({ nodeId, groupId, user, timeoutMs = DEFAULT_NO
149
150
  });
150
151
  await user.connectMQTT();
151
152
  }
152
- // 2. Register (if needed) and subscribe before the shadow may exist
153
- if (!alreadyRegistered) {
154
- NodeMQTTOrchestrator.NodeMQTTOrchestrator.registerNode(nodeId, shadowName);
155
- }
153
+ // 2. Bind to the membership shadow and subscribe before the shadow may exist.
154
+ // Always registerNode so a leftover longer/stale binding for the same nodeId
155
+ // is rebound to constructShadowName(groupId, subgroupIds).
156
+ NodeMQTTOrchestrator.NodeMQTTOrchestrator.registerNode(nodeId, shadowName);
156
157
  await NodeMQTTOrchestrator.NodeMQTTOrchestrator.subscribeToNode(nodeId, onUpdate);
157
158
  logger.debug("Subscribed to node shadow for online wait", {
158
159
  nodeId,
@@ -1 +1 @@
1
- {"version":3,"file":"waitForNodeOnline.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"waitForNodeOnline.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -22,6 +22,12 @@ class ESPDevice {
22
22
  name;
23
23
  transport;
24
24
  security;
25
+ /**
26
+ * What a completed association produced, kept so `retryNetworkCredentials`
27
+ * can resume the flow instead of repeating it. Set once verification
28
+ * succeeds; `undefined` until then.
29
+ */
30
+ provisionResumeState;
25
31
  constructor(deviceConfig) {
26
32
  this.name = deviceConfig.name;
27
33
  this.transport = deviceConfig.transport;
@@ -1 +1 @@
1
- {"version":3,"file":"ESPDevice.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"ESPDevice.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -183,7 +183,7 @@ class ESPRMNeoBase {
183
183
  }
184
184
  /**
185
185
  * Sets the local control adapter used to talk to nodes over the LAN via
186
- * the `esp_local_ctrl` protocol.
186
+ * the `rmaker_local_ctrl` protocol.
187
187
  *
188
188
  * @param adapter - Adapter implementing {@link ESPLocalControlAdapterInterface}.
189
189
  * @throws {Error} If the SDK is not initialized or the adapter is invalid.
@@ -38,14 +38,19 @@ class ESPRMNeoNode {
38
38
  subgroupIds = [];
39
39
  devices = [];
40
40
  services = [];
41
+ /**
42
+ * Last-known connectivity. Seeded from cached `connectivity_status` when
43
+ * present (cloud config does not provide it); otherwise starts offline until
44
+ * an MQTT shadow `online` update arrives.
45
+ */
41
46
  connectivityStatus = {
42
47
  isConnected: false,
43
48
  lastConnectionTimestamp: 0,
44
49
  };
45
50
  /**
46
51
  * Transports currently usable for this node, keyed by mode.
47
- * - `mqtt` (cloud) is added when the node reports online and removed when
48
- * it goes offline (via shadow updates or seeded `connectivity_status`).
52
+ * - `mqtt` (cloud) is added when the node is connected and removed when it
53
+ * goes offline (from cached `connectivity_status` or shadow updates).
49
54
  * - `local` is added/removed at runtime by a `localDiscovery` subscriber as the
50
55
  * node appears/disappears on the LAN (via {@link addTransport}/{@link removeTransport}).
51
56
  * Apps may also add custom string-keyed entries (pair with
@@ -78,16 +83,11 @@ class ESPRMNeoNode {
78
83
  this.subgroupIds = asStringArray(subgroupIdOrIds);
79
84
  this.transportOrder = ESPRMNeoBase.getTransportOrder();
80
85
  this.availableTransports = {};
81
- this.applyNodeConfig(config);
82
86
  if (config.connectivity_status) {
83
87
  this.connectivityStatus = config.connectivity_status;
84
88
  }
85
- if (this.connectivityStatus.isConnected) {
86
- this.addTransport(ESPTransportMode.mqtt, {
87
- type: ESPTransportMode.mqtt,
88
- metadata: {},
89
- });
90
- }
89
+ this.applyNodeConfig(config);
90
+ this.syncMqttTransportAvailability();
91
91
  this.subscribeToMqttUpdates();
92
92
  }
93
93
  /**
@@ -167,11 +167,14 @@ class ESPRMNeoNode {
167
167
  this.devices = deviceRecords.map((d) => new ESPRMNeoDevice(transformNodeDevice(d), nodeRef));
168
168
  this.services = serviceRecords.map((s) => new ESPRMNeoService(transformNodeService(s), nodeRef));
169
169
  // Keep wire records for cache writes (never persist live class instances).
170
+ // Preserve last-known connectivity when the incoming config omits it
171
+ // (cloud node config does not include connectivity_status).
170
172
  this.wireConfig = {
171
173
  ...config,
172
174
  info,
173
175
  devices: deviceRecords,
174
176
  services: serviceRecords,
177
+ connectivity_status: config.connectivity_status ?? this.connectivityStatus,
175
178
  };
176
179
  this.config = {
177
180
  ...config,
@@ -241,19 +244,27 @@ class ESPRMNeoNode {
241
244
  this.wireConfig.params = this.config.params;
242
245
  }
243
246
  this.applyConnectivityStatus(shadow, connectivityStatus);
244
- ESPRMNeoStorage.setItem(StorageKeys.NODE_CONFIG_PREFIX + this.nodeId, JSON.stringify({ ...this.wireConfig, node_id: this.nodeId }));
247
+ this.persistWireConfig();
245
248
  this.refreshConfigIfNcfgChanged(shadow);
246
249
  }
247
250
  /**
248
- * Updates {@link connectivityStatus} and MQTT transport availability when the
249
- * shadow reports `online`. Partial updates without `online` are ignored so
250
- * an existing status is not cleared.
251
+ * Updates {@link connectivityStatus} when the shadow reports `online`, then
252
+ * syncs MQTT transport availability. Partial updates without `online` are
253
+ * ignored so an existing status is not cleared.
251
254
  */
252
255
  applyConnectivityStatus(shadow, connectivityStatus) {
253
256
  if (shadow.state?.reported?.online === undefined)
254
257
  return;
255
258
  this.connectivityStatus = connectivityStatus;
256
- if (connectivityStatus.isConnected) {
259
+ this.wireConfig.connectivity_status = connectivityStatus;
260
+ this.syncMqttTransportAvailability();
261
+ }
262
+ /**
263
+ * Registers the MQTT transport only while {@link connectivityStatus} reports
264
+ * the node as connected; removes it when offline.
265
+ */
266
+ syncMqttTransportAvailability() {
267
+ if (this.connectivityStatus.isConnected) {
257
268
  this.addTransport(ESPTransportMode.mqtt, {
258
269
  type: ESPTransportMode.mqtt,
259
270
  metadata: {},
@@ -263,6 +274,14 @@ class ESPRMNeoNode {
263
274
  this.removeTransport(ESPTransportMode.mqtt);
264
275
  }
265
276
  }
277
+ /** Persists {@link wireConfig} (including last-known connectivity) to storage. */
278
+ persistWireConfig() {
279
+ ESPRMNeoStorage.setItem(StorageKeys.NODE_CONFIG_PREFIX + this.nodeId, JSON.stringify({
280
+ ...this.wireConfig,
281
+ node_id: this.nodeId,
282
+ connectivity_status: this.connectivityStatus,
283
+ }));
284
+ }
266
285
  /** When cloud `ncfg_ver` changes, refetch config and persist the new marker. */
267
286
  async refreshConfigIfNcfgChanged(shadow) {
268
287
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"ESPRMNeoNode.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"ESPRMNeoNode.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/esm/index.js CHANGED
@@ -15,7 +15,7 @@ export { ESPDevice } from './ESPDevice.js';
15
15
  export { ESPDiscoveryProtocol, ESPRMNeoEventType } from './types/discovery.js';
16
16
  export { ESPClaimStatus, ESPConnectStatus, ESPProvResponseStatus, ESPProvisionStatus, ESPSecurity, ESPTransport } from './types/provision.js';
17
17
  export { resolveNodeId } from './types/subscription.js';
18
- export { DEFAULT_TRANSPORT_ORDER, ESPTransportMode } from './types/transport.js';
18
+ export { DEFAULT_LOCAL_CONTROL_PROTOCOL, DEFAULT_TRANSPORT_ORDER, ESPLocalControlProtocol, ESPTransportMode } from './types/transport.js';
19
19
  import './methods/ESPRMNeoAuth/ChangePassword.js';
20
20
  import './methods/ESPRMNeoAuth/ConfirmSignUp.js';
21
21
  import './methods/ESPRMNeoAuth/ForgotPassword.js';
@@ -102,6 +102,8 @@ import './methods/ESPDevice/SetProofOfPossession.js';
102
102
  import './methods/ESPDevice/SendData.js';
103
103
  import './methods/ESPDevice/InitializeSession.js';
104
104
  import './methods/ESPDevice/SetNetworkCredentials.js';
105
+ import './methods/ESPDevice/ResetWifiStatus.js';
106
+ import './methods/ESPDevice/RetryNetworkCredentials.js';
105
107
  import './methods/ESPDevice/InitiateUserNodeMapping.js';
106
108
  import './methods/ESPDevice/VerifyUserNodeMapping.js';
107
109
  import './methods/ESPDevice/StartAssistedClaiming.js';
@@ -109,7 +111,7 @@ export { buildGroupControlParamsTopic, buildRainMakerUserParamsTopic, buildShado
109
111
  export { coerceToFiniteNumber, coerceToNonEmptyString, coerceToString } from './utils/coerce.js';
110
112
  export { buildCanonicalQueryString, createAuthorizationHeader, generateIotDeviceGatewayMqttSignedUrl, generateSigV4AuthHeader } from './utils/awsSigv4Utils.js';
111
113
  export { buildMainApiUrl, buildUserCredentialsUrl, ensureValidIdToken, extractTemporaryCredentials, isExpiredTokenAuthError, parseCredentialsErrorMessage, postUserCredentials, refreshUserSession } from './utils/awsUtils.js';
112
- export { APICallValidationErrorCodes, APIEndpoints, APIOperations, APIPathV1, AWSCredentialsErrorMessages, AuthErrorCodes, AuthSuccessMessages, AutomationStatusValues, AutomationSuccessMessages, CLAIM_CSR_MAX_CHUNKS, CLAIM_DEVICE_CSR_KEYS, CLAIM_DEVICE_MAC_KEYS, CLAIM_MAC_HEX_LENGTHS, CLAIM_MAC_SEPARATORS, CLAIM_MAX_FRAGMENT_SIZE, ClaimCapabilities, ClaimCapabilityPolicies, ClaimEndpoints, ClaimErrorCodes, ClaimProgressMessages, ConfigErrorCodes, DEFAULT_REST_API_VERSION, ESPProvProgressMessages, ESPRMNeoErrorCodes, ESPRMNeoStorageKeys, ESPServiceParamType, ESPServiceType, Endpoint, ErrorLabels, GroupSuccessMessages, GroupUserAliases, HTTPMethods, IntegrationSuccessMessages, NodeSuccessMessages, NodeWarnMessages, ProtocolType, ProvErrorCodes, ProvisionType, SDK_VERSION, ScheduleErrorMessages, ScheduleSuccessMessages, ServiceType, SharingSuccessMessages, StatusMessage, StorageAdapterErrorCodes, StorageKeys, SubscriptionChannelIds, TokenErrorCodes, TriggerErrorMessages, TriggerSuccessMessages, ValidationErrorCodes } from './utils/constants.js';
114
+ export { APICallValidationErrorCodes, APIEndpoints, APIOperations, APIPathV1, AWSCredentialsErrorMessages, AssumeRoleErrorMessages, AuthErrorCodes, AuthSuccessMessages, AutomationStatusValues, AutomationSuccessMessages, CLAIM_CSR_MAX_CHUNKS, CLAIM_DEVICE_CSR_KEYS, CLAIM_DEVICE_MAC_KEYS, CLAIM_MAC_HEX_LENGTHS, CLAIM_MAC_SEPARATORS, CLAIM_MAX_FRAGMENT_SIZE, ClaimCapabilities, ClaimCapabilityPolicies, ClaimEndpoints, ClaimErrorCodes, ClaimProgressMessages, ConfigErrorCodes, DEFAULT_REST_API_VERSION, ESPProvProgressMessages, ESPRMNeoErrorCodes, ESPRMNeoStorageKeys, ESPServiceParamType, ESPServiceType, Endpoint, ErrorLabels, GroupSuccessMessages, GroupUserAliases, HTTPMethods, IntegrationSuccessMessages, NodeSuccessMessages, NodeWarnMessages, ProtocolType, ProvErrorCodes, ProvisionType, RMAKER_LOCAL_CTRL_FRAGMENT_SIZE, RMAKER_LOCAL_CTRL_VERSION_KEY, RMakerLocalCtrlCapability, RMakerLocalCtrlEndpoint, RMakerLocalCtrlSetParamsStatus, RMakerLocalCtrlTxtKey, SDK_VERSION, ScheduleErrorMessages, ScheduleSuccessMessages, ServiceType, SharingSuccessMessages, StatusMessage, StorageAdapterErrorCodes, StorageKeys, SubscriptionChannelIds, TokenErrorCodes, TriggerErrorMessages, TriggerSuccessMessages, ValidationErrorCodes } from './utils/constants.js';
113
115
  export { LogLevel, Logger } from './utils/logger.js';
114
116
  export { concurrentFetchPool } from './utils/mapLimit.js';
115
117
  export { EventEmitter } from './utils/eventEmitter.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -65,6 +65,13 @@ async function runChallengeResponseFlow(device, ssid, passphrase, groupId, onPro
65
65
  challenge_response: signedChallenge,
66
66
  node_id: nodeId,
67
67
  });
68
+ // Association is verified and cannot be repeated; remember what step 6 needs
69
+ // so `retryNetworkCredentials` can resume from the Wi-Fi step.
70
+ device.provisionResumeState = {
71
+ nodeId: nodeId,
72
+ groupId,
73
+ options: options,
74
+ };
68
75
  // 5. SET NETWORK CREDENTIALS
69
76
  reportProgress(onProgress, ESPProvResponseStatus.onProgress, ESPProvProgressMessages.SETTING_NETWORK_CREDENTIALS);
70
77
  await device.setNetworkCredentials(ssid, passphrase);
@@ -1 +1 @@
1
- {"version":3,"file":"Provision.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"Provision.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,24 @@
1
+ import { ESPDevice } from '../../ESPDevice.js';
2
+ import { Logger } from '../../utils/logger.js';
3
+
4
+ /*
5
+ * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
6
+ *
7
+ * SPDX-License-Identifier: Apache-2.0
8
+ */
9
+ const logger = new Logger("ResetWifiStatus");
10
+ ESPDevice.prototype.resetWifiStatus = async function () {
11
+ if (!this.ESPProvisionAdapter.resetWifiStatus) {
12
+ logger.warn(`Adapter has no resetWifiStatus; treating as not acknowledged for "${this.name}"`);
13
+ return false;
14
+ }
15
+ try {
16
+ const acknowledged = await this.ESPProvisionAdapter.resetWifiStatus(this.name);
17
+ return acknowledged;
18
+ }
19
+ catch (error) {
20
+ logger.error(`<- device "${this.name}": reset failed`, error);
21
+ throw error;
22
+ }
23
+ };
24
+ //# sourceMappingURL=ResetWifiStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResetWifiStatus.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;"}