@enyo-energy/sunspec-sdk 0.0.28 → 0.0.30

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.
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /**
3
+ * Connection Retry Manager with Exponential Backoff
4
+ *
5
+ * Manages automatic connection retries with configurable exponential backoff.
6
+ * Backoff sequence (with defaults): 1s → 1.5s → 2.25s → 3.375s → 5.06s → 7.59s → 11.39s → 17.09s → 25.63s → 30s (capped)
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ConnectionRetryManager = void 0;
10
+ const sunspec_interfaces_js_1 = require("./sunspec-interfaces.cjs");
11
+ class ConnectionRetryManager {
12
+ config;
13
+ currentAttempt = 0;
14
+ pendingRetryTimeout = null;
15
+ isRetrying = false;
16
+ constructor(config) {
17
+ this.config = { ...sunspec_interfaces_js_1.DEFAULT_RETRY_CONFIG, ...config };
18
+ }
19
+ /**
20
+ * Calculate the next delay using exponential backoff
21
+ * Formula: min(initialDelayMs * backoffFactor^attempt, maxDelayMs)
22
+ */
23
+ getNextDelay() {
24
+ const delay = this.config.initialDelayMs * Math.pow(this.config.backoffFactor, this.currentAttempt);
25
+ return Math.min(delay, this.config.maxDelayMs);
26
+ }
27
+ /**
28
+ * Reset the retry state on successful connection
29
+ */
30
+ reset() {
31
+ this.currentAttempt = 0;
32
+ this.isRetrying = false;
33
+ this.cancelPendingRetry();
34
+ }
35
+ /**
36
+ * Check if we should retry based on max attempts
37
+ * Returns true if we haven't exceeded maxAttempts or if maxAttempts is -1 (infinite)
38
+ */
39
+ shouldRetry() {
40
+ if (this.config.maxAttempts === -1) {
41
+ return true;
42
+ }
43
+ return this.currentAttempt < this.config.maxAttempts;
44
+ }
45
+ /**
46
+ * Get the current attempt number (0-indexed)
47
+ */
48
+ getCurrentAttempt() {
49
+ return this.currentAttempt;
50
+ }
51
+ /**
52
+ * Get the max attempts configuration
53
+ */
54
+ getMaxAttempts() {
55
+ return this.config.maxAttempts;
56
+ }
57
+ /**
58
+ * Check if a retry is currently in progress
59
+ */
60
+ isRetryInProgress() {
61
+ return this.isRetrying;
62
+ }
63
+ /**
64
+ * Schedule a reconnection attempt with exponential backoff delay
65
+ * Returns a promise that resolves when the callback completes
66
+ */
67
+ async scheduleRetry(callback) {
68
+ if (!this.shouldRetry()) {
69
+ console.log(`Max retry attempts (${this.config.maxAttempts}) reached. Giving up.`);
70
+ return false;
71
+ }
72
+ if (this.isRetrying) {
73
+ console.log('Retry already in progress, skipping duplicate request.');
74
+ return false;
75
+ }
76
+ this.isRetrying = true;
77
+ const delay = this.getNextDelay();
78
+ const attemptNumber = this.currentAttempt + 1;
79
+ const maxAttemptsStr = this.config.maxAttempts === -1 ? '∞' : this.config.maxAttempts.toString();
80
+ console.log(`Scheduling reconnection attempt ${attemptNumber}/${maxAttemptsStr} in ${delay}ms`);
81
+ return new Promise((resolve) => {
82
+ this.pendingRetryTimeout = setTimeout(async () => {
83
+ this.pendingRetryTimeout = null;
84
+ this.currentAttempt++;
85
+ try {
86
+ console.log(`Attempting reconnection (attempt ${attemptNumber}/${maxAttemptsStr})...`);
87
+ const success = await callback();
88
+ if (success) {
89
+ console.log('Reconnection successful!');
90
+ this.reset();
91
+ resolve(true);
92
+ }
93
+ else {
94
+ console.log('Reconnection attempt failed.');
95
+ this.isRetrying = false;
96
+ resolve(false);
97
+ }
98
+ }
99
+ catch (error) {
100
+ console.error(`Reconnection attempt failed with error: ${error}`);
101
+ this.isRetrying = false;
102
+ resolve(false);
103
+ }
104
+ }, delay);
105
+ });
106
+ }
107
+ /**
108
+ * Cancel any pending retry attempt
109
+ */
110
+ cancelPendingRetry() {
111
+ if (this.pendingRetryTimeout) {
112
+ clearTimeout(this.pendingRetryTimeout);
113
+ this.pendingRetryTimeout = null;
114
+ this.isRetrying = false;
115
+ console.log('Pending retry cancelled.');
116
+ }
117
+ }
118
+ /**
119
+ * Get the current configuration
120
+ */
121
+ getConfig() {
122
+ return { ...this.config };
123
+ }
124
+ }
125
+ exports.ConnectionRetryManager = ConnectionRetryManager;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Connection Retry Manager with Exponential Backoff
3
+ *
4
+ * Manages automatic connection retries with configurable exponential backoff.
5
+ * Backoff sequence (with defaults): 1s → 1.5s → 2.25s → 3.375s → 5.06s → 7.59s → 11.39s → 17.09s → 25.63s → 30s (capped)
6
+ */
7
+ import { IRetryConfig } from './sunspec-interfaces.cjs';
8
+ export declare class ConnectionRetryManager {
9
+ private config;
10
+ private currentAttempt;
11
+ private pendingRetryTimeout;
12
+ private isRetrying;
13
+ constructor(config?: Partial<IRetryConfig>);
14
+ /**
15
+ * Calculate the next delay using exponential backoff
16
+ * Formula: min(initialDelayMs * backoffFactor^attempt, maxDelayMs)
17
+ */
18
+ getNextDelay(): number;
19
+ /**
20
+ * Reset the retry state on successful connection
21
+ */
22
+ reset(): void;
23
+ /**
24
+ * Check if we should retry based on max attempts
25
+ * Returns true if we haven't exceeded maxAttempts or if maxAttempts is -1 (infinite)
26
+ */
27
+ shouldRetry(): boolean;
28
+ /**
29
+ * Get the current attempt number (0-indexed)
30
+ */
31
+ getCurrentAttempt(): number;
32
+ /**
33
+ * Get the max attempts configuration
34
+ */
35
+ getMaxAttempts(): number;
36
+ /**
37
+ * Check if a retry is currently in progress
38
+ */
39
+ isRetryInProgress(): boolean;
40
+ /**
41
+ * Schedule a reconnection attempt with exponential backoff delay
42
+ * Returns a promise that resolves when the callback completes
43
+ */
44
+ scheduleRetry(callback: () => Promise<boolean>): Promise<boolean>;
45
+ /**
46
+ * Cancel any pending retry attempt
47
+ */
48
+ cancelPendingRetry(): void;
49
+ /**
50
+ * Get the current configuration
51
+ */
52
+ getConfig(): IRetryConfig;
53
+ }
@@ -14,10 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.getSdkVersion = exports.SDK_VERSION = void 0;
17
+ exports.getSdkVersion = exports.SDK_VERSION = exports.ConnectionRetryManager = void 0;
18
18
  __exportStar(require("./sunspec-interfaces.cjs"), exports);
19
19
  __exportStar(require("./sunspec-devices.cjs"), exports);
20
20
  __exportStar(require("./sunspec-modbus-client.cjs"), exports);
21
+ var connection_retry_manager_js_1 = require("./connection-retry-manager.cjs");
22
+ Object.defineProperty(exports, "ConnectionRetryManager", { enumerable: true, get: function () { return connection_retry_manager_js_1.ConnectionRetryManager; } });
21
23
  var version_js_1 = require("./version.cjs");
22
24
  Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return version_js_1.SDK_VERSION; } });
23
25
  Object.defineProperty(exports, "getSdkVersion", { enumerable: true, get: function () { return version_js_1.getSdkVersion; } });
@@ -1,4 +1,5 @@
1
1
  export * from './sunspec-interfaces.cjs';
2
2
  export * from './sunspec-devices.cjs';
3
3
  export * from './sunspec-modbus-client.cjs';
4
+ export { ConnectionRetryManager } from './connection-retry-manager.cjs';
4
5
  export { SDK_VERSION, getSdkVersion } from './version.cjs';
@@ -31,15 +31,19 @@ class BaseSunspecDevice {
31
31
  sunspecClient;
32
32
  applianceManager;
33
33
  unitId;
34
+ port;
35
+ baseAddress;
34
36
  applianceId;
35
37
  lastUpdateTime = 0;
36
- constructor(energyApp, name, networkDevice, sunspecClient, applianceManager, unitId = 1) {
38
+ constructor(energyApp, name, networkDevice, sunspecClient, applianceManager, unitId = 1, port = 502, baseAddress = 40000) {
37
39
  this.energyApp = energyApp;
38
40
  this.name = name;
39
41
  this.networkDevice = networkDevice;
40
42
  this.sunspecClient = sunspecClient;
41
43
  this.applianceManager = applianceManager;
42
44
  this.unitId = unitId;
45
+ this.port = port;
46
+ this.baseAddress = baseAddress;
43
47
  }
44
48
  /**
45
49
  * Check if the device is connected
@@ -55,8 +59,10 @@ class BaseSunspecDevice {
55
59
  */
56
60
  async ensureConnected() {
57
61
  if (!this.sunspecClient.isConnected()) {
58
- await this.sunspecClient.connect(this.networkDevice.ipAddress, 502, this.unitId);
59
- await this.sunspecClient.discoverModels();
62
+ await this.sunspecClient.connect(this.networkDevice.hostname, // primary
63
+ this.port, this.unitId, this.networkDevice.ipAddress // secondary fallback
64
+ );
65
+ await this.sunspecClient.discoverModels(this.baseAddress);
60
66
  }
61
67
  }
62
68
  }
@@ -68,8 +74,10 @@ class SunspecInverter extends BaseSunspecDevice {
68
74
  async connect() {
69
75
  // Ensure Sunspec client is connected
70
76
  if (!this.sunspecClient.isConnected()) {
71
- await this.sunspecClient.connect(this.networkDevice.ipAddress, 502, this.unitId);
72
- await this.sunspecClient.discoverModels();
77
+ await this.sunspecClient.connect(this.networkDevice.hostname, // primary
78
+ this.port, this.unitId, this.networkDevice.ipAddress // secondary fallback
79
+ );
80
+ await this.sunspecClient.discoverModels(this.baseAddress);
73
81
  }
74
82
  // Get device info from common block
75
83
  const commonData = await this.sunspecClient.readCommonBlock();
@@ -241,6 +249,8 @@ exports.SunspecInverter = SunspecInverter;
241
249
  * Sunspec Battery implementation
242
250
  */
243
251
  class SunspecBattery extends BaseSunspecDevice {
252
+ dataBusListenerId;
253
+ dataBus;
244
254
  /**
245
255
  * Connect to the battery and create/update the appliance
246
256
  */
@@ -284,12 +294,14 @@ class SunspecBattery extends BaseSunspecDevice {
284
294
  }
285
295
  });
286
296
  console.log(`Sunspec Battery connected: ${this.networkDevice.hostname} (${this.applianceId})`);
297
+ this.startDataBusListening();
287
298
  }
288
299
  catch (error) {
289
300
  console.error(`Failed to create battery appliance: ${error}`);
290
301
  }
291
302
  }
292
303
  async disconnect() {
304
+ this.stopDataBusListening();
293
305
  if (this.applianceId) {
294
306
  await this.applianceManager.updateApplianceState(this.applianceId, enyo_appliance_js_1.EnyoApplianceConnectionType.Connector, enyo_appliance_js_1.EnyoApplianceStateEnum.Offline);
295
307
  }
@@ -558,6 +570,155 @@ class SunspecBattery extends BaseSunspecDevice {
558
570
  }
559
571
  return controls.chaGriSet === 1; // 1 = GRID, 0 = PV
560
572
  }
573
+ /**
574
+ * Start listening for storage commands on the data bus.
575
+ * Idempotent — does nothing if already listening.
576
+ */
577
+ startDataBusListening() {
578
+ if (this.dataBusListenerId) {
579
+ return;
580
+ }
581
+ this.dataBus = this.energyApp.useDataBus();
582
+ this.dataBusListenerId = this.dataBus.listenForMessages([
583
+ enyo_data_bus_value_js_1.EnyoDataBusMessageEnum.StartStorageGridChargeV1,
584
+ enyo_data_bus_value_js_1.EnyoDataBusMessageEnum.StopStorageGridChargeV1,
585
+ enyo_data_bus_value_js_1.EnyoDataBusMessageEnum.SetStorageDischargeLimitV1
586
+ ], (entry) => this.handleStorageCommand(entry));
587
+ console.log(`Battery ${this.applianceId}: started data bus listening (listener ${this.dataBusListenerId})`);
588
+ }
589
+ /**
590
+ * Stop listening for storage commands on the data bus.
591
+ */
592
+ stopDataBusListening() {
593
+ if (this.dataBusListenerId && this.dataBus) {
594
+ this.dataBus.unsubscribe(this.dataBusListenerId);
595
+ console.log(`Battery ${this.applianceId}: stopped data bus listening (listener ${this.dataBusListenerId})`);
596
+ }
597
+ this.dataBusListenerId = undefined;
598
+ this.dataBus = undefined;
599
+ }
600
+ handleStorageCommand(entry) {
601
+ if (entry.applianceId !== this.applianceId) {
602
+ return;
603
+ }
604
+ void (async () => {
605
+ try {
606
+ switch (entry.message) {
607
+ case enyo_data_bus_value_js_1.EnyoDataBusMessageEnum.StartStorageGridChargeV1:
608
+ await this.handleStartGridCharge(entry);
609
+ break;
610
+ case enyo_data_bus_value_js_1.EnyoDataBusMessageEnum.StopStorageGridChargeV1:
611
+ await this.handleStopGridCharge(entry);
612
+ break;
613
+ case enyo_data_bus_value_js_1.EnyoDataBusMessageEnum.SetStorageDischargeLimitV1:
614
+ await this.handleSetDischargeLimit(entry);
615
+ break;
616
+ }
617
+ }
618
+ catch (error) {
619
+ console.error(`Battery ${this.applianceId}: error handling ${entry.message}:`, error);
620
+ }
621
+ })();
622
+ }
623
+ async handleStartGridCharge(msg) {
624
+ if (!this.isConnected() || !this.applianceId) {
625
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Rejected, "Not connected");
626
+ return;
627
+ }
628
+ console.log(`Battery ${this.applianceId}: handling StartStorageGridChargeV1 (powerLimitW=${msg.data.powerLimitW})`);
629
+ // Read current state for logging and rollback
630
+ const controls = await this.getBatteryControls();
631
+ console.log(`Battery ${this.applianceId}: current state - chaGriSet=${controls?.chaGriSet}, wChaMax=${controls?.wChaMax}, storCtlMod=${controls?.storCtlMod}`);
632
+ const originalChaGriSet = controls?.chaGriSet;
633
+ const originalWChaMax = controls?.wChaMax;
634
+ // Step 1: Enable grid charging (Register 17: chaGriSet=GRID)
635
+ const step1 = await this.enableGridCharging(true);
636
+ if (!step1) {
637
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Rejected, 'Failed to enable grid charging');
638
+ return;
639
+ }
640
+ // Step 2: Set charging power (Register 2: wChaMax)
641
+ const step2 = await this.setChargingPower(msg.data.powerLimitW);
642
+ if (!step2) {
643
+ // Rollback step 1
644
+ await this.writeBatteryControls({ chaGriSet: originalChaGriSet });
645
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Rejected, 'Failed to set charging power');
646
+ return;
647
+ }
648
+ // Step 3: Set storage mode to CHARGE (Register 5: storCtlMod=0x0001)
649
+ const step3 = await this.setStorageMode(sunspec_interfaces_js_1.SunspecStorageMode.CHARGE);
650
+ if (!step3) {
651
+ // Rollback steps 1+2
652
+ await this.writeBatteryControls({ chaGriSet: originalChaGriSet, wChaMax: originalWChaMax });
653
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Rejected, 'Failed to set storage mode to charge');
654
+ return;
655
+ }
656
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Accepted);
657
+ }
658
+ async handleStopGridCharge(msg) {
659
+ if (!this.isConnected() || !this.applianceId) {
660
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.NotSupported);
661
+ return;
662
+ }
663
+ console.log(`Battery ${this.applianceId}: handling StopStorageGridChargeV1`);
664
+ // Read current state for logging and rollback
665
+ const controls = await this.getBatteryControls();
666
+ console.log(`Battery ${this.applianceId}: current state - chaGriSet=${controls?.chaGriSet}, storCtlMod=${controls?.storCtlMod}`);
667
+ const originalChaGriSet = controls?.chaGriSet;
668
+ // Step 1: Disable grid charging (Register 17: chaGriSet=PV)
669
+ const step1 = await this.enableGridCharging(false);
670
+ if (!step1) {
671
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Rejected, 'Failed to disable grid charging');
672
+ return;
673
+ }
674
+ // Step 2: Set storage mode to AUTO (Register 5: storCtlMod=0x0003)
675
+ const step2 = await this.setStorageMode(sunspec_interfaces_js_1.SunspecStorageMode.AUTO);
676
+ if (!step2) {
677
+ // Rollback step 1
678
+ await this.writeBatteryControls({ chaGriSet: originalChaGriSet });
679
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Rejected, 'Failed to set storage mode to auto');
680
+ return;
681
+ }
682
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Accepted);
683
+ }
684
+ async handleSetDischargeLimit(msg) {
685
+ if (!this.isConnected() || !this.applianceId) {
686
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.NotSupported);
687
+ return;
688
+ }
689
+ console.log(`Battery ${this.applianceId}: handling SetStorageDischargeLimitV1 (dischargeLimitPercent=${msg.data.dischargeLimitPercent})`);
690
+ // Read current state for logging
691
+ const controls = await this.getBatteryControls();
692
+ console.log(`Battery ${this.applianceId}: current state - outWRte=${controls?.outWRte}`);
693
+ // Set discharge limit (Register 12: outWRte)
694
+ const success = await this.writeBatteryControls({ outWRte: msg.data.dischargeLimitPercent });
695
+ if (!success) {
696
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Rejected, 'Failed to set discharge limit');
697
+ return;
698
+ }
699
+ this.sendCommandAcknowledge(msg.id, msg.message, enyo_data_bus_value_js_1.EnyoCommandAcknowledgeAnswerEnum.Accepted);
700
+ }
701
+ sendCommandAcknowledge(messageId, acknowledgeMessage, answer, rejectionReason) {
702
+ if (!this.dataBus || !this.applianceId) {
703
+ return;
704
+ }
705
+ const ackMessage = {
706
+ id: (0, node_crypto_1.randomUUID)(),
707
+ message: enyo_data_bus_value_js_1.EnyoDataBusMessageEnum.CommandAcknowledgeV1,
708
+ type: 'answer',
709
+ source: enyo_source_enum_js_1.EnyoSourceEnum.Device,
710
+ applianceId: this.applianceId,
711
+ timestampIso: new Date().toISOString(),
712
+ data: {
713
+ messageId,
714
+ acknowledgeMessage,
715
+ answer,
716
+ rejectionReason
717
+ }
718
+ };
719
+ console.log(`Battery ${this.applianceId}: sending ${answer} for ${acknowledgeMessage} (messageId=${messageId}${rejectionReason ? `, reason=${rejectionReason}` : ''})`);
720
+ this.dataBus.sendMessage([ackMessage]);
721
+ }
561
722
  }
562
723
  exports.SunspecBattery = SunspecBattery;
563
724
  /**
@@ -14,9 +14,11 @@ export declare abstract class BaseSunspecDevice {
14
14
  protected readonly sunspecClient: SunspecModbusClient;
15
15
  protected readonly applianceManager: ApplianceManager;
16
16
  protected readonly unitId: number;
17
+ protected readonly port: number;
18
+ protected readonly baseAddress: number;
17
19
  protected applianceId?: string;
18
20
  protected lastUpdateTime: number;
19
- constructor(energyApp: EnergyApp, name: EnyoApplianceName[], networkDevice: EnyoNetworkDevice, sunspecClient: SunspecModbusClient, applianceManager: ApplianceManager, unitId?: number);
21
+ constructor(energyApp: EnergyApp, name: EnyoApplianceName[], networkDevice: EnyoNetworkDevice, sunspecClient: SunspecModbusClient, applianceManager: ApplianceManager, unitId?: number, port?: number, baseAddress?: number);
20
22
  /**
21
23
  * Connect to the device and create/update the appliance
22
24
  */
@@ -62,6 +64,8 @@ export declare class SunspecInverter extends BaseSunspecDevice {
62
64
  * Sunspec Battery implementation
63
65
  */
64
66
  export declare class SunspecBattery extends BaseSunspecDevice {
67
+ private dataBusListenerId?;
68
+ private dataBus?;
65
69
  /**
66
70
  * Connect to the battery and create/update the appliance
67
71
  */
@@ -150,6 +154,20 @@ export declare class SunspecBattery extends BaseSunspecDevice {
150
154
  * @returns Promise<boolean | null> - true if enabled, false if disabled, null if error
151
155
  */
152
156
  isGridChargingEnabled(): Promise<boolean | null>;
157
+ /**
158
+ * Start listening for storage commands on the data bus.
159
+ * Idempotent — does nothing if already listening.
160
+ */
161
+ startDataBusListening(): void;
162
+ /**
163
+ * Stop listening for storage commands on the data bus.
164
+ */
165
+ stopDataBusListening(): void;
166
+ private handleStorageCommand;
167
+ private handleStartGridCharge;
168
+ private handleStopGridCharge;
169
+ private handleSetDischargeLimit;
170
+ private sendCommandAcknowledge;
153
171
  }
154
172
  /**
155
173
  * Sunspec Meter implementation
@@ -3,7 +3,13 @@
3
3
  * SunSpec block interfaces with block numbers
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.SunspecStorageMode = exports.SunspecChargeSource = exports.SunspecVArPctMode = exports.SunspecEnableControl = exports.SunspecConnectionControl = exports.SunspecStorageControlMode = exports.SunspecBatteryChargeState = exports.SunspecMPPTOperatingState = exports.SunspecModelId = void 0;
6
+ exports.SunspecStorageMode = exports.SunspecChargeSource = exports.SunspecVArPctMode = exports.SunspecEnableControl = exports.SunspecConnectionControl = exports.SunspecStorageControlMode = exports.SunspecBatteryChargeState = exports.SunspecMPPTOperatingState = exports.SunspecModelId = exports.DEFAULT_RETRY_CONFIG = void 0;
7
+ exports.DEFAULT_RETRY_CONFIG = {
8
+ initialDelayMs: 1000,
9
+ maxDelayMs: 30000,
10
+ backoffFactor: 1.5,
11
+ maxAttempts: 10
12
+ };
7
13
  /**
8
14
  * Common Sunspec Model IDs
9
15
  */
@@ -1,6 +1,16 @@
1
1
  /**
2
2
  * SunSpec block interfaces with block numbers
3
3
  */
4
+ /**
5
+ * Configuration for connection retry with exponential backoff
6
+ */
7
+ export interface IRetryConfig {
8
+ initialDelayMs: number;
9
+ maxDelayMs: number;
10
+ backoffFactor: number;
11
+ maxAttempts: number;
12
+ }
13
+ export declare const DEFAULT_RETRY_CONFIG: IRetryConfig;
4
14
  /**
5
15
  * Base interface for all SunSpec blocks
6
16
  */