@enyo-energy/sunspec-sdk 0.0.32 → 0.0.34

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.
@@ -16,8 +16,7 @@
16
16
  * - pad: 0x8000 (always returns this value)
17
17
  * - string: all registers 0x0000 (NULL)
18
18
  */
19
- import { SunspecModelId, SunspecBatteryChargeState, SunspecStorageControlMode, SunspecChargeSource, SunspecStorageMode, SunspecBatteryType, SunspecBatteryBankState } from "./sunspec-interfaces.js";
20
- import { ConnectionRetryManager } from "./connection-retry-manager.js";
19
+ import { SunspecModelId, SunspecBatteryChargeState, SunspecStorageControlMode, SunspecChargeSource, SunspecEnableControl, SunspecStorageMode, SunspecBatteryType, SunspecBatteryBankState, } from "./sunspec-interfaces.js";
21
20
  import { EnergyAppModbusConnectionHealth } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusConnectionHealth.js";
22
21
  import { EnergyAppModbusFaultTolerantReader } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusFaultTolerantReader.js";
23
22
  import { EnergyAppModbusDataTypeConverter } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusDataTypeConverter.js";
@@ -30,13 +29,11 @@ export class SunspecModbusClient {
30
29
  faultTolerantReader = null;
31
30
  modbusDataTypeConverter;
32
31
  connectionParams = null;
33
- retryManager;
34
32
  autoReconnectEnabled = true;
35
- constructor(energyApp, retryConfig) {
33
+ constructor(energyApp) {
36
34
  this.energyApp = energyApp;
37
35
  this.connectionHealth = new EnergyAppModbusConnectionHealth();
38
36
  this.modbusDataTypeConverter = new EnergyAppModbusDataTypeConverter();
39
- this.retryManager = new ConnectionRetryManager(retryConfig);
40
37
  }
41
38
  /**
42
39
  * Connect to Modbus device
@@ -63,15 +60,12 @@ export class SunspecModbusClient {
63
60
  }
64
61
  this.connected = true;
65
62
  this.connectionHealth.recordSuccess();
66
- this.retryManager.reset();
67
63
  console.log(`Connected to Sunspec device at ${host}:${port} unit ${unitId}`);
68
64
  }
69
65
  /**
70
66
  * Disconnect from Modbus device
71
67
  */
72
68
  async disconnect() {
73
- // Cancel any pending retry attempts
74
- this.retryManager.cancelPendingRetry();
75
69
  if (this.modbusClient && this.connected) {
76
70
  await this.modbusClient.disconnect();
77
71
  this.modbusClient = null;
@@ -150,61 +144,12 @@ export class SunspecModbusClient {
150
144
  return false;
151
145
  }
152
146
  }
153
- /**
154
- * Check connection health and trigger automatic reconnection if unhealthy
155
- * Returns true if connection is healthy or was successfully restored
156
- */
157
- async ensureHealthyConnection() {
158
- // If already healthy, return immediately
159
- if (this.isHealthy()) {
160
- return true;
161
- }
162
- // If no connection params, we can't reconnect
163
- if (!this.connectionParams) {
164
- console.error('Connection unhealthy and no connection parameters stored for reconnection.');
165
- return false;
166
- }
167
- // If auto-reconnect is disabled, just report the status
168
- if (!this.autoReconnectEnabled) {
169
- console.log('Connection unhealthy but auto-reconnect is disabled.');
170
- return false;
171
- }
172
- // If a retry is already in progress, don't start another
173
- if (this.retryManager.isRetryInProgress()) {
174
- console.log('Retry already in progress...');
175
- return false;
176
- }
177
- console.log('Connection unhealthy, initiating reconnection with exponential backoff...');
178
- // Attempt reconnection with exponential backoff
179
- let success = false;
180
- while (this.retryManager.shouldRetry() && !success) {
181
- success = await this.retryManager.scheduleRetry(() => this.reconnect());
182
- if (success) {
183
- // Re-discover models after successful reconnection
184
- try {
185
- await this.discoverModels();
186
- console.log('Models re-discovered after reconnection.');
187
- }
188
- catch (e) {
189
- console.warn('Failed to re-discover models after reconnection:', e);
190
- }
191
- return true;
192
- }
193
- }
194
- if (!success) {
195
- console.error('Failed to restore healthy connection after all retry attempts.');
196
- }
197
- return success;
198
- }
199
147
  /**
200
148
  * Enable or disable automatic reconnection
201
149
  */
202
150
  setAutoReconnect(enabled) {
203
151
  this.autoReconnectEnabled = enabled;
204
152
  console.log(`Auto-reconnect ${enabled ? 'enabled' : 'disabled'}`);
205
- if (!enabled) {
206
- this.retryManager.cancelPendingRetry();
207
- }
208
153
  }
209
154
  /**
210
155
  * Check if auto-reconnect is enabled
@@ -212,12 +157,6 @@ export class SunspecModbusClient {
212
157
  isAutoReconnectEnabled() {
213
158
  return this.autoReconnectEnabled;
214
159
  }
215
- /**
216
- * Get the retry manager for advanced configuration
217
- */
218
- getRetryManager() {
219
- return this.retryManager;
220
- }
221
160
  /**
222
161
  * Detect the base address and addressing mode (0-based or 1-based) for SunSpec
223
162
  */
@@ -497,7 +436,7 @@ export class SunspecModbusClient {
497
436
  }
498
437
  }
499
438
  /**
500
- * Read inverter data from Model 103 (Three Phase)
439
+ * Read inverter data from Model 101 (Single Phase) / Model 103 (Three Phase)
501
440
  */
502
441
  async readInverterData() {
503
442
  const model = this.findModel(SunspecModelId.Inverter3Phase);
@@ -714,8 +653,7 @@ export class SunspecModbusClient {
714
653
  }
715
654
  }
716
655
  /**
717
- * Read MPPT Scale Factors for a specific module
718
- * Returns the scale factors for DC Current, DC Voltage, DC Power, and DC Energy
656
+ * Read scale factors from Model 160 (MPPT)
719
657
  *
720
658
  * MPPT Model 160 Scale Factor Register Offsets (relative to module start):
721
659
  * - DCA_SF (Current Scale Factor): Offset 2
@@ -835,7 +773,7 @@ export class SunspecModbusClient {
835
773
  }
836
774
  }
837
775
  /**
838
- * Read all available MPPT strings
776
+ * Read all MPPT strings from Model 160 (Multiple MPPT)
839
777
  */
840
778
  async readAllMPPTData() {
841
779
  const mpptData = [];
@@ -1149,7 +1087,7 @@ export class SunspecModbusClient {
1149
1087
  }
1150
1088
  }
1151
1089
  /**
1152
- * Read battery data from Model 124 (Basic Storage Controls)
1090
+ * Read battery data from Model 124 (Basic Storage) with fallback to Model 802 / Model 803
1153
1091
  */
1154
1092
  async readBatteryData() {
1155
1093
  // Try Model 124 first (Basic Storage Controls)
@@ -1417,7 +1355,7 @@ export class SunspecModbusClient {
1417
1355
  return this.writeBatteryControls({ chaGriSet });
1418
1356
  }
1419
1357
  /**
1420
- * Read current battery control settings
1358
+ * Read battery control settings from Model 124 (Basic Storage Controls)
1421
1359
  */
1422
1360
  async readBatteryControls() {
1423
1361
  const model = this.findModel(SunspecModelId.Battery);
@@ -1462,7 +1400,7 @@ export class SunspecModbusClient {
1462
1400
  }
1463
1401
  }
1464
1402
  /**
1465
- * Read meter data (Model 203 for 3-phase)
1403
+ * Read meter data from Model 201 (Single Phase) / Model 203 (Three Phase) / Model 204 (Split Phase)
1466
1404
  */
1467
1405
  async readMeterData() {
1468
1406
  let model = this.findModel(SunspecModelId.Meter3Phase);
@@ -1624,7 +1562,7 @@ export class SunspecModbusClient {
1624
1562
  return this.connectionHealth;
1625
1563
  }
1626
1564
  /**
1627
- * Read Block 121 - Inverter Basic Settings
1565
+ * Read inverter settings from Model 121 (Inverter Settings)
1628
1566
  */
1629
1567
  async readInverterSettings() {
1630
1568
  const model = this.findModel(SunspecModelId.Settings);
@@ -1713,7 +1651,7 @@ export class SunspecModbusClient {
1713
1651
  }
1714
1652
  }
1715
1653
  /**
1716
- * Read Block 123 - Immediate Inverter Controls
1654
+ * Read inverter controls from Model 123 (Immediate Inverter Controls)
1717
1655
  */
1718
1656
  async readInverterControls() {
1719
1657
  const model = this.findModel(SunspecModelId.Controls);
@@ -1843,7 +1781,7 @@ export class SunspecModbusClient {
1843
1781
  }
1844
1782
  }
1845
1783
  /**
1846
- * Write Block 123 - Immediate Inverter Controls
1784
+ * Write inverter controls to Model 123 (Immediate Inverter Controls)
1847
1785
  */
1848
1786
  async writeInverterControls(controls) {
1849
1787
  const model = this.findModel(SunspecModelId.Controls);
@@ -1853,32 +1791,35 @@ export class SunspecModbusClient {
1853
1791
  }
1854
1792
  const baseAddr = model.address;
1855
1793
  try {
1856
- // Connection control
1857
- if (controls.Conn !== undefined && this.modbusClient) {
1858
- // Writing registers needs to be implemented in EnergyAppModbusInstance
1859
- console.log(`Would write connection control ${controls.Conn} to register ${baseAddr + 2}`);
1794
+ // Connection control (Register 2)
1795
+ if (controls.Conn !== undefined) {
1796
+ await this.writeRegisterValue(baseAddr + 2, controls.Conn, 'uint16');
1797
+ console.log(`Set connection control to ${controls.Conn}`);
1860
1798
  }
1861
- // Power limit control
1862
- if (controls.WMaxLimPct !== undefined && this.modbusClient) {
1863
- const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 21, 1);
1864
- const scaleFactor = sfBuffer.readInt16BE(0);
1799
+ // Power limit control (Register 3) - needs scale factor
1800
+ if (controls.WMaxLimPct !== undefined) {
1801
+ const scaleFactor = await this.readRegisterValue(baseAddr + 21, 1, 'int16');
1865
1802
  const scaledValue = Math.round(controls.WMaxLimPct / Math.pow(10, scaleFactor));
1866
- console.log(`Would write power limit ${scaledValue} to register ${baseAddr + 3}`);
1803
+ await this.writeRegisterValue(baseAddr + 3, scaledValue, 'uint16');
1804
+ console.log(`Set power limit to ${controls.WMaxLimPct}% (scaled: ${scaledValue})`);
1867
1805
  }
1868
- if (controls.WMaxLim_Ena !== undefined && this.modbusClient) {
1869
- console.log(`Would write throttle enable ${controls.WMaxLim_Ena} to register ${baseAddr + 7}`);
1806
+ // Throttle enable/disable (Register 7)
1807
+ if (controls.WMaxLim_Ena !== undefined) {
1808
+ await this.writeRegisterValue(baseAddr + 7, controls.WMaxLim_Ena, 'uint16');
1809
+ console.log(`Set throttle enable to ${controls.WMaxLim_Ena}`);
1870
1810
  }
1871
- // Power factor control
1872
- if (controls.OutPFSet !== undefined && this.modbusClient) {
1873
- const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 22, 1);
1874
- const scaleFactor = sfBuffer.readInt16BE(0);
1811
+ // Power factor control (Register 8) - needs scale factor
1812
+ if (controls.OutPFSet !== undefined) {
1813
+ const scaleFactor = await this.readRegisterValue(baseAddr + 22, 1, 'int16');
1875
1814
  const scaledValue = Math.round(controls.OutPFSet / Math.pow(10, scaleFactor));
1876
- console.log(`Would write power factor ${scaledValue} to register ${baseAddr + 8}`);
1815
+ await this.writeRegisterValue(baseAddr + 8, scaledValue, 'int16');
1816
+ console.log(`Set power factor to ${controls.OutPFSet} (scaled: ${scaledValue})`);
1877
1817
  }
1878
- if (controls.OutPFSet_Ena !== undefined && this.modbusClient) {
1879
- console.log(`Would write PF enable ${controls.OutPFSet_Ena} to register ${baseAddr + 12}`);
1818
+ // Power factor enable/disable (Register 12)
1819
+ if (controls.OutPFSet_Ena !== undefined) {
1820
+ await this.writeRegisterValue(baseAddr + 12, controls.OutPFSet_Ena, 'uint16');
1821
+ console.log(`Set PF enable to ${controls.OutPFSet_Ena}`);
1880
1822
  }
1881
- // Add more control writes as needed
1882
1823
  console.log('Inverter controls written successfully');
1883
1824
  return true;
1884
1825
  }
@@ -1887,4 +1828,33 @@ export class SunspecModbusClient {
1887
1828
  return false;
1888
1829
  }
1889
1830
  }
1831
+ /**
1832
+ * Set the inverter feed-in power limit using Model 123 (Immediate Inverter Controls)
1833
+ *
1834
+ * When limitW is a number, reads WMax from Model 121, computes percentage,
1835
+ * writes WMaxLimPct and enables WMaxLim_Ena.
1836
+ * When limitW is null, disables the limit by setting WMaxLim_Ena = DISABLED.
1837
+ *
1838
+ * @param limitW - Power limit in Watts, or null to remove the limit
1839
+ * @returns true if successful, false otherwise
1840
+ */
1841
+ async setFeedInLimit(limitW) {
1842
+ if (limitW === null) {
1843
+ // Remove limit: disable WMaxLim_Ena
1844
+ console.log('Removing feed-in limit (disabling WMaxLim_Ena)');
1845
+ return this.writeInverterControls({ WMaxLim_Ena: SunspecEnableControl.DISABLED });
1846
+ }
1847
+ // Read WMax from Model 121 to compute percentage
1848
+ const settings = await this.readInverterSettings();
1849
+ if (!settings || !settings.WMax) {
1850
+ console.error('Cannot set feed-in limit: unable to read WMax from Model 121');
1851
+ return false;
1852
+ }
1853
+ const pct = (limitW / settings.WMax) * 100;
1854
+ console.log(`Setting feed-in limit to ${limitW}W (${pct.toFixed(2)}% of WMax ${settings.WMax}W)`);
1855
+ return this.writeInverterControls({
1856
+ WMaxLimPct: pct,
1857
+ WMaxLim_Ena: SunspecEnableControl.ENABLED
1858
+ });
1859
+ }
1890
1860
  }
package/dist/version.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Current version of the enyo Energy App SDK.
7
7
  */
8
- export declare const SDK_VERSION = "0.0.32";
8
+ export declare const SDK_VERSION = "0.0.34";
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK
package/dist/version.js CHANGED
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Current version of the enyo Energy App SDK.
7
7
  */
8
- export const SDK_VERSION = '0.0.32';
8
+ export const SDK_VERSION = '0.0.34';
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enyo-energy/sunspec-sdk",
3
- "version": "0.0.32",
3
+ "version": "0.0.34",
4
4
  "description": "enyo Energy Sunspec SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -37,7 +37,7 @@
37
37
  "typescript": "^5.8.3"
38
38
  },
39
39
  "dependencies": {
40
- "@enyo-energy/energy-app-sdk": "^0.0.60"
40
+ "@enyo-energy/energy-app-sdk": "^0.0.68"
41
41
  },
42
42
  "volta": {
43
43
  "node": "22.17.0"